From 439234e507c834e6cdd544fb2f8a7f5df5f31dd7 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 3 Jan 2023 10:08:08 +0100 Subject: [PATCH 0001/1089] Updated `.gitignore` --- .gitignore | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2380e02e..d3dc09b3 100644 --- a/.gitignore +++ b/.gitignore @@ -290,5 +290,75 @@ dist .pnp.* ### Docker Compose - *.prod.yml + +### C template +# Object files +*.ko +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers + +# Libraries + +# Shared objects (inc. Windows DLLs) +*.so.* + +# Executables +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +### C++ template +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app From 636d2ba75d67886f05656c937eeb559219255314 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 3 Jan 2023 10:10:34 +0100 Subject: [PATCH 0002/1089] Adding new project module --- .idea/encodings.xml | 2 ++ dl4se-tree-sitter/pom.xml | 18 ++++++++++++++++++ pom.xml | 1 + 3 files changed, 21 insertions(+) create mode 100644 dl4se-tree-sitter/pom.xml diff --git a/.idea/encodings.xml b/.idea/encodings.xml index 16f8e3eb..eacbf96d 100644 --- a/.idea/encodings.xml +++ b/.idea/encodings.xml @@ -13,5 +13,7 @@ + + \ No newline at end of file diff --git a/dl4se-tree-sitter/pom.xml b/dl4se-tree-sitter/pom.xml new file mode 100644 index 00000000..ed7145ce --- /dev/null +++ b/dl4se-tree-sitter/pom.xml @@ -0,0 +1,18 @@ + + + 4.0.0 + + dl4se + usi.si.seart + ${revision} + ../pom.xml + + + dl4se-tree-sitter + + dl4se-tree-sitter + + + UTF-8 + + diff --git a/pom.xml b/pom.xml index 3570691e..3880ddaa 100644 --- a/pom.xml +++ b/pom.xml @@ -28,6 +28,7 @@ dl4se-model dl4se-server dl4se-src2abs + dl4se-tree-sitter From f203f0c69a8234cb06eb2a7e7ac7583b4c722ad7 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 3 Jan 2023 10:12:31 +0100 Subject: [PATCH 0003/1089] Adding required `tree-sitter` submodules --- .gitmodules | 18 ++++++++++++++++++ .idea/vcs.xml | 6 ++++++ dl4se-tree-sitter/tree-sitter | 1 + dl4se-tree-sitter/tree-sitter-c | 1 + dl4se-tree-sitter/tree-sitter-cpp | 1 + dl4se-tree-sitter/tree-sitter-java | 1 + dl4se-tree-sitter/tree-sitter-javascript | 1 + dl4se-tree-sitter/tree-sitter-python | 1 + 8 files changed, 30 insertions(+) create mode 100644 .gitmodules create mode 160000 dl4se-tree-sitter/tree-sitter create mode 160000 dl4se-tree-sitter/tree-sitter-c create mode 160000 dl4se-tree-sitter/tree-sitter-cpp create mode 160000 dl4se-tree-sitter/tree-sitter-java create mode 160000 dl4se-tree-sitter/tree-sitter-javascript create mode 160000 dl4se-tree-sitter/tree-sitter-python diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..5bebf0a5 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,18 @@ +[submodule "tree-sitter"] + path = dl4se-tree-sitter/tree-sitter + url = https://github.com/tree-sitter/tree-sitter.git +[submodule "tree-sitter-c"] + path = dl4se-tree-sitter/tree-sitter-c + url = https://github.com/tree-sitter/tree-sitter-c.git +[submodule "tree-sitter-cpp"] + path = dl4se-tree-sitter/tree-sitter-cpp + url = https://github.com/tree-sitter/tree-sitter-cpp.git +[submodule "tree-sitter-java"] + path = dl4se-tree-sitter/tree-sitter-java + url = https://github.com/tree-sitter/tree-sitter-java.git +[submodule "tree-sitter-javascript"] + path = dl4se-tree-sitter/tree-sitter-javascript + url = https://github.com/tree-sitter/tree-sitter-javascript.git +[submodule "tree-sitter-python"] + path = dl4se-tree-sitter/tree-sitter-python + url = https://github.com/tree-sitter/tree-sitter-python.git diff --git a/.idea/vcs.xml b/.idea/vcs.xml index a081b18c..a0ee5a33 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -9,5 +9,11 @@ + + + + + + \ No newline at end of file diff --git a/dl4se-tree-sitter/tree-sitter b/dl4se-tree-sitter/tree-sitter new file mode 160000 index 00000000..e85a279c --- /dev/null +++ b/dl4se-tree-sitter/tree-sitter @@ -0,0 +1 @@ +Subproject commit e85a279cf29da1b08648e27214dda20a841e57c8 diff --git a/dl4se-tree-sitter/tree-sitter-c b/dl4se-tree-sitter/tree-sitter-c new file mode 160000 index 00000000..a584fc98 --- /dev/null +++ b/dl4se-tree-sitter/tree-sitter-c @@ -0,0 +1 @@ +Subproject commit a584fc98ca1bbbb9788d55026f8b483bd725a60a diff --git a/dl4se-tree-sitter/tree-sitter-cpp b/dl4se-tree-sitter/tree-sitter-cpp new file mode 160000 index 00000000..f4450914 --- /dev/null +++ b/dl4se-tree-sitter/tree-sitter-cpp @@ -0,0 +1 @@ +Subproject commit f44509141e7e483323d2ec178f2d2e6c0fc041c1 diff --git a/dl4se-tree-sitter/tree-sitter-java b/dl4se-tree-sitter/tree-sitter-java new file mode 160000 index 00000000..ac14b4b1 --- /dev/null +++ b/dl4se-tree-sitter/tree-sitter-java @@ -0,0 +1 @@ +Subproject commit ac14b4b1884102839455d32543ab6d53ae089ab7 diff --git a/dl4se-tree-sitter/tree-sitter-javascript b/dl4se-tree-sitter/tree-sitter-javascript new file mode 160000 index 00000000..fdeb68ac --- /dev/null +++ b/dl4se-tree-sitter/tree-sitter-javascript @@ -0,0 +1 @@ +Subproject commit fdeb68ac8d2bd5a78b943528bb68ceda3aade2eb diff --git a/dl4se-tree-sitter/tree-sitter-python b/dl4se-tree-sitter/tree-sitter-python new file mode 160000 index 00000000..2b9e9e0d --- /dev/null +++ b/dl4se-tree-sitter/tree-sitter-python @@ -0,0 +1 @@ +Subproject commit 2b9e9e0d231d5dd9f491d47f704817baee7d5af0 From 98484baee8420e421f467993c7dc024c3adcbdb0 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 3 Jan 2023 10:38:23 +0100 Subject: [PATCH 0004/1089] Migrating classes from `src/main/java` Includes Lombok integration into our `java-tree-sitter` fork --- .../usi/si/seart/treesitter/InputEdit.java | 19 ++ .../usi/si/seart/treesitter/Language.java | 56 +++++ .../usi/si/seart/treesitter/Languages.java | 40 ++++ .../si/seart/treesitter/LibraryLoader.java | 47 ++++ .../java/usi/si/seart/treesitter/Node.java | 218 ++++++++++++++++++ .../java/usi/si/seart/treesitter/Parser.java | 80 +++++++ .../java/usi/si/seart/treesitter/Point.java | 20 ++ .../java/usi/si/seart/treesitter/Query.java | 44 ++++ .../usi/si/seart/treesitter/QueryCapture.java | 15 ++ .../usi/si/seart/treesitter/QueryCursor.java | 46 ++++ .../usi/si/seart/treesitter/QueryMatch.java | 16 ++ .../java/usi/si/seart/treesitter/Range.java | 21 ++ .../java/usi/si/seart/treesitter/Tree.java | 39 ++++ .../usi/si/seart/treesitter/TreeCursor.java | 93 ++++++++ .../si/seart/treesitter/TreeCursorNode.java | 20 ++ .../usi/si/seart/treesitter/TreePrinter.java | 59 +++++ .../usi/si/seart/treesitter/TreeSitter.java | 97 ++++++++ .../seart/treesitter/TreeSitterException.java | 7 + 18 files changed, 937 insertions(+) create mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/InputEdit.java create mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Language.java create mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Languages.java create mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/LibraryLoader.java create mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java create mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java create mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Point.java create mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java create mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCapture.java create mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCursor.java create mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryMatch.java create mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Range.java create mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java create mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursor.java create mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursorNode.java create mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreePrinter.java create mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitter.java create mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitterException.java diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/InputEdit.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/InputEdit.java new file mode 100644 index 00000000..fcc88784 --- /dev/null +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/InputEdit.java @@ -0,0 +1,19 @@ +package usi.si.seart.treesitter; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.experimental.FieldDefaults; + +@Getter +@AllArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +public class InputEdit { + + int startByte; + int oldEndByte; + int newEndByte; + Point startPoint; + Point oldEndPoint; + Point newEndPoint; +} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Language.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Language.java new file mode 100644 index 00000000..83a44671 --- /dev/null +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Language.java @@ -0,0 +1,56 @@ +package usi.si.seart.treesitter; + +import lombok.Getter; + +import java.util.function.LongSupplier; + +public enum Language { + + AGDA(Languages::agda), + BASH(Languages::bash), + C(Languages::c), + CSHARP(Languages::cSharp), + CPP(Languages::cpp), + CSS(Languages::css), + DART(Languages::dart), + ELM(Languages::elm), + EMBEDDED_TEMPLATE(Languages::embeddedTemplate), + ENO(Languages::eno), + GO(Languages::go), + HASKELL(Languages::haskell), + HTML(Languages::html), + JAVA(Languages::java), + JAVASCRIPT(Languages::javascript), + JULIA(Languages::julia), + KOTLIN(Languages::kotlin), + LUA(Languages::lua), + MARKDOWN(Languages::markdown), + OCAML(Languages::ocaml), + PHP(Languages::php), + PYTHON(Languages::python), + RUBY(Languages::ruby), + RUST(Languages::rust), + SCALA(Languages::scala), + SCSS(Languages::scss), + SWIFT(Languages::swift), + TOML(Languages::toml), + TSX(Languages::tsx), + TYPESCRIPT(Languages::typescript), + VUE(Languages::vue), + YAML(Languages::yaml), + WASM(Languages::wasm); + + @Getter + private final long id; + + Language(LongSupplier supplier) { + long id = 0L; + try { + id = supplier.getAsLong(); + } catch (UnsatisfiedLinkError ignored) { + // Triggered whenever a language is not included in the native library. + } finally { + this.id = id; + } + } +} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Languages.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Languages.java new file mode 100644 index 00000000..383ee50a --- /dev/null +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Languages.java @@ -0,0 +1,40 @@ +package usi.si.seart.treesitter; + +import lombok.experimental.UtilityClass; + +@UtilityClass +class Languages { + static native long agda(); + static native long bash(); + static native long c(); + static native long cSharp(); + static native long cpp(); + static native long css(); + static native long dart(); + static native long elm(); + static native long embeddedTemplate(); + static native long eno(); + static native long go(); + static native long haskell(); + static native long html(); + static native long java(); + static native long javascript(); + static native long julia(); + static native long kotlin(); + static native long lua(); + static native long markdown(); + static native long ocaml(); + static native long php(); + static native long python(); + static native long ruby(); + static native long rust(); + static native long scala(); + static native long scss(); + static native long swift(); + static native long toml(); + static native long tsx(); + static native long typescript(); + static native long vue(); + static native long yaml(); + static native long wasm(); +} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/LibraryLoader.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/LibraryLoader.java new file mode 100644 index 00000000..1749d608 --- /dev/null +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/LibraryLoader.java @@ -0,0 +1,47 @@ +package usi.si.seart.treesitter; + +import lombok.experimental.UtilityClass; + +import java.io.FileNotFoundException; +import java.net.URL; + +@UtilityClass +public class LibraryLoader { + + public void load() { + String format = "libjava-tree-sitter.%s"; + String filename; + switch (currentOS()) { + case MACOS: + filename = String.format(format, "dylib"); + break; + case LINUX: + filename = String.format(format, "so"); + break; + default: + throw new TreeSitterException("tree-sitter library was not compiled for this platform!"); + } + URL libURL = ClassLoader.getSystemResource(filename); + if (libURL != null) { + String libPath = libURL.getPath(); + System.load(libPath); + } else { + Exception cause = new FileNotFoundException("Resource could not be found!"); + throw new TreeSitterException(cause); + } + } + + private OS currentOS() { + String osName = System.getProperty("os.name").toLowerCase(); + if (osName.contains("nix") || osName.contains("nux") || osName.contains("aix")) + return OS.LINUX; + else if (osName.contains("mac") || osName.contains("darwin")) + return OS.MACOS; + else + return OS.UNSUPPORTED; + } + + private enum OS { + MACOS, LINUX, UNSUPPORTED + } +} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java new file mode 100644 index 00000000..e2529747 --- /dev/null +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java @@ -0,0 +1,218 @@ +package usi.si.seart.treesitter; + +import lombok.NoArgsConstructor; + +/** + * A Node represents a single node in the syntax tree. It tracks its start and end positions in the source code, + * as well as its relation to other nodes like its parent, siblings and children. + */ +@NoArgsConstructor +public class Node { + private int context0; + private int context1; + private int context2; + private int context3; + private long id; + private long tree; + + /** + * Get the node's child at the given index, where zero represents the first child. + * + * @param child The zero-indexed child + * @return The Node's child at the given index + */ + public Node getChild(int child) { + return TreeSitter.nodeChild(this, child); + } + + /** + * @param name The node field name. + * @return The node's child with the given field name. + */ + public Node getChildByFieldName(String name) { + return TreeSitter.nodeChildByFieldName(this, name); + } + + /** + * @return The node's number of children. + */ + public int getChildCount() { + return TreeSitter.nodeChildCount(this); + } + + /** + * @param startByte The starting byte of the range + * @param endByte The ending byte of the range + * @return The smallest node within this node that spans the given range of bytes + */ + public Node getDescendantForByteRange(int startByte, int endByte) { + return TreeSitter.nodeDescendantForByteRange(this, startByte, endByte); + } + + /** + * @return The node's end byte. + */ + public int getEndByte() { + return TreeSitter.nodeEndByte(this); + } + + /** + * @return The node's end position in terms of rows and columns. + */ + public Point getEndPoint() { + return TreeSitter.nodeEndPoint(this); + } + + /** + * @return The field name for node's child at the given index, where zero represents the first child. + * Returns NULL, if no field is found. + */ + public String getFieldNameForChild(int child) { + return TreeSitter.nodeFieldNameForChild(this, child); + } + + /** + * @param offset The offset in bytes. + * @return The node's first child that extends beyond the given byte offset. + */ + public Node getFirstChildForByte(int offset) { + return TreeSitter.nodeFirstChildForByte(this, offset); + } + + /** + * @param offset The offset in bytes. + * @return The node's first named child that extends beyond the given byte offset. + */ + public Node getFirstNamedChildForByte(int offset) { + return TreeSitter.nodeFirstNamedChildForByte(this, offset); + } + + /** + * This string is allocated with malloc and the caller is responsible for freeing it using free. + * + * @return An S-expression representing the node as a string. + */ + public String getNodeString() { + return TreeSitter.nodeString(this); + } + + /** + * @return The node's next named sibling. + */ + public Node getNextNamedSibling() { + return TreeSitter.nodeNextNamedSibling(this); + } + + /** + * @return The node's next sibling. + */ + public Node getNextSibling() { + return TreeSitter.nodeNextSibling(this); + } + + /** + * @return The node's previous named sibling. + */ + public Node getPrevNamedSibling() { + return TreeSitter.nodePrevNamedSibling(this); + } + + /** + * @return The node's previous sibling. + */ + public Node getPrevSibling() { + return TreeSitter.nodePrevSibling(this); + } + + /** + * @return The node's immediate parent. + */ + public Node getParent() { + return TreeSitter.nodeParent(this); + } + + public Range getRange() { + return new Range(this); + } + + /** + * @return The node's start byte. + */ + public int getStartByte() { + return TreeSitter.nodeStartByte(this); + } + + /** + * @return The node's start position in terms of rows and columns. + */ + public Point getStartPoint() { + return TreeSitter.nodeStartPoint(this); + } + + /** + * @return The node's type as a null-terminated string + */ + public String getType() { + return TreeSitter.nodeType(this); + } + + /** + * @return true if the node is a syntax error or contains any syntax errors, false otherwise. + */ + public boolean hasError() { + return TreeSitter.nodeHasError(this); + } + + /** + * Check if the node is extra. Extra nodes represent things like comments, + * which are not required the grammar, but can appear anywhere. + * + * @return true if the node is an extra, false otherwise. + */ + public boolean isExtra() { + return TreeSitter.nodeIsExtra(this); + } + + /** + * Check if the node is missing. Missing nodes are inserted by the parser in order to recover from certain + * kinds of syntax errors. + * + * @return true if the node is missing, false otherwise. + */ + public boolean isMissing() { + return TreeSitter.nodeIsMissing(this); + } + + /** + * Check if the node is named. Named nodes correspond to named rules in the grammar, whereas anonymous nodes + * correspond to string literals in the grammar. + * + * @return true if the node is named, false otherwise. + */ + public boolean isNamed() { + return TreeSitter.nodeIsNamed(this); + } + + /** + * A tree cursor allows you to walk a syntax tree more efficiently than is possible using the TSNode functions. + * It is a mutable object that is always on a certain syntax node, and can be moved imperatively to different nodes. + * + * @return A new tree cursor starting from the given node. + */ + public TreeCursor walk() { + return new TreeCursor(TreeSitter.treeCursorNew(this)); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + if (obj == null || getClass() != obj.getClass()) return false; + Node other = (Node) obj; + return TreeSitter.nodeEq(this, other); + } + + @Override + public int hashCode() { + return Long.hashCode(id); + } +} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java new file mode 100644 index 00000000..578a6ca0 --- /dev/null +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java @@ -0,0 +1,80 @@ +package usi.si.seart.treesitter; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; + +import java.io.File; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; + +/** + * Parsers are stateful objects that can be assigned a language and used to produce a + * {@link Tree Tree} based on some source code. + */ +@AllArgsConstructor(access = AccessLevel.PACKAGE) +public class Parser implements AutoCloseable { + + private final long pointer; + + public Parser() { + this(TreeSitter.parserNew()); + } + + /** + * Set the language that the parser should use for parsing. + * + * @param language The language used for parsing. + */ + public void setLanguage(Language language) { + TreeSitter.parserSetLanguage(pointer, language.getId()); + } + + /** + * Use the parser to parse some source code stored in one contiguous buffer. + * + * @param source The source code string to be parsed. + * @return A tree-sitter Tree matching the provided source. + */ + public Tree parseString(String source) throws UnsupportedEncodingException { + byte[] bytes = source.getBytes(StandardCharsets.UTF_16LE); + return new Tree(TreeSitter.parserParseBytes(pointer, bytes, bytes.length)); + } + + public Tree parseString(Tree oldTree, String source) throws UnsupportedEncodingException { + byte[] bytes = source.getBytes(StandardCharsets.UTF_16LE); + return new Tree(TreeSitter.parserIncrementalParseBytes(pointer, oldTree.getPointer(), bytes, bytes.length)); + } + + /** + * Use the parser to parse some source code found in a file at the specified path. + * + * @param path The path of the file to be parsed. + * @return A tree-sitter Tree matching the provided source. + */ + public Tree parseFile(Path path) throws IOException { + String source = Files.readString(path); + return parseString(source); + } + + /** + * Use the parser to parse some source code found in a file represented by the reference. + * + * @param file The reference to the file which will be parsed. + * @return A tree-sitter Tree matching the provided source. + */ + public Tree parseFile(File file) throws IOException { + Path path = file.toPath(); + return parseFile(path); + } + + /** + * Delete the parser, freeing all the memory that it used. + */ + @Override + public void close() { + TreeSitter.parserDelete(pointer); + } +} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Point.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Point.java new file mode 100644 index 00000000..405ab050 --- /dev/null +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Point.java @@ -0,0 +1,20 @@ +package usi.si.seart.treesitter; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.experimental.FieldDefaults; + +@Getter +@AllArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +public class Point { + + int row; + int column; + + @Override + public String toString() { + return row + ":" + column; + } +} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java new file mode 100644 index 00000000..e1a412ff --- /dev/null +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java @@ -0,0 +1,44 @@ +package usi.si.seart.treesitter; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * A query consists of one or more patterns, where each pattern is an S-expression that matches a certain set of nodes + * in a syntax tree. The query is associated with a particular language, and can only be run on syntax nodes parsed with + * that language. The expression to match a given node consists of a pair of parentheses containing two things: the + * node's type, and optionally, a series of other S-expressions that match the node's children. For example, this + * pattern would match any {@code binary_expression} node whose children are both {@code number_literal} nodes: + * + *
+ *     (binary_expression (number_literal) (number_literal))
+ * 
+ * + * Children can also be omitted. For example, this would match any {@code binary_expression} where at least one of + * child is a {@code string_literal} node: + * + *
+ *     (binary_expression (string_literal))
+ * 
+ * + * @apiNote The underlying query value is immutable and can be safely shared between threads. + */ +@Getter +@AllArgsConstructor(access = AccessLevel.PACKAGE) +public class Query implements AutoCloseable { + + private final long pointer; + + public Query(Language language, String source) { + this(TreeSitter.queryNew(language.getId(), source)); + } + + /** + * Delete a query, freeing all the memory that it used. + */ + @Override + public void close() { + TreeSitter.queryDelete(pointer); + } +} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCapture.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCapture.java new file mode 100644 index 00000000..3f47e89b --- /dev/null +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCapture.java @@ -0,0 +1,15 @@ +package usi.si.seart.treesitter; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.experimental.FieldDefaults; + +@Getter +@AllArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +public class QueryCapture { + + Node node; + int index; +} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCursor.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCursor.java new file mode 100644 index 00000000..6c5c9e6f --- /dev/null +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCursor.java @@ -0,0 +1,46 @@ +package usi.si.seart.treesitter; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; + +/** + * Cursor used for executing queries, carrying the state needed to process them. + * + * @apiNote The query cursor should not be shared between threads, but can be reused for many query executions. + */ +@AllArgsConstructor(access = AccessLevel.PACKAGE) +public class QueryCursor implements AutoCloseable { + + private final long pointer; + + public QueryCursor() { + this(TreeSitter.queryCursorNew()); + } + + /** + * Start running a given query on a given node. + * + * @param query The query to execute. + * @param node The node which the query will be executed on. + */ + public void execQuery(Query query, Node node) { + TreeSitter.queryCursorExec(pointer, query.getPointer(), node); + } + + /** + * Advance to the next match of the currently running query. + * + * @return A match if there is one, null otherwise. + */ + public QueryMatch nextMatch() { + return TreeSitter.queryCursorNextMatch(pointer); + } + + /** + * Delete a query cursor, freeing all the memory that it used. + */ + @Override + public void close() { + TreeSitter.queryCursorDelete(pointer); + } +} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryMatch.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryMatch.java new file mode 100644 index 00000000..dc4826e0 --- /dev/null +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryMatch.java @@ -0,0 +1,16 @@ +package usi.si.seart.treesitter; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.experimental.FieldDefaults; + +@Getter +@AllArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +public class QueryMatch { + + int id; + int pattern_index; + QueryCapture[] captures; +} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Range.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Range.java new file mode 100644 index 00000000..94124908 --- /dev/null +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Range.java @@ -0,0 +1,21 @@ +package usi.si.seart.treesitter; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.experimental.FieldDefaults; + +@Getter +@AllArgsConstructor(access = AccessLevel.PACKAGE) +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +public class Range { + + int startByte; + int endByte; + Point startPoint; + Point endPoint; + + public Range(Node node) { + this(node.getStartByte(), node.getEndByte(), node.getStartPoint(), node.getEndPoint()); + } +} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java new file mode 100644 index 00000000..7b50b068 --- /dev/null +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java @@ -0,0 +1,39 @@ +package usi.si.seart.treesitter; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * A Tree represents the syntax tree of an entire source code file. It contains {@link Node Node} + * instances that indicate the structure of the source code. + */ +@Getter +@AllArgsConstructor +public class Tree implements AutoCloseable { + + private final long pointer; + + /** + * Delete the syntax tree, freeing all the memory that it used. + */ + @Override + public void close() { + TreeSitter.treeDelete(pointer); + } + + /** + * Edit the syntax tree to keep it in sync with source code that has been edited. + * + * @param edit Changes made to the source code in terms of both byte offsets and row/column coordinates. + */ + public void edit(InputEdit edit) { + TreeSitter.treeEdit(pointer, edit); + } + + /** + * @return The root node of the syntax tree. + */ + public Node getRootNode() { + return TreeSitter.treeRootNode(pointer); + } +} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursor.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursor.java new file mode 100644 index 00000000..6bb4b849 --- /dev/null +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursor.java @@ -0,0 +1,93 @@ +package usi.si.seart.treesitter; + +import lombok.RequiredArgsConstructor; + +import java.util.function.Consumer; + +/** + * A tree cursor is a stateful object that allows you to walk a syntax tree with maximum efficiency. + */ +@RequiredArgsConstructor +public class TreeCursor implements AutoCloseable { + + private final long pointer; + private int context0; + private int context1; + private long id; + private long tree; + + /** + * Delete the tree cursor, freeing all the memory that it used. + */ + @Override + public void close() { + TreeSitter.treeCursorDelete(pointer); + } + + /** + * @return The tree cursor's current node. + */ + public Node getCurrentNode() { + return TreeSitter.treeCursorCurrentNode(pointer); + } + + /** + * @return The field name of the tree cursor's current node. + * Will return null if the current node doesn't have a field. + */ + public String getCurrentFieldName() { + return TreeSitter.treeCursorCurrentFieldName(pointer); + } + + /** + * @return The tree cursor's current node. + */ + public TreeCursorNode getCurrentTreeCursorNode() { + return TreeSitter.treeCursorCurrentTreeCursorNode(pointer); + } + + /** + * Move the cursor to the first child of its current node. + * + * @return true if the cursor successfully moved, and false if there were no children. + */ + public boolean gotoFirstChild() { + return TreeSitter.treeCursorGotoFirstChild(pointer); + } + + /** + * Move the cursor to the next sibling of its current node. + * + * @return true if the cursor successfully moved, and false if there was no next sibling node. + */ + public boolean gotoNextSibling() { + return TreeSitter.treeCursorGotoNextSibling(pointer); + } + + /** + * Move the cursor to the parent of its current node. + * + * @return true if the cursor successfully moved, and false if there was no parent node + * (the cursor was already on the root node). + */ + public boolean gotoParent() { + return TreeSitter.treeCursorGotoParent(pointer); + } + + /** + * Iteratively traverse over the parse tree, applying a callback to the nodes before they are visited. + * + * @param callback The callback consumer which will execute upon visiting a node. + */ + public void preorderTraversal(Consumer callback) { + for (;;) { + callback.accept(this.getCurrentNode()); + if (this.gotoFirstChild() || this.gotoNextSibling()) + continue; + do { + if (!this.gotoParent()) + return; + } while (!this.gotoNextSibling()); + } + } +} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursorNode.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursorNode.java new file mode 100644 index 00000000..eac4b480 --- /dev/null +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursorNode.java @@ -0,0 +1,20 @@ +package usi.si.seart.treesitter; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.experimental.FieldDefaults; + +@Getter +@AllArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +public class TreeCursorNode { + + String type; + String name; + int startByte; + int endByte; + Point startPoint; + Point endPoint; + boolean isNamed; +} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreePrinter.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreePrinter.java new file mode 100644 index 00000000..a3022628 --- /dev/null +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreePrinter.java @@ -0,0 +1,59 @@ +package usi.si.seart.treesitter; + +import lombok.AccessLevel; +import lombok.Cleanup; +import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; + +/** + * Utility used for pretty-printing parse trees. + */ +@RequiredArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE) +public class TreePrinter { + + int indentLevel = 0; + final Tree tree; + + /** + * @return A string representation of the parse tree. Consists only of named nodes. + */ + public String printParseTree() { + StringBuilder stringBuilder = new StringBuilder(); + Node root = this.tree.getRootNode(); + @Cleanup TreeCursor cursor = root.walk(); + for (;;) { + TreeCursorNode treeCursorNode = cursor.getCurrentTreeCursorNode(); + if (treeCursorNode.isNamed()) { + String treeNode = printTreeNode(treeCursorNode); + stringBuilder.append(treeNode); + } + if (cursor.gotoFirstChild()) { + indentLevel++; + continue; + } + if (cursor.gotoNextSibling()) { + continue; + } + do { + if (cursor.gotoParent()) { + indentLevel--; + } else { + return stringBuilder.toString(); + } + } while (!cursor.gotoNextSibling()); + } + } + + private String printTreeNode(TreeCursorNode treeCursorNode) { + String name = treeCursorNode.getName(); + String type = treeCursorNode.getType(); + Point startPoint = treeCursorNode.getStartPoint(); + Point endPoint = treeCursorNode.getEndPoint(); + return String.format("%s%s%s [%s] - [%s]%n", + " ".repeat(this.indentLevel), + (name != null) ? name + ": " : "", + type, startPoint, endPoint + ); + } +} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitter.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitter.java new file mode 100644 index 00000000..ff95245d --- /dev/null +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitter.java @@ -0,0 +1,97 @@ +package usi.si.seart.treesitter; + +import lombok.experimental.UtilityClass; + +@UtilityClass +class TreeSitter { + + static native Node nodeChild(Node node, int child); + + static native Node nodeChildByFieldName(Node node, String name); + + static native int nodeChildCount(Node node); + + static native Node nodeDescendantForByteRange(Node node, int startByte, int endByte); + + static native int nodeEndByte(Node node); + + static native Point nodeEndPoint(Node node); + + static native boolean nodeEq(Node node, Node other); + + static native String nodeFieldNameForChild(Node node, int child); + + static native Node nodeFirstChildForByte(Node node, int offset); + + static native Node nodeFirstNamedChildForByte(Node node, int offset); + + static native boolean nodeHasError(Node node); + + static native boolean nodeIsExtra(Node node); + + static native boolean nodeIsMissing(Node node); + + static native boolean nodeIsNamed(Node node); + + static native Node nodeParent(Node node); + + static native Node nodePrevNamedSibling(Node node); + + static native Node nodePrevSibling(Node node); + + static native Node nodeNextNamedSibling(Node node); + + static native Node nodeNextSibling(Node node); + + static native int nodeStartByte(Node node); + + static native Point nodeStartPoint(Node node); + + static native String nodeString(Node node); + + static native String nodeType(Node node); + + static native long parserNew(); + + static native void parserDelete(long parser); + + static native void parserSetLanguage(long parser, long language); + + static native long parserParseBytes(long parser, byte[] source, int length); + + static native long parserIncrementalParseBytes(long parser, long old_tree, byte[] source, int length); + + static native void queryDelete(long query); + + static native long queryNew(long language, String source); + + static native void queryCursorDelete(long query_cursor); + + static native long queryCursorNew(); + + static native void queryCursorExec(long query_cursor, long query, Node node); + + static native QueryMatch queryCursorNextMatch(long query_cursor); + + static native long treeCursorNew(Node node); + + static native TreeCursorNode treeCursorCurrentTreeCursorNode(long cursor); + + static native String treeCursorCurrentFieldName(long cursor); + + static native Node treeCursorCurrentNode(long cursor); + + static native void treeCursorDelete(long cursor); + + static native boolean treeCursorGotoFirstChild(long cursor); + + static native boolean treeCursorGotoNextSibling(long cursor); + + static native boolean treeCursorGotoParent(long cursor); + + static native void treeDelete(long tree); + + static native void treeEdit(long tree, InputEdit edit); + + static native Node treeRootNode(long tree); +} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitterException.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitterException.java new file mode 100644 index 00000000..25453e17 --- /dev/null +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitterException.java @@ -0,0 +1,7 @@ +package usi.si.seart.treesitter; + +import lombok.experimental.StandardException; + +@StandardException +public class TreeSitterException extends RuntimeException { +} From 2c12e96c39c1fcf6f41ba9ea114f0640c7a704c2 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 3 Jan 2023 10:38:54 +0100 Subject: [PATCH 0005/1089] Committing `resources` directory --- dl4se-tree-sitter/src/main/resources/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 dl4se-tree-sitter/src/main/resources/.gitkeep diff --git a/dl4se-tree-sitter/src/main/resources/.gitkeep b/dl4se-tree-sitter/src/main/resources/.gitkeep new file mode 100644 index 00000000..e69de29b From d508578c54d990ec13a9f91c5dd1bead1d5fd4e9 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 3 Jan 2023 10:39:29 +0100 Subject: [PATCH 0006/1089] Migrating classes from `src/test/java` Includes Lombok integration into our `java-tree-sitter` fork tests --- .../usi/si/seart/treesitter/NodeTest.java | 239 ++++++++++++++++++ .../usi/si/seart/treesitter/ParserTest.java | 45 ++++ .../si/seart/treesitter/QueryCursorTest.java | 34 +++ .../usi/si/seart/treesitter/QueryTest.java | 20 ++ .../usi/si/seart/treesitter/TestBase.java | 8 + .../si/seart/treesitter/TreeCursorTest.java | 39 +++ .../usi/si/seart/treesitter/TreeTest.java | 41 +++ 7 files changed, 426 insertions(+) create mode 100644 dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java create mode 100644 dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/ParserTest.java create mode 100644 dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryCursorTest.java create mode 100644 dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java create mode 100644 dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TestBase.java create mode 100644 dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeCursorTest.java create mode 100644 dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeTest.java diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java new file mode 100644 index 00000000..6f38db9d --- /dev/null +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java @@ -0,0 +1,239 @@ +package usi.si.seart.treesitter; + +import lombok.Cleanup; +import lombok.SneakyThrows; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.io.UnsupportedEncodingException; + +class NodeTest extends TestBase { + + private static final String source = "def foo(bar, baz):\n print(bar)\n print(baz)"; + + @Test + @SneakyThrows({UnsupportedEncodingException.class}) + void testGetChild() { + @Cleanup Parser parser = new Parser(); + parser.setLanguage(Language.PYTHON); + @Cleanup Tree tree = parser.parseString(source); + Node root = tree.getRootNode(); + Assertions.assertEquals(1, root.getChildCount()); + Assertions.assertEquals("module", root.getType()); + Assertions.assertEquals(0, root.getStartByte()); + Assertions.assertEquals(44, root.getEndByte()); + + Node function = root.getChild(0); + Assertions.assertEquals("function_definition", function.getType()); + Assertions.assertEquals(5, function.getChildCount()); + } + + @Test + @SneakyThrows({UnsupportedEncodingException.class}) + void testGetChildByFieldName() { + @Cleanup Parser parser = new Parser(); + parser.setLanguage(Language.PYTHON); + @Cleanup Tree tree = parser.parseString(source); + Node root = tree.getRootNode(); + Node function = root.getChild(0); + Node identifier = function.getChild(1); + Assertions.assertEquals(identifier, function.getChildByFieldName("name")); + } + + @Test + @SneakyThrows({UnsupportedEncodingException.class}) + void testGetDescendantForByteRange() { + @Cleanup Parser parser = new Parser(); + parser.setLanguage(Language.PYTHON); + @Cleanup Tree tree = parser.parseString(source); + Node root = tree.getRootNode(); + Node function = root.getChild(0); + Node def = function.getChild(0); + Node identifier = function.getChild(1); + Node parameters = function.getChild(2); + Node colon = function.getChild(3); + Node body = function.getChild(4); + Assertions.assertEquals(def, root.getDescendantForByteRange(def.getStartByte(), def.getEndByte())); + Assertions.assertEquals(identifier, root.getDescendantForByteRange(identifier.getStartByte(), identifier.getEndByte())); + Assertions.assertEquals(parameters, root.getDescendantForByteRange(parameters.getStartByte(), parameters.getEndByte())); + Assertions.assertEquals(colon, root.getDescendantForByteRange(colon.getStartByte(), colon.getEndByte())); + Assertions.assertEquals(body, root.getDescendantForByteRange(body.getStartByte(), body.getEndByte())); + } + + @Test + @SneakyThrows({UnsupportedEncodingException.class}) + void testGetFieldNameForChild() { + @Cleanup Parser parser = new Parser(); + parser.setLanguage(Language.PYTHON); + @Cleanup Tree tree = parser.parseString(source); + Node root = tree.getRootNode(); + Node function = root.getChild(0); + Assertions.assertNull(function.getFieldNameForChild(0)); // `def` + Assertions.assertEquals("name", function.getFieldNameForChild(1)); // "name" + Assertions.assertEquals("parameters", function.getFieldNameForChild(2)); // "parameters" + Assertions.assertNull(function.getFieldNameForChild(3)); // `:` + Assertions.assertEquals("body", function.getFieldNameForChild(4)); // "body" + } + + @Test + @SneakyThrows({UnsupportedEncodingException.class}) + void testGetFirstChildForByte() { + @Cleanup Parser parser = new Parser(); + parser.setLanguage(Language.PYTHON); + @Cleanup Tree tree = parser.parseString(source); + Node root = tree.getRootNode(); + Node function = root.getChild(0); + Node def = function.getChild(0); + Node identifier = function.getChild(1); + Node parameters = function.getChild(2); + Node colon = function.getChild(3); + Node body = function.getChild(4); + Assertions.assertEquals(def, function.getFirstChildForByte(def.getStartByte())); + Assertions.assertEquals(identifier, function.getFirstChildForByte(identifier.getStartByte())); + Assertions.assertEquals(parameters, function.getFirstChildForByte(parameters.getStartByte())); + Assertions.assertEquals(colon, function.getFirstChildForByte(colon.getStartByte())); + Assertions.assertEquals(body, function.getFirstChildForByte(body.getStartByte())); + } + + @Test + @SneakyThrows({UnsupportedEncodingException.class}) + void testGetFirstNamedChildForByte() { + @Cleanup Parser parser = new Parser(); + parser.setLanguage(Language.PYTHON); + @Cleanup Tree tree = parser.parseString(source); + Node root = tree.getRootNode(); + Node function = root.getChild(0); + Node def = function.getChild(0); + Node identifier = function.getChild(1); + Node parameters = function.getChild(2); + Node colon = function.getChild(3); + Node body = function.getChild(4); + Assertions.assertEquals(identifier, function.getFirstNamedChildForByte(def.getStartByte())); + Assertions.assertEquals(identifier, function.getFirstNamedChildForByte(identifier.getStartByte())); + Assertions.assertEquals(parameters, function.getFirstNamedChildForByte(parameters.getStartByte())); + Assertions.assertEquals(body, function.getFirstNamedChildForByte(colon.getStartByte())); + Assertions.assertEquals(body, function.getFirstNamedChildForByte(body.getStartByte())); + } + + @Test + @SneakyThrows({UnsupportedEncodingException.class}) + void testGetParent() { + @Cleanup Parser parser = new Parser(); + parser.setLanguage(Language.PYTHON); + @Cleanup Tree tree = parser.parseString(source); + Node root = tree.getRootNode(); + Assertions.assertNull(root.getParent()); + Assertions.assertEquals(root, root.getChild(0).getParent()); + } + + @Test + @SneakyThrows({UnsupportedEncodingException.class}) + void testGetNextNamedSibling() { + @Cleanup Parser parser = new Parser(); + parser.setLanguage(Language.PYTHON); + @Cleanup Tree tree = parser.parseString(source); + Node root = tree.getRootNode(); + Node function = root.getChild(0); + Node def = function.getChild(0); + Node identifier = function.getChild(1); + Assertions.assertNull(root.getNextNamedSibling()); + Assertions.assertEquals(identifier, def.getNextNamedSibling()); + } + + @Test + @SneakyThrows({UnsupportedEncodingException.class}) + void testGetNextSibling() { + @Cleanup Parser parser = new Parser(); + parser.setLanguage(Language.PYTHON); + @Cleanup Tree tree = parser.parseString(source); + Node root = tree.getRootNode(); + Node function = root.getChild(0); + Node def = function.getChild(0); + Node identifier = function.getChild(1); + Assertions.assertNull(root.getNextSibling()); + Assertions.assertEquals(identifier, def.getNextSibling()); + } + + @Test + @SneakyThrows({UnsupportedEncodingException.class}) + void testGetPrevNamedSibling() { + @Cleanup Parser parser = new Parser(); + parser.setLanguage(Language.PYTHON); + @Cleanup Tree tree = parser.parseString(source); + Node root = tree.getRootNode(); + Node function = root.getChild(0); + Node identifier = function.getChild(1); + Node parameters = function.getChild(2); + Assertions.assertNull(root.getPrevNamedSibling()); + Assertions.assertEquals(identifier, parameters.getPrevNamedSibling()); + } + + @Test + @SneakyThrows({UnsupportedEncodingException.class}) + void testGetPrevSibling() { + @Cleanup Parser parser = new Parser(); + parser.setLanguage(Language.PYTHON); + @Cleanup Tree tree = parser.parseString(source); + Node root = tree.getRootNode(); + Node function = root.getChild(0); + Node def = function.getChild(0); + Node identifier = function.getChild(1); + Assertions.assertNull(root.getPrevSibling()); + Assertions.assertEquals(def, identifier.getPrevSibling()); + } + + @Test + @SneakyThrows({UnsupportedEncodingException.class}) + void testHasError() { + @Cleanup Parser parser = new Parser(); + parser.setLanguage(Language.PYTHON); + @Cleanup Tree tree = parser.parseString("def foo(bar, baz):\n print(bar.)"); + Node root = tree.getRootNode(); + Node function = root.getChild(0); + Node def = function.getChild(0); + Assertions.assertTrue(root.hasError()); + Assertions.assertTrue(function.hasError()); + Assertions.assertFalse(def.hasError()); + } + + @Test + @SneakyThrows({UnsupportedEncodingException.class}) + void testIsExtra() { + @Cleanup Parser parser = new Parser(); + parser.setLanguage(Language.PYTHON); + @Cleanup Tree tree = parser.parseString("# this is just a comment"); + Node root = tree.getRootNode(); + Node comment = root.getChild(0); + Assertions.assertFalse(root.isExtra()); + Assertions.assertTrue(comment.isExtra()); + } + + @Test + @SneakyThrows({UnsupportedEncodingException.class}) + void testIsMissing() { + @Cleanup Parser parser = new Parser(); + parser.setLanguage(Language.JAVA); + @Cleanup Tree tree = parser.parseString("class C { public static final int i = 6 }"); + Node root = tree.getRootNode(); + Assertions.assertFalse(root.isMissing()); + Assertions.assertFalse(root.getChild(0).isMissing()); + Assertions.assertFalse(root.getChild(0).getChild(2).isMissing()); + Assertions.assertFalse(root.getChild(0).getChild(2).getChild(1).isMissing()); + Assertions.assertFalse(root.getChild(0).getChild(2).getChild(1).getChild(2).isMissing()); + Assertions.assertTrue(root.getChild(0).getChild(2).getChild(1).getChild(3).isMissing()); + } + + @Test + @SneakyThrows({UnsupportedEncodingException.class}) + void testIsNamed() { + @Cleanup Parser parser = new Parser(); + parser.setLanguage(Language.PYTHON); + @Cleanup Tree tree = parser.parseString(source); + Node root = tree.getRootNode(); + Node function = root.getChild(0); + Node def = function.getChild(0); + Node identifier = function.getChild(1); + Assertions.assertFalse(def.isNamed()); + Assertions.assertTrue(identifier.isNamed()); + } +} diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/ParserTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/ParserTest.java new file mode 100644 index 00000000..0a01079d --- /dev/null +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/ParserTest.java @@ -0,0 +1,45 @@ +package usi.si.seart.treesitter; + +import lombok.Cleanup; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.nio.file.Files; +import java.nio.file.Path; + +class ParserTest extends TestBase { + + @TempDir + static Path tmp; + static Path tmpFile; + + static final String source = "print(\"hi\")\n"; + static final String nodeString = + "(module (expression_statement (call function: (identifier) arguments: (argument_list (string)))))"; + + @BeforeAll + static void beforeAll() throws IOException { + tmpFile = Files.createFile(tmp.resolve("print.py")); + Files.writeString(tmpFile, source); + } + + @Test + void testParseString() throws UnsupportedEncodingException { + @Cleanup Parser parser = new Parser(); + parser.setLanguage(Language.PYTHON); + @Cleanup Tree tree = parser.parseString(source); + Assertions.assertEquals(nodeString, tree.getRootNode().getNodeString()); + } + + @Test + void testParseFile() throws IOException { + @Cleanup Parser parser = new Parser(); + parser.setLanguage(Language.PYTHON); + @Cleanup Tree tree = parser.parseFile(tmpFile); + Assertions.assertEquals(nodeString, tree.getRootNode().getNodeString()); + } +} diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryCursorTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryCursorTest.java new file mode 100644 index 00000000..203371e4 --- /dev/null +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryCursorTest.java @@ -0,0 +1,34 @@ +package usi.si.seart.treesitter; + +import lombok.Cleanup; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.io.UnsupportedEncodingException; + +class QueryCursorTest extends TestBase { + + @Test + void testExecSimpleQuery() throws UnsupportedEncodingException { + @Cleanup Parser parser = new Parser(); + parser.setLanguage(Language.JAVA); + @Cleanup Tree tree = parser.parseString("class Hello {}"); + @Cleanup Query query = new Query(Language.JAVA, "(class_body) @test"); + @Cleanup QueryCursor cursor = new QueryCursor(); + cursor.execQuery(query, tree.getRootNode()); + int numMatches = 0; + while (cursor.nextMatch() != null) numMatches++; + Assertions.assertEquals(1, numMatches, "Finds one match"); + } + + @Test + void testExecNoResultQuery() throws UnsupportedEncodingException { + @Cleanup Parser parser = new Parser(); + parser.setLanguage(Language.JAVA); + @Cleanup Tree tree = parser.parseString("class Hello {}"); + @Cleanup Query query = new Query(Language.JAVA, "(method_declaration) @method"); + @Cleanup QueryCursor cursor = new QueryCursor(); + cursor.execQuery(query, tree.getRootNode()); + Assertions.assertNull(cursor.nextMatch()); + } +} diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java new file mode 100644 index 00000000..ea800ac4 --- /dev/null +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java @@ -0,0 +1,20 @@ +package usi.si.seart.treesitter; + +import lombok.Cleanup; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class QueryTest extends TestBase { + + @Test + void testQuery() { + @Cleanup Query query = new Query(Language.JAVA, "(class_declaration)"); + Assertions.assertNotEquals(0, query.getPointer(), "Pointer is not null"); + } + + @Test + void testInvalidQuery() { + @Cleanup Query query = new Query(Language.JAVA, "(class_declaration"); + Assertions.assertEquals(0, query.getPointer(), "Pointer is null"); + } +} diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TestBase.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TestBase.java new file mode 100644 index 00000000..9b23b398 --- /dev/null +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TestBase.java @@ -0,0 +1,8 @@ +package usi.si.seart.treesitter; + +class TestBase { + + static { + LibraryLoader.load(); + } +} diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeCursorTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeCursorTest.java new file mode 100644 index 00000000..4a2f98c2 --- /dev/null +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeCursorTest.java @@ -0,0 +1,39 @@ +package usi.si.seart.treesitter; + +import lombok.Cleanup; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.io.UnsupportedEncodingException; + +class TreeCursorTest extends TestBase { + + @Test + void testWalk() throws UnsupportedEncodingException { + @Cleanup Parser parser = new Parser(); + parser.setLanguage(Language.PYTHON); + @Cleanup Tree tree = parser.parseString("def foo(bar, baz):\n print(bar)\n print(baz)"); + @Cleanup TreeCursor cursor = tree.getRootNode().walk(); + Assertions.assertEquals("module", cursor.getCurrentTreeCursorNode().getType()); + Assertions.assertEquals("module", cursor.getCurrentNode().getType()); + Assertions.assertTrue(cursor.gotoFirstChild()); + Assertions.assertEquals("function_definition", cursor.getCurrentNode().getType()); + Assertions.assertTrue(cursor.gotoFirstChild()); + + Assertions.assertEquals("def", cursor.getCurrentNode().getType()); + Assertions.assertTrue(cursor.gotoNextSibling()); + Assertions.assertEquals("identifier", cursor.getCurrentNode().getType()); + Assertions.assertTrue(cursor.gotoNextSibling()); + Assertions.assertEquals("parameters", cursor.getCurrentNode().getType()); + Assertions.assertTrue(cursor.gotoNextSibling()); + Assertions.assertEquals(":", cursor.getCurrentNode().getType()); + Assertions.assertTrue(cursor.gotoNextSibling()); + Assertions.assertEquals("block", cursor.getCurrentNode().getType()); + Assertions.assertEquals("body", cursor.getCurrentFieldName()); + Assertions.assertFalse(cursor.gotoNextSibling()); + + Assertions.assertTrue(cursor.gotoParent()); + Assertions.assertEquals("function_definition", cursor.getCurrentNode().getType()); + Assertions.assertTrue(cursor.gotoFirstChild()); + } +} diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeTest.java new file mode 100644 index 00000000..8134781c --- /dev/null +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeTest.java @@ -0,0 +1,41 @@ +package usi.si.seart.treesitter; + +import lombok.Cleanup; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.io.UnsupportedEncodingException; + +class TreeTest extends TestBase { + + @Test + void testTreeEdit() throws UnsupportedEncodingException { + @Cleanup Parser parser = new Parser(); + parser.setLanguage(Language.JAVA); + + Tree tree = parser.parseString("class Main {\n // This is a line comment\n}"); + + Node root = tree.getRootNode(); + Node body = root.getChild(0).getChildByFieldName("body"); + int newEndByte = 13; + Point newEndPoint = new Point(1, 1); + InputEdit inputEdit = new InputEdit( + body.getStartByte(), + body.getEndByte(), + newEndByte, + body.getStartPoint(), + body.getEndPoint(), + newEndPoint + ); + + String oldSExp = tree.getRootNode().getNodeString(); + + tree.edit(inputEdit); + + tree = parser.parseString(tree, "class Main {\n}"); + + String newSExp = tree.getRootNode().getNodeString(); + Assertions.assertNotEquals(oldSExp, newSExp); + } + +} From d5f4044ec906f56333346ef26a9cbc106cdf6cfc Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 3 Jan 2023 10:40:18 +0100 Subject: [PATCH 0007/1089] Migrating files from `lib` Includes both the C++ code and generate headers --- .../lib/usi_si_seart_treesitter_Languages.cc | 235 ++++++++ .../lib/usi_si_seart_treesitter_Languages.h | 277 ++++++++++ .../lib/usi_si_seart_treesitter_TreeSitter.cc | 504 ++++++++++++++++++ .../lib/usi_si_seart_treesitter_TreeSitter.h | 373 +++++++++++++ 4 files changed, 1389 insertions(+) create mode 100644 dl4se-tree-sitter/lib/usi_si_seart_treesitter_Languages.cc create mode 100644 dl4se-tree-sitter/lib/usi_si_seart_treesitter_Languages.h create mode 100644 dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc create mode 100644 dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.h diff --git a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_Languages.cc b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_Languages.cc new file mode 100644 index 00000000..253db39a --- /dev/null +++ b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_Languages.cc @@ -0,0 +1,235 @@ +#include "usi_si_seart_treesitter_Languages.h" +#include +#include +#include + +#ifdef TS_LANGUAGE_AGDA +extern "C" TSLanguage* tree_sitter_agda(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_agda(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_agda(); +} +#endif + +#ifdef TS_LANGUAGE_BASH +extern "C" TSLanguage* tree_sitter_bash(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_bash(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_bash(); +} +#endif + +#ifdef TS_LANGUAGE_C +extern "C" TSLanguage* tree_sitter_c(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_c(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_c(); +} +#endif + +#ifdef TS_LANGUAGE_C_SHARP +extern "C" TSLanguage* tree_sitter_c_sharp(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_cSharp(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_c_sharp(); +} +#endif + +#ifdef TS_LANGUAGE_CPP +extern "C" TSLanguage* tree_sitter_cpp(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_cpp(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_cpp(); +} +#endif + +#ifdef TS_LANGUAGE_CSS +extern "C" TSLanguage* tree_sitter_css(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_css(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_css(); +} +#endif + +#ifdef TS_LANGUAGE_DART +extern "C" TSLanguage* tree_sitter_dart(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_dart(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_dart(); +} +#endif + +#ifdef TS_LANGUAGE_ELM +extern "C" TSLanguage* tree_sitter_elm(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_elm(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_elm(); +} +#endif + +#ifdef TS_LANGUAGE_EMBEDDED_TEMPLATE +extern "C" TSLanguage* tree_sitter_embedded_template(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_embeddedTemplate(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_embedded_template(); +} +#endif + +#ifdef TS_LANGUAGE_ENO +extern "C" TSLanguage* tree_sitter_eno(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_eno(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_eno(); +} +#endif + +#ifdef TS_LANGUAGE_GO +extern "C" TSLanguage* tree_sitter_go(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_go(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_go(); +} +#endif + +#ifdef TS_LANGUAGE_HASKELL +extern "C" TSLanguage* tree_sitter_haskell(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_haskell(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_haskell(); +} +#endif + +#ifdef TS_LANGUAGE_HTML +extern "C" TSLanguage* tree_sitter_html(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_html(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_html(); +} +#endif + +#ifdef TS_LANGUAGE_JAVA +extern "C" TSLanguage* tree_sitter_java(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_java(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_java(); +} +#endif + +#ifdef TS_LANGUAGE_JAVASCRIPT +extern "C" TSLanguage* tree_sitter_javascript(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_javascript(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_javascript(); +} +#endif + +#ifdef TS_LANGUAGE_JULIA +extern "C" TSLanguage* tree_sitter_julia(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_julia(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_julia(); +} +#endif + +#ifdef TS_LANGUAGE_KOTLIN +extern "C" TSLanguage* tree_sitter_kotlin(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_kotlin(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_kotlin(); +} +#endif + +#ifdef TS_LANGUAGE_LUA +extern "C" TSLanguage* tree_sitter_lua(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_lua(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_lua(); +} +#endif + +#ifdef TS_LANGUAGE_MARKDOWN +extern "C" TSLanguage* tree_sitter_markdown(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_markdown(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_markdown(); +} +#endif + +#ifdef TS_LANGUAGE_OCAML +extern "C" TSLanguage* tree_sitter_ocaml(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_ocaml(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_ocaml(); +} +#endif + +#ifdef TS_LANGUAGE_PHP +extern "C" TSLanguage* tree_sitter_php(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_php(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_php(); +} +#endif + +#ifdef TS_LANGUAGE_PYTHON +extern "C" TSLanguage* tree_sitter_python(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_python(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_python(); +} +#endif + +#ifdef TS_LANGUAGE_RUBY +extern "C" TSLanguage* tree_sitter_ruby(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_ruby(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_ruby(); +} +#endif + +#ifdef TS_LANGUAGE_RUST +extern "C" TSLanguage* tree_sitter_rust(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_rust(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_rust(); +} +#endif + +#ifdef TS_LANGUAGE_SCALA +extern "C" TSLanguage* tree_sitter_scala(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_scala(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_scala(); +} +#endif + +#ifdef TS_LANGUAGE_SCSS +extern "C" TSLanguage* tree_sitter_scss(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_scss(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_scss(); +} +#endif + +#ifdef TS_LANGUAGE_SWIFT +extern "C" TSLanguage* tree_sitter_swift(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_swift(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_swift(); +} +#endif + +#ifdef TS_LANGUAGE_TOML +extern "C" TSLanguage* tree_sitter_toml(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_toml(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_toml(); +} +#endif + +#ifdef TS_LANGUAGE_TSX +extern "C" TSLanguage* tree_sitter_tsx(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_tsx(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_tsx(); +} +#endif + +#ifdef TS_LANGUAGE_TYPESCRIPT +extern "C" TSLanguage* tree_sitter_typescript(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_typescript(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_typescript(); +} +#endif + +#ifdef TS_LANGUAGE_VUE +extern "C" TSLanguage* tree_sitter_vue(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_vue(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_vue(); +} +#endif + +#ifdef TS_LANGUAGE_YAML +extern "C" TSLanguage* tree_sitter_yaml(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_yaml(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_yaml(); +} +#endif + +#ifdef TS_LANGUAGE_WASM +extern "C" TSLanguage* tree_sitter_wasm(); +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_wasm(JNIEnv* env, jclass self) { + return (jlong)tree_sitter_wasm(); +} +#endif diff --git a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_Languages.h b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_Languages.h new file mode 100644 index 00000000..e7cec52d --- /dev/null +++ b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_Languages.h @@ -0,0 +1,277 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class usi_si_seart_treesitter_Languages */ + +#ifndef _Included_usi_si_seart_treesitter_Languages +#define _Included_usi_si_seart_treesitter_Languages +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: usi_si_seart_treesitter_Languages + * Method: agda + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_agda + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: bash + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_bash + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: c + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_c + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: cSharp + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_cSharp + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: cpp + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_cpp + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: css + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_css + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: dart + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_dart + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: elm + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_elm + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: embeddedTemplate + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_embeddedTemplate + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: eno + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_eno + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: go + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_go + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: haskell + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_haskell + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: html + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_html + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: java + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_java + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: javascript + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_javascript + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: julia + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_julia + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: kotlin + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_kotlin + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: lua + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_lua + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: markdown + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_markdown + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: ocaml + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_ocaml + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: php + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_php + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: python + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_python + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: ruby + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_ruby + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: rust + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_rust + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: scala + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_scala + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: scss + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_scss + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: swift + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_swift + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: toml + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_toml + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: tsx + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_tsx + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: typescript + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_typescript + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: vue + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_vue + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: yaml + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_yaml + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_Languages + * Method: wasm + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_wasm + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc new file mode 100644 index 00000000..c90934e1 --- /dev/null +++ b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc @@ -0,0 +1,504 @@ +#include "usi_si_seart_treesitter_TreeSitter.h" + +#include +#include +#include + +struct TreeCursorNode { + const char* type; + const char* name; + uint32_t startByte; + uint32_t endByte; + TSPoint startPoint; + TSPoint endPoint; + bool isNamed; +}; + +static jint JNI_VERSION = JNI_VERSION_10; + +static jclass _inputEditClass; +static jfieldID _inputEditStartByteField; +static jfieldID _inputEditOldEndByteField; +static jfieldID _inputEditNewEndByteField; +static jfieldID _inputEditStartPointField; +static jfieldID _inputEditOldEndPointField; +static jfieldID _inputEditNewEndPointField; + +static jclass _nodeClass; +static jfieldID _nodeContext0Field; +static jfieldID _nodeContext1Field; +static jfieldID _nodeContext2Field; +static jfieldID _nodeContext3Field; +static jfieldID _nodeIdField; +static jfieldID _nodeTreeField; + +static jclass _pointClass; +static jfieldID _pointRowField; +static jfieldID _pointColumnField; + +static jclass _queryCursorClass; + +static jclass _queryMatchClass; +static jfieldID _queryMatchIdField; +static jfieldID _queryMatchPatternIndexField; +static jfieldID _queryMatchCapturesField; + +static jclass _queryCaptureClass; +static jfieldID _queryCaptureNode; +static jfieldID _queryCaptureIndex; + +static jclass _treeCursorNodeClass; +static jfieldID _treeCursorNodeTypeField; +static jfieldID _treeCursorNodeNameField; +static jfieldID _treeCursorNodeStartByteField; +static jfieldID _treeCursorNodeEndByteField; +static jfieldID _treeCursorNodeStartPointField; +static jfieldID _treeCursorNodeEndPointField; +static jfieldID _treeCursorNodeIsNamed; + +#define _loadClass(VARIABLE, NAME) \ + { \ + jclass tmp; \ + tmp = env->FindClass(NAME); \ + VARIABLE = (jclass)env->NewGlobalRef(tmp); \ + env->DeleteLocalRef(tmp); \ + } + +#define _loadField(VARIABLE, CLASS, NAME, TYPE) \ + { VARIABLE = env->GetFieldID(CLASS, NAME, TYPE); } + +jint JNI_OnLoad(JavaVM* vm, void* reserved) { + JNIEnv* env; + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION) != JNI_OK) { + return JNI_ERR; + } + + _loadClass(_nodeClass, "usi/si/seart/treesitter/Node"); + _loadField(_nodeContext0Field, _nodeClass, "context0", "I"); + _loadField(_nodeContext1Field, _nodeClass, "context1", "I"); + _loadField(_nodeContext2Field, _nodeClass, "context2", "I"); + _loadField(_nodeContext3Field, _nodeClass, "context3", "I"); + _loadField(_nodeIdField, _nodeClass, "id", "J"); + _loadField(_nodeTreeField, _nodeClass, "tree", "J"); + + _loadClass(_pointClass, "usi/si/seart/treesitter/Point"); + _loadField(_pointRowField, _pointClass, "row", "I"); + _loadField(_pointColumnField, _pointClass, "column", "I"); + + _loadClass(_queryCursorClass, "usi/si/seart/treesitter/QueryCursor"); + + _loadClass(_queryCaptureClass, "usi/si/seart/treesitter/QueryCapture"); + _loadField(_queryCaptureNode, _queryCaptureClass, "node", "Lusi/si/seart/treesitter/Node;"); + _loadField(_queryCaptureIndex, _queryCaptureClass, "index", "I"); + + _loadClass(_queryMatchClass, "usi/si/seart/treesitter/QueryMatch"); + _loadField(_queryMatchIdField, _queryMatchClass, "id", "I"); + _loadField(_queryMatchPatternIndexField, _queryMatchClass, "pattern_index", "I"); + _loadField(_queryMatchCapturesField, _queryMatchClass, "captures", "[Lusi/si/seart/treesitter/QueryCapture;"); + + _loadClass(_treeCursorNodeClass, "usi/si/seart/treesitter/TreeCursorNode"); + _loadField(_treeCursorNodeTypeField, _treeCursorNodeClass, "type", "Ljava/lang/String;"); + _loadField(_treeCursorNodeNameField, _treeCursorNodeClass, "name", "Ljava/lang/String;"); + _loadField(_treeCursorNodeStartByteField, _treeCursorNodeClass, "startByte", "I"); + _loadField(_treeCursorNodeEndByteField, _treeCursorNodeClass, "endByte", "I"); + _loadField(_treeCursorNodeStartPointField, _treeCursorNodeClass, "startPoint", "Lusi/si/seart/treesitter/Point;"); + _loadField(_treeCursorNodeEndPointField, _treeCursorNodeClass, "endPoint", "Lusi/si/seart/treesitter/Point;"); + _loadField(_treeCursorNodeIsNamed, _treeCursorNodeClass, "isNamed", "Z"); + + _loadClass(_inputEditClass, "usi/si/seart/treesitter/InputEdit"); + _loadField(_inputEditStartByteField, _inputEditClass, "startByte", "I"); + _loadField(_inputEditOldEndByteField, _inputEditClass, "oldEndByte", "I"); + _loadField(_inputEditNewEndByteField, _inputEditClass, "newEndByte", "I"); + _loadField(_inputEditStartPointField, _inputEditClass, "startPoint", "Lusi/si/seart/treesitter/Point;"); + _loadField(_inputEditOldEndPointField, _inputEditClass, "oldEndPoint", "Lusi/si/seart/treesitter/Point;"); + _loadField(_inputEditNewEndPointField, _inputEditClass, "newEndPoint", "Lusi/si/seart/treesitter/Point;"); + + return JNI_VERSION; +} + +void JNI_OnUnload(JavaVM* vm, void* reserved) { + JNIEnv* env; + vm->GetEnv(reinterpret_cast(&env), JNI_VERSION); + env->DeleteGlobalRef(_nodeClass); + env->DeleteGlobalRef(_treeCursorNodeClass); +} + +jobject _marshalNode(JNIEnv* env, TSNode node) { + jobject javaObject = env->AllocObject(_nodeClass); + env->SetIntField(javaObject, _nodeContext0Field, node.context[0]); + env->SetIntField(javaObject, _nodeContext1Field, node.context[1]); + env->SetIntField(javaObject, _nodeContext2Field, node.context[2]); + env->SetIntField(javaObject, _nodeContext3Field, node.context[3]); + env->SetLongField(javaObject, _nodeIdField, (jlong)node.id); + env->SetLongField(javaObject, _nodeTreeField, (jlong)node.tree); + return javaObject; +} + +TSNode _unmarshalNode(JNIEnv* env, jobject javaObject) { + return (TSNode){ + { + (uint32_t)env->GetIntField(javaObject, _nodeContext0Field), + (uint32_t)env->GetIntField(javaObject, _nodeContext1Field), + (uint32_t)env->GetIntField(javaObject, _nodeContext2Field), + (uint32_t)env->GetIntField(javaObject, _nodeContext3Field), + }, + (const void*)env->GetLongField(javaObject, _nodeIdField), + (const TSTree*)env->GetLongField(javaObject, _nodeTreeField)}; +} + +jobject _marshalPoint(JNIEnv* env, TSPoint point) { + jobject javaObject = env->AllocObject(_pointClass); + env->SetIntField(javaObject, _pointRowField, point.row); + env->SetIntField(javaObject, _pointColumnField, point.column / 2); + // Not sure why I need to divide by two, probably because of utf-16 + return javaObject; +} + +TSPoint _unmarshalPoint(JNIEnv* env, jobject javaObject) { + return (TSPoint) { + (uint32_t)env->GetIntField(javaObject, _pointRowField), + (uint32_t)env->GetIntField(javaObject, _pointColumnField), + }; +} + +jobject _marshalQueryCapture(JNIEnv* env, TSQueryCapture capture) { + jobject javaObject = env->AllocObject(_queryCaptureClass); + env->SetIntField(javaObject, _queryCaptureIndex, capture.index); + env->SetObjectField(javaObject, _queryCaptureNode, _marshalNode(env, capture.node)); + + return javaObject; +} + +jobject _marshalQueryMatch(JNIEnv* env, TSQueryMatch match) { + jobject javaObject = env->AllocObject(_queryMatchClass); + env->SetIntField(javaObject, _queryMatchIdField, match.id); + env->SetIntField(javaObject, _queryMatchPatternIndexField, match.pattern_index); + + jobjectArray captures = (*env).NewObjectArray(match.capture_count, _queryCaptureClass, NULL); + for (int i = 0; i < match.capture_count; i++) { + env->SetObjectArrayElement(captures, i, _marshalQueryCapture(env, match.captures[i])); + } + env->SetObjectField(javaObject, _queryMatchCapturesField, captures); + + return javaObject; +} + +jobject _marshalTreeCursorNode(JNIEnv* env, TreeCursorNode node) { + jobject javaObject = env->AllocObject(_treeCursorNodeClass); + env->SetObjectField(javaObject, _treeCursorNodeTypeField, env->NewStringUTF(node.type)); + env->SetObjectField(javaObject, _treeCursorNodeNameField, env->NewStringUTF(node.name)); + env->SetIntField(javaObject, _treeCursorNodeStartByteField, node.startByte); + env->SetIntField(javaObject, _treeCursorNodeEndByteField, node.endByte); + env->SetObjectField(javaObject, _treeCursorNodeStartPointField, _marshalPoint(env, node.startPoint)); + env->SetObjectField(javaObject, _treeCursorNodeEndPointField, _marshalPoint(env, node.endPoint)); + env->SetBooleanField(javaObject, _treeCursorNodeIsNamed, node.isNamed); + return javaObject; +} + +TSInputEdit _unmarshalInputEdit(JNIEnv* env, jobject inputEdit) { + return (TSInputEdit) { + (uint32_t)env->GetIntField(inputEdit, _inputEditStartByteField), + (uint32_t)env->GetIntField(inputEdit, _inputEditOldEndByteField), + (uint32_t)env->GetIntField(inputEdit, _inputEditNewEndByteField), + _unmarshalPoint(env, env->GetObjectField(inputEdit, _inputEditStartPointField)), + _unmarshalPoint(env, env->GetObjectField(inputEdit, _inputEditOldEndPointField)), + _unmarshalPoint(env, env->GetObjectField(inputEdit, _inputEditNewEndPointField)), + }; +} + +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeChild( + JNIEnv* env, jclass self, jobject node, jint child) { + return _marshalNode(env, ts_node_child(_unmarshalNode(env, node), (uint32_t)child)); +} + +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeChildByFieldName( + JNIEnv* env, jclass self, jobject node, jstring name) { + const char* c_name; + uint32_t name_length = env->GetStringLength(name); + c_name = env->GetStringUTFChars(name, NULL); + TSNode child = ts_node_child_by_field_name(_unmarshalNode(env, node), c_name, name_length); + if (ts_node_is_null(child)) return NULL; + return _marshalNode(env, child); +} + +JNIEXPORT jint JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeChildCount( + JNIEnv* env, jclass self, jobject node) { + return (jint)ts_node_child_count(_unmarshalNode(env, node)); +} + +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeDescendantForByteRange( + JNIEnv* env, jclass self, jobject node, jint start, jint end) { + TSNode descendant = ts_node_descendant_for_byte_range( + _unmarshalNode(env, node), (uint32_t)start * 2, (uint32_t)end * 2 + // Not sure why I need to multiply by two, again probably because of utf-16 + ); + return _marshalNode(env, descendant); +} + +JNIEXPORT jstring JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeString( + JNIEnv* env, jclass self, jobject node) { + char* nodeString = ts_node_string(_unmarshalNode(env, node)); + jstring result = env->NewStringUTF(nodeString); + free(nodeString); + return result; +} + +JNIEXPORT jint JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeEndByte( + JNIEnv* env, jclass self, jobject node) { + return (jint)ts_node_end_byte(_unmarshalNode(env, node)) / 2; +} + +JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeEq( + JNIEnv* env, jclass self, jobject node, jobject other) { + TSNode node_1 = _unmarshalNode(env, node); + TSNode node_2 = _unmarshalNode(env, other); + return ts_node_eq(node_1, node_2); +} + +JNIEXPORT jstring JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeFieldNameForChild( + JNIEnv* env, jclass self, jobject node, jint child) { + const char* nameForChild = ts_node_field_name_for_child(_unmarshalNode(env, node), (uint32_t)child); + jstring result = env->NewStringUTF(nameForChild); + return result; +} + +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeFirstChildForByte( + JNIEnv* env, jclass self, jobject node, jint offset) { + TSNode child = ts_node_first_child_for_byte(_unmarshalNode(env, node), (uint32_t)offset * 2); + return _marshalNode(env, child); +} + +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeFirstNamedChildForByte( + JNIEnv* env, jclass self, jobject node, jint offset) { + TSNode child = ts_node_first_named_child_for_byte(_unmarshalNode(env, node), (uint32_t)offset * 2); + return _marshalNode(env, child); +} + +JNIEXPORT jint JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeStartByte( + JNIEnv* env, jclass self, jobject node) { + return (jint)ts_node_start_byte(_unmarshalNode(env, node)) / 2; +} + +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeStartPoint( + JNIEnv* env, jclass self, jobject node) { + return _marshalPoint(env, ts_node_start_point(_unmarshalNode(env, node))); +} + +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeEndPoint( + JNIEnv* env, jclass self, jobject node) { + return _marshalPoint(env, ts_node_end_point(_unmarshalNode(env, node))); +} + +JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeHasError( + JNIEnv* env, jclass self, jobject node) { + return (jboolean) ts_node_has_error(_unmarshalNode(env, node)); +} + +JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeIsExtra( + JNIEnv* env, jclass self, jobject node) { + return (jboolean) ts_node_is_extra(_unmarshalNode(env, node)); +} + +JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeIsMissing( + JNIEnv* env, jclass self, jobject node) { + return (jboolean) ts_node_is_missing(_unmarshalNode(env, node)); +} + +JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeIsNamed( + JNIEnv* env, jclass self, jobject node) { + return (jboolean) ts_node_is_named(_unmarshalNode(env, node)); +} + +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeParent( + JNIEnv* env, jclass self, jobject node) { + TSNode parent = ts_node_parent(_unmarshalNode(env, node)); + if (ts_node_is_null(parent)) return NULL; + return _marshalNode(env, parent); +} + +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeNextNamedSibling( + JNIEnv* env, jclass self, jobject node) { + TSNode sibling = ts_node_next_named_sibling(_unmarshalNode(env, node)); + if (ts_node_is_null(sibling)) return NULL; + return _marshalNode(env, sibling); +} + +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeNextSibling( + JNIEnv* env, jclass self, jobject node) { + TSNode sibling = ts_node_next_sibling(_unmarshalNode(env, node)); + if (ts_node_is_null(sibling)) return NULL; + return _marshalNode(env, sibling); +} + +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodePrevNamedSibling( + JNIEnv* env, jclass self, jobject node) { + TSNode sibling = ts_node_prev_named_sibling(_unmarshalNode(env, node)); + if (ts_node_is_null(sibling)) return NULL; + return _marshalNode(env, sibling); +} + +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodePrevSibling( + JNIEnv* env, jclass self, jobject node) { + TSNode sibling = ts_node_prev_sibling(_unmarshalNode(env, node)); + if (ts_node_is_null(sibling)) return NULL; + return _marshalNode(env, sibling); +} + +JNIEXPORT jstring JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeType( + JNIEnv* env, jclass self, jobject node) { + const char* type = ts_node_type(_unmarshalNode(env, node)); + jstring result = env->NewStringUTF(type); + return result; +} + +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_parserNew( + JNIEnv* env, jclass self) { + return (jlong)ts_parser_new(); +} + +JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_parserDelete( + JNIEnv* env, jclass self, jlong parser) { + ts_parser_delete((TSParser*)parser); +} + +JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_parserSetLanguage( + JNIEnv* env, jclass self, jlong parser, jlong language) { + ts_parser_set_language((TSParser*)parser, (TSLanguage*)language); +} + +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_parserParseBytes( + JNIEnv* env, jclass self, jlong parser, jbyteArray source_bytes, jint length) { + jbyte* source = env->GetByteArrayElements(source_bytes, NULL); + jlong result = (jlong)ts_parser_parse_string_encoding( + (TSParser*)parser, NULL, reinterpret_cast(source), length, TSInputEncodingUTF16 + ); + env->ReleaseByteArrayElements(source_bytes, source, JNI_ABORT); + return result; +} + +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_parserIncrementalParseBytes( + JNIEnv* env, jclass self, jlong parser, jlong old_tree, jbyteArray source_bytes, jint length) { + jbyte* source = env->GetByteArrayElements(source_bytes, NULL); + jlong result = (jlong)ts_parser_parse_string_encoding( + (TSParser*)parser, (TSTree*)old_tree, reinterpret_cast(source), length, TSInputEncodingUTF16 + ); + env->ReleaseByteArrayElements(source_bytes, source, JNI_ABORT); + return result; +} + +JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryDelete( + JNIEnv* env, jclass self, jlong query) { + ts_query_delete((TSQuery*)query); +} + +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryNew( + JNIEnv* env, jclass self, jlong language, jstring source) { + const char* c_source; + uint32_t source_length = env->GetStringLength(source); + c_source = env->GetStringUTFChars(source, NULL); + uint32_t* error_offset = new uint32_t; + TSQueryError* error_type = new TSQueryError; + TSQuery* query = ts_query_new((TSLanguage*) language, c_source, source_length, error_offset, error_type); + return (jlong) query; +} + +JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryCursorDelete( + JNIEnv* env, jclass self, jlong query_cursor) { + ts_query_cursor_delete((TSQueryCursor*)query_cursor); +} + +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryCursorNew( + JNIEnv* env, jclass self) { + TSQueryCursor* cursor = ts_query_cursor_new(); + return (jlong)cursor; +} + +JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryCursorExec( + JNIEnv* env, jclass self, jlong query_cursor, jlong query, jobject node) { + ts_query_cursor_exec((TSQueryCursor*) query_cursor, (TSQuery*) query, _unmarshalNode(env,node)); +} + +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryCursorNextMatch( + JNIEnv * env, jclass self, jlong query_cursor) { + TSQueryMatch query_match; + bool found = ts_query_cursor_next_match((TSQueryCursor*)query_cursor, &query_match); + if (!found) return NULL; + return _marshalQueryMatch(env, query_match); +} + +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorNew( + JNIEnv* env, jclass self, jobject node) { + TSTreeCursor* cursor = new TSTreeCursor(ts_tree_cursor_new(_unmarshalNode(env, node))); + return (jlong)cursor; +} + +JNIEXPORT jstring JNICALL +Java_usi_si_seart_treesitter_TreeSitter_treeCursorCurrentFieldName( + JNIEnv* env, jclass self, jlong cursor) { + const char* name = ts_tree_cursor_current_field_name((TSTreeCursor*)cursor); + jstring result = env->NewStringUTF(name); + return result; +} + +JNIEXPORT jobject JNICALL +Java_usi_si_seart_treesitter_TreeSitter_treeCursorCurrentNode( + JNIEnv* env, jclass self, jlong cursor) { + return _marshalNode(env, ts_tree_cursor_current_node((TSTreeCursor*)cursor)); +} + +JNIEXPORT jobject JNICALL +Java_usi_si_seart_treesitter_TreeSitter_treeCursorCurrentTreeCursorNode( + JNIEnv* env, jclass self, jlong cursor) { + TSNode node = ts_tree_cursor_current_node((TSTreeCursor*)cursor); + return _marshalTreeCursorNode( + env, + (TreeCursorNode){ + ts_node_type(node), + ts_tree_cursor_current_field_name((TSTreeCursor*)cursor), + ts_node_start_byte(node) / 2, + ts_node_end_byte(node) / 2, + ts_node_start_point(node), + ts_node_end_point(node), + ts_node_is_named(node) + } + ); +} + +JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorDelete( + JNIEnv* env, jclass self, jlong cursor) { + delete (TSTreeCursor*)cursor; +} + +JNIEXPORT jboolean JNICALL +Java_usi_si_seart_treesitter_TreeSitter_treeCursorGotoFirstChild( + JNIEnv* env, jclass self, jlong cursor) { + return (jboolean)ts_tree_cursor_goto_first_child((TSTreeCursor*)cursor); +} + +JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorGotoNextSibling( + JNIEnv* env, jclass self, jlong cursor) { + return (jboolean)ts_tree_cursor_goto_next_sibling((TSTreeCursor*)cursor); +} + +JNIEXPORT jboolean JNICALL +Java_usi_si_seart_treesitter_TreeSitter_treeCursorGotoParent( + JNIEnv* env, jclass self, jlong cursor) { + return (jboolean)ts_tree_cursor_goto_parent((TSTreeCursor*)cursor); +} + +JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeDelete( + JNIEnv* env, jclass self, jlong tree) { + ts_tree_delete((TSTree*)tree); +} + + +JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeEdit( + JNIEnv* env, jclass self, jlong tree, jobject inputEdit) { + TSInputEdit edit = _unmarshalInputEdit(env, inputEdit); + ts_tree_edit((TSTree*) tree, &edit); +} + +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeRootNode( + JNIEnv* env, jclass self, jlong tree) { + return _marshalNode(env, ts_tree_root_node((TSTree*)tree)); +} diff --git a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.h b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.h new file mode 100644 index 00000000..29c3c426 --- /dev/null +++ b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.h @@ -0,0 +1,373 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class usi_si_seart_treesitter_TreeSitter */ + +#ifndef _Included_usi_si_seart_treesitter_TreeSitter +#define _Included_usi_si_seart_treesitter_TreeSitter +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: nodeChild + * Signature: (Lusi/si/seart/treesitter/Node;I)Lusi/si/seart/treesitter/Node; + */ +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeChild + (JNIEnv *, jclass, jobject, jint); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: nodeChildByFieldName + * Signature: (Lusi/si/seart/treesitter/Node;Ljava/lang/String;)Lusi/si/seart/treesitter/Node; + */ +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeChildByFieldName + (JNIEnv *, jclass, jobject, jstring); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: nodeChildCount + * Signature: (Lusi/si/seart/treesitter/Node;)I + */ +JNIEXPORT jint JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeChildCount + (JNIEnv *, jclass, jobject); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: nodeDescendantForByteRange + * Signature: (Lusi/si/seart/treesitter/Node;II)Lusi/si/seart/treesitter/Node; + */ +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeDescendantForByteRange + (JNIEnv *, jclass, jobject, jint, jint); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: nodeEndByte + * Signature: (Lusi/si/seart/treesitter/Node;)I + */ +JNIEXPORT jint JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeEndByte + (JNIEnv *, jclass, jobject); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: nodeEndPoint + * Signature: (Lusi/si/seart/treesitter/Node;)Lusi/si/seart/treesitter/Point; + */ +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeEndPoint + (JNIEnv *, jclass, jobject); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: nodeEq + * Signature: (Lusi/si/seart/treesitter/Node;Lusi/si/seart/treesitter/Node;)Z + */ +JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeEq + (JNIEnv *, jclass, jobject, jobject); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: nodeFieldNameForChild + * Signature: (Lusi/si/seart/treesitter/Node;I)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeFieldNameForChild + (JNIEnv *, jclass, jobject, jint); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: nodeFirstChildForByte + * Signature: (Lusi/si/seart/treesitter/Node;I)Lusi/si/seart/treesitter/Node; + */ +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeFirstChildForByte + (JNIEnv *, jclass, jobject, jint); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: nodeFirstNamedChildForByte + * Signature: (Lusi/si/seart/treesitter/Node;I)Lusi/si/seart/treesitter/Node; + */ +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeFirstNamedChildForByte + (JNIEnv *, jclass, jobject, jint); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: nodeHasError + * Signature: (Lusi/si/seart/treesitter/Node;)Z + */ +JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeHasError + (JNIEnv *, jclass, jobject); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: nodeIsExtra + * Signature: (Lusi/si/seart/treesitter/Node;)Z + */ +JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeIsExtra + (JNIEnv *, jclass, jobject); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: nodeIsMissing + * Signature: (Lusi/si/seart/treesitter/Node;)Z + */ +JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeIsMissing + (JNIEnv *, jclass, jobject); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: nodeIsNamed + * Signature: (Lusi/si/seart/treesitter/Node;)Z + */ +JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeIsNamed + (JNIEnv *, jclass, jobject); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: nodeParent + * Signature: (Lusi/si/seart/treesitter/Node;)Lusi/si/seart/treesitter/Node; + */ +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeParent + (JNIEnv *, jclass, jobject); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: nodePrevNamedSibling + * Signature: (Lusi/si/seart/treesitter/Node;)Lusi/si/seart/treesitter/Node; + */ +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodePrevNamedSibling + (JNIEnv *, jclass, jobject); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: nodePrevSibling + * Signature: (Lusi/si/seart/treesitter/Node;)Lusi/si/seart/treesitter/Node; + */ +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodePrevSibling + (JNIEnv *, jclass, jobject); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: nodeNextNamedSibling + * Signature: (Lusi/si/seart/treesitter/Node;)Lusi/si/seart/treesitter/Node; + */ +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeNextNamedSibling + (JNIEnv *, jclass, jobject); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: nodeNextSibling + * Signature: (Lusi/si/seart/treesitter/Node;)Lusi/si/seart/treesitter/Node; + */ +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeNextSibling + (JNIEnv *, jclass, jobject); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: nodeStartByte + * Signature: (Lusi/si/seart/treesitter/Node;)I + */ +JNIEXPORT jint JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeStartByte + (JNIEnv *, jclass, jobject); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: nodeStartPoint + * Signature: (Lusi/si/seart/treesitter/Node;)Lusi/si/seart/treesitter/Point; + */ +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeStartPoint + (JNIEnv *, jclass, jobject); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: nodeString + * Signature: (Lusi/si/seart/treesitter/Node;)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeString + (JNIEnv *, jclass, jobject); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: nodeType + * Signature: (Lusi/si/seart/treesitter/Node;)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeType + (JNIEnv *, jclass, jobject); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: parserNew + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_parserNew + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: parserDelete + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_parserDelete + (JNIEnv *, jclass, jlong); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: parserSetLanguage + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_parserSetLanguage + (JNIEnv *, jclass, jlong, jlong); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: parserParseBytes + * Signature: (J[BI)J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_parserParseBytes + (JNIEnv *, jclass, jlong, jbyteArray, jint); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: parserIncrementalParseBytes + * Signature: (JJ[BI)J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_parserIncrementalParseBytes + (JNIEnv *, jclass, jlong, jlong, jbyteArray, jint); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: queryDelete + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryDelete + (JNIEnv *, jclass, jlong); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: queryNew + * Signature: (JLjava/lang/String;)J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryNew + (JNIEnv *, jclass, jlong, jstring); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: queryCursorDelete + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryCursorDelete + (JNIEnv *, jclass, jlong); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: queryCursorNew + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryCursorNew + (JNIEnv *, jclass); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: queryCursorExec + * Signature: (JJLusi/si/seart/treesitter/Node;)V + */ +JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryCursorExec + (JNIEnv *, jclass, jlong, jlong, jobject); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: queryCursorNextMatch + * Signature: (J)Lusi/si/seart/treesitter/QueryMatch; + */ +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryCursorNextMatch + (JNIEnv *, jclass, jlong); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: treeCursorNew + * Signature: (Lusi/si/seart/treesitter/Node;)J + */ +JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorNew + (JNIEnv *, jclass, jobject); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: treeCursorCurrentTreeCursorNode + * Signature: (J)Lusi/si/seart/treesitter/TreeCursorNode; + */ +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorCurrentTreeCursorNode + (JNIEnv *, jclass, jlong); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: treeCursorCurrentFieldName + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorCurrentFieldName + (JNIEnv *, jclass, jlong); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: treeCursorCurrentNode + * Signature: (J)Lusi/si/seart/treesitter/Node; + */ +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorCurrentNode + (JNIEnv *, jclass, jlong); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: treeCursorDelete + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorDelete + (JNIEnv *, jclass, jlong); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: treeCursorGotoFirstChild + * Signature: (J)Z + */ +JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorGotoFirstChild + (JNIEnv *, jclass, jlong); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: treeCursorGotoNextSibling + * Signature: (J)Z + */ +JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorGotoNextSibling + (JNIEnv *, jclass, jlong); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: treeCursorGotoParent + * Signature: (J)Z + */ +JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorGotoParent + (JNIEnv *, jclass, jlong); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: treeDelete + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeDelete + (JNIEnv *, jclass, jlong); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: treeEdit + * Signature: (JLusi/si/seart/treesitter/InputEdit;)V + */ +JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeEdit + (JNIEnv *, jclass, jlong, jobject); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: treeRootNode + * Signature: (J)Lusi/si/seart/treesitter/Node; + */ +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeRootNode + (JNIEnv *, jclass, jlong); + +#ifdef __cplusplus +} +#endif +#endif From ffee4ea0b9d7695361b8ab024964f57e12616e39 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 3 Jan 2023 10:41:06 +0100 Subject: [PATCH 0008/1089] `.gitkeep` no longer bundled in the JAR --- dl4se-tree-sitter/pom.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/dl4se-tree-sitter/pom.xml b/dl4se-tree-sitter/pom.xml index ed7145ce..9734d6b0 100644 --- a/dl4se-tree-sitter/pom.xml +++ b/dl4se-tree-sitter/pom.xml @@ -15,4 +15,15 @@ UTF-8 + + + + + src/main/resources + + **/.gitkeep + + + + From 4678b34e1125aa156a64eeefc28108a2fdf5ee9c Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 3 Jan 2023 10:41:46 +0100 Subject: [PATCH 0009/1089] Added `build.py` script --- dl4se-tree-sitter/build.py | 136 +++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100755 dl4se-tree-sitter/build.py diff --git a/dl4se-tree-sitter/build.py b/dl4se-tree-sitter/build.py new file mode 100755 index 00000000..68f70b63 --- /dev/null +++ b/dl4se-tree-sitter/build.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python3 + +import argparse +import ctypes.util +import distutils.ccompiler +import os +import platform +import tempfile + + +# adapted from https://github.com/tree-sitter/py-tree-sitter +def build(repositories, output_path="libjava-tree-sitter", arch=None, verbose=False): + if arch and platform.system() != "Darwin": + arch = "64" if "64" in arch else "32" + + output_path = f"{output_path}.{'dylib' if platform.system() == 'Darwin' else 'so'}" + here = os.path.dirname(os.path.realpath(__file__)) + env = "" + if arch: + env += ( + f"CFLAGS='-arch {arch} -mmacosx-version-min=11.0' LDFLAGS='-arch {arch}'" + if platform.system() == "Darwin" + else f"CFLAGS='-m{arch}' LDFLAGS='-m{arch}'" + ) + + os.system( + f"make -C {os.path.join(here, 'tree-sitter')} clean {'> /dev/null' if not verbose else ''}" + ) + os.system( + f"{env} make -C {os.path.join(here, 'tree-sitter')} {'> /dev/null' if not verbose else ''}" + ) + + cpp = False + source_paths = [ + os.path.join(here, "lib", "usi_si_seart_treesitter_Languages.cc"), + os.path.join(here, "lib", "usi_si_seart_treesitter_TreeSitter.cc"), + ] + + compiler = distutils.ccompiler.new_compiler() + for repository in repositories: + src_path = os.path.join(repository, "src") + source_paths.append(os.path.join(src_path, "parser.c")) + scanner_c = os.path.join(src_path, "scanner.c") + scanner_cc = os.path.join(src_path, "scanner.cc") + if os.path.exists(scanner_cc): + cpp = True + source_paths.append(scanner_cc) + elif os.path.exists(scanner_c): + source_paths.append(scanner_c) + + compiler.define_macro( + f"TS_LANGUAGE_{os.path.split(repository.rstrip('/'))[1].split('tree-sitter-')[-1].replace('-', '_').upper()}", + "1", + ) + + source_mtimes = [os.path.getmtime(__file__)] + [os.path.getmtime(path) for path in source_paths] + if cpp: + if ctypes.util.find_library("stdc++"): + compiler.add_library("stdc++") + elif ctypes.util.find_library("c++"): + compiler.add_library("c++") + + output_mtime = os.path.getmtime(output_path) if os.path.exists(output_path) else 0 + if max(source_mtimes) <= output_mtime: + return False + + with tempfile.TemporaryDirectory(suffix="tree_sitter_language") as out_dir: + object_paths = [] + for source_path in source_paths: + flags = ["-O3"] + + if platform.system() == "Linux": + flags.append("-fPIC") + + if source_path.endswith(".c"): + flags.append("-std=c99") + + if arch: + flags += ["-arch", arch] if platform.system() == "Darwin" else [f"-m{arch}"] + + include_dirs = [ + os.path.dirname(source_path), + os.path.join(here, "tree-sitter", "lib", "include"), + os.path.join(os.environ["JAVA_HOME"], "include"), + ] + + if platform.system() == "Linux": + include_dirs.append(os.path.join(os.environ["JAVA_HOME"], "include", "linux")) + elif platform.system() == "Darwin": + include_dirs.append(os.path.join(os.environ["JAVA_HOME"], "include", "darwin")) + + object_paths.append( + compiler.compile( + [source_path], + output_dir=out_dir, + include_dirs=include_dirs, + extra_preargs=flags, + )[0] + ) + + extra_preargs = [] + if platform.system() == "Darwin": + extra_preargs.append("-dynamiclib") + + if arch: + extra_preargs += ["-arch", arch] if platform.system() == "Darwin" else [f"-m{arch}"] + + compiler.link_shared_object( + object_paths, + output_path, + extra_preargs=extra_preargs, + extra_postargs=[os.path.join(here, "tree-sitter", "libtree-sitter.a")], + library_dirs=[os.path.join(here, "tree-sitter")], + ) + + return True + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Build a tree-sitter library") + parser.add_argument( + "-a", + "--arch", + help="Architecture to build for (x86, x86_64, arm64)", + ) + parser.add_argument("-o", "--output", default="libjava-tree-sitter", help="Output file name") + parser.add_argument("-v", "--verbose", action="store_true", help="Print verbose output") + parser.add_argument( + "repositories", + nargs="+", + help="tree-sitter repositories to include in build", + ) + + args = parser.parse_args() + distutils.log.set_verbosity(int(args.verbose)) + build(args.repositories, args.output, args.arch, args.verbose) From 152bc9bdf8b8ba1c5d09011885b2c6fca5ad5d41 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 3 Jan 2023 10:42:20 +0100 Subject: [PATCH 0010/1089] Added executions for cleaning, compilation, etc. --- dl4se-tree-sitter/pom.xml | 77 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/dl4se-tree-sitter/pom.xml b/dl4se-tree-sitter/pom.xml index 9734d6b0..b27e75a9 100644 --- a/dl4se-tree-sitter/pom.xml +++ b/dl4se-tree-sitter/pom.xml @@ -25,5 +25,82 @@ + + + maven-shade-plugin + + + package + + shade + + + + + + org.codehaus.mojo + exec-maven-plugin + 1.2.1 + + + clean-generated-files + pre-clean + + exec + + + sh + ${project.basedir} + + -c + printf "Removed files:\n$(rm -vf src/main/resources/libjava-tree-sitter.*)\n" + + + + + generate-jni-headers + generate-sources + + exec + + + javah + ${project.basedir} + + -verbose + -jni + -classpath + ${project.build.sourceDirectory} + -d + ${project.basedir}/lib + usi.si.seart.treesitter.Languages + usi.si.seart.treesitter.TreeSitter + + + + + generate-dynamic-library + generate-sources + + exec + + + python + ${project.basedir} + + build.py + -o + src/main/resources/libjava-tree-sitter + tree-sitter-c + tree-sitter-cpp + tree-sitter-java + tree-sitter-javascript + tree-sitter-python + + + + + + From aaf8c841269edbf3f80daedbef65d6c3f3cf9d68 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 3 Jan 2023 10:54:04 +0100 Subject: [PATCH 0011/1089] Streamlined `TreePrinter` implementation through custom cursor --- .../usi/si/seart/treesitter/TreePrinter.java | 37 ++++++++++++------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreePrinter.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreePrinter.java index a3022628..5275856a 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreePrinter.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreePrinter.java @@ -21,26 +21,16 @@ public class TreePrinter { public String printParseTree() { StringBuilder stringBuilder = new StringBuilder(); Node root = this.tree.getRootNode(); - @Cleanup TreeCursor cursor = root.walk(); + @Cleanup TreeCursor cursor = new TreePrinterCursor(root); for (;;) { TreeCursorNode treeCursorNode = cursor.getCurrentTreeCursorNode(); if (treeCursorNode.isNamed()) { String treeNode = printTreeNode(treeCursorNode); stringBuilder.append(treeNode); } - if (cursor.gotoFirstChild()) { - indentLevel++; - continue; - } - if (cursor.gotoNextSibling()) { - continue; - } + if (cursor.gotoFirstChild() || cursor.gotoNextSibling()) continue; do { - if (cursor.gotoParent()) { - indentLevel--; - } else { - return stringBuilder.toString(); - } + if (!cursor.gotoParent()) return stringBuilder.toString(); } while (!cursor.gotoNextSibling()); } } @@ -56,4 +46,25 @@ private String printTreeNode(TreeCursorNode treeCursorNode) { type, startPoint, endPoint ); } + + private final class TreePrinterCursor extends TreeCursor { + + private TreePrinterCursor(Node node) { + super(TreeSitter.treeCursorNew(node)); + } + + @Override + public boolean gotoFirstChild() { + boolean success = super.gotoFirstChild(); + if (success) indentLevel++; + return success; + } + + @Override + public boolean gotoParent() { + boolean success = super.gotoParent(); + if (success) indentLevel--; + return success; + } + } } From 8882c6a708280c7368fd4e20c9b85f29f9945883 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 5 Jan 2023 17:11:05 +0100 Subject: [PATCH 0012/1089] Added `dl4se-analyzer` module --- .idea/encodings.xml | 2 ++ dl4se-analyzer/pom.xml | 49 ++++++++++++++++++++++++++++++++++++++++++ pom.xml | 1 + 3 files changed, 52 insertions(+) create mode 100644 dl4se-analyzer/pom.xml diff --git a/.idea/encodings.xml b/.idea/encodings.xml index eacbf96d..cd7f91d0 100644 --- a/.idea/encodings.xml +++ b/.idea/encodings.xml @@ -3,6 +3,8 @@ + + diff --git a/dl4se-analyzer/pom.xml b/dl4se-analyzer/pom.xml new file mode 100644 index 00000000..2e40683d --- /dev/null +++ b/dl4se-analyzer/pom.xml @@ -0,0 +1,49 @@ + + + 4.0.0 + + dl4se + usi.si.seart + ${revision} + ../pom.xml + + + dl4se-analyzer + + dl4se-analyzer + + + UTF-8 + + + + + usi.si.seart + dl4se-model + ${project.version} + + + usi.si.seart + dl4se-tree-sitter + ${project.version} + + + + + + + maven-shade-plugin + + + package + + shade + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 3880ddaa..6f0d6e56 100644 --- a/pom.xml +++ b/pom.xml @@ -29,6 +29,7 @@ dl4se-server dl4se-src2abs dl4se-tree-sitter + dl4se-analyzer From 1888d5057d5f960d2a23d775a62a0170325a43e7 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 5 Jan 2023 17:12:07 +0100 Subject: [PATCH 0013/1089] Added `Hasher` class hierarchy --- .../usi/si/seart/analyzer/hash/Hasher.java | 7 ++++ .../si/seart/analyzer/hash/SHA256Hasher.java | 39 +++++++++++++++++++ .../seart/analyzer/hash/SyntaxTreeHasher.java | 29 ++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/Hasher.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SHA256Hasher.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SyntaxTreeHasher.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/Hasher.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/Hasher.java new file mode 100644 index 00000000..f63c251d --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/Hasher.java @@ -0,0 +1,7 @@ +package usi.si.seart.analyzer.hash; + +import usi.si.seart.treesitter.Tree; + +public interface Hasher { + String hash(Tree tree); +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SHA256Hasher.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SHA256Hasher.java new file mode 100644 index 00000000..06c57efa --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SHA256Hasher.java @@ -0,0 +1,39 @@ +package usi.si.seart.analyzer.hash; + +import lombok.SneakyThrows; +import usi.si.seart.treesitter.Node; +import usi.si.seart.treesitter.Tree; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public abstract class SHA256Hasher implements Hasher { + + public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_16LE; + + protected final MessageDigest md; + + @SneakyThrows(NoSuchAlgorithmException.class) + protected SHA256Hasher() { + this.md = MessageDigest.getInstance("SHA-256"); + } + + @Override + public String hash(Tree tree) { + return sha256(tree.getRootNode()); + } + + protected abstract String sha256(Node node); + + static String bytesToHex(byte[] bytes) { + StringBuilder hexBuilder = new StringBuilder(2 * bytes.length); + for (byte b : bytes) { + String hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) hexBuilder.append('0'); + hexBuilder.append(hex); + } + return hexBuilder.toString(); + } +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SyntaxTreeHasher.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SyntaxTreeHasher.java new file mode 100644 index 00000000..8e002bd9 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SyntaxTreeHasher.java @@ -0,0 +1,29 @@ +package usi.si.seart.analyzer.hash; + +import lombok.Cleanup; +import usi.si.seart.treesitter.Node; +import usi.si.seart.treesitter.TreeCursor; + +public class SyntaxTreeHasher extends SHA256Hasher { + + public SyntaxTreeHasher() { + super(); + } + + @Override + protected String sha256(Node node) { + @Cleanup TreeCursor cursor = node.walk(); + cursor.preorderTraversal(current -> { + boolean leafNode = current.getChildCount() == 0; + boolean isComment = current.getType().contains("comment"); + if (leafNode && !isComment) { + String type = current.getType(); + byte[] bytes = type.getBytes(DEFAULT_CHARSET); + md.update(bytes); + } + }); + + byte[] hash = md.digest(); + return bytesToHex(hash); + } +} From 2af6a4f509b557895fac58315c3d41292f07e65a Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 5 Jan 2023 17:12:38 +0100 Subject: [PATCH 0014/1089] Added tests for the new hasher --- .../si/seart/analyzer/hash/HasherTest.java | 17 ++++ .../analyzer/hash/SyntaxTreeHasherTest.java | 96 +++++++++++++++++++ .../usi/si/seart/analyzer/test/BaseTest.java | 9 ++ 3 files changed, 122 insertions(+) create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/HasherTest.java create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/SyntaxTreeHasherTest.java create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/HasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/HasherTest.java new file mode 100644 index 00000000..f8679d79 --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/HasherTest.java @@ -0,0 +1,17 @@ +package usi.si.seart.analyzer.hash; + +import lombok.SneakyThrows; +import usi.si.seart.analyzer.test.BaseTest; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public abstract class HasherTest extends BaseTest { + + @SneakyThrows({NoSuchAlgorithmException.class}) + protected String sha256(String input) { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + byte[] hash = md.digest(input.getBytes(SHA256Hasher.DEFAULT_CHARSET)); + return SHA256Hasher.bytesToHex(hash); + } +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/SyntaxTreeHasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/SyntaxTreeHasherTest.java new file mode 100644 index 00000000..002a9fe4 --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/SyntaxTreeHasherTest.java @@ -0,0 +1,96 @@ +package usi.si.seart.analyzer.hash; + +import lombok.SneakyThrows; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import usi.si.seart.treesitter.Language; +import usi.si.seart.treesitter.Parser; +import usi.si.seart.treesitter.Tree; + +import java.io.UnsupportedEncodingException; + +class SyntaxTreeHasherTest extends HasherTest { + + private static Parser parser; + + private Tree tree; + + private static final String input = + "package ch.usi.si;\n" + + "\n" + + "public class Main {\n" + + "\tpublic static void main(String[] args) {\n" + + "\t\t//line comment\n" + + "\t\tSystem.out.println(\"Hello, World!\");\n" + + "\t}\n" + + "}"; + + private static final String otherInput = + "package ch.usi.si;\n" + + "\n" + + "public class Main {\n" + + "\tpublic static void main(String[] args) {\n" + + "\t\t/*\n" + + "\t\t * Block comment\n" + + "\t\t * on multiple lines\n" + + "\t\t */\n" + + "\t\tSystem.out.println(\"Hello, World!\");\n" + + "\t}\n" + + "}"; + + private static final String abs = + "packageidentifier.identifier.identifier;publicclassidentifier{publicstaticvoid_typeidentifier(type_identifier[]identifier){identifier.identifier.identifier(string_literal);}}"; + + @BeforeAll + static void beforeAll() { + parser = new Parser(); + parser.setLanguage(Language.JAVA); + } + + @BeforeEach + @SneakyThrows(UnsupportedEncodingException.class) + void setUp() { + tree = parser.parseString(input); + } + + @Test + void hashTest() { + Hasher hasher = new SyntaxTreeHasher(); + String actual = hasher.hash(tree); + String expected = sha256(abs); + Assertions.assertEquals(expected, actual, "Incrementally digested hash of leaf node names should be equal to the manual digest of the flattened, abstract, typed code!"); + } + + @Test + void idempotencyTest() { + Hasher hasher = new SyntaxTreeHasher(); + String first = hasher.hash(tree); + String second = hasher.hash(tree); + Assertions.assertEquals(first, second, "Same instance should be reusable for multiple invocations!"); + } + + @Test + @SneakyThrows(UnsupportedEncodingException.class) + void noCommentImpactTest() { + Tree other = parser.parseString(otherInput); + Hasher hasher = new SyntaxTreeHasher(); + String first = hasher.hash(tree); + String second = hasher.hash(other); + Assertions.assertEquals(first, second, "Comments should not impact the hashing result!"); + } + + @AfterEach + void tearDown() { + tree.close(); + tree = null; + } + + @AfterAll + static void afterAll() { + parser.close(); + } +} \ No newline at end of file diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java new file mode 100644 index 00000000..810cc101 --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java @@ -0,0 +1,9 @@ +package usi.si.seart.analyzer.test; + +import usi.si.seart.treesitter.LibraryLoader; + +public abstract class BaseTest { + static { + LibraryLoader.load(); + } +} From 2b4704b97f005b01551bbdccefbc1d6569378a0d Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 5 Jan 2023 17:12:54 +0100 Subject: [PATCH 0015/1089] Added run config for test in new module --- .idea/runConfigurations/Tests__dl4se_analyzer.xml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .idea/runConfigurations/Tests__dl4se_analyzer.xml diff --git a/.idea/runConfigurations/Tests__dl4se_analyzer.xml b/.idea/runConfigurations/Tests__dl4se_analyzer.xml new file mode 100644 index 00000000..635b8dbb --- /dev/null +++ b/.idea/runConfigurations/Tests__dl4se_analyzer.xml @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file From b4b617ec5817cead1a62d8e0e740bff50840c48a Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 5 Jan 2023 17:16:02 +0100 Subject: [PATCH 0016/1089] First draft of `ContentHasher` The fact that I have to use a backing `bytes` field ruins the polymorphism. I have to find a better way to do this. --- .../si/seart/analyzer/hash/ContentHasher.java | 50 +++++++++ .../analyzer/hash/ContentHasherTest.java | 102 ++++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java new file mode 100644 index 00000000..8ea2296f --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java @@ -0,0 +1,50 @@ +package usi.si.seart.analyzer.hash; + +import lombok.Cleanup; +import lombok.Getter; +import usi.si.seart.treesitter.Node; +import usi.si.seart.treesitter.TreeCursor; + +import java.util.Arrays; + +@Getter +public class ContentHasher extends SHA256Hasher { + + private byte[] bytes; + private boolean ready; + + public ContentHasher() { + super(); + this.bytes = new byte[0]; + this.ready = false; + } + + public ContentHasher(byte[] bytes) { + super(); + this.bytes = bytes; + this.ready = true; + } + + public void setBytes(byte[] bytes) { + this.bytes = bytes; + this.ready = bytes.length > 0; + } + + @Override + protected String sha256(Node node) { + if (!ready) return null; + @Cleanup TreeCursor cursor = node.walk(); + cursor.preorderTraversal(current -> { + boolean leafNode = current.getChildCount() == 0; + boolean isComment = current.getType().contains("comment"); + if (leafNode && !isComment) { + int startByte = current.getStartByte() * 2; + int endByte = current.getEndByte() * 2; + md.update(Arrays.copyOfRange(this.bytes, startByte, endByte)); + } + }); + + byte[] hash = md.digest(); + return bytesToHex(hash); + } +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java new file mode 100644 index 00000000..74c1acab --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java @@ -0,0 +1,102 @@ +package usi.si.seart.analyzer.hash; + +import lombok.SneakyThrows; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import usi.si.seart.treesitter.Language; +import usi.si.seart.treesitter.Parser; +import usi.si.seart.treesitter.Tree; + +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; + +class ContentHasherTest extends HasherTest { + + private static Parser parser; + + private Tree tree; + + private static final String input = + "package ch.usi.si;\n" + + "\n" + + "public class Main {\n" + + "\tpublic static void main(String[] args) {\n" + + "\t\t//line comment\n" + + "\t\tSystem.out.println(\"Hello, World!\");\n" + + "\t}\n" + + "}"; + + private static final String otherInput = + "package ch.usi.si;\n" + + "\n" + + "public class Main {\n" + + "\tpublic static void main(String[] args) {\n" + + "\t\t/*\n" + + "\t\t * Block comment\n" + + "\t\t * on multiple lines\n" + + "\t\t */\n" + + "\t\tSystem.out.println(\"Hello, World!\");\n" + + "\t}\n" + + "}"; + + private static final String inputFlat = + "packagech.usi.si;publicclassMain{publicstaticvoidmain(String[]args){System.out.println(\"Hello, World!\");}}"; + + private static final byte[] bytes = input.getBytes(StandardCharsets.UTF_16LE); + private static final byte[] otherBytes = otherInput.getBytes(StandardCharsets.UTF_16LE); + + @BeforeAll + static void beforeAll() { + parser = new Parser(); + parser.setLanguage(Language.JAVA); + } + + @BeforeEach + @SneakyThrows(UnsupportedEncodingException.class) + void setUp() { + tree = parser.parseString(input); + } + + @Test + void hashTest() { + Hasher hasher = new ContentHasher(bytes); + String actual = hasher.hash(tree); + String expected = sha256(inputFlat); + Assertions.assertEquals(expected, actual, "Incrementally digested tree hash should be equal to the flat code manual digest!"); + } + + @Test + void idempotencyTest() { + Hasher hasher = new ContentHasher(bytes); + String first = hasher.hash(tree); + String second = hasher.hash(tree); + Assertions.assertEquals(first, second, "Same instance should be reusable for multiple invocations!"); + } + + @Test + @SneakyThrows(UnsupportedEncodingException.class) + void noCommentImpactTest() { + Tree other = parser.parseString(otherInput); + ContentHasher hasher = new ContentHasher(); + hasher.setBytes(bytes); + String first = hasher.hash(tree); + hasher.setBytes(otherBytes); + String second = hasher.hash(other); + Assertions.assertEquals(first, second, "Comments should not impact the hashing result!"); + } + + @AfterEach + void tearDown() { + tree.close(); + tree = null; + } + + @AfterAll + static void afterAll() { + parser.close(); + } +} \ No newline at end of file From cdb224e0a2eb6dde3cc06a2771aca9a1a30825f2 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 5 Jan 2023 17:21:15 +0100 Subject: [PATCH 0017/1089] Added common interface for backing byte mutations --- .../java/usi/si/seart/analyzer/hash/ByteArrayBacked.java | 6 ++++++ .../main/java/usi/si/seart/analyzer/hash/ContentHasher.java | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ByteArrayBacked.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ByteArrayBacked.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ByteArrayBacked.java new file mode 100644 index 00000000..77fbfa72 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ByteArrayBacked.java @@ -0,0 +1,6 @@ +package usi.si.seart.analyzer.hash; + +public interface ByteArrayBacked { + byte[] getBytes(); + void setBytes(byte[] bytes); +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java index 8ea2296f..940f499f 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java @@ -8,7 +8,7 @@ import java.util.Arrays; @Getter -public class ContentHasher extends SHA256Hasher { +public class ContentHasher extends SHA256Hasher implements ByteArrayBacked { private byte[] bytes; private boolean ready; @@ -25,6 +25,7 @@ public ContentHasher(byte[] bytes) { this.ready = true; } + @Override public void setBytes(byte[] bytes) { this.bytes = bytes; this.ready = bytes.length > 0; From 8d27269445db7f4c64c1a73566af56bd79ff3dd6 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 6 Jan 2023 09:19:55 +0100 Subject: [PATCH 0018/1089] Revert "Added common interface for backing byte mutations" --- .../java/usi/si/seart/analyzer/hash/ByteArrayBacked.java | 6 ------ .../main/java/usi/si/seart/analyzer/hash/ContentHasher.java | 3 +-- 2 files changed, 1 insertion(+), 8 deletions(-) delete mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ByteArrayBacked.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ByteArrayBacked.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ByteArrayBacked.java deleted file mode 100644 index 77fbfa72..00000000 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ByteArrayBacked.java +++ /dev/null @@ -1,6 +0,0 @@ -package usi.si.seart.analyzer.hash; - -public interface ByteArrayBacked { - byte[] getBytes(); - void setBytes(byte[] bytes); -} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java index 940f499f..8ea2296f 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java @@ -8,7 +8,7 @@ import java.util.Arrays; @Getter -public class ContentHasher extends SHA256Hasher implements ByteArrayBacked { +public class ContentHasher extends SHA256Hasher { private byte[] bytes; private boolean ready; @@ -25,7 +25,6 @@ public ContentHasher(byte[] bytes) { this.ready = true; } - @Override public void setBytes(byte[] bytes) { this.bytes = bytes; this.ready = bytes.length > 0; From bf5906d4acc5ad70cdf2eefa6eae5814cef0b7aa Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 6 Jan 2023 11:23:01 +0100 Subject: [PATCH 0019/1089] API change to use `Node` instead of `Tree` This allows the classes to be applicable to both entire files (i.e. trees), along with subtrees of the file. --- .../java/usi/si/seart/analyzer/hash/ContentHasher.java | 2 +- .../main/java/usi/si/seart/analyzer/hash/Hasher.java | 4 ++-- .../java/usi/si/seart/analyzer/hash/SHA256Hasher.java | 9 --------- .../usi/si/seart/analyzer/hash/SyntaxTreeHasher.java | 2 +- .../usi/si/seart/analyzer/hash/ContentHasherTest.java | 10 +++++----- .../si/seart/analyzer/hash/SyntaxTreeHasherTest.java | 10 +++++----- 6 files changed, 14 insertions(+), 23 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java index 8ea2296f..9768cd2c 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java @@ -31,7 +31,7 @@ public void setBytes(byte[] bytes) { } @Override - protected String sha256(Node node) { + public String hash(Node node) { if (!ready) return null; @Cleanup TreeCursor cursor = node.walk(); cursor.preorderTraversal(current -> { diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/Hasher.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/Hasher.java index f63c251d..a134e18d 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/Hasher.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/Hasher.java @@ -1,7 +1,7 @@ package usi.si.seart.analyzer.hash; -import usi.si.seart.treesitter.Tree; +import usi.si.seart.treesitter.Node; public interface Hasher { - String hash(Tree tree); + String hash(Node node); } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SHA256Hasher.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SHA256Hasher.java index 06c57efa..c914f2a0 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SHA256Hasher.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SHA256Hasher.java @@ -1,8 +1,6 @@ package usi.si.seart.analyzer.hash; import lombok.SneakyThrows; -import usi.si.seart.treesitter.Node; -import usi.si.seart.treesitter.Tree; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; @@ -20,13 +18,6 @@ protected SHA256Hasher() { this.md = MessageDigest.getInstance("SHA-256"); } - @Override - public String hash(Tree tree) { - return sha256(tree.getRootNode()); - } - - protected abstract String sha256(Node node); - static String bytesToHex(byte[] bytes) { StringBuilder hexBuilder = new StringBuilder(2 * bytes.length); for (byte b : bytes) { diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SyntaxTreeHasher.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SyntaxTreeHasher.java index 8e002bd9..d8e66ed9 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SyntaxTreeHasher.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SyntaxTreeHasher.java @@ -11,7 +11,7 @@ public SyntaxTreeHasher() { } @Override - protected String sha256(Node node) { + public String hash(Node node) { @Cleanup TreeCursor cursor = node.walk(); cursor.preorderTraversal(current -> { boolean leafNode = current.getChildCount() == 0; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java index 74c1acab..9d4a3937 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java @@ -64,7 +64,7 @@ void setUp() { @Test void hashTest() { Hasher hasher = new ContentHasher(bytes); - String actual = hasher.hash(tree); + String actual = hasher.hash(tree.getRootNode()); String expected = sha256(inputFlat); Assertions.assertEquals(expected, actual, "Incrementally digested tree hash should be equal to the flat code manual digest!"); } @@ -72,8 +72,8 @@ void hashTest() { @Test void idempotencyTest() { Hasher hasher = new ContentHasher(bytes); - String first = hasher.hash(tree); - String second = hasher.hash(tree); + String first = hasher.hash(tree.getRootNode()); + String second = hasher.hash(tree.getRootNode()); Assertions.assertEquals(first, second, "Same instance should be reusable for multiple invocations!"); } @@ -83,9 +83,9 @@ void noCommentImpactTest() { Tree other = parser.parseString(otherInput); ContentHasher hasher = new ContentHasher(); hasher.setBytes(bytes); - String first = hasher.hash(tree); + String first = hasher.hash(tree.getRootNode()); hasher.setBytes(otherBytes); - String second = hasher.hash(other); + String second = hasher.hash(other.getRootNode()); Assertions.assertEquals(first, second, "Comments should not impact the hashing result!"); } diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/SyntaxTreeHasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/SyntaxTreeHasherTest.java index 002a9fe4..a2fefeaa 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/SyntaxTreeHasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/SyntaxTreeHasherTest.java @@ -60,7 +60,7 @@ void setUp() { @Test void hashTest() { Hasher hasher = new SyntaxTreeHasher(); - String actual = hasher.hash(tree); + String actual = hasher.hash(tree.getRootNode()); String expected = sha256(abs); Assertions.assertEquals(expected, actual, "Incrementally digested hash of leaf node names should be equal to the manual digest of the flattened, abstract, typed code!"); } @@ -68,8 +68,8 @@ void hashTest() { @Test void idempotencyTest() { Hasher hasher = new SyntaxTreeHasher(); - String first = hasher.hash(tree); - String second = hasher.hash(tree); + String first = hasher.hash(tree.getRootNode()); + String second = hasher.hash(tree.getRootNode()); Assertions.assertEquals(first, second, "Same instance should be reusable for multiple invocations!"); } @@ -78,8 +78,8 @@ void idempotencyTest() { void noCommentImpactTest() { Tree other = parser.parseString(otherInput); Hasher hasher = new SyntaxTreeHasher(); - String first = hasher.hash(tree); - String second = hasher.hash(other); + String first = hasher.hash(tree.getRootNode()); + String second = hasher.hash(other.getRootNode()); Assertions.assertEquals(first, second, "Comments should not impact the hashing result!"); } From fcab4ad28047bd9e2931bc4b96594ee9663bf005 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 6 Jan 2023 15:37:34 +0100 Subject: [PATCH 0020/1089] Refactored tests for future additions --- .../analyzer/hash/ContentHasherTest.java | 44 ++------ .../analyzer/hash/SyntaxTreeHasherTest.java | 32 +----- .../usi/si/seart/analyzer/test/BaseTest.java | 105 ++++++++++++++++++ 3 files changed, 115 insertions(+), 66 deletions(-) diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java index 9d4a3937..0729c9fb 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java @@ -12,7 +12,6 @@ import usi.si.seart.treesitter.Tree; import java.io.UnsupportedEncodingException; -import java.nio.charset.StandardCharsets; class ContentHasherTest extends HasherTest { @@ -20,35 +19,6 @@ class ContentHasherTest extends HasherTest { private Tree tree; - private static final String input = - "package ch.usi.si;\n" + - "\n" + - "public class Main {\n" + - "\tpublic static void main(String[] args) {\n" + - "\t\t//line comment\n" + - "\t\tSystem.out.println(\"Hello, World!\");\n" + - "\t}\n" + - "}"; - - private static final String otherInput = - "package ch.usi.si;\n" + - "\n" + - "public class Main {\n" + - "\tpublic static void main(String[] args) {\n" + - "\t\t/*\n" + - "\t\t * Block comment\n" + - "\t\t * on multiple lines\n" + - "\t\t */\n" + - "\t\tSystem.out.println(\"Hello, World!\");\n" + - "\t}\n" + - "}"; - - private static final String inputFlat = - "packagech.usi.si;publicclassMain{publicstaticvoidmain(String[]args){System.out.println(\"Hello, World!\");}}"; - - private static final byte[] bytes = input.getBytes(StandardCharsets.UTF_16LE); - private static final byte[] otherBytes = otherInput.getBytes(StandardCharsets.UTF_16LE); - @BeforeAll static void beforeAll() { parser = new Parser(); @@ -58,20 +28,20 @@ static void beforeAll() { @BeforeEach @SneakyThrows(UnsupportedEncodingException.class) void setUp() { - tree = parser.parseString(input); + tree = parser.parseString(input_1); } @Test void hashTest() { - Hasher hasher = new ContentHasher(bytes); + Hasher hasher = new ContentHasher(bytes_1); String actual = hasher.hash(tree.getRootNode()); - String expected = sha256(inputFlat); + String expected = sha256(tokens_joined_1); Assertions.assertEquals(expected, actual, "Incrementally digested tree hash should be equal to the flat code manual digest!"); } @Test void idempotencyTest() { - Hasher hasher = new ContentHasher(bytes); + Hasher hasher = new ContentHasher(bytes_1); String first = hasher.hash(tree.getRootNode()); String second = hasher.hash(tree.getRootNode()); Assertions.assertEquals(first, second, "Same instance should be reusable for multiple invocations!"); @@ -80,11 +50,11 @@ void idempotencyTest() { @Test @SneakyThrows(UnsupportedEncodingException.class) void noCommentImpactTest() { - Tree other = parser.parseString(otherInput); + Tree other = parser.parseString(input_2); ContentHasher hasher = new ContentHasher(); - hasher.setBytes(bytes); + hasher.setBytes(bytes_1); String first = hasher.hash(tree.getRootNode()); - hasher.setBytes(otherBytes); + hasher.setBytes(bytes_2); String second = hasher.hash(other.getRootNode()); Assertions.assertEquals(first, second, "Comments should not impact the hashing result!"); } diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/SyntaxTreeHasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/SyntaxTreeHasherTest.java index a2fefeaa..ee55b307 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/SyntaxTreeHasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/SyntaxTreeHasherTest.java @@ -19,32 +19,6 @@ class SyntaxTreeHasherTest extends HasherTest { private Tree tree; - private static final String input = - "package ch.usi.si;\n" + - "\n" + - "public class Main {\n" + - "\tpublic static void main(String[] args) {\n" + - "\t\t//line comment\n" + - "\t\tSystem.out.println(\"Hello, World!\");\n" + - "\t}\n" + - "}"; - - private static final String otherInput = - "package ch.usi.si;\n" + - "\n" + - "public class Main {\n" + - "\tpublic static void main(String[] args) {\n" + - "\t\t/*\n" + - "\t\t * Block comment\n" + - "\t\t * on multiple lines\n" + - "\t\t */\n" + - "\t\tSystem.out.println(\"Hello, World!\");\n" + - "\t}\n" + - "}"; - - private static final String abs = - "packageidentifier.identifier.identifier;publicclassidentifier{publicstaticvoid_typeidentifier(type_identifier[]identifier){identifier.identifier.identifier(string_literal);}}"; - @BeforeAll static void beforeAll() { parser = new Parser(); @@ -54,14 +28,14 @@ static void beforeAll() { @BeforeEach @SneakyThrows(UnsupportedEncodingException.class) void setUp() { - tree = parser.parseString(input); + tree = parser.parseString(input_1); } @Test void hashTest() { Hasher hasher = new SyntaxTreeHasher(); String actual = hasher.hash(tree.getRootNode()); - String expected = sha256(abs); + String expected = sha256(nodes_joined_1); Assertions.assertEquals(expected, actual, "Incrementally digested hash of leaf node names should be equal to the manual digest of the flattened, abstract, typed code!"); } @@ -76,7 +50,7 @@ void idempotencyTest() { @Test @SneakyThrows(UnsupportedEncodingException.class) void noCommentImpactTest() { - Tree other = parser.parseString(otherInput); + Tree other = parser.parseString(input_2); Hasher hasher = new SyntaxTreeHasher(); String first = hasher.hash(tree.getRootNode()); String second = hasher.hash(other.getRootNode()); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java index 810cc101..fc084e0f 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java @@ -2,8 +2,113 @@ import usi.si.seart.treesitter.LibraryLoader; +import java.nio.charset.StandardCharsets; +import java.util.List; + public abstract class BaseTest { + static { LibraryLoader.load(); } + + protected final String input_1 = + "package ch.usi.si;\n" + + "\n" + + "public class Main {\n" + + "\tpublic static void main(String[] args) {\n" + + "\t\t//line comment\n" + + "\t\tSystem.out.println(\"Hello, World!\");\n" + + "\t}\n" + + "}"; + + protected final List tokens_1 = List.of( + "package", + "ch", + ".", + "usi", + ".", + "si", + ";", + "public", + "class", + "Main", + "{", + "public", + "static", + "void", + "main", + "(", + "String", + "[]", + "args", + ")", + "{", + "System", + ".", + "out", + ".", + "println", + "(", + "\"Hello, World!\"", + ")", + ";", + "}", + "}" + ); + + protected final String tokens_joined_1 = String.join("", tokens_1); + + protected final List nodes_1 = List.of( + "package", + "identifier", + ".", + "identifier", + ".", + "identifier", + ";", + "public", + "class", + "identifier", + "{", + "public", + "static", + "void_type", + "identifier", + "(", + "type_identifier", + "[]", + "identifier", + ")", + "{", + "identifier", + ".", + "identifier", + ".", + "identifier", + "(", + "string_literal", + ")", + ";", + "}", + "}" + ); + + protected final String nodes_joined_1 = String.join("", nodes_1); + + protected final byte[] bytes_1 = input_1.getBytes(StandardCharsets.UTF_16LE); + + protected final String input_2 = + "package ch.usi.si;\n" + + "\n" + + "public class Main {\n" + + "\tpublic static void main(String[] args) {\n" + + "\t\t/*\n" + + "\t\t * Block comment\n" + + "\t\t * on multiple lines\n" + + "\t\t */\n" + + "\t\tSystem.out.println(\"Hello, World!\");\n" + + "\t}\n" + + "}"; + + protected final byte[] bytes_2 = input_2.getBytes(StandardCharsets.UTF_16LE); } From d8a585fcc7ecf2930d0207f07f6527e2d1d3444b Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 6 Jan 2023 15:51:06 +0100 Subject: [PATCH 0021/1089] Even more restructuring to simplify tests --- .../analyzer/hash/ContentHasherTest.java | 33 ----------------- .../analyzer/hash/SyntaxTreeHasherTest.java | 33 ----------------- .../usi/si/seart/analyzer/test/BaseTest.java | 36 +++++++++++++++++++ 3 files changed, 36 insertions(+), 66 deletions(-) diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java index 0729c9fb..7b7a0164 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java @@ -1,36 +1,14 @@ package usi.si.seart.analyzer.hash; import lombok.SneakyThrows; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import usi.si.seart.treesitter.Language; -import usi.si.seart.treesitter.Parser; import usi.si.seart.treesitter.Tree; import java.io.UnsupportedEncodingException; class ContentHasherTest extends HasherTest { - private static Parser parser; - - private Tree tree; - - @BeforeAll - static void beforeAll() { - parser = new Parser(); - parser.setLanguage(Language.JAVA); - } - - @BeforeEach - @SneakyThrows(UnsupportedEncodingException.class) - void setUp() { - tree = parser.parseString(input_1); - } - @Test void hashTest() { Hasher hasher = new ContentHasher(bytes_1); @@ -58,15 +36,4 @@ void noCommentImpactTest() { String second = hasher.hash(other.getRootNode()); Assertions.assertEquals(first, second, "Comments should not impact the hashing result!"); } - - @AfterEach - void tearDown() { - tree.close(); - tree = null; - } - - @AfterAll - static void afterAll() { - parser.close(); - } } \ No newline at end of file diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/SyntaxTreeHasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/SyntaxTreeHasherTest.java index ee55b307..85664816 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/SyntaxTreeHasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/SyntaxTreeHasherTest.java @@ -1,36 +1,14 @@ package usi.si.seart.analyzer.hash; import lombok.SneakyThrows; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import usi.si.seart.treesitter.Language; -import usi.si.seart.treesitter.Parser; import usi.si.seart.treesitter.Tree; import java.io.UnsupportedEncodingException; class SyntaxTreeHasherTest extends HasherTest { - private static Parser parser; - - private Tree tree; - - @BeforeAll - static void beforeAll() { - parser = new Parser(); - parser.setLanguage(Language.JAVA); - } - - @BeforeEach - @SneakyThrows(UnsupportedEncodingException.class) - void setUp() { - tree = parser.parseString(input_1); - } - @Test void hashTest() { Hasher hasher = new SyntaxTreeHasher(); @@ -56,15 +34,4 @@ void noCommentImpactTest() { String second = hasher.hash(other.getRootNode()); Assertions.assertEquals(first, second, "Comments should not impact the hashing result!"); } - - @AfterEach - void tearDown() { - tree.close(); - tree = null; - } - - @AfterAll - static void afterAll() { - parser.close(); - } } \ No newline at end of file diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java index fc084e0f..1f50307a 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java @@ -1,16 +1,52 @@ package usi.si.seart.analyzer.test; +import lombok.SneakyThrows; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import usi.si.seart.treesitter.Language; import usi.si.seart.treesitter.LibraryLoader; +import usi.si.seart.treesitter.Parser; +import usi.si.seart.treesitter.Tree; +import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; import java.util.List; public abstract class BaseTest { + protected static Parser parser; + static { LibraryLoader.load(); } + @BeforeAll + static void beforeAll() { + parser = new Parser(); + parser.setLanguage(Language.JAVA); + } + + @AfterAll + static void afterAll() { + parser.close(); + } + + protected Tree tree; + + @BeforeEach + @SneakyThrows(UnsupportedEncodingException.class) + void setUp() { + tree = parser.parseString(input_1); + } + + @AfterEach + void tearDown() { + tree.close(); + tree = null; + } + protected final String input_1 = "package ch.usi.si;\n" + "\n" + From 1f29b2e112e8b7a366ba6290bfb8c9376522e0cb Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 6 Jan 2023 17:16:53 +0100 Subject: [PATCH 0022/1089] Added various counting utilities for syntax trees --- .../analyzer/count/CharacterCounter.java | 27 +++++++++++ .../analyzer/count/CodeTokenCounter.java | 13 +++++ .../count/ContentTraverseCounter.java | 47 +++++++++++++++++++ .../usi/si/seart/analyzer/count/Counter.java | 7 +++ .../si/seart/analyzer/count/LineCounter.java | 16 +++++++ .../si/seart/analyzer/count/TokenCounter.java | 44 +++++++++++++++++ .../seart/analyzer/count/TraverseCounter.java | 32 +++++++++++++ 7 files changed, 186 insertions(+) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CharacterCounter.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CodeTokenCounter.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/ContentTraverseCounter.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/Counter.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/LineCounter.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TokenCounter.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TraverseCounter.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CharacterCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CharacterCounter.java new file mode 100644 index 00000000..4685a377 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CharacterCounter.java @@ -0,0 +1,27 @@ +package usi.si.seart.analyzer.count; + +import usi.si.seart.treesitter.Node; +import usi.si.seart.treesitter.Range; + +public class CharacterCounter extends ContentTraverseCounter { + + public CharacterCounter() { + super(); + } + + public CharacterCounter(byte[] bytes) { + super(bytes); + } + + @Override + protected void nodeCallback(Node node) { + if (!isReady()) return; + boolean leafNode = node.getChildCount() == 0; + if (leafNode) { + Range range = node.getRange(); + String content = getContentForRange(range); + String noSpace = content.replaceAll("\\s", ""); + count.addAndGet(noSpace.length()); + } + } +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CodeTokenCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CodeTokenCounter.java new file mode 100644 index 00000000..336d1f66 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CodeTokenCounter.java @@ -0,0 +1,13 @@ +package usi.si.seart.analyzer.count; + +import usi.si.seart.treesitter.Node; + +public class CodeTokenCounter extends TraverseCounter { + + @Override + protected void nodeCallback(Node node) { + boolean leafNode = node.getChildCount() == 0; + boolean isComment = node.getType().contains("comment"); + if (leafNode && !isComment) count.incrementAndGet(); + } +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/ContentTraverseCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/ContentTraverseCounter.java new file mode 100644 index 00000000..4ef8fb0c --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/ContentTraverseCounter.java @@ -0,0 +1,47 @@ +package usi.si.seart.analyzer.count; + +import usi.si.seart.treesitter.Range; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +public abstract class ContentTraverseCounter extends TraverseCounter { + + public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_16LE; + + private byte[] bytes; + private boolean ready; + + protected ContentTraverseCounter() { + super(); + this.bytes = new byte[0]; + this.ready = false; + } + + protected ContentTraverseCounter(byte[] bytes) { + super(); + this.bytes = bytes; + this.ready = true; + } + + protected boolean isReady() { + return ready; + } + + public void setBytes(byte[] bytes) { + this.bytes = bytes; + this.ready = bytes.length > 0; + } + + private byte[] getBytesForRange(Range range) { + int startByte = range.getStartByte() * 2; + int endByte = range.getEndByte() * 2; + return Arrays.copyOfRange(this.bytes, startByte, endByte); + } + + protected final String getContentForRange(Range range) { + byte[] bytes = getBytesForRange(range); + return new String(bytes, DEFAULT_CHARSET); + } +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/Counter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/Counter.java new file mode 100644 index 00000000..24ef3463 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/Counter.java @@ -0,0 +1,7 @@ +package usi.si.seart.analyzer.count; + +import usi.si.seart.treesitter.Node; + +public interface Counter { + Long count(Node node); +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/LineCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/LineCounter.java new file mode 100644 index 00000000..0836046a --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/LineCounter.java @@ -0,0 +1,16 @@ +package usi.si.seart.analyzer.count; + +import usi.si.seart.treesitter.Node; +import usi.si.seart.treesitter.Point; +import usi.si.seart.treesitter.Range; + +public class LineCounter implements Counter { + + @Override + public Long count(Node node) { + Range range = node.getRange(); + Point startPoint = range.getStartPoint(); + Point endPoint = range.getEndPoint(); + return (long) (endPoint.getRow() - startPoint.getRow() + 1); + } +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TokenCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TokenCounter.java new file mode 100644 index 00000000..6225c23a --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TokenCounter.java @@ -0,0 +1,44 @@ +package usi.si.seart.analyzer.count; + +import usi.si.seart.treesitter.Node; +import usi.si.seart.treesitter.Range; + +public class TokenCounter extends ContentTraverseCounter { + + public TokenCounter() { + super(); + } + + public TokenCounter(byte[] bytes) { + super(bytes); + } + + @Override + protected void nodeCallback(Node node) { + if (!isReady()) return; + boolean leafNode = node.getChildCount() == 0; + if (leafNode) { + String[] tokens; + Range range = node.getRange(); + String content = getContentForRange(range); + String type = node.getType(); + switch (type) { + case "block_comment": + int idxLo = (content.startsWith("/**")) ? 3 : 2; + int idxHi = content.length() - 2; + content = content.substring(idxLo, idxHi); + tokens = content.split("\\s+"); + count.addAndGet(tokens.length + 2L); + break; + case "line_comment": + content = content.substring(2); + tokens = content.split("\\s+"); + count.addAndGet(tokens.length + 1L); + break; + default: + count.addAndGet(1L); + break; + } + } + } +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TraverseCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TraverseCounter.java new file mode 100644 index 00000000..e84b0b98 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TraverseCounter.java @@ -0,0 +1,32 @@ +package usi.si.seart.analyzer.count; + +import lombok.AccessLevel; +import lombok.Cleanup; +import lombok.NoArgsConstructor; +import lombok.experimental.FieldDefaults; +import usi.si.seart.treesitter.Node; +import usi.si.seart.treesitter.TreeCursor; + +import java.util.concurrent.atomic.AtomicLong; + +@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public abstract class TraverseCounter implements Counter { + + AtomicLong count = new AtomicLong(); + + @Override + public Long count(Node node) { + @Cleanup TreeCursor cursor = node.walk(); + cursor.preorderTraversal(this::nodeCallback); + Long result = count.get(); + this.reset(); + return result; + } + + protected abstract void nodeCallback(Node node); + + protected void reset() { + this.count.set(0); + } +} From 81997717b673d3077bf39e2ca51736d11b4e867c Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 6 Jan 2023 17:17:43 +0100 Subject: [PATCH 0023/1089] Introducing tests for the newly implemented counters --- .../analyzer/count/CharacterCounterTest.java | 29 +++++++ .../analyzer/count/CodeTokenCounterTest.java | 19 +++++ .../seart/analyzer/count/LineCounterTest.java | 18 +++++ .../analyzer/count/TokenCounterTest.java | 28 +++++++ .../si/seart/analyzer/hash/HasherTest.java | 75 +++++++++++++++++++ .../usi/si/seart/analyzer/test/BaseTest.java | 8 +- 6 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CharacterCounterTest.java create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CodeTokenCounterTest.java create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/LineCounterTest.java create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/TokenCounterTest.java diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CharacterCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CharacterCounterTest.java new file mode 100644 index 00000000..9a9efd95 --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CharacterCounterTest.java @@ -0,0 +1,29 @@ +package usi.si.seart.analyzer.count; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import usi.si.seart.analyzer.test.BaseTest; + +class CharacterCounterTest extends BaseTest { + + @Test + void countTest(){ + Counter counter = new CharacterCounter(bytes_1); + Long actual = counter.count(tree.getRootNode()); + // Remove 2 for the space in string and comment + Assertions.assertEquals( + tokens_joined_1.length() - 2, + actual, + "Total number of characters should be equal to the joined tree string without spaces!" + ); + } + + @Test + void isNotReadyTest() { + Counter counter = new CharacterCounter(); + Long actual = counter.count(tree.getRootNode()); + Assertions.assertEquals( + 0L, actual, "Total number of characters should be zero if backing byte array was not set!" + ); + } +} \ No newline at end of file diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CodeTokenCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CodeTokenCounterTest.java new file mode 100644 index 00000000..1bec435b --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CodeTokenCounterTest.java @@ -0,0 +1,19 @@ +package usi.si.seart.analyzer.count; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import usi.si.seart.analyzer.test.BaseTest; + +class CodeTokenCounterTest extends BaseTest { + + @Test + void countTest() { + Counter counter = new CodeTokenCounter(); + Long actual = counter.count(tree.getRootNode()); + // Remove 1 for the comment node + Assertions.assertEquals( + nodes_1.size() - 1, actual, + "Total number of code tokens should be equal to the number of input tokens without the comments!" + ); + } +} \ No newline at end of file diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/LineCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/LineCounterTest.java new file mode 100644 index 00000000..b1e131b2 --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/LineCounterTest.java @@ -0,0 +1,18 @@ +package usi.si.seart.analyzer.count; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import usi.si.seart.analyzer.test.BaseTest; + +class LineCounterTest extends BaseTest { + + @Test + void countTest() { + Counter counter = new LineCounter(); + Long actual = counter.count(tree.getRootNode()); + Assertions.assertEquals( + input_1.lines().count(), actual, + "Total number of lines should be equal to the number of lines reported by String method" + ); + } +} \ No newline at end of file diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/TokenCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/TokenCounterTest.java new file mode 100644 index 00000000..36eff9a6 --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/TokenCounterTest.java @@ -0,0 +1,28 @@ +package usi.si.seart.analyzer.count; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import usi.si.seart.analyzer.test.BaseTest; + +class TokenCounterTest extends BaseTest { + + @Test + void countTest() { + Counter counter = new TokenCounter(bytes_1); + Long actual = counter.count(tree.getRootNode()); + // Add 1 for the extra comment word + Assertions.assertEquals( + nodes_1.size() + 2, actual, + "Total number of tokens should be equal to the number of input tokens including comment tokens (words)!" + ); + } + + @Test + void isNotReadyTest() { + Counter counter = new TokenCounter(); + Long actual = counter.count(tree.getRootNode()); + Assertions.assertEquals( + 0L, actual, "Total number of tokens should be zero if backing byte array was not set!" + ); + } +} \ No newline at end of file diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/HasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/HasherTest.java index f8679d79..a9fd3c31 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/HasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/HasherTest.java @@ -5,9 +5,84 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.util.List; public abstract class HasherTest extends BaseTest { + protected final List tokens_1 = List.of( + "package", + "ch", + ".", + "usi", + ".", + "si", + ";", + "public", + "class", + "Main", + "{", + "public", + "static", + "void", + "main", + "(", + "String", + "[]", + "args", + ")", + "{", + "System", + ".", + "out", + ".", + "println", + "(", + "\"Hello, World!\"", + ")", + ";", + "}", + "}" + ); + + protected final String tokens_joined_1 = String.join("", tokens_1); + + protected final List nodes_1 = List.of( + "package", + "identifier", + ".", + "identifier", + ".", + "identifier", + ";", + "public", + "class", + "identifier", + "{", + "public", + "static", + "void_type", + "identifier", + "(", + "type_identifier", + "[]", + "identifier", + ")", + "{", + "identifier", + ".", + "identifier", + ".", + "identifier", + "(", + "string_literal", + ")", + ";", + "}", + "}" + ); + + protected final String nodes_joined_1 = String.join("", nodes_1); + @SneakyThrows({NoSuchAlgorithmException.class}) protected String sha256(String input) { MessageDigest md = MessageDigest.getInstance("SHA-256"); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java index 1f50307a..ce926232 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java @@ -69,13 +69,15 @@ void tearDown() { "class", "Main", "{", + "//line comment", "public", "static", "void", "main", "(", "String", - "[]", + "[", + "]", "args", ")", "{", @@ -106,13 +108,15 @@ void tearDown() { "class", "identifier", "{", + "line_comment", "public", "static", "void_type", "identifier", "(", "type_identifier", - "[]", + "[", + "]", "identifier", ")", "{", From 6ddac798eb256d935f39d02a36edbdba1d793d8b Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 9 Jan 2023 12:49:00 +0100 Subject: [PATCH 0024/1089] Added `Predicate` class hierarchy and class for non-ASCII checks --- .../analyzer/predicate/ContainsNonAscii.java | 28 +++++++++++++++ .../analyzer/predicate/ContentPredicate.java | 36 +++++++++++++++++++ .../seart/analyzer/predicate/Predicate.java | 7 ++++ .../predicate/ContainsNonAsciiTest.java | 36 +++++++++++++++++++ .../analyzer/predicate/PredicateTest.java | 20 +++++++++++ 5 files changed, 127 insertions(+) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsNonAscii.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContentPredicate.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/Predicate.java create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiTest.java create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/PredicateTest.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsNonAscii.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsNonAscii.java new file mode 100644 index 00000000..d602e541 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsNonAscii.java @@ -0,0 +1,28 @@ +package usi.si.seart.analyzer.predicate; + +import usi.si.seart.treesitter.Node; +import usi.si.seart.treesitter.Range; + +public class ContainsNonAscii extends ContentPredicate { + + public ContainsNonAscii() { + super(); + } + + public ContainsNonAscii(byte[] bytes) { + super(bytes); + } + + @Override + public Boolean test(Node node) { + if (!isReady()) return null; + Range range = node.getRange(); + byte[] bytes = getBytesForRange(range); + for (int i = 0; i < bytes.length; i += 2) { + if (bytes[i] < 0 || bytes[i + 1] != 0) { + return true; + } + } + return false; + } +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContentPredicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContentPredicate.java new file mode 100644 index 00000000..67cd8df7 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContentPredicate.java @@ -0,0 +1,36 @@ +package usi.si.seart.analyzer.predicate; + +import usi.si.seart.treesitter.Range; + +import java.util.Arrays; + +public abstract class ContentPredicate implements Predicate { + + private byte[] bytes; + private boolean ready; + + protected ContentPredicate() { + this.bytes = new byte[0]; + this.ready = false; + } + + protected ContentPredicate(byte[] bytes) { + this.bytes = bytes; + this.ready = true; + } + + protected boolean isReady() { + return ready; + } + + public void setBytes(byte[] bytes) { + this.bytes = bytes; + this.ready = bytes.length > 0; + } + + protected byte[] getBytesForRange(Range range) { + int startByte = range.getStartByte() * 2; + int endByte = range.getEndByte() * 2; + return Arrays.copyOfRange(this.bytes, startByte, endByte); + } +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/Predicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/Predicate.java new file mode 100644 index 00000000..fa4597c7 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/Predicate.java @@ -0,0 +1,7 @@ +package usi.si.seart.analyzer.predicate; + +import usi.si.seart.treesitter.Node; + +public interface Predicate { + Boolean test(Node node); +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiTest.java new file mode 100644 index 00000000..363ba40b --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiTest.java @@ -0,0 +1,36 @@ +package usi.si.seart.analyzer.predicate; + +import lombok.SneakyThrows; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import usi.si.seart.treesitter.Tree; + +import java.io.UnsupportedEncodingException; + +class ContainsNonAsciiTest extends PredicateTest { + + @Test + void containsNonAsciiTest() { + Predicate predicate = new ContainsNonAscii(bytes_1); + Boolean result = predicate.test(tree.getRootNode()); + Assertions.assertNotNull(result); + Assertions.assertTrue(result); + } + + @Test + @SneakyThrows(UnsupportedEncodingException.class) + void containsOnlyAsciiTest() { + Predicate predicate = new ContainsNonAscii(bytes_2); + Tree tree = parser.parseString(input_2); + Boolean result = predicate.test(tree.getRootNode()); + Assertions.assertNotNull(result); + Assertions.assertFalse(result); + } + + @Test + void isNotReadyTest() { + Predicate predicate = new ContainsNonAscii(); + Boolean result = predicate.test(tree.getRootNode()); + Assertions.assertNull(result); + } +} \ No newline at end of file diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/PredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/PredicateTest.java new file mode 100644 index 00000000..13ea7033 --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/PredicateTest.java @@ -0,0 +1,20 @@ +package usi.si.seart.analyzer.predicate; + +import usi.si.seart.analyzer.test.BaseTest; + +import java.nio.charset.StandardCharsets; + +public abstract class PredicateTest extends BaseTest { + + protected final String input_1 = + "package ch.usi.si;\n" + + "\n" + + "public class Main {\n" + + "\tpublic static void main(String[] args) {\n" + + "\t\t// 软件工程的深度学习\n" + + "\t\tSystem.out.println(\"Hello, World!\");\n" + + "\t}\n" + + "}"; + + protected final byte[] bytes_1 = input_1.getBytes(StandardCharsets.UTF_16LE); +} From ce32b6dbcdab61fd7c422d5255d25c20f2e2f986 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 10 Jan 2023 10:39:10 +0100 Subject: [PATCH 0025/1089] Both `Node` and `Tree` now implement the `Iterable` interface --- .../java/usi/si/seart/treesitter/Node.java | 33 ++++++++++++++++++- .../java/usi/si/seart/treesitter/Tree.java | 12 ++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java index e2529747..eec532bf 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java @@ -2,12 +2,16 @@ import lombok.NoArgsConstructor; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Stack; + /** * A Node represents a single node in the syntax tree. It tracks its start and end positions in the source code, * as well as its relation to other nodes like its parent, siblings and children. */ @NoArgsConstructor -public class Node { +public class Node implements Iterable { private int context0; private int context1; private int context2; @@ -215,4 +219,31 @@ public boolean equals(Object obj) { public int hashCode() { return Long.hashCode(id); } + + /** + * @return An iterator over the node subtree, starting from the current node. + */ + @Override + public Iterator iterator() { + return new Iterator<>() { + + private final Stack stack = new Stack<>() {{ push(Node.this); }}; + + @Override + public boolean hasNext() { + return !stack.isEmpty(); + } + + @Override + public Node next() { + if (!hasNext()) throw new NoSuchElementException(); + Node node = stack.pop(); + int children = node.getChildCount(); + for (int child = children - 1; child >= 0; child--) { + stack.push(node.getChild(child)); + } + return node; + } + }; + } } diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java index 7b50b068..c4f5fd19 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java @@ -3,13 +3,15 @@ import lombok.AllArgsConstructor; import lombok.Getter; +import java.util.Iterator; + /** * A Tree represents the syntax tree of an entire source code file. It contains {@link Node Node} * instances that indicate the structure of the source code. */ @Getter @AllArgsConstructor -public class Tree implements AutoCloseable { +public class Tree implements AutoCloseable, Iterable { private final long pointer; @@ -36,4 +38,12 @@ public void edit(InputEdit edit) { public Node getRootNode() { return TreeSitter.treeRootNode(pointer); } + + /** + * @return An iterator over the entire syntax tree, starting from the root node. + */ + @Override + public Iterator iterator() { + return getRootNode().iterator(); + } } From c881495d3d85378a5f864d222b83260c0a56ff9a Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 10 Jan 2023 17:36:34 +0100 Subject: [PATCH 0026/1089] Added `Printer` interface --- .../analyzer/printer/AbstractPrinter.java | 47 +++++++++++++++++++ .../seart/analyzer/printer/NodePrinter.java | 34 ++++++++++++++ .../si/seart/analyzer/printer/Printer.java | 7 +++ .../analyzer/printer/NodePrinterTest.java | 34 ++++++++++++++ 4 files changed, 122 insertions(+) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/AbstractPrinter.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/Printer.java create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/AbstractPrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/AbstractPrinter.java new file mode 100644 index 00000000..6fe9839b --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/AbstractPrinter.java @@ -0,0 +1,47 @@ +package usi.si.seart.analyzer.printer; + +import usi.si.seart.treesitter.Range; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +public abstract class AbstractPrinter implements Printer { + + public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_16LE; + + private byte[] bytes; + private boolean ready; + + public AbstractPrinter() { + super(); + this.bytes = new byte[0]; + this.ready = false; + } + + public AbstractPrinter(byte[] bytes) { + super(); + this.bytes = bytes; + this.ready = true; + } + + protected boolean isReady() { + return ready; + } + + public void setBytes(byte[] bytes) { + this.bytes = bytes; + this.ready = bytes.length > 0; + } + + private byte[] getBytesForRange(Range range) { + int startByte = range.getStartByte() * 2; + int endByte = range.getEndByte() * 2; + return Arrays.copyOfRange(this.bytes, startByte, endByte); + } + + protected final String getContentForRange(Range range) { + byte[] bytes = getBytesForRange(range); + return new String(bytes, DEFAULT_CHARSET); + } +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java new file mode 100644 index 00000000..66f8abfa --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java @@ -0,0 +1,34 @@ +package usi.si.seart.analyzer.printer; + +import usi.si.seart.treesitter.Node; +import usi.si.seart.treesitter.Range; + +import java.util.List; +import java.util.stream.Collectors; + +public class NodePrinter extends AbstractPrinter { + + public NodePrinter() { + super(); + } + + public NodePrinter(byte[] bytes) { + super(bytes); + } + + @Override + public String print(Node node) { + if (!isReady()) return null; + Range range = node.getRange(); + String content = getContentForRange(range); + int offset = node.getStartPoint().getColumn(); + List lines = content.lines().collect(Collectors.toList()); + for (int i = 1; i < lines.size(); i++) { + String line = lines.get(i); + if (line.length() > offset) + lines.set(i, line.substring(offset)); + } + return String.join("\n", lines); + } + +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/Printer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/Printer.java new file mode 100644 index 00000000..93f51fe6 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/Printer.java @@ -0,0 +1,7 @@ +package usi.si.seart.analyzer.printer; + +import usi.si.seart.treesitter.Node; + +public interface Printer { + String print(Node node); +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java new file mode 100644 index 00000000..a0b363f5 --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java @@ -0,0 +1,34 @@ +package usi.si.seart.analyzer.printer; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import usi.si.seart.analyzer.test.BaseTest; +import usi.si.seart.treesitter.Node; + +class NodePrinterTest extends BaseTest { + + @Test + void printTest() { + Printer printer = new NodePrinter(bytes_1); + Node root = tree.getRootNode(); + String actual = printer.print(root); + String expected = input_1; + Assertions.assertEquals(expected, actual); + + Node method = root.getChild(1).getChildByFieldName("body").getChild(1); + actual = printer.print(method); + expected = + "public static void main(String[] args) {\n" + + "\t//line comment\n" + + "\tSystem.out.println(\"Hello, World!\");\n" + + "}"; + Assertions.assertEquals(expected, actual); + } + + @Test + void isNotReadyTest() { + Printer printer = new NodePrinter(); + String actual = printer.print(tree.getRootNode()); + Assertions.assertNull(actual); + } +} \ No newline at end of file From 5be00e5768d7e02b5c12674b286aea44df9ee596 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 12 Jan 2023 11:29:01 +0100 Subject: [PATCH 0027/1089] Simplified the `count`, `hash`, `predicate` and `printer` hierarchies By favoring composition over inheritance, we remove a lot of duplicate code. The main class utilising these smaller logical components will essentially define how the bytes are obtained for mapping Nodes back to source code content. --- .../usi/si/seart/analyzer/NodeMapper.java | 21 +++++++++ .../java/usi/si/seart/analyzer/Settings.java | 8 ++++ .../analyzer/count/CharacterCounter.java | 12 ++---- .../count/ContentTraverseCounter.java | 43 ++----------------- .../si/seart/analyzer/count/TokenCounter.java | 12 ++---- .../si/seart/analyzer/hash/ContentHasher.java | 30 +++---------- .../analyzer/predicate/ContainsNonAscii.java | 12 ++---- .../analyzer/predicate/ContentPredicate.java | 32 ++------------ .../analyzer/printer/AbstractPrinter.java | 43 ++----------------- .../seart/analyzer/printer/NodePrinter.java | 12 ++---- .../analyzer/count/CharacterCounterTest.java | 14 ++---- .../analyzer/count/TokenCounterTest.java | 14 ++---- .../analyzer/hash/ContentHasherTest.java | 16 ++++--- .../predicate/ContainsNonAsciiTest.java | 11 +---- .../analyzer/printer/NodePrinterTest.java | 12 ++---- 15 files changed, 87 insertions(+), 205 deletions(-) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/NodeMapper.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Settings.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/NodeMapper.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/NodeMapper.java new file mode 100644 index 00000000..7fd8f545 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/NodeMapper.java @@ -0,0 +1,21 @@ +package usi.si.seart.analyzer; + +import usi.si.seart.treesitter.Range; + +import java.util.Arrays; + +public interface NodeMapper { + + byte[] getBytes(); + + default byte[] getBytesForRange(Range range) { + int startByte = range.getStartByte() * 2; + int endByte = range.getEndByte() * 2; + return Arrays.copyOfRange(getBytes(), startByte, endByte); + } + + default String getContentForRange(Range range) { + byte[] bytes = getBytesForRange(range); + return new String(bytes, Settings.DEFAULT_CHARSET); + } +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Settings.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Settings.java new file mode 100644 index 00000000..bc161b63 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Settings.java @@ -0,0 +1,8 @@ +package usi.si.seart.analyzer; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +public interface Settings { + Charset DEFAULT_CHARSET = StandardCharsets.UTF_16LE; +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CharacterCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CharacterCounter.java index 4685a377..5ee51c91 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CharacterCounter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CharacterCounter.java @@ -1,25 +1,21 @@ package usi.si.seart.analyzer.count; +import usi.si.seart.analyzer.NodeMapper; import usi.si.seart.treesitter.Node; import usi.si.seart.treesitter.Range; public class CharacterCounter extends ContentTraverseCounter { - public CharacterCounter() { - super(); - } - - public CharacterCounter(byte[] bytes) { - super(bytes); + public CharacterCounter(NodeMapper mapper) { + super(mapper); } @Override protected void nodeCallback(Node node) { - if (!isReady()) return; boolean leafNode = node.getChildCount() == 0; if (leafNode) { Range range = node.getRange(); - String content = getContentForRange(range); + String content = mapper.getContentForRange(range); String noSpace = content.replaceAll("\\s", ""); count.addAndGet(noSpace.length()); } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/ContentTraverseCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/ContentTraverseCounter.java index 4ef8fb0c..c5b154ee 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/ContentTraverseCounter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/ContentTraverseCounter.java @@ -1,47 +1,12 @@ package usi.si.seart.analyzer.count; -import usi.si.seart.treesitter.Range; - -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; +import usi.si.seart.analyzer.NodeMapper; public abstract class ContentTraverseCounter extends TraverseCounter { - public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_16LE; - - private byte[] bytes; - private boolean ready; - - protected ContentTraverseCounter() { - super(); - this.bytes = new byte[0]; - this.ready = false; - } - - protected ContentTraverseCounter(byte[] bytes) { - super(); - this.bytes = bytes; - this.ready = true; - } - - protected boolean isReady() { - return ready; - } - - public void setBytes(byte[] bytes) { - this.bytes = bytes; - this.ready = bytes.length > 0; - } - - private byte[] getBytesForRange(Range range) { - int startByte = range.getStartByte() * 2; - int endByte = range.getEndByte() * 2; - return Arrays.copyOfRange(this.bytes, startByte, endByte); - } + protected final NodeMapper mapper; - protected final String getContentForRange(Range range) { - byte[] bytes = getBytesForRange(range); - return new String(bytes, DEFAULT_CHARSET); + protected ContentTraverseCounter(NodeMapper mapper) { + this.mapper = mapper; } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TokenCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TokenCounter.java index 6225c23a..a1cc56bc 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TokenCounter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TokenCounter.java @@ -1,26 +1,22 @@ package usi.si.seart.analyzer.count; +import usi.si.seart.analyzer.NodeMapper; import usi.si.seart.treesitter.Node; import usi.si.seart.treesitter.Range; public class TokenCounter extends ContentTraverseCounter { - public TokenCounter() { - super(); - } - - public TokenCounter(byte[] bytes) { - super(bytes); + public TokenCounter(NodeMapper mapper) { + super(mapper); } @Override protected void nodeCallback(Node node) { - if (!isReady()) return; boolean leafNode = node.getChildCount() == 0; if (leafNode) { String[] tokens; Range range = node.getRange(); - String content = getContentForRange(range); + String content = mapper.getContentForRange(range); String type = node.getType(); switch (type) { case "block_comment": diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java index 9768cd2c..f754c9ca 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java @@ -2,45 +2,29 @@ import lombok.Cleanup; import lombok.Getter; +import usi.si.seart.analyzer.NodeMapper; import usi.si.seart.treesitter.Node; +import usi.si.seart.treesitter.Range; import usi.si.seart.treesitter.TreeCursor; -import java.util.Arrays; - @Getter public class ContentHasher extends SHA256Hasher { - private byte[] bytes; - private boolean ready; - - public ContentHasher() { - super(); - this.bytes = new byte[0]; - this.ready = false; - } - - public ContentHasher(byte[] bytes) { - super(); - this.bytes = bytes; - this.ready = true; - } + protected final NodeMapper mapper; - public void setBytes(byte[] bytes) { - this.bytes = bytes; - this.ready = bytes.length > 0; + public ContentHasher(NodeMapper mapper) { + this.mapper = mapper; } @Override public String hash(Node node) { - if (!ready) return null; @Cleanup TreeCursor cursor = node.walk(); cursor.preorderTraversal(current -> { boolean leafNode = current.getChildCount() == 0; boolean isComment = current.getType().contains("comment"); if (leafNode && !isComment) { - int startByte = current.getStartByte() * 2; - int endByte = current.getEndByte() * 2; - md.update(Arrays.copyOfRange(this.bytes, startByte, endByte)); + Range range = current.getRange(); + md.update(mapper.getBytesForRange(range)); } }); diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsNonAscii.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsNonAscii.java index d602e541..7972821c 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsNonAscii.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsNonAscii.java @@ -1,23 +1,19 @@ package usi.si.seart.analyzer.predicate; +import usi.si.seart.analyzer.NodeMapper; import usi.si.seart.treesitter.Node; import usi.si.seart.treesitter.Range; public class ContainsNonAscii extends ContentPredicate { - public ContainsNonAscii() { - super(); - } - - public ContainsNonAscii(byte[] bytes) { - super(bytes); + public ContainsNonAscii(NodeMapper mapper) { + super(mapper); } @Override public Boolean test(Node node) { - if (!isReady()) return null; Range range = node.getRange(); - byte[] bytes = getBytesForRange(range); + byte[] bytes = mapper.getBytesForRange(range); for (int i = 0; i < bytes.length; i += 2) { if (bytes[i] < 0 || bytes[i + 1] != 0) { return true; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContentPredicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContentPredicate.java index 67cd8df7..d2300377 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContentPredicate.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContentPredicate.java @@ -1,36 +1,12 @@ package usi.si.seart.analyzer.predicate; -import usi.si.seart.treesitter.Range; - -import java.util.Arrays; +import usi.si.seart.analyzer.NodeMapper; public abstract class ContentPredicate implements Predicate { - private byte[] bytes; - private boolean ready; - - protected ContentPredicate() { - this.bytes = new byte[0]; - this.ready = false; - } - - protected ContentPredicate(byte[] bytes) { - this.bytes = bytes; - this.ready = true; - } - - protected boolean isReady() { - return ready; - } - - public void setBytes(byte[] bytes) { - this.bytes = bytes; - this.ready = bytes.length > 0; - } + protected final NodeMapper mapper; - protected byte[] getBytesForRange(Range range) { - int startByte = range.getStartByte() * 2; - int endByte = range.getEndByte() * 2; - return Arrays.copyOfRange(this.bytes, startByte, endByte); + protected ContentPredicate(NodeMapper mapper) { + this.mapper = mapper; } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/AbstractPrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/AbstractPrinter.java index 6fe9839b..449f0d30 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/AbstractPrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/AbstractPrinter.java @@ -1,47 +1,12 @@ package usi.si.seart.analyzer.printer; -import usi.si.seart.treesitter.Range; - -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; +import usi.si.seart.analyzer.NodeMapper; public abstract class AbstractPrinter implements Printer { - public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_16LE; - - private byte[] bytes; - private boolean ready; - - public AbstractPrinter() { - super(); - this.bytes = new byte[0]; - this.ready = false; - } - - public AbstractPrinter(byte[] bytes) { - super(); - this.bytes = bytes; - this.ready = true; - } - - protected boolean isReady() { - return ready; - } - - public void setBytes(byte[] bytes) { - this.bytes = bytes; - this.ready = bytes.length > 0; - } - - private byte[] getBytesForRange(Range range) { - int startByte = range.getStartByte() * 2; - int endByte = range.getEndByte() * 2; - return Arrays.copyOfRange(this.bytes, startByte, endByte); - } + protected final NodeMapper mapper; - protected final String getContentForRange(Range range) { - byte[] bytes = getBytesForRange(range); - return new String(bytes, DEFAULT_CHARSET); + protected AbstractPrinter(NodeMapper mapper) { + this.mapper = mapper; } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java index 66f8abfa..e254e2e5 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java @@ -1,5 +1,6 @@ package usi.si.seart.analyzer.printer; +import usi.si.seart.analyzer.NodeMapper; import usi.si.seart.treesitter.Node; import usi.si.seart.treesitter.Range; @@ -8,19 +9,14 @@ public class NodePrinter extends AbstractPrinter { - public NodePrinter() { - super(); - } - - public NodePrinter(byte[] bytes) { - super(bytes); + public NodePrinter(NodeMapper mapper) { + super(mapper); } @Override public String print(Node node) { - if (!isReady()) return null; Range range = node.getRange(); - String content = getContentForRange(range); + String content = mapper.getContentForRange(range); int offset = node.getStartPoint().getColumn(); List lines = content.lines().collect(Collectors.toList()); for (int i = 1; i < lines.size(); i++) { diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CharacterCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CharacterCounterTest.java index 9a9efd95..d16c86b0 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CharacterCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CharacterCounterTest.java @@ -2,13 +2,16 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import usi.si.seart.analyzer.NodeMapper; import usi.si.seart.analyzer.test.BaseTest; class CharacterCounterTest extends BaseTest { + private final NodeMapper mapper = () -> bytes_1; + @Test void countTest(){ - Counter counter = new CharacterCounter(bytes_1); + Counter counter = new CharacterCounter(mapper); Long actual = counter.count(tree.getRootNode()); // Remove 2 for the space in string and comment Assertions.assertEquals( @@ -17,13 +20,4 @@ void countTest(){ "Total number of characters should be equal to the joined tree string without spaces!" ); } - - @Test - void isNotReadyTest() { - Counter counter = new CharacterCounter(); - Long actual = counter.count(tree.getRootNode()); - Assertions.assertEquals( - 0L, actual, "Total number of characters should be zero if backing byte array was not set!" - ); - } } \ No newline at end of file diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/TokenCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/TokenCounterTest.java index 36eff9a6..01f655b6 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/TokenCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/TokenCounterTest.java @@ -2,13 +2,16 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import usi.si.seart.analyzer.NodeMapper; import usi.si.seart.analyzer.test.BaseTest; class TokenCounterTest extends BaseTest { + private final NodeMapper mapper = () -> bytes_1; + @Test void countTest() { - Counter counter = new TokenCounter(bytes_1); + Counter counter = new TokenCounter(mapper); Long actual = counter.count(tree.getRootNode()); // Add 1 for the extra comment word Assertions.assertEquals( @@ -16,13 +19,4 @@ void countTest() { "Total number of tokens should be equal to the number of input tokens including comment tokens (words)!" ); } - - @Test - void isNotReadyTest() { - Counter counter = new TokenCounter(); - Long actual = counter.count(tree.getRootNode()); - Assertions.assertEquals( - 0L, actual, "Total number of tokens should be zero if backing byte array was not set!" - ); - } } \ No newline at end of file diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java index 7b7a0164..f42e0ef2 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java @@ -3,15 +3,18 @@ import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import usi.si.seart.analyzer.NodeMapper; import usi.si.seart.treesitter.Tree; import java.io.UnsupportedEncodingException; class ContentHasherTest extends HasherTest { + private final NodeMapper mapper = () -> bytes_1; + @Test void hashTest() { - Hasher hasher = new ContentHasher(bytes_1); + Hasher hasher = new ContentHasher(mapper); String actual = hasher.hash(tree.getRootNode()); String expected = sha256(tokens_joined_1); Assertions.assertEquals(expected, actual, "Incrementally digested tree hash should be equal to the flat code manual digest!"); @@ -19,7 +22,7 @@ void hashTest() { @Test void idempotencyTest() { - Hasher hasher = new ContentHasher(bytes_1); + Hasher hasher = new ContentHasher(mapper); String first = hasher.hash(tree.getRootNode()); String second = hasher.hash(tree.getRootNode()); Assertions.assertEquals(first, second, "Same instance should be reusable for multiple invocations!"); @@ -29,11 +32,10 @@ void idempotencyTest() { @SneakyThrows(UnsupportedEncodingException.class) void noCommentImpactTest() { Tree other = parser.parseString(input_2); - ContentHasher hasher = new ContentHasher(); - hasher.setBytes(bytes_1); - String first = hasher.hash(tree.getRootNode()); - hasher.setBytes(bytes_2); - String second = hasher.hash(other.getRootNode()); + ContentHasher hasher_1 = new ContentHasher(() -> bytes_1); + ContentHasher hasher_2 = new ContentHasher(() -> bytes_2); + String first = hasher_1.hash(tree.getRootNode()); + String second = hasher_2.hash(other.getRootNode()); Assertions.assertEquals(first, second, "Comments should not impact the hashing result!"); } } \ No newline at end of file diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiTest.java index 363ba40b..16cc82fb 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiTest.java @@ -11,7 +11,7 @@ class ContainsNonAsciiTest extends PredicateTest { @Test void containsNonAsciiTest() { - Predicate predicate = new ContainsNonAscii(bytes_1); + Predicate predicate = new ContainsNonAscii(() -> bytes_1); Boolean result = predicate.test(tree.getRootNode()); Assertions.assertNotNull(result); Assertions.assertTrue(result); @@ -20,17 +20,10 @@ void containsNonAsciiTest() { @Test @SneakyThrows(UnsupportedEncodingException.class) void containsOnlyAsciiTest() { - Predicate predicate = new ContainsNonAscii(bytes_2); + Predicate predicate = new ContainsNonAscii(() -> bytes_2); Tree tree = parser.parseString(input_2); Boolean result = predicate.test(tree.getRootNode()); Assertions.assertNotNull(result); Assertions.assertFalse(result); } - - @Test - void isNotReadyTest() { - Predicate predicate = new ContainsNonAscii(); - Boolean result = predicate.test(tree.getRootNode()); - Assertions.assertNull(result); - } } \ No newline at end of file diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java index a0b363f5..70b39df9 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java @@ -2,14 +2,17 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import usi.si.seart.analyzer.NodeMapper; import usi.si.seart.analyzer.test.BaseTest; import usi.si.seart.treesitter.Node; class NodePrinterTest extends BaseTest { + private final NodeMapper mapper = () -> bytes_1; + @Test void printTest() { - Printer printer = new NodePrinter(bytes_1); + Printer printer = new NodePrinter(mapper); Node root = tree.getRootNode(); String actual = printer.print(root); String expected = input_1; @@ -24,11 +27,4 @@ void printTest() { "}"; Assertions.assertEquals(expected, actual); } - - @Test - void isNotReadyTest() { - Printer printer = new NodePrinter(); - String actual = printer.print(tree.getRootNode()); - Assertions.assertNull(actual); - } } \ No newline at end of file From 16aeea7e8d0b671511747e36dfdea22fd2d2606c Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 12 Jan 2023 15:22:31 +0100 Subject: [PATCH 0028/1089] Added `queries` hierarchy for, you guessed it, running queries! --- .../query/JavaSingleCaptureQueries.java | 23 +++++++++ .../usi/si/seart/analyzer/query/Queries.java | 11 +++++ .../analyzer/query/SingleCaptureQueries.java | 48 +++++++++++++++++++ .../si/seart/analyzer/query/Validated.java | 21 ++++++++ .../query/VoidSingleCaptureQueries.java | 29 +++++++++++ 5 files changed, 132 insertions(+) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/JavaSingleCaptureQueries.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/Queries.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/SingleCaptureQueries.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/Validated.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/VoidSingleCaptureQueries.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/JavaSingleCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/JavaSingleCaptureQueries.java new file mode 100644 index 00000000..9e8d3e03 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/JavaSingleCaptureQueries.java @@ -0,0 +1,23 @@ +package usi.si.seart.analyzer.query; + +import usi.si.seart.treesitter.Language; +import usi.si.seart.treesitter.Node; + +import java.util.List; + +public class JavaSingleCaptureQueries extends SingleCaptureQueries { + + public JavaSingleCaptureQueries() { + super(Language.JAVA); + } + + @Override + public List getComments(Node node) { + return execute(node, "[(line_comment) (block_comment)] @comment"); + } + + @Override + public List getCallableDeclarations(Node node) { + return execute(node, "[(constructor_declaration) (method_declaration)] @declaration"); + } +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/Queries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/Queries.java new file mode 100644 index 00000000..812d0157 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/Queries.java @@ -0,0 +1,11 @@ +package usi.si.seart.analyzer.query; + +import usi.si.seart.treesitter.Node; + +import java.util.Collection; + +public interface Queries> { + C getNodes(Node node); + C getComments(Node node); + C getCallableDeclarations(Node node); +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/SingleCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/SingleCaptureQueries.java new file mode 100644 index 00000000..74e1c944 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/SingleCaptureQueries.java @@ -0,0 +1,48 @@ +package usi.si.seart.analyzer.query; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Cleanup; +import usi.si.seart.treesitter.Language; +import usi.si.seart.treesitter.Node; +import usi.si.seart.treesitter.Query; +import usi.si.seart.treesitter.QueryCapture; +import usi.si.seart.treesitter.QueryCursor; +import usi.si.seart.treesitter.QueryMatch; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +@AllArgsConstructor(access = AccessLevel.PROTECTED) +public abstract class SingleCaptureQueries implements Queries>, Validated { + + private final Language language; + + @Override + public List getNodes(Node node) { + return execute(node, "(_) @node"); + } + + protected List execute(Node node, String sExpr) { + validate(sExpr, "Queries must contain at least one capture!"); + @Cleanup Query query = new Query(this.language, sExpr); + @Cleanup QueryCursor cursor = new QueryCursor(); + cursor.execQuery(query, node); + List matches = new ArrayList<>(); + QueryMatch match; + while ((match = cursor.nextMatch()) != null) + matches.add(match); + return matches.stream() + .map(QueryMatch::getCaptures) + .flatMap(Arrays::stream) + .map(QueryCapture::getNode) + .collect(Collectors.toList()); + } + + @Override + public boolean isPastThreshold(int count) { + return count >= 1; + } +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/Validated.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/Validated.java new file mode 100644 index 00000000..c69833d2 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/Validated.java @@ -0,0 +1,21 @@ +package usi.si.seart.analyzer.query; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public interface Validated { + + Pattern CAPTURE_PATTERN = Pattern.compile("@[A-Za-z0-9_]+"); + + default void validate(String sExpr, String message) { + int count = 0; + Matcher matcher = CAPTURE_PATTERN.matcher(sExpr); + while (matcher.find()) count++; + if (!isPastThreshold(count)) + throw new IllegalArgumentException(message); + } + + default boolean isPastThreshold(int count) { + return count >= 0; + } +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/VoidSingleCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/VoidSingleCaptureQueries.java new file mode 100644 index 00000000..a0216b96 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/VoidSingleCaptureQueries.java @@ -0,0 +1,29 @@ +package usi.si.seart.analyzer.query; + +import usi.si.seart.treesitter.Node; + +import java.util.List; + +public class VoidSingleCaptureQueries extends SingleCaptureQueries { + + private static final List NO_RESULTS = List.of(); + + public VoidSingleCaptureQueries() { + super(null); + } + + @Override + public List getNodes(Node node) { + return NO_RESULTS; + } + + @Override + public List getComments(Node node) { + return NO_RESULTS; + } + + @Override + public List getCallableDeclarations(Node node) { + return NO_RESULTS; + } +} From d236286e0ddf5cd8a66f386c5e260be406632597 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 13 Jan 2023 16:43:03 +0100 Subject: [PATCH 0029/1089] Parser language must now be specified when creating a new instance! This minimizes the risk of segfaults due to the parser being used without any language being set. Although parser instances can be reused by changing the set language, creating a parser instance means defining the "starting" language. --- .../usi/si/seart/analyzer/test/BaseTest.java | 3 +- .../java/usi/si/seart/treesitter/Parser.java | 12 ++--- .../usi/si/seart/treesitter/NodeTest.java | 45 +++++++------------ .../usi/si/seart/treesitter/ParserTest.java | 6 +-- .../si/seart/treesitter/QueryCursorTest.java | 6 +-- .../si/seart/treesitter/TreeCursorTest.java | 3 +- .../usi/si/seart/treesitter/TreeTest.java | 3 +- 7 files changed, 28 insertions(+), 50 deletions(-) diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java index ce926232..4c2c44b3 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java @@ -24,8 +24,7 @@ public abstract class BaseTest { @BeforeAll static void beforeAll() { - parser = new Parser(); - parser.setLanguage(Language.JAVA); + parser = new Parser(Language.JAVA); } @AfterAll diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java index 578a6ca0..5f4d3584 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java @@ -1,26 +1,25 @@ package usi.si.seart.treesitter; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; - import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Objects; /** * Parsers are stateful objects that can be assigned a language and used to produce a * {@link Tree Tree} based on some source code. */ -@AllArgsConstructor(access = AccessLevel.PACKAGE) public class Parser implements AutoCloseable { private final long pointer; - public Parser() { - this(TreeSitter.parserNew()); + public Parser(Language language) { + Objects.requireNonNull(language, "Language must not be null!"); + this.pointer = TreeSitter.parserNew(); + this.setLanguage(language); } /** @@ -29,6 +28,7 @@ public Parser() { * @param language The language used for parsing. */ public void setLanguage(Language language) { + Objects.requireNonNull(language, "Language must not be null!"); TreeSitter.parserSetLanguage(pointer, language.getId()); } diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java index 6f38db9d..ea6ae62c 100644 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java @@ -14,8 +14,7 @@ class NodeTest extends TestBase { @Test @SneakyThrows({UnsupportedEncodingException.class}) void testGetChild() { - @Cleanup Parser parser = new Parser(); - parser.setLanguage(Language.PYTHON); + @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString(source); Node root = tree.getRootNode(); Assertions.assertEquals(1, root.getChildCount()); @@ -31,8 +30,7 @@ void testGetChild() { @Test @SneakyThrows({UnsupportedEncodingException.class}) void testGetChildByFieldName() { - @Cleanup Parser parser = new Parser(); - parser.setLanguage(Language.PYTHON); + @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString(source); Node root = tree.getRootNode(); Node function = root.getChild(0); @@ -43,8 +41,7 @@ void testGetChildByFieldName() { @Test @SneakyThrows({UnsupportedEncodingException.class}) void testGetDescendantForByteRange() { - @Cleanup Parser parser = new Parser(); - parser.setLanguage(Language.PYTHON); + @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString(source); Node root = tree.getRootNode(); Node function = root.getChild(0); @@ -63,8 +60,7 @@ void testGetDescendantForByteRange() { @Test @SneakyThrows({UnsupportedEncodingException.class}) void testGetFieldNameForChild() { - @Cleanup Parser parser = new Parser(); - parser.setLanguage(Language.PYTHON); + @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString(source); Node root = tree.getRootNode(); Node function = root.getChild(0); @@ -78,8 +74,7 @@ void testGetFieldNameForChild() { @Test @SneakyThrows({UnsupportedEncodingException.class}) void testGetFirstChildForByte() { - @Cleanup Parser parser = new Parser(); - parser.setLanguage(Language.PYTHON); + @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString(source); Node root = tree.getRootNode(); Node function = root.getChild(0); @@ -98,8 +93,7 @@ void testGetFirstChildForByte() { @Test @SneakyThrows({UnsupportedEncodingException.class}) void testGetFirstNamedChildForByte() { - @Cleanup Parser parser = new Parser(); - parser.setLanguage(Language.PYTHON); + @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString(source); Node root = tree.getRootNode(); Node function = root.getChild(0); @@ -118,8 +112,7 @@ void testGetFirstNamedChildForByte() { @Test @SneakyThrows({UnsupportedEncodingException.class}) void testGetParent() { - @Cleanup Parser parser = new Parser(); - parser.setLanguage(Language.PYTHON); + @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString(source); Node root = tree.getRootNode(); Assertions.assertNull(root.getParent()); @@ -129,8 +122,7 @@ void testGetParent() { @Test @SneakyThrows({UnsupportedEncodingException.class}) void testGetNextNamedSibling() { - @Cleanup Parser parser = new Parser(); - parser.setLanguage(Language.PYTHON); + @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString(source); Node root = tree.getRootNode(); Node function = root.getChild(0); @@ -143,8 +135,7 @@ void testGetNextNamedSibling() { @Test @SneakyThrows({UnsupportedEncodingException.class}) void testGetNextSibling() { - @Cleanup Parser parser = new Parser(); - parser.setLanguage(Language.PYTHON); + @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString(source); Node root = tree.getRootNode(); Node function = root.getChild(0); @@ -157,8 +148,7 @@ void testGetNextSibling() { @Test @SneakyThrows({UnsupportedEncodingException.class}) void testGetPrevNamedSibling() { - @Cleanup Parser parser = new Parser(); - parser.setLanguage(Language.PYTHON); + @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString(source); Node root = tree.getRootNode(); Node function = root.getChild(0); @@ -171,8 +161,7 @@ void testGetPrevNamedSibling() { @Test @SneakyThrows({UnsupportedEncodingException.class}) void testGetPrevSibling() { - @Cleanup Parser parser = new Parser(); - parser.setLanguage(Language.PYTHON); + @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString(source); Node root = tree.getRootNode(); Node function = root.getChild(0); @@ -185,8 +174,7 @@ void testGetPrevSibling() { @Test @SneakyThrows({UnsupportedEncodingException.class}) void testHasError() { - @Cleanup Parser parser = new Parser(); - parser.setLanguage(Language.PYTHON); + @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString("def foo(bar, baz):\n print(bar.)"); Node root = tree.getRootNode(); Node function = root.getChild(0); @@ -199,8 +187,7 @@ void testHasError() { @Test @SneakyThrows({UnsupportedEncodingException.class}) void testIsExtra() { - @Cleanup Parser parser = new Parser(); - parser.setLanguage(Language.PYTHON); + @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString("# this is just a comment"); Node root = tree.getRootNode(); Node comment = root.getChild(0); @@ -211,8 +198,7 @@ void testIsExtra() { @Test @SneakyThrows({UnsupportedEncodingException.class}) void testIsMissing() { - @Cleanup Parser parser = new Parser(); - parser.setLanguage(Language.JAVA); + @Cleanup Parser parser = new Parser(Language.JAVA); @Cleanup Tree tree = parser.parseString("class C { public static final int i = 6 }"); Node root = tree.getRootNode(); Assertions.assertFalse(root.isMissing()); @@ -226,8 +212,7 @@ void testIsMissing() { @Test @SneakyThrows({UnsupportedEncodingException.class}) void testIsNamed() { - @Cleanup Parser parser = new Parser(); - parser.setLanguage(Language.PYTHON); + @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString(source); Node root = tree.getRootNode(); Node function = root.getChild(0); diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/ParserTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/ParserTest.java index 0a01079d..ea5c3baf 100644 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/ParserTest.java +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/ParserTest.java @@ -29,16 +29,14 @@ static void beforeAll() throws IOException { @Test void testParseString() throws UnsupportedEncodingException { - @Cleanup Parser parser = new Parser(); - parser.setLanguage(Language.PYTHON); + @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString(source); Assertions.assertEquals(nodeString, tree.getRootNode().getNodeString()); } @Test void testParseFile() throws IOException { - @Cleanup Parser parser = new Parser(); - parser.setLanguage(Language.PYTHON); + @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseFile(tmpFile); Assertions.assertEquals(nodeString, tree.getRootNode().getNodeString()); } diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryCursorTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryCursorTest.java index 203371e4..48772263 100644 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryCursorTest.java +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryCursorTest.java @@ -10,8 +10,7 @@ class QueryCursorTest extends TestBase { @Test void testExecSimpleQuery() throws UnsupportedEncodingException { - @Cleanup Parser parser = new Parser(); - parser.setLanguage(Language.JAVA); + @Cleanup Parser parser = new Parser(Language.JAVA); @Cleanup Tree tree = parser.parseString("class Hello {}"); @Cleanup Query query = new Query(Language.JAVA, "(class_body) @test"); @Cleanup QueryCursor cursor = new QueryCursor(); @@ -23,8 +22,7 @@ void testExecSimpleQuery() throws UnsupportedEncodingException { @Test void testExecNoResultQuery() throws UnsupportedEncodingException { - @Cleanup Parser parser = new Parser(); - parser.setLanguage(Language.JAVA); + @Cleanup Parser parser = new Parser(Language.JAVA); @Cleanup Tree tree = parser.parseString("class Hello {}"); @Cleanup Query query = new Query(Language.JAVA, "(method_declaration) @method"); @Cleanup QueryCursor cursor = new QueryCursor(); diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeCursorTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeCursorTest.java index 4a2f98c2..b1fad3cb 100644 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeCursorTest.java +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeCursorTest.java @@ -10,8 +10,7 @@ class TreeCursorTest extends TestBase { @Test void testWalk() throws UnsupportedEncodingException { - @Cleanup Parser parser = new Parser(); - parser.setLanguage(Language.PYTHON); + @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString("def foo(bar, baz):\n print(bar)\n print(baz)"); @Cleanup TreeCursor cursor = tree.getRootNode().walk(); Assertions.assertEquals("module", cursor.getCurrentTreeCursorNode().getType()); diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeTest.java index 8134781c..ecdd6ef7 100644 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeTest.java +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeTest.java @@ -10,8 +10,7 @@ class TreeTest extends TestBase { @Test void testTreeEdit() throws UnsupportedEncodingException { - @Cleanup Parser parser = new Parser(); - parser.setLanguage(Language.JAVA); + @Cleanup Parser parser = new Parser(Language.JAVA); Tree tree = parser.parseString("class Main {\n // This is a line comment\n}"); From 3013bbaee82fc419e4bface41f9b1cee1c294a04 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 13 Jan 2023 16:48:27 +0100 Subject: [PATCH 0030/1089] Added run config for tree-sitter binding tests --- .idea/runConfigurations/Tests__dl4se_tree_sitter.xml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .idea/runConfigurations/Tests__dl4se_tree_sitter.xml diff --git a/.idea/runConfigurations/Tests__dl4se_tree_sitter.xml b/.idea/runConfigurations/Tests__dl4se_tree_sitter.xml new file mode 100644 index 00000000..30c44902 --- /dev/null +++ b/.idea/runConfigurations/Tests__dl4se_tree_sitter.xml @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file From ecc3ceff65ce67d4e8b84bd2d66cd16244fe0b53 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 16 Jan 2023 10:07:30 +0100 Subject: [PATCH 0031/1089] Renamed `AbstractPrinter` to `ContentPrinter` --- .../printer/{AbstractPrinter.java => ContentPrinter.java} | 4 ++-- .../main/java/usi/si/seart/analyzer/printer/NodePrinter.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/{AbstractPrinter.java => ContentPrinter.java} (59%) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/AbstractPrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/ContentPrinter.java similarity index 59% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/AbstractPrinter.java rename to dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/ContentPrinter.java index 449f0d30..76cff436 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/AbstractPrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/ContentPrinter.java @@ -2,11 +2,11 @@ import usi.si.seart.analyzer.NodeMapper; -public abstract class AbstractPrinter implements Printer { +public abstract class ContentPrinter implements Printer { protected final NodeMapper mapper; - protected AbstractPrinter(NodeMapper mapper) { + protected ContentPrinter(NodeMapper mapper) { this.mapper = mapper; } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java index e254e2e5..64951fad 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java @@ -7,7 +7,7 @@ import java.util.List; import java.util.stream.Collectors; -public class NodePrinter extends AbstractPrinter { +public class NodePrinter extends ContentPrinter { public NodePrinter(NodeMapper mapper) { super(mapper); From 219496028e40d167aff321a0bd1b5c3ec6e603db Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 16 Jan 2023 10:36:57 +0100 Subject: [PATCH 0032/1089] Removed the redundant `VoidSingleCaptureQueries` definition --- .../analyzer/query/SingleCaptureQueries.java | 23 +++++++++++++++ .../query/VoidSingleCaptureQueries.java | 29 ------------------- 2 files changed, 23 insertions(+), 29 deletions(-) delete mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/VoidSingleCaptureQueries.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/SingleCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/SingleCaptureQueries.java index 74e1c944..942b4f1a 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/SingleCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/SingleCaptureQueries.java @@ -45,4 +45,27 @@ protected List execute(Node node, String sExpr) { public boolean isPastThreshold(int count) { return count >= 1; } + + public static SingleCaptureQueries forLanguage(Language language) { + switch (language) { + case JAVA: return new JavaSingleCaptureQueries(); + default: return new SingleCaptureQueries(null) { + + @Override + public List getNodes(Node node) { + return List.of(); + } + + @Override + public List getComments(Node node) { + return List.of(); + } + + @Override + public List getCallableDeclarations(Node node) { + return List.of(); + } + }; + } + } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/VoidSingleCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/VoidSingleCaptureQueries.java deleted file mode 100644 index a0216b96..00000000 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/VoidSingleCaptureQueries.java +++ /dev/null @@ -1,29 +0,0 @@ -package usi.si.seart.analyzer.query; - -import usi.si.seart.treesitter.Node; - -import java.util.List; - -public class VoidSingleCaptureQueries extends SingleCaptureQueries { - - private static final List NO_RESULTS = List.of(); - - public VoidSingleCaptureQueries() { - super(null); - } - - @Override - public List getNodes(Node node) { - return NO_RESULTS; - } - - @Override - public List getComments(Node node) { - return NO_RESULTS; - } - - @Override - public List getCallableDeclarations(Node node) { - return NO_RESULTS; - } -} From d583055dd314ae412827b43248cac6dd8421db83 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 16 Jan 2023 10:41:02 +0100 Subject: [PATCH 0033/1089] Removed the redundant `Predicate` interface --- .../seart/analyzer/predicate/ContainsNonAscii.java | 2 +- .../seart/analyzer/predicate/ContentPredicate.java | 5 ++++- .../usi/si/seart/analyzer/predicate/Predicate.java | 7 ------- .../analyzer/predicate/ContainsNonAsciiTest.java | 12 ++++++------ 4 files changed, 11 insertions(+), 15 deletions(-) delete mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/Predicate.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsNonAscii.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsNonAscii.java index 7972821c..de77c243 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsNonAscii.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsNonAscii.java @@ -11,7 +11,7 @@ public ContainsNonAscii(NodeMapper mapper) { } @Override - public Boolean test(Node node) { + public boolean test(Node node) { Range range = node.getRange(); byte[] bytes = mapper.getBytesForRange(range); for (int i = 0; i < bytes.length; i += 2) { diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContentPredicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContentPredicate.java index d2300377..fdad4e3c 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContentPredicate.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContentPredicate.java @@ -1,8 +1,11 @@ package usi.si.seart.analyzer.predicate; import usi.si.seart.analyzer.NodeMapper; +import usi.si.seart.treesitter.Node; -public abstract class ContentPredicate implements Predicate { +import java.util.function.Predicate; + +public abstract class ContentPredicate implements Predicate { protected final NodeMapper mapper; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/Predicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/Predicate.java deleted file mode 100644 index fa4597c7..00000000 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/Predicate.java +++ /dev/null @@ -1,7 +0,0 @@ -package usi.si.seart.analyzer.predicate; - -import usi.si.seart.treesitter.Node; - -public interface Predicate { - Boolean test(Node node); -} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiTest.java index 16cc82fb..b93e30a0 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiTest.java @@ -3,27 +3,27 @@ import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import usi.si.seart.treesitter.Node; import usi.si.seart.treesitter.Tree; import java.io.UnsupportedEncodingException; +import java.util.function.Predicate; class ContainsNonAsciiTest extends PredicateTest { @Test void containsNonAsciiTest() { - Predicate predicate = new ContainsNonAscii(() -> bytes_1); - Boolean result = predicate.test(tree.getRootNode()); - Assertions.assertNotNull(result); + Predicate predicate = new ContainsNonAscii(() -> bytes_1); + boolean result = predicate.test(tree.getRootNode()); Assertions.assertTrue(result); } @Test @SneakyThrows(UnsupportedEncodingException.class) void containsOnlyAsciiTest() { - Predicate predicate = new ContainsNonAscii(() -> bytes_2); + Predicate predicate = new ContainsNonAscii(() -> bytes_2); Tree tree = parser.parseString(input_2); - Boolean result = predicate.test(tree.getRootNode()); - Assertions.assertNotNull(result); + boolean result = predicate.test(tree.getRootNode()); Assertions.assertFalse(result); } } \ No newline at end of file From 9825d38f0f7deb04ff01605e1e2337cfde64abb3 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 16 Jan 2023 10:51:11 +0100 Subject: [PATCH 0034/1089] Better naming for defined `Predicate` classes --- ...ContainsNonAscii.java => ContainsNonAsciiPredicate.java} | 4 ++-- ...NonAsciiTest.java => ContainsNonAsciiPredicateTest.java} | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) rename dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/{ContainsNonAscii.java => ContainsNonAsciiPredicate.java} (80%) rename dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/{ContainsNonAsciiTest.java => ContainsNonAsciiPredicateTest.java} (76%) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsNonAscii.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiPredicate.java similarity index 80% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsNonAscii.java rename to dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiPredicate.java index de77c243..c6aa1a2b 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsNonAscii.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiPredicate.java @@ -4,9 +4,9 @@ import usi.si.seart.treesitter.Node; import usi.si.seart.treesitter.Range; -public class ContainsNonAscii extends ContentPredicate { +public class ContainsNonAsciiPredicate extends ContentPredicate { - public ContainsNonAscii(NodeMapper mapper) { + public ContainsNonAsciiPredicate(NodeMapper mapper) { super(mapper); } diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiPredicateTest.java similarity index 76% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiTest.java rename to dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiPredicateTest.java index b93e30a0..12c084c3 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiPredicateTest.java @@ -9,11 +9,11 @@ import java.io.UnsupportedEncodingException; import java.util.function.Predicate; -class ContainsNonAsciiTest extends PredicateTest { +class ContainsNonAsciiPredicateTest extends PredicateTest { @Test void containsNonAsciiTest() { - Predicate predicate = new ContainsNonAscii(() -> bytes_1); + Predicate predicate = new ContainsNonAsciiPredicate(() -> bytes_1); boolean result = predicate.test(tree.getRootNode()); Assertions.assertTrue(result); } @@ -21,7 +21,7 @@ void containsNonAsciiTest() { @Test @SneakyThrows(UnsupportedEncodingException.class) void containsOnlyAsciiTest() { - Predicate predicate = new ContainsNonAscii(() -> bytes_2); + Predicate predicate = new ContainsNonAsciiPredicate(() -> bytes_2); Tree tree = parser.parseString(input_2); boolean result = predicate.test(tree.getRootNode()); Assertions.assertFalse(result); From f31c0951484a39b86cf4d4da9192d3731abb1f46 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 16 Jan 2023 11:05:19 +0100 Subject: [PATCH 0035/1089] Added `Predicate` class for basic node error detection Do we need a separate class just for running one line of code? Not really but since everything is a class at this point we might as well isolate this code too to be consistent. --- .../predicate/ContainsErrorPredicate.java | 13 +++++++ .../predicate/ContainsErrorPredicateTest.java | 34 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsErrorPredicate.java create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsErrorPredicateTest.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsErrorPredicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsErrorPredicate.java new file mode 100644 index 00000000..7e5adeb6 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsErrorPredicate.java @@ -0,0 +1,13 @@ +package usi.si.seart.analyzer.predicate; + +import usi.si.seart.treesitter.Node; + +import java.util.function.Predicate; + +public class ContainsErrorPredicate implements Predicate { + + @Override + public boolean test(Node node) { + return node.hasError(); + } +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsErrorPredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsErrorPredicateTest.java new file mode 100644 index 00000000..aee2b643 --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsErrorPredicateTest.java @@ -0,0 +1,34 @@ +package usi.si.seart.analyzer.predicate; + +import lombok.Cleanup; +import lombok.SneakyThrows; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import usi.si.seart.treesitter.Language; +import usi.si.seart.treesitter.Node; +import usi.si.seart.treesitter.Parser; +import usi.si.seart.treesitter.Tree; + +import java.io.UnsupportedEncodingException; +import java.util.function.Predicate; + +class ContainsErrorPredicateTest extends PredicateTest { + + @Test + @SneakyThrows(UnsupportedEncodingException.class) + void containsErrorTest() { + @Cleanup Parser parser = new Parser(Language.C); + Tree error = parser.parseString(input_1); + Node root = error.getRootNode(); + Predicate predicate = new ContainsErrorPredicate(); + boolean result = predicate.test(root); + Assertions.assertTrue(result); + } + + @Test + void containsNoErrorTest() { + Predicate predicate = new ContainsErrorPredicate(); + boolean result = predicate.test(tree.getRootNode()); + Assertions.assertFalse(result); + } +} \ No newline at end of file From ea95bf7c7d40d0dcf33443f4fa71f4e0a2cbda7c Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 16 Jan 2023 11:41:23 +0100 Subject: [PATCH 0036/1089] Added `Predicate` classes for file `Path` testing --- .../predicate/JavaTestFilePredicate.java | 27 ++++++++++++ .../analyzer/predicate/TestFilePredicate.java | 26 +++++++++++ .../predicate/JavaTestFilePredicateTest.java | 43 +++++++++++++++++++ .../predicate/TestFilePredicateTest.java | 37 ++++++++++++++++ 4 files changed, 133 insertions(+) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/JavaTestFilePredicate.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/TestFilePredicate.java create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/JavaTestFilePredicateTest.java create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/TestFilePredicateTest.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/JavaTestFilePredicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/JavaTestFilePredicate.java new file mode 100644 index 00000000..b2d8c19f --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/JavaTestFilePredicate.java @@ -0,0 +1,27 @@ +package usi.si.seart.analyzer.predicate; + +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.PathMatcher; +import java.util.Set; +import java.util.stream.Collectors; + +public class JavaTestFilePredicate extends TestFilePredicate { + + private static final Set FILE_PATTERNS = Set.of( + "**/Test*.java", + "**/*Test.java", + "**/*Tests.java", + "**/*TestCase.java", + "**/IT*.java", + "**/*IT.java", + "**/*ITCase.java" + ); + + @Override + public boolean test(Path path) { + String glob = FILE_PATTERNS.stream().collect(Collectors.joining(",", "glob:{", "}")); + PathMatcher matcher = FileSystems.getDefault().getPathMatcher(glob); + return super.test(path) || matcher.matches(path); + } +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/TestFilePredicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/TestFilePredicate.java new file mode 100644 index 00000000..23111a67 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/TestFilePredicate.java @@ -0,0 +1,26 @@ +package usi.si.seart.analyzer.predicate; + +import usi.si.seart.treesitter.Language; + +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.PathMatcher; +import java.util.function.Predicate; + +public abstract class TestFilePredicate implements Predicate { + + @Override + public boolean test(Path path) { + String glob = "glob:{**/test/**,**/tests/**}"; + PathMatcher matcher = FileSystems.getDefault().getPathMatcher(glob); + return matcher.matches(path); + } + + public static TestFilePredicate forLanguage(Language language) { + switch (language) { + case JAVA: return new JavaTestFilePredicate(); + default: return new TestFilePredicate() {}; + } + } + +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/JavaTestFilePredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/JavaTestFilePredicateTest.java new file mode 100644 index 00000000..bae7f094 --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/JavaTestFilePredicateTest.java @@ -0,0 +1,43 @@ +package usi.si.seart.analyzer.predicate; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; + +import java.nio.file.Path; +import java.util.function.Predicate; +import java.util.stream.Stream; + +class JavaTestFilePredicateTest { + + private static class JavaPathPredicateProvider implements ArgumentsProvider { + + @Override + public Stream provideArguments(ExtensionContext extensionContext) throws Exception { + return Stream.of( + Arguments.of(Path.of("/src", "test", "README"), true), + Arguments.of(Path.of("/src", "tests", "README"), true), + Arguments.of(Path.of("/src", "latest", "README"), false), + Arguments.of(Path.of("/src", "main", "App.java"), false), + Arguments.of(Path.of("/src", "main", "Test.java"), true), + Arguments.of(Path.of("/src", "main", "TestApp.java"), true), + Arguments.of(Path.of("/src", "main", "AppTest.java"), true), + Arguments.of(Path.of("/src", "main", "AppTests.java"), true), + Arguments.of(Path.of("/src", "main", "AppTestCase.java"), true), + Arguments.of(Path.of("/src", "main", "AppIT.java"), true), + Arguments.of(Path.of("/src", "main", "ITApp.java"), true), + Arguments.of(Path.of("/src", "main", "AppITCase.java"), true) + ); + } + } + + @ParameterizedTest + @ArgumentsSource(JavaPathPredicateProvider.class) + void pathPredicateTest(Path path, boolean expected) { + Predicate predicate = new JavaTestFilePredicate(); + Assertions.assertEquals(expected, predicate.test(path)); + } +} \ No newline at end of file diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/TestFilePredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/TestFilePredicateTest.java new file mode 100644 index 00000000..bac724b9 --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/TestFilePredicateTest.java @@ -0,0 +1,37 @@ +package usi.si.seart.analyzer.predicate; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; + +import java.nio.file.Path; +import java.util.function.Predicate; +import java.util.stream.Stream; + +class TestFilePredicateTest { + + private static class PathPredicateProvider implements ArgumentsProvider { + + @Override + public Stream provideArguments(ExtensionContext extensionContext) throws Exception { + return Stream.of( + Arguments.of(Path.of("/src", "test", "README"), true), + Arguments.of(Path.of("/src", "tests", "README"), true), + Arguments.of(Path.of("/src", "latest", "README"), false), + Arguments.of(Path.of("/src", "main", "App.java"), false), + Arguments.of(Path.of("/src", "main", "Test.java"), false), + Arguments.of(Path.of("/src", "main", "TestApp.java"), false) + ); + } + } + + @ParameterizedTest + @ArgumentsSource(PathPredicateProvider.class) + void pathPredicateTest(Path path, boolean expected) { + Predicate predicate = new TestFilePredicate() {}; + Assertions.assertEquals(expected, predicate.test(path)); + } +} \ No newline at end of file From 7be5836e5b9d9287ee8d11db5e3490f9553b251e Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 16 Jan 2023 14:59:15 +0100 Subject: [PATCH 0037/1089] Added `Enumerator` hierarchy Think of this as a more opinionated conversion interface. While the input always has to be a `Node` (as is convention among other utilities in the module), the output is generalized to any Java `Enum` subtype. For now, we only concern ourselves with the `Boilerplate` enum classes. --- .../enumerator/BoilerplateEnumerator.java | 13 +++ .../seart/analyzer/enumerator/Enumerator.java | 7 ++ .../enumerator/JavaBoilerplateEnumerator.java | 32 +++++++ .../JavaBoilerplateEnumeratorTest.java | 87 +++++++++++++++++++ 4 files changed, 139 insertions(+) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/BoilerplateEnumerator.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/Enumerator.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumerator.java create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/BoilerplateEnumerator.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/BoilerplateEnumerator.java new file mode 100644 index 00000000..e1e3df41 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/BoilerplateEnumerator.java @@ -0,0 +1,13 @@ +package usi.si.seart.analyzer.enumerator; + +import usi.si.seart.analyzer.NodeMapper; +import usi.si.seart.model.code.Boilerplate; + +public abstract class BoilerplateEnumerator implements Enumerator { + + protected final NodeMapper mapper; + + protected BoilerplateEnumerator(NodeMapper mapper) { + this.mapper = mapper; + } +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/Enumerator.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/Enumerator.java new file mode 100644 index 00000000..27439ec9 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/Enumerator.java @@ -0,0 +1,7 @@ +package usi.si.seart.analyzer.enumerator; + +import usi.si.seart.treesitter.Node; + +public interface Enumerator> { + E asEnum(Node node); +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumerator.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumerator.java new file mode 100644 index 00000000..43fcc57f --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumerator.java @@ -0,0 +1,32 @@ +package usi.si.seart.analyzer.enumerator; + +import usi.si.seart.analyzer.NodeMapper; +import usi.si.seart.model.code.Boilerplate; +import usi.si.seart.treesitter.Node; +import usi.si.seart.treesitter.Range; + +public class JavaBoilerplateEnumerator extends BoilerplateEnumerator { + + public JavaBoilerplateEnumerator(NodeMapper mapper) { + super(mapper); + } + + @Override + public Boilerplate asEnum(Node node) { + String type = node.getType(); + if (type.equals("constructor_declaration")) return Boilerplate.CONSTRUCTOR; + if (!type.equals("method_declaration")) return null; + Node identifier = node.getChildByFieldName("name"); + Range range = identifier.getRange(); + String name = mapper.getContentForRange(range); + if (name.startsWith("set")) return Boilerplate.SETTER; + if (name.startsWith("get")) return Boilerplate.GETTER; + switch (name) { + case "builder": return Boilerplate.BUILDER; + case "equals": return Boilerplate.EQUALS; + case "hashCode": return Boilerplate.HASH_CODE; + case "toString": return Boilerplate.TO_STRING; + default: return null; + } + } +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java new file mode 100644 index 00000000..8be9c507 --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java @@ -0,0 +1,87 @@ +package usi.si.seart.analyzer.enumerator; + +import lombok.Cleanup; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; +import usi.si.seart.analyzer.test.BaseTest; +import usi.si.seart.model.code.Boilerplate; +import usi.si.seart.treesitter.Language; +import usi.si.seart.treesitter.Node; +import usi.si.seart.treesitter.Parser; +import usi.si.seart.treesitter.Tree; + +import java.nio.charset.StandardCharsets; +import java.util.stream.Stream; + +class JavaBoilerplateEnumeratorTest extends BaseTest { + + private static final String input_static = + "package ch.usi.si;\n" + + "\n" + + "public class Main {\n" + + "\tpublic Main() {}\n" + + "\tpublic Main(int i) {}\n" + + "\tpublic void getI() {}\n" + + "\tpublic void getI(int i) {}\n" + + "\tpublic void setI() {}\n" + + "\tpublic void setI(int i) {}\n" + + "\tpublic void builder() {}\n" + + "\tpublic void equals() {}\n" + + "\tpublic void hashCode() {}\n" + + "\tpublic void toString() {}\n" + + "\tpublic void run() {}\n" + + "\tpublic static void main(String[] args) {}\n" + + "}"; + + protected final String input_1 = input_static; + protected final byte[] bytes_1 = input_1.getBytes(StandardCharsets.UTF_16LE); + + private static class JavaBoilerplateMethodProvider implements ArgumentsProvider { + + @Override + public Stream provideArguments(ExtensionContext extensionContext) throws Exception { + @Cleanup Parser parser = new Parser(Language.JAVA); + Tree tree = parser.parseString(input_static); + Node root = tree.getRootNode(); + Node clazz = root.getChild(1); + Node body = clazz.getChildByFieldName("body"); + Node constructor_0 = body.getChild(1); + Node constructor_1 = body.getChild(2); + Node method_0 = body.getChild(3); + Node method_1 = body.getChild(4); + Node method_2 = body.getChild(5); + Node method_3 = body.getChild(6); + Node method_4 = body.getChild(7); + Node method_5 = body.getChild(8); + Node method_6 = body.getChild(9); + Node method_7 = body.getChild(10); + Node method_8 = body.getChild(11); + Node method_9 = body.getChild(12); + return Stream.of( + Arguments.of(constructor_0, Boilerplate.CONSTRUCTOR), + Arguments.of(constructor_1, Boilerplate.CONSTRUCTOR), + Arguments.of(method_0, Boilerplate.GETTER), + Arguments.of(method_1, Boilerplate.GETTER), + Arguments.of(method_2, Boilerplate.SETTER), + Arguments.of(method_3, Boilerplate.SETTER), + Arguments.of(method_4, Boilerplate.BUILDER), + Arguments.of(method_5, Boilerplate.EQUALS), + Arguments.of(method_6, Boilerplate.HASH_CODE), + Arguments.of(method_7, Boilerplate.TO_STRING), + Arguments.of(method_8, null), + Arguments.of(method_9, null) + ); + } + } + + @ParameterizedTest(name = "[{index}] {1}") + @ArgumentsSource(JavaBoilerplateMethodProvider.class) + void boilerplateDetectionTest(Node node, Boilerplate expected) { + BoilerplateEnumerator enumerator = new JavaBoilerplateEnumerator(() -> bytes_1); + Assertions.assertEquals(expected, enumerator.asEnum(node)); + } +} \ No newline at end of file From 36230f9640c26e9920775004794373948c3da1a6 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 17 Jan 2023 10:37:14 +0100 Subject: [PATCH 0038/1089] Replacing tab characters with spaces in tests --- .../JavaBoilerplateEnumeratorTest.java | 24 +++++++++---------- .../analyzer/predicate/PredicateTest.java | 8 +++---- .../analyzer/printer/NodePrinterTest.java | 4 ++-- .../usi/si/seart/analyzer/test/BaseTest.java | 22 ++++++++--------- 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java index 8be9c507..ffed351c 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java @@ -23,18 +23,18 @@ class JavaBoilerplateEnumeratorTest extends BaseTest { "package ch.usi.si;\n" + "\n" + "public class Main {\n" + - "\tpublic Main() {}\n" + - "\tpublic Main(int i) {}\n" + - "\tpublic void getI() {}\n" + - "\tpublic void getI(int i) {}\n" + - "\tpublic void setI() {}\n" + - "\tpublic void setI(int i) {}\n" + - "\tpublic void builder() {}\n" + - "\tpublic void equals() {}\n" + - "\tpublic void hashCode() {}\n" + - "\tpublic void toString() {}\n" + - "\tpublic void run() {}\n" + - "\tpublic static void main(String[] args) {}\n" + + " public Main() {}\n" + + " public Main(int i) {}\n" + + " public void getI() {}\n" + + " public void getI(int i) {}\n" + + " public void setI() {}\n" + + " public void setI(int i) {}\n" + + " public void builder() {}\n" + + " public void equals() {}\n" + + " public void hashCode() {}\n" + + " public void toString() {}\n" + + " public void run() {}\n" + + " public static void main(String[] args) {}\n" + "}"; protected final String input_1 = input_static; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/PredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/PredicateTest.java index 13ea7033..b69ed792 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/PredicateTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/PredicateTest.java @@ -10,10 +10,10 @@ public abstract class PredicateTest extends BaseTest { "package ch.usi.si;\n" + "\n" + "public class Main {\n" + - "\tpublic static void main(String[] args) {\n" + - "\t\t// 软件工程的深度学习\n" + - "\t\tSystem.out.println(\"Hello, World!\");\n" + - "\t}\n" + + " public static void main(String[] args) {\n" + + " // 软件工程的深度学习\n" + + " System.out.println(\"Hello, World!\");\n" + + " }\n" + "}"; protected final byte[] bytes_1 = input_1.getBytes(StandardCharsets.UTF_16LE); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java index 70b39df9..809faa9a 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java @@ -22,8 +22,8 @@ void printTest() { actual = printer.print(method); expected = "public static void main(String[] args) {\n" + - "\t//line comment\n" + - "\tSystem.out.println(\"Hello, World!\");\n" + + " //line comment\n" + + " System.out.println(\"Hello, World!\");\n" + "}"; Assertions.assertEquals(expected, actual); } diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java index 4c2c44b3..a10f48cc 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java @@ -50,10 +50,10 @@ void tearDown() { "package ch.usi.si;\n" + "\n" + "public class Main {\n" + - "\tpublic static void main(String[] args) {\n" + - "\t\t//line comment\n" + - "\t\tSystem.out.println(\"Hello, World!\");\n" + - "\t}\n" + + " public static void main(String[] args) {\n" + + " //line comment\n" + + " System.out.println(\"Hello, World!\");\n" + + " }\n" + "}"; protected final List tokens_1 = List.of( @@ -140,13 +140,13 @@ void tearDown() { "package ch.usi.si;\n" + "\n" + "public class Main {\n" + - "\tpublic static void main(String[] args) {\n" + - "\t\t/*\n" + - "\t\t * Block comment\n" + - "\t\t * on multiple lines\n" + - "\t\t */\n" + - "\t\tSystem.out.println(\"Hello, World!\");\n" + - "\t}\n" + + " public static void main(String[] args) {\n" + + " /*\n" + + " * Block comment\n" + + " * on multiple lines\n" + + " */\n" + + " System.out.println(\"Hello, World!\");\n" + + " }\n" + "}"; protected final byte[] bytes_2 = input_2.getBytes(StandardCharsets.UTF_16LE); From 583cbd4be59f826e83fc548ff7ca31146263d2f2 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 17 Jan 2023 10:49:13 +0100 Subject: [PATCH 0039/1089] Replaced `TreePrinter` with the more robust `SyntaxTreePrinter` This slightly modified implementation allows us to print _any_ subtree of a syntax tree. Will be greatly useful within the context of the analyzer. --- .../{TreePrinter.java => SyntaxTreePrinter.java} | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) rename dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/{TreePrinter.java => SyntaxTreePrinter.java} (81%) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreePrinter.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/SyntaxTreePrinter.java similarity index 81% rename from dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreePrinter.java rename to dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/SyntaxTreePrinter.java index 5275856a..271b2147 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreePrinter.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/SyntaxTreePrinter.java @@ -6,22 +6,22 @@ import lombok.experimental.FieldDefaults; /** - * Utility used for pretty-printing parse trees. + * Utility used for pretty-printing entire syntax trees, as well as their subtrees. */ @RequiredArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE) -public class TreePrinter { +public class SyntaxTreePrinter { int indentLevel = 0; - final Tree tree; + final Node node; /** - * @return A string representation of the parse tree. Consists only of named nodes. + * @return A string representation of the subtree. Consists only of named nodes. + * @see Syntax Tree Playground */ - public String printParseTree() { + public String printSubtree() { StringBuilder stringBuilder = new StringBuilder(); - Node root = this.tree.getRootNode(); - @Cleanup TreeCursor cursor = new TreePrinterCursor(root); + @Cleanup TreeCursor cursor = new TreePrinterCursor(node); for (;;) { TreeCursorNode treeCursorNode = cursor.getCurrentTreeCursorNode(); if (treeCursorNode.isNamed()) { From 308ee13ebeec531dffa8231939a0c978f671f8af Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 17 Jan 2023 10:50:14 +0100 Subject: [PATCH 0040/1089] Added `SyntaxTreePrinter` adapter to the `dl4se-analyzer` module --- .../analyzer/printer/SyntaxTreePrinter.java | 11 +++ .../printer/SyntaxTreePrinterTest.java | 74 +++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java new file mode 100644 index 00000000..e48e90fc --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java @@ -0,0 +1,11 @@ +package usi.si.seart.analyzer.printer; + +import usi.si.seart.treesitter.Node; + +public class SyntaxTreePrinter implements Printer { + + @Override + public String print(Node node) { + return new usi.si.seart.treesitter.SyntaxTreePrinter(node).printSubtree(); + } +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java new file mode 100644 index 00000000..a819b60b --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java @@ -0,0 +1,74 @@ +package usi.si.seart.analyzer.printer; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import usi.si.seart.analyzer.test.BaseTest; +import usi.si.seart.treesitter.Node; + +class SyntaxTreePrinterTest extends BaseTest { + + @Test + void printTest() { + Printer printer = new SyntaxTreePrinter(); + Node root = tree.getRootNode(); + String actual = printer.print(root); + String expected = + "program [0:0] - [7:1]\n" + + " package_declaration [0:0] - [0:18]\n" + + " scoped_identifier [0:8] - [0:17]\n" + + " scope: scoped_identifier [0:8] - [0:14]\n" + + " scope: identifier [0:8] - [0:10]\n" + + " name: identifier [0:11] - [0:14]\n" + + " name: identifier [0:15] - [0:17]\n" + + " class_declaration [2:0] - [7:1]\n" + + " modifiers [2:0] - [2:6]\n" + + " name: identifier [2:13] - [2:17]\n" + + " body: class_body [2:18] - [7:1]\n" + + " method_declaration [3:4] - [6:5]\n" + + " modifiers [3:4] - [3:17]\n" + + " type: void_type [3:18] - [3:22]\n" + + " name: identifier [3:23] - [3:27]\n" + + " parameters: formal_parameters [3:27] - [3:42]\n" + + " formal_parameter [3:28] - [3:41]\n" + + " type: array_type [3:28] - [3:36]\n" + + " element: type_identifier [3:28] - [3:34]\n" + + " dimensions: dimensions [3:34] - [3:36]\n" + + " name: identifier [3:37] - [3:41]\n" + + " body: block [3:43] - [6:5]\n" + + " line_comment [4:8] - [4:22]\n" + + " expression_statement [5:8] - [5:44]\n" + + " method_invocation [5:8] - [5:43]\n" + + " object: field_access [5:8] - [5:18]\n" + + " object: identifier [5:8] - [5:14]\n" + + " field: identifier [5:15] - [5:18]\n" + + " name: identifier [5:19] - [5:26]\n" + + " arguments: argument_list [5:26] - [5:43]\n" + + " string_literal [5:27] - [5:42]\n"; + Assertions.assertEquals(expected, actual); + + Node method = root.getChild(1).getChildByFieldName("body").getChild(1); + actual = printer.print(method); + expected = + "method_declaration [3:4] - [6:5]\n" + + " modifiers [3:4] - [3:17]\n" + + " type: void_type [3:18] - [3:22]\n" + + " name: identifier [3:23] - [3:27]\n" + + " parameters: formal_parameters [3:27] - [3:42]\n" + + " formal_parameter [3:28] - [3:41]\n" + + " type: array_type [3:28] - [3:36]\n" + + " element: type_identifier [3:28] - [3:34]\n" + + " dimensions: dimensions [3:34] - [3:36]\n" + + " name: identifier [3:37] - [3:41]\n" + + " body: block [3:43] - [6:5]\n" + + " line_comment [4:8] - [4:22]\n" + + " expression_statement [5:8] - [5:44]\n" + + " method_invocation [5:8] - [5:43]\n" + + " object: field_access [5:8] - [5:18]\n" + + " object: identifier [5:8] - [5:14]\n" + + " field: identifier [5:15] - [5:18]\n" + + " name: identifier [5:19] - [5:26]\n" + + " arguments: argument_list [5:26] - [5:43]\n" + + " string_literal [5:27] - [5:42]\n"; + Assertions.assertEquals(expected, actual); + } +} \ No newline at end of file From 969f8ec2b849631e2272b78bbe633658d0fb838b Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 17 Jan 2023 11:22:40 +0100 Subject: [PATCH 0041/1089] Added `SExpressionPrinter` One could argue that this might not be necessary, and I totally agree, I just like being consistent is all. --- .../analyzer/printer/SExpressionPrinter.java | 11 +++ .../printer/SExpressionPrinterTest.java | 74 +++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SExpressionPrinter.java create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SExpressionPrinterTest.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SExpressionPrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SExpressionPrinter.java new file mode 100644 index 00000000..d16ddeff --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SExpressionPrinter.java @@ -0,0 +1,11 @@ +package usi.si.seart.analyzer.printer; + +import usi.si.seart.treesitter.Node; + +public class SExpressionPrinter implements Printer { + + @Override + public String print(Node node) { + return node.getNodeString(); + } +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SExpressionPrinterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SExpressionPrinterTest.java new file mode 100644 index 00000000..2817e0e1 --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SExpressionPrinterTest.java @@ -0,0 +1,74 @@ +package usi.si.seart.analyzer.printer; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import usi.si.seart.analyzer.test.BaseTest; +import usi.si.seart.treesitter.Node; + +class SExpressionPrinterTest extends BaseTest { + + @Test + void printTest() { + Printer printer = new SExpressionPrinter(); + Node root = tree.getRootNode(); + String actual = printer.print(root); + String expected = + "(program " + + "(package_declaration " + + "(scoped_identifier " + + "scope: (scoped_identifier " + + "scope: (identifier) " + + "name: (identifier)) " + + "name: (identifier))) " + + "(class_declaration " + + "(modifiers) " + + "name: (identifier) " + + "body: (class_body " + + "(method_declaration " + + "(modifiers) " + + "type: (void_type) " + + "name: (identifier) " + + "parameters: (formal_parameters " + + "(formal_parameter " + + "type: (array_type " + + "element: (type_identifier) " + + "dimensions: (dimensions)) " + + "name: (identifier))) " + + "body: (block " + + "(line_comment) " + + "(expression_statement " + + "(method_invocation " + + "object: (field_access " + + "object: (identifier) " + + "field: (identifier)) " + + "name: (identifier) " + + "arguments: (argument_list " + + "(string_literal)))))))))"; + Assertions.assertEquals(expected, actual); + + Node method = root.getChild(1).getChildByFieldName("body").getChild(1); + actual = printer.print(method); + expected = + "(method_declaration " + + "(modifiers) " + + "type: (void_type) " + + "name: (identifier) " + + "parameters: (formal_parameters " + + "(formal_parameter " + + "type: (array_type " + + "element: (type_identifier) " + + "dimensions: (dimensions)) " + + "name: (identifier))) " + + "body: (block " + + "(line_comment) " + + "(expression_statement " + + "(method_invocation " + + "object: (field_access " + + "object: (identifier) " + + "field: (identifier)) " + + "name: (identifier) " + + "arguments: (argument_list " + + "(string_literal))))))"; + Assertions.assertEquals(expected, actual); + } +} \ No newline at end of file From d6bfff363e53458a0485b93e22abe1002b1463f5 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 17 Jan 2023 13:49:39 +0100 Subject: [PATCH 0042/1089] Just updating some documentation that was not clear --- .../main/java/usi/si/seart/treesitter/Parser.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java index 5f4d3584..fc5a25e7 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java @@ -33,16 +33,24 @@ public void setLanguage(Language language) { } /** - * Use the parser to parse some source code stored in one contiguous buffer. + * Use the parser to parse some source code and create a syntax tree. * * @param source The source code string to be parsed. - * @return A tree-sitter Tree matching the provided source. + * @return A syntax tree matching the provided source. */ public Tree parseString(String source) throws UnsupportedEncodingException { byte[] bytes = source.getBytes(StandardCharsets.UTF_16LE); return new Tree(TreeSitter.parserParseBytes(pointer, bytes, bytes.length)); } + /** + * Use the parser to incrementally parse a changed source code string, + * reusing unchanged parts of the tree to speed up the process. + * + * @param oldTree The syntax tree before changes were made. + * @param source The source code string to be parsed. + * @return A syntax tree matching the provided source. + */ public Tree parseString(Tree oldTree, String source) throws UnsupportedEncodingException { byte[] bytes = source.getBytes(StandardCharsets.UTF_16LE); return new Tree(TreeSitter.parserIncrementalParseBytes(pointer, oldTree.getPointer(), bytes, bytes.length)); From 4edd95914acbf8a75a1b02ba4f5043e1342a67f1 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 17 Jan 2023 16:24:48 +0100 Subject: [PATCH 0043/1089] Using polymorphism instead of relying on hiding, much better! --- .../analyzer/count/CharacterCounterTest.java | 8 +- .../analyzer/count/CodeTokenCounterTest.java | 2 +- .../seart/analyzer/count/LineCounterTest.java | 2 +- .../analyzer/count/TokenCounterTest.java | 7 +- .../JavaBoilerplateEnumeratorTest.java | 92 +++++++------------ .../analyzer/hash/ContentHasherTest.java | 26 ++++-- .../si/seart/analyzer/hash/HasherTest.java | 18 ++-- .../analyzer/hash/SyntaxTreeHasherTest.java | 14 ++- .../predicate/ContainsErrorPredicateTest.java | 2 +- .../ContainsNonAsciiPredicateTest.java | 16 +++- .../analyzer/predicate/PredicateTest.java | 9 +- .../analyzer/printer/NodePrinterTest.java | 7 +- .../usi/si/seart/analyzer/test/BaseTest.java | 54 +++++------ 13 files changed, 132 insertions(+), 125 deletions(-) diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CharacterCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CharacterCounterTest.java index d16c86b0..c3ef92ef 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CharacterCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CharacterCounterTest.java @@ -2,21 +2,17 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import usi.si.seart.analyzer.NodeMapper; import usi.si.seart.analyzer.test.BaseTest; class CharacterCounterTest extends BaseTest { - private final NodeMapper mapper = () -> bytes_1; - @Test void countTest(){ - Counter counter = new CharacterCounter(mapper); + Counter counter = new CharacterCounter(getNodeMapper()); Long actual = counter.count(tree.getRootNode()); // Remove 2 for the space in string and comment Assertions.assertEquals( - tokens_joined_1.length() - 2, - actual, + getJoinedTokens().length() - 2, actual, "Total number of characters should be equal to the joined tree string without spaces!" ); } diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CodeTokenCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CodeTokenCounterTest.java index 1bec435b..5ef1c07b 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CodeTokenCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CodeTokenCounterTest.java @@ -12,7 +12,7 @@ void countTest() { Long actual = counter.count(tree.getRootNode()); // Remove 1 for the comment node Assertions.assertEquals( - nodes_1.size() - 1, actual, + getNodes().size() - 1, actual, "Total number of code tokens should be equal to the number of input tokens without the comments!" ); } diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/LineCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/LineCounterTest.java index b1e131b2..29de27a0 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/LineCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/LineCounterTest.java @@ -11,7 +11,7 @@ void countTest() { Counter counter = new LineCounter(); Long actual = counter.count(tree.getRootNode()); Assertions.assertEquals( - input_1.lines().count(), actual, + getInput().lines().count(), actual, "Total number of lines should be equal to the number of lines reported by String method" ); } diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/TokenCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/TokenCounterTest.java index 01f655b6..660b0433 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/TokenCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/TokenCounterTest.java @@ -2,20 +2,17 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import usi.si.seart.analyzer.NodeMapper; import usi.si.seart.analyzer.test.BaseTest; class TokenCounterTest extends BaseTest { - private final NodeMapper mapper = () -> bytes_1; - @Test void countTest() { - Counter counter = new TokenCounter(mapper); + Counter counter = new TokenCounter(getNodeMapper()); Long actual = counter.count(tree.getRootNode()); // Add 1 for the extra comment word Assertions.assertEquals( - nodes_1.size() + 2, actual, + getNodes().size() + 2, actual, "Total number of tokens should be equal to the number of input tokens including comment tokens (words)!" ); } diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java index ffed351c..5c94a34b 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java @@ -1,25 +1,16 @@ package usi.si.seart.analyzer.enumerator; -import lombok.Cleanup; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.ArgumentsProvider; -import org.junit.jupiter.params.provider.ArgumentsSource; +import org.junit.jupiter.api.Test; import usi.si.seart.analyzer.test.BaseTest; import usi.si.seart.model.code.Boilerplate; -import usi.si.seart.treesitter.Language; import usi.si.seart.treesitter.Node; -import usi.si.seart.treesitter.Parser; -import usi.si.seart.treesitter.Tree; - -import java.nio.charset.StandardCharsets; -import java.util.stream.Stream; class JavaBoilerplateEnumeratorTest extends BaseTest { - private static final String input_static = + @Override + protected String getInput() { + return "package ch.usi.si;\n" + "\n" + "public class Main {\n" + @@ -36,52 +27,37 @@ class JavaBoilerplateEnumeratorTest extends BaseTest { " public void run() {}\n" + " public static void main(String[] args) {}\n" + "}"; - - protected final String input_1 = input_static; - protected final byte[] bytes_1 = input_1.getBytes(StandardCharsets.UTF_16LE); - - private static class JavaBoilerplateMethodProvider implements ArgumentsProvider { - - @Override - public Stream provideArguments(ExtensionContext extensionContext) throws Exception { - @Cleanup Parser parser = new Parser(Language.JAVA); - Tree tree = parser.parseString(input_static); - Node root = tree.getRootNode(); - Node clazz = root.getChild(1); - Node body = clazz.getChildByFieldName("body"); - Node constructor_0 = body.getChild(1); - Node constructor_1 = body.getChild(2); - Node method_0 = body.getChild(3); - Node method_1 = body.getChild(4); - Node method_2 = body.getChild(5); - Node method_3 = body.getChild(6); - Node method_4 = body.getChild(7); - Node method_5 = body.getChild(8); - Node method_6 = body.getChild(9); - Node method_7 = body.getChild(10); - Node method_8 = body.getChild(11); - Node method_9 = body.getChild(12); - return Stream.of( - Arguments.of(constructor_0, Boilerplate.CONSTRUCTOR), - Arguments.of(constructor_1, Boilerplate.CONSTRUCTOR), - Arguments.of(method_0, Boilerplate.GETTER), - Arguments.of(method_1, Boilerplate.GETTER), - Arguments.of(method_2, Boilerplate.SETTER), - Arguments.of(method_3, Boilerplate.SETTER), - Arguments.of(method_4, Boilerplate.BUILDER), - Arguments.of(method_5, Boilerplate.EQUALS), - Arguments.of(method_6, Boilerplate.HASH_CODE), - Arguments.of(method_7, Boilerplate.TO_STRING), - Arguments.of(method_8, null), - Arguments.of(method_9, null) - ); - } } - @ParameterizedTest(name = "[{index}] {1}") - @ArgumentsSource(JavaBoilerplateMethodProvider.class) - void boilerplateDetectionTest(Node node, Boilerplate expected) { - BoilerplateEnumerator enumerator = new JavaBoilerplateEnumerator(() -> bytes_1); - Assertions.assertEquals(expected, enumerator.asEnum(node)); + @Test + void asEnumTest() { + BoilerplateEnumerator enumerator = new JavaBoilerplateEnumerator(getNodeMapper()); + Node root = tree.getRootNode(); + Node clazz = root.getChild(1); + Node body = clazz.getChildByFieldName("body"); + Node constructor_0 = body.getChild(1); + Node constructor_1 = body.getChild(2); + Node method_0 = body.getChild(3); + Node method_1 = body.getChild(4); + Node method_2 = body.getChild(5); + Node method_3 = body.getChild(6); + Node method_4 = body.getChild(7); + Node method_5 = body.getChild(8); + Node method_6 = body.getChild(9); + Node method_7 = body.getChild(10); + Node method_8 = body.getChild(11); + Node method_9 = body.getChild(12); + Assertions.assertEquals(Boilerplate.CONSTRUCTOR, enumerator.asEnum(constructor_0)); + Assertions.assertEquals(Boilerplate.CONSTRUCTOR, enumerator.asEnum(constructor_1)); + Assertions.assertEquals(Boilerplate.GETTER, enumerator.asEnum(method_0)); + Assertions.assertEquals(Boilerplate.GETTER, enumerator.asEnum(method_1)); + Assertions.assertEquals(Boilerplate.SETTER, enumerator.asEnum(method_2)); + Assertions.assertEquals(Boilerplate.SETTER, enumerator.asEnum(method_3)); + Assertions.assertEquals(Boilerplate.BUILDER, enumerator.asEnum(method_4)); + Assertions.assertEquals(Boilerplate.EQUALS, enumerator.asEnum(method_5)); + Assertions.assertEquals(Boilerplate.HASH_CODE, enumerator.asEnum(method_6)); + Assertions.assertEquals(Boilerplate.TO_STRING, enumerator.asEnum(method_7)); + Assertions.assertNull(enumerator.asEnum(method_8)); + Assertions.assertNull(enumerator.asEnum(method_9)); } } \ No newline at end of file diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java index f42e0ef2..5e1b74d5 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java @@ -3,26 +3,24 @@ import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import usi.si.seart.analyzer.NodeMapper; import usi.si.seart.treesitter.Tree; import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; class ContentHasherTest extends HasherTest { - private final NodeMapper mapper = () -> bytes_1; - @Test void hashTest() { - Hasher hasher = new ContentHasher(mapper); + Hasher hasher = new ContentHasher(getNodeMapper()); String actual = hasher.hash(tree.getRootNode()); - String expected = sha256(tokens_joined_1); + String expected = sha256(getJoinedTokens()); Assertions.assertEquals(expected, actual, "Incrementally digested tree hash should be equal to the flat code manual digest!"); } @Test void idempotencyTest() { - Hasher hasher = new ContentHasher(mapper); + Hasher hasher = new ContentHasher(getNodeMapper()); String first = hasher.hash(tree.getRootNode()); String second = hasher.hash(tree.getRootNode()); Assertions.assertEquals(first, second, "Same instance should be reusable for multiple invocations!"); @@ -31,8 +29,22 @@ void idempotencyTest() { @Test @SneakyThrows(UnsupportedEncodingException.class) void noCommentImpactTest() { + String input_2 = + "package ch.usi.si;\n" + + "\n" + + "public class Main {\n" + + " public static void main(String[] args) {\n" + + " /*\n" + + " * Block comment\n" + + " * on multiple lines\n" + + " */\n" + + " System.out.println(\"Hello, World!\");\n" + + " }\n" + + "}"; + + byte[] bytes_2 = input_2.getBytes(StandardCharsets.UTF_16LE); Tree other = parser.parseString(input_2); - ContentHasher hasher_1 = new ContentHasher(() -> bytes_1); + ContentHasher hasher_1 = new ContentHasher(getNodeMapper()); ContentHasher hasher_2 = new ContentHasher(() -> bytes_2); String first = hasher_1.hash(tree.getRootNode()); String second = hasher_2.hash(other.getRootNode()); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/HasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/HasherTest.java index a9fd3c31..7ba36307 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/HasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/HasherTest.java @@ -9,7 +9,9 @@ public abstract class HasherTest extends BaseTest { - protected final List tokens_1 = List.of( + @Override + protected List getTokens() { + return List.of( "package", "ch", ".", @@ -42,11 +44,12 @@ public abstract class HasherTest extends BaseTest { ";", "}", "}" - ); - - protected final String tokens_joined_1 = String.join("", tokens_1); + ); + } - protected final List nodes_1 = List.of( + @Override + protected List getNodes() { + return List.of( "package", "identifier", ".", @@ -79,9 +82,8 @@ public abstract class HasherTest extends BaseTest { ";", "}", "}" - ); - - protected final String nodes_joined_1 = String.join("", nodes_1); + ); + } @SneakyThrows({NoSuchAlgorithmException.class}) protected String sha256(String input) { diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/SyntaxTreeHasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/SyntaxTreeHasherTest.java index 85664816..05e35813 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/SyntaxTreeHasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/SyntaxTreeHasherTest.java @@ -13,7 +13,7 @@ class SyntaxTreeHasherTest extends HasherTest { void hashTest() { Hasher hasher = new SyntaxTreeHasher(); String actual = hasher.hash(tree.getRootNode()); - String expected = sha256(nodes_joined_1); + String expected = sha256(getJoinedNodes()); Assertions.assertEquals(expected, actual, "Incrementally digested hash of leaf node names should be equal to the manual digest of the flattened, abstract, typed code!"); } @@ -28,6 +28,18 @@ void idempotencyTest() { @Test @SneakyThrows(UnsupportedEncodingException.class) void noCommentImpactTest() { + String input_2 = + "package ch.usi.si;\n" + + "\n" + + "public class Main {\n" + + " public static void main(String[] args) {\n" + + " /*\n" + + " * Block comment\n" + + " * on multiple lines\n" + + " */\n" + + " System.out.println(\"Hello, World!\");\n" + + " }\n" + + "}"; Tree other = parser.parseString(input_2); Hasher hasher = new SyntaxTreeHasher(); String first = hasher.hash(tree.getRootNode()); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsErrorPredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsErrorPredicateTest.java index aee2b643..9c9f69cd 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsErrorPredicateTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsErrorPredicateTest.java @@ -18,7 +18,7 @@ class ContainsErrorPredicateTest extends PredicateTest { @SneakyThrows(UnsupportedEncodingException.class) void containsErrorTest() { @Cleanup Parser parser = new Parser(Language.C); - Tree error = parser.parseString(input_1); + Tree error = parser.parseString(getInput()); Node root = error.getRootNode(); Predicate predicate = new ContainsErrorPredicate(); boolean result = predicate.test(root); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiPredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiPredicateTest.java index 12c084c3..7d80f088 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiPredicateTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiPredicateTest.java @@ -7,13 +7,14 @@ import usi.si.seart.treesitter.Tree; import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; import java.util.function.Predicate; class ContainsNonAsciiPredicateTest extends PredicateTest { @Test void containsNonAsciiTest() { - Predicate predicate = new ContainsNonAsciiPredicate(() -> bytes_1); + Predicate predicate = new ContainsNonAsciiPredicate(getNodeMapper()); boolean result = predicate.test(tree.getRootNode()); Assertions.assertTrue(result); } @@ -21,6 +22,19 @@ void containsNonAsciiTest() { @Test @SneakyThrows(UnsupportedEncodingException.class) void containsOnlyAsciiTest() { + String input_2 = + "package ch.usi.si;\n" + + "\n" + + "public class Main {\n" + + " public static void main(String[] args) {\n" + + " /*\n" + + " * Block comment\n" + + " * on multiple lines\n" + + " */\n" + + " System.out.println(\"Hello, World!\");\n" + + " }\n" + + "}"; + byte[] bytes_2 = input_2.getBytes(StandardCharsets.UTF_16LE); Predicate predicate = new ContainsNonAsciiPredicate(() -> bytes_2); Tree tree = parser.parseString(input_2); boolean result = predicate.test(tree.getRootNode()); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/PredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/PredicateTest.java index b69ed792..dbde698f 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/PredicateTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/PredicateTest.java @@ -2,11 +2,11 @@ import usi.si.seart.analyzer.test.BaseTest; -import java.nio.charset.StandardCharsets; - public abstract class PredicateTest extends BaseTest { - protected final String input_1 = + @Override + protected String getInput() { + return "package ch.usi.si;\n" + "\n" + "public class Main {\n" + @@ -15,6 +15,5 @@ public abstract class PredicateTest extends BaseTest { " System.out.println(\"Hello, World!\");\n" + " }\n" + "}"; - - protected final byte[] bytes_1 = input_1.getBytes(StandardCharsets.UTF_16LE); + } } diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java index 809faa9a..86b15f6e 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java @@ -2,20 +2,17 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import usi.si.seart.analyzer.NodeMapper; import usi.si.seart.analyzer.test.BaseTest; import usi.si.seart.treesitter.Node; class NodePrinterTest extends BaseTest { - private final NodeMapper mapper = () -> bytes_1; - @Test void printTest() { - Printer printer = new NodePrinter(mapper); + Printer printer = new NodePrinter(getNodeMapper()); Node root = tree.getRootNode(); String actual = printer.print(root); - String expected = input_1; + String expected = getInput(); Assertions.assertEquals(expected, actual); Node method = root.getChild(1).getChildByFieldName("body").getChild(1); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java index a10f48cc..ed43fdaa 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java @@ -5,6 +5,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; +import usi.si.seart.analyzer.NodeMapper; import usi.si.seart.treesitter.Language; import usi.si.seart.treesitter.LibraryLoader; import usi.si.seart.treesitter.Parser; @@ -37,7 +38,7 @@ static void afterAll() { @BeforeEach @SneakyThrows(UnsupportedEncodingException.class) void setUp() { - tree = parser.parseString(input_1); + tree = parser.parseString(getInput()); } @AfterEach @@ -46,7 +47,8 @@ void tearDown() { tree = null; } - protected final String input_1 = + protected String getInput() { + return "package ch.usi.si;\n" + "\n" + "public class Main {\n" + @@ -55,8 +57,18 @@ void tearDown() { " System.out.println(\"Hello, World!\");\n" + " }\n" + "}"; - - protected final List tokens_1 = List.of( + } + + protected byte[] getBytes() { + return getInput().getBytes(StandardCharsets.UTF_16LE); + } + + protected NodeMapper getNodeMapper() { + return this::getBytes; + } + + protected List getTokens() { + return List.of( "package", "ch", ".", @@ -91,11 +103,15 @@ void tearDown() { ";", "}", "}" - ); + ); + } - protected final String tokens_joined_1 = String.join("", tokens_1); + protected String getJoinedTokens() { + return String.join("", getTokens()); + } - protected final List nodes_1 = List.of( + protected List getNodes() { + return List.of( "package", "identifier", ".", @@ -130,24 +146,10 @@ void tearDown() { ";", "}", "}" - ); - - protected final String nodes_joined_1 = String.join("", nodes_1); - - protected final byte[] bytes_1 = input_1.getBytes(StandardCharsets.UTF_16LE); - - protected final String input_2 = - "package ch.usi.si;\n" + - "\n" + - "public class Main {\n" + - " public static void main(String[] args) {\n" + - " /*\n" + - " * Block comment\n" + - " * on multiple lines\n" + - " */\n" + - " System.out.println(\"Hello, World!\");\n" + - " }\n" + - "}"; + ); + } - protected final byte[] bytes_2 = input_2.getBytes(StandardCharsets.UTF_16LE); + protected String getJoinedNodes() { + return String.join("", getNodes()); + } } From 94bc39f449593df8672577c37500eb0bd503986c Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 17 Jan 2023 16:26:47 +0100 Subject: [PATCH 0044/1089] Added `Traverser` hierarchy This will hopefully only be needed for C-like languages, and not require any additional overriding. --- .../traverser/PreviousCommentTraverser.java | 24 +++++++ .../seart/analyzer/traverser/Traverser.java | 9 +++ .../PreviousCommentTraverserTest.java | 72 +++++++++++++++++++ 3 files changed, 105 insertions(+) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/traverser/PreviousCommentTraverser.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/traverser/Traverser.java create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/traverser/PreviousCommentTraverserTest.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/traverser/PreviousCommentTraverser.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/traverser/PreviousCommentTraverser.java new file mode 100644 index 00000000..f7e00211 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/traverser/PreviousCommentTraverser.java @@ -0,0 +1,24 @@ +package usi.si.seart.analyzer.traverser; + +import usi.si.seart.treesitter.Node; + +import java.util.ArrayList; +import java.util.List; + +public class PreviousCommentTraverser implements Traverser> { + + @Override + public List getNodes(Node node) { + List results = new ArrayList<>(); + Node current = node; + while (current != null) { + Node previous = current.getPrevSibling(); + if (previous == null) break; + String type = previous.getType(); + if (!type.contains("comment")) break; + results.add(previous); + current = previous; + } + return results; + } +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/traverser/Traverser.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/traverser/Traverser.java new file mode 100644 index 00000000..919148c4 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/traverser/Traverser.java @@ -0,0 +1,9 @@ +package usi.si.seart.analyzer.traverser; + +import usi.si.seart.treesitter.Node; + +import java.util.Collection; + +public interface Traverser> { + C getNodes(Node node); +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/traverser/PreviousCommentTraverserTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/traverser/PreviousCommentTraverserTest.java new file mode 100644 index 00000000..aede66d5 --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/traverser/PreviousCommentTraverserTest.java @@ -0,0 +1,72 @@ +package usi.si.seart.analyzer.traverser; + +import lombok.SneakyThrows; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import usi.si.seart.analyzer.test.BaseTest; +import usi.si.seart.treesitter.Node; + +import java.util.Collection; + +class PreviousCommentTraverserTest extends BaseTest { + + @Override + protected String getInput() { + return + "/**\n" + + " * A simple example class that contains a single field and two methods\n" + + " */\n" + + "public class Example {\n" + + "\n" + + " private int value;\n" + + " \n" + + " /**\n" + + " * Constructor that initializes the value field\n" + + " * @param val the initial value\n" + + " */\n" + + " public Example(int val) {\n" + + " this.value = val;\n" + + " }\n" + + " \n" + + " /**\n" + + " * This method updates the value of the field with the new value\n" + + " * passed as an argument\n" + + " */\n" + + " // Returns the current value\n" + + " public int getValue() {\n" + + " return value;\n" + + " }\n" + + " \n" + + " /**\n" + + " * Method to update the value field\n" + + " */\n" + + " /*\n" + + " * This method updates the value of the field with the new value\n" + + " * passed as an argument\n" + + " */\n" + + " public void setValue(int newVal) {\n" + + " this.value = newVal;\n" + + " }\n" + + "}"; + } + + @Test + @SneakyThrows + void getNodesTest() { + Node root = tree.getRootNode(); + Node body = root.getChild(1).getChildByFieldName("body"); + Traverser traverser = new PreviousCommentTraverser(); + + Node target = body.getChild(3); // constructor + Collection actual = traverser.getNodes(target); + Assertions.assertEquals(1, actual.size()); + + target = body.getChild(6); // getter + actual = traverser.getNodes(target); + Assertions.assertEquals(2, actual.size()); + + target = body.getChild(9); // setter + actual = traverser.getNodes(target); + Assertions.assertEquals(2, actual.size()); + } +} \ No newline at end of file From 8b4d345ce80d17dd4764e6c956aca057d54b9f6b Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 18 Jan 2023 09:59:00 +0100 Subject: [PATCH 0045/1089] First draft of the `Analyzer` hierarchy Meant to serve as a replacement for the existing `Parser` hierarchy from the `dl4se-crawler` module. In the report I mentioned how it was a misnomer, and all I have done thus far was done with the intent to address this issue. The beauty of this new interface and subtypes is that it will be completely modular. While a lot of operations are generalizable (thanks to tree-sitter), all steps within the `Analyzer` related to constructing the requisite entities will allow redefinitions for a language-specific `Analyzer`. --- .../si/seart/analyzer/AbstractAnalyzer.java | 177 ++++++++++++++++++ .../java/usi/si/seart/analyzer/Analyzer.java | 38 ++++ .../usi/si/seart/analyzer/JavaAnalyzer.java | 20 ++ .../analyzer/predicate/TestFilePredicate.java | 10 - .../analyzer/query/SingleCaptureQueries.java | 23 --- 5 files changed, 235 insertions(+), 33 deletions(-) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java new file mode 100644 index 00000000..ed284986 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java @@ -0,0 +1,177 @@ +package usi.si.seart.analyzer; + +import lombok.AccessLevel; +import lombok.SneakyThrows; +import lombok.experimental.FieldDefaults; +import usi.si.seart.analyzer.count.CharacterCounter; +import usi.si.seart.analyzer.count.CodeTokenCounter; +import usi.si.seart.analyzer.count.Counter; +import usi.si.seart.analyzer.count.LineCounter; +import usi.si.seart.analyzer.count.TokenCounter; +import usi.si.seart.analyzer.enumerator.Enumerator; +import usi.si.seart.analyzer.hash.ContentHasher; +import usi.si.seart.analyzer.hash.Hasher; +import usi.si.seart.analyzer.hash.SyntaxTreeHasher; +import usi.si.seart.analyzer.predicate.ContainsErrorPredicate; +import usi.si.seart.analyzer.predicate.ContainsNonAsciiPredicate; +import usi.si.seart.analyzer.predicate.TestFilePredicate; +import usi.si.seart.analyzer.printer.NodePrinter; +import usi.si.seart.analyzer.printer.Printer; +import usi.si.seart.analyzer.printer.SExpressionPrinter; +import usi.si.seart.analyzer.printer.SyntaxTreePrinter; +import usi.si.seart.analyzer.query.Queries; +import usi.si.seart.analyzer.traverser.Traverser; +import usi.si.seart.model.code.Boilerplate; +import usi.si.seart.model.code.File; +import usi.si.seart.model.code.Function; +import usi.si.seart.treesitter.Language; +import usi.si.seart.treesitter.Node; +import usi.si.seart.treesitter.Parser; +import usi.si.seart.treesitter.Tree; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.StringJoiner; +import java.util.function.Predicate; +import java.util.stream.Collector; + +@FieldDefaults(level = AccessLevel.PROTECTED) +public abstract class AbstractAnalyzer implements Analyzer { + + Language language; + Parser parser; + Tree tree; + + LocalClone localClone; + Path path; + String source; + + Counter lineCounter = new LineCounter(); + Counter codeTokenCounter = new CodeTokenCounter(); + Counter totalTokenCounter; + Counter characterCounter; + + Hasher contentHasher; + Hasher syntaxTreeHasher = new SyntaxTreeHasher(); + + Predicate containsError = new ContainsErrorPredicate(); + Predicate containsNonAscii; + + Predicate testFilePredicate = new TestFilePredicate() {}; + + Printer nodePrinter; + Printer syntaxTreePrinter = new SyntaxTreePrinter(); + Printer sExpressionPrinter = new SExpressionPrinter(); + + Queries> queries = new Queries<>() { + @Override + public List getNodes(Node node) { + return List.of(); + } + + @Override + public List getComments(Node node) { + return List.of(); + } + + @Override + public List getCallableDeclarations(Node node) { + return List.of(); + } + }; + + Enumerator boilerplateEnumerator = node -> null; + + Traverser> previousCommentTraverser = node -> List.of(); + + @SneakyThrows({IOException.class}) + protected AbstractAnalyzer(LocalClone localClone, Path path, Language language) { + this.language = language; + this.parser = new Parser(language); + this.localClone = localClone; + this.path = path; + this.source = Files.readString(path); + this.tree = parser.parseString(source); + NodeMapper mapper = this::getSourceBytes; + this.totalTokenCounter = new TokenCounter(mapper); + this.characterCounter = new CharacterCounter(mapper); + this.contentHasher = new ContentHasher(mapper); + this.containsNonAscii = new ContainsNonAsciiPredicate(mapper); + this.nodePrinter = new NodePrinter(mapper); + } + + protected final byte[] getSourceBytes() { + return source.getBytes(Settings.DEFAULT_CHARSET); + } + + @Override + public void close() { + tree.close(); + parser.close(); + } + + @Override + public final Result analyze() { + File file = extractFileEntity(); + List functions = extractFunctionEntities(file); + return new Analyzer.Result(file, functions); + } + + private File extractFileEntity() { + Node fileNode = tree.getRootNode(); + return File.builder() + .repo(localClone.getGitRepo()) + .path(localClone.relativePathOf(path).toString()) + .content(nodePrinter.print(fileNode)) + .contentHash(contentHasher.hash(fileNode)) + .ast(syntaxTreePrinter.print(fileNode)) + .astHash(syntaxTreeHasher.hash(fileNode)) + .sExpression(sExpressionPrinter.print(fileNode)) + .totalTokens(totalTokenCounter.count(fileNode)) + .codeTokens(codeTokenCounter.count(fileNode)) + .lines(lineCounter.count(fileNode)) + .characters(characterCounter.count(fileNode)) + .containsNonAscii(containsNonAscii.test(fileNode)) + .containsError(containsError.test(fileNode)) + .isTest(testFilePredicate.test(path)) + .build(); + } + + private List extractFunctionEntities(File file) { + List targets = queries.getCallableDeclarations(tree.getRootNode()); + List functions = new ArrayList<>(targets.size()); + for (Node fnNode: targets) { + List comments = previousCommentTraverser.getNodes(fnNode); + String prefixDoc = comments.stream() + .map(node -> nodePrinter.print(node)) + .collect(Collector.of( + () -> new StringJoiner("\n", "", "\n").setEmptyValue(""), + StringJoiner::add, + StringJoiner::merge, + StringJoiner::toString + )); + Function function = Function.builder() + .file(file) + .repo(localClone.getGitRepo()) + .content(prefixDoc + nodePrinter.print(fnNode)) + .contentHash(contentHasher.hash(fnNode)) + .ast(syntaxTreePrinter.print(fnNode)) + .astHash(syntaxTreeHasher.hash(fnNode)) + .sExpression(sExpressionPrinter.print(fnNode)) + .totalTokens(totalTokenCounter.count(fnNode)) + .codeTokens(codeTokenCounter.count(fnNode)) + .lines(lineCounter.count(fnNode)) + .characters(characterCounter.count(fnNode)) + .containsNonAscii(containsNonAscii.test(fnNode)) + .containsError(containsError.test(fnNode)) + .boilerplateType(boilerplateEnumerator.asEnum(fnNode)) + .isTest(file.getIsTest()) + .build(); + functions.add(function); + } + return functions; + } +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java new file mode 100644 index 00000000..877199fc --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java @@ -0,0 +1,38 @@ +package usi.si.seart.analyzer; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.experimental.FieldDefaults; +import usi.si.seart.model.GitRepo; +import usi.si.seart.model.code.File; +import usi.si.seart.model.code.Function; + +import java.nio.file.Path; +import java.util.List; + +public interface Analyzer extends AutoCloseable { + + Result analyze(); + + @Getter + @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) + @AllArgsConstructor + final class Result { + File file; + List functions; + } + + @Getter + @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) + @AllArgsConstructor + final class LocalClone { + + GitRepo gitRepo; + Path diskPath; + + public Path relativePathOf(Path path) { + return diskPath.relativize(path); + } + } +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java new file mode 100644 index 00000000..b7d5ba8b --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java @@ -0,0 +1,20 @@ +package usi.si.seart.analyzer; + +import usi.si.seart.analyzer.enumerator.JavaBoilerplateEnumerator; +import usi.si.seart.analyzer.predicate.JavaTestFilePredicate; +import usi.si.seart.analyzer.query.JavaSingleCaptureQueries; +import usi.si.seart.analyzer.traverser.PreviousCommentTraverser; +import usi.si.seart.treesitter.Language; + +import java.nio.file.Path; + +public class JavaAnalyzer extends AbstractAnalyzer { + + public JavaAnalyzer(LocalClone localClone, Path path) { + super(localClone, path, Language.JAVA); + this.testFilePredicate = new JavaTestFilePredicate(); + this.queries = new JavaSingleCaptureQueries(); + this.boilerplateEnumerator = new JavaBoilerplateEnumerator(this::getSourceBytes); + this.previousCommentTraverser = new PreviousCommentTraverser(); + } +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/TestFilePredicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/TestFilePredicate.java index 23111a67..65c22e0f 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/TestFilePredicate.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/TestFilePredicate.java @@ -1,7 +1,5 @@ package usi.si.seart.analyzer.predicate; -import usi.si.seart.treesitter.Language; - import java.nio.file.FileSystems; import java.nio.file.Path; import java.nio.file.PathMatcher; @@ -15,12 +13,4 @@ public boolean test(Path path) { PathMatcher matcher = FileSystems.getDefault().getPathMatcher(glob); return matcher.matches(path); } - - public static TestFilePredicate forLanguage(Language language) { - switch (language) { - case JAVA: return new JavaTestFilePredicate(); - default: return new TestFilePredicate() {}; - } - } - } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/SingleCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/SingleCaptureQueries.java index 942b4f1a..74e1c944 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/SingleCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/SingleCaptureQueries.java @@ -45,27 +45,4 @@ protected List execute(Node node, String sExpr) { public boolean isPastThreshold(int count) { return count >= 1; } - - public static SingleCaptureQueries forLanguage(Language language) { - switch (language) { - case JAVA: return new JavaSingleCaptureQueries(); - default: return new SingleCaptureQueries(null) { - - @Override - public List getNodes(Node node) { - return List.of(); - } - - @Override - public List getComments(Node node) { - return List.of(); - } - - @Override - public List getCallableDeclarations(Node node) { - return List.of(); - } - }; - } - } } From 272af65724193a9e4f2b571c392836e57e797c9f Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 18 Jan 2023 16:34:11 +0100 Subject: [PATCH 0046/1089] Added `DelimiterSuffixedStringCollector` This verbosely named class was introduced for 2 reasons: 1) To provide a Collector abstraction for the coming comment 2) To make sure what I envisioned is tested and works as expected --- .../DelimiterSuffixedStringCollector.java | 50 +++++++++++++++++++ .../DelimiterSuffixedStringCollectorTest.java | 40 +++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/util/stream/DelimiterSuffixedStringCollector.java create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/util/stream/DelimiterSuffixedStringCollectorTest.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/util/stream/DelimiterSuffixedStringCollector.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/util/stream/DelimiterSuffixedStringCollector.java new file mode 100644 index 00000000..aa96d27a --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/util/stream/DelimiterSuffixedStringCollector.java @@ -0,0 +1,50 @@ +package usi.si.seart.analyzer.util.stream; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; + +import java.util.Collections; +import java.util.Set; +import java.util.StringJoiner; +import java.util.function.BiConsumer; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collector; + +@AllArgsConstructor +@RequiredArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE) +public class DelimiterSuffixedStringCollector implements Collector { + + final String delimiter; + String empty = ""; + + @Override + public Supplier supplier() { + return () -> new StringJoiner(delimiter, "", delimiter).setEmptyValue(empty); + } + + @Override + public BiConsumer accumulator() { + return StringJoiner::add; + } + + @Override + public BinaryOperator combiner() { + return StringJoiner::merge; + } + + @Override + public Function finisher() { + return StringJoiner::toString; + } + + @Override + public Set characteristics() { + // TODO: 18.01.23 Define optimization characteristics... + return Collections.emptySet(); + } +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/util/stream/DelimiterSuffixedStringCollectorTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/util/stream/DelimiterSuffixedStringCollectorTest.java new file mode 100644 index 00000000..37da8d90 --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/util/stream/DelimiterSuffixedStringCollectorTest.java @@ -0,0 +1,40 @@ +package usi.si.seart.analyzer.util.stream; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; + +import java.util.stream.Stream; + +class DelimiterSuffixedStringCollectorTest { + + private static class StringsArgumentsProvider implements ArgumentsProvider { + + @Override + public Stream provideArguments(ExtensionContext extensionContext) throws Exception { + return Stream.of( + Arguments.of("", Stream.of(), " "), + Arguments.of("A ", Stream.of("A"), " "), + Arguments.of("ABC", Stream.of("A", "B", "C"), ""), + Arguments.of("A B C ", Stream.of("A", "B", "C"), " ") + ); + } + } + + @ParameterizedTest(name = "[{index}] {0}") + @ArgumentsSource(StringsArgumentsProvider.class) + void collectorTest(String expected, Stream input, String delimiter) { + Assertions.assertEquals(expected, input.collect(new DelimiterSuffixedStringCollector(delimiter))); + } + + @Test + void customEmptyTest() { + String expected = "null"; + Stream input = Stream.of(); + Assertions.assertEquals(expected, input.collect(new DelimiterSuffixedStringCollector(" ", expected))); + } +} \ No newline at end of file From 302f2ef708656f0f337e96a75669f43bb1db9e13 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 18 Jan 2023 16:40:27 +0100 Subject: [PATCH 0047/1089] The `JavaAnalyzer` information now takes previous comments into account Limitation of initial implementation: while the comments were concatenated the function source, the rest of the statistics were not updated to match. With this comment the `JavaAnalyzer`, which is currently the only analyzer requiring these actions, was updated to perform additional recalculations for the previous sibling comments. As a result of this change, the S-Expression field is now wrapped with an additional wrapper node. While not a part of the tree-sitter grammar, it is nonetheless needed to provide a valid structure that will allow the expression to be queried in the future. --- .../si/seart/analyzer/AbstractAnalyzer.java | 81 +++++++++---------- .../usi/si/seart/analyzer/JavaAnalyzer.java | 45 +++++++++++ 2 files changed, 83 insertions(+), 43 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java index ed284986..18b94e46 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java @@ -34,9 +34,7 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; -import java.util.StringJoiner; import java.util.function.Predicate; -import java.util.stream.Collector; @FieldDefaults(level = AccessLevel.PROTECTED) public abstract class AbstractAnalyzer implements Analyzer { @@ -120,58 +118,55 @@ public final Result analyze() { return new Analyzer.Result(file, functions); } - private File extractFileEntity() { - Node fileNode = tree.getRootNode(); + protected File extractFileEntity() { + Node node = tree.getRootNode(); return File.builder() .repo(localClone.getGitRepo()) .path(localClone.relativePathOf(path).toString()) - .content(nodePrinter.print(fileNode)) - .contentHash(contentHasher.hash(fileNode)) - .ast(syntaxTreePrinter.print(fileNode)) - .astHash(syntaxTreeHasher.hash(fileNode)) - .sExpression(sExpressionPrinter.print(fileNode)) - .totalTokens(totalTokenCounter.count(fileNode)) - .codeTokens(codeTokenCounter.count(fileNode)) - .lines(lineCounter.count(fileNode)) - .characters(characterCounter.count(fileNode)) - .containsNonAscii(containsNonAscii.test(fileNode)) - .containsError(containsError.test(fileNode)) + .content(nodePrinter.print(node)) + .contentHash(contentHasher.hash(node)) + .ast(syntaxTreePrinter.print(node)) + .astHash(syntaxTreeHasher.hash(node)) + .sExpression("(sexp " + sExpressionPrinter.print(node) + ")") + .totalTokens(totalTokenCounter.count(node)) + .codeTokens(codeTokenCounter.count(node)) + .lines(lineCounter.count(node)) + .characters(characterCounter.count(node)) + .containsNonAscii(containsNonAscii.test(node)) + .containsError(containsError.test(node)) .isTest(testFilePredicate.test(path)) .build(); } - private List extractFunctionEntities(File file) { + protected List extractFunctionEntities(File file) { List targets = queries.getCallableDeclarations(tree.getRootNode()); List functions = new ArrayList<>(targets.size()); - for (Node fnNode: targets) { - List comments = previousCommentTraverser.getNodes(fnNode); - String prefixDoc = comments.stream() - .map(node -> nodePrinter.print(node)) - .collect(Collector.of( - () -> new StringJoiner("\n", "", "\n").setEmptyValue(""), - StringJoiner::add, - StringJoiner::merge, - StringJoiner::toString - )); - Function function = Function.builder() - .file(file) - .repo(localClone.getGitRepo()) - .content(prefixDoc + nodePrinter.print(fnNode)) - .contentHash(contentHasher.hash(fnNode)) - .ast(syntaxTreePrinter.print(fnNode)) - .astHash(syntaxTreeHasher.hash(fnNode)) - .sExpression(sExpressionPrinter.print(fnNode)) - .totalTokens(totalTokenCounter.count(fnNode)) - .codeTokens(codeTokenCounter.count(fnNode)) - .lines(lineCounter.count(fnNode)) - .characters(characterCounter.count(fnNode)) - .containsNonAscii(containsNonAscii.test(fnNode)) - .containsError(containsError.test(fnNode)) - .boilerplateType(boilerplateEnumerator.asEnum(fnNode)) - .isTest(file.getIsTest()) - .build(); + for (Node node: targets) { + Function function = extractFunctionEntity(node); + // These operations are invariant by + // nature and should not be overridden + function.setFile(file); + function.setIsTest(file.getIsTest()); functions.add(function); } return functions; } + + protected Function extractFunctionEntity(Node node) { + return Function.builder() + .repo(localClone.getGitRepo()) + .content(nodePrinter.print(node)) + .contentHash(contentHasher.hash(node)) + .ast(syntaxTreePrinter.print(node)) + .astHash(syntaxTreeHasher.hash(node)) + .sExpression("(sexp " + sExpressionPrinter.print(node) + ")") + .totalTokens(totalTokenCounter.count(node)) + .codeTokens(codeTokenCounter.count(node)) + .lines(lineCounter.count(node)) + .characters(characterCounter.count(node)) + .containsNonAscii(containsNonAscii.test(node)) + .containsError(containsError.test(node)) + .boilerplateType(boilerplateEnumerator.asEnum(node)) + .build(); + } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java index b7d5ba8b..7ab4de82 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java @@ -4,9 +4,13 @@ import usi.si.seart.analyzer.predicate.JavaTestFilePredicate; import usi.si.seart.analyzer.query.JavaSingleCaptureQueries; import usi.si.seart.analyzer.traverser.PreviousCommentTraverser; +import usi.si.seart.analyzer.util.stream.DelimiterSuffixedStringCollector; +import usi.si.seart.model.code.Function; import usi.si.seart.treesitter.Language; +import usi.si.seart.treesitter.Node; import java.nio.file.Path; +import java.util.List; public class JavaAnalyzer extends AbstractAnalyzer { @@ -17,4 +21,45 @@ public JavaAnalyzer(LocalClone localClone, Path path) { this.boilerplateEnumerator = new JavaBoilerplateEnumerator(this::getSourceBytes); this.previousCommentTraverser = new PreviousCommentTraverser(); } + + @Override + protected Function extractFunctionEntity(Node node) { + List comments = previousCommentTraverser.getNodes(node); + String doc = comments.stream() + .map(comment -> nodePrinter.print(comment)) + .collect(new DelimiterSuffixedStringCollector("\n")); + String docAst = comments.stream() + .map(comment -> syntaxTreePrinter.print(comment)) + .collect(new DelimiterSuffixedStringCollector("\n")); + String docSExpression = comments.stream() + .map(comment -> sExpressionPrinter.print(comment)) + .collect(new DelimiterSuffixedStringCollector(" ")); + Long docLines = comments.stream() + .mapToLong(comment -> lineCounter.count(comment)) + .sum(); + Long docTotalTokens = comments.stream() + .mapToLong(comment -> totalTokenCounter.count(comment)) + .sum(); + Long docCharacters = comments.stream() + .mapToLong(comment -> characterCounter.count(comment)) + .sum(); + boolean docContainsNonAscii = comments.stream() + .anyMatch(comment -> containsNonAscii.test(comment)); + + return Function.builder() + .repo(localClone.getGitRepo()) + .content(doc + nodePrinter.print(node)) + .contentHash(contentHasher.hash(node)) + .ast(docAst + syntaxTreePrinter.print(node)) + .astHash(syntaxTreeHasher.hash(node)) + .sExpression("(sexp " + docSExpression + sExpressionPrinter.print(node)+")") + .totalTokens(docTotalTokens + totalTokenCounter.count(node)) + .codeTokens(codeTokenCounter.count(node)) + .lines(docLines + lineCounter.count(node)) + .characters(docCharacters + characterCounter.count(node)) + .containsNonAscii(docContainsNonAscii || containsNonAscii.test(node)) + .containsError(containsError.test(node)) + .boilerplateType(boilerplateEnumerator.asEnum(node)) + .build(); + } } From 34aafe4cabe3167fe2c22164c15453d5040f6e2e Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 18 Jan 2023 16:48:52 +0100 Subject: [PATCH 0048/1089] Removed the `Traverser` from `AbstractAnalyzer` since it isn't needed... ...there. But it is needed in `JavaAnalyzer`, since sibling comment nodes need to be attached to every extracted function. I will probably introduce another layer of abstraction since this may also be the case for languages like C and C++. --- .../src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java | 3 --- .../src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java index 18b94e46..e5441395 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java @@ -20,7 +20,6 @@ import usi.si.seart.analyzer.printer.SExpressionPrinter; import usi.si.seart.analyzer.printer.SyntaxTreePrinter; import usi.si.seart.analyzer.query.Queries; -import usi.si.seart.analyzer.traverser.Traverser; import usi.si.seart.model.code.Boilerplate; import usi.si.seart.model.code.File; import usi.si.seart.model.code.Function; @@ -83,8 +82,6 @@ public List getCallableDeclarations(Node node) { Enumerator boilerplateEnumerator = node -> null; - Traverser> previousCommentTraverser = node -> List.of(); - @SneakyThrows({IOException.class}) protected AbstractAnalyzer(LocalClone localClone, Path path, Language language) { this.language = language; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java index 7ab4de82..eca7a7d1 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java @@ -4,6 +4,7 @@ import usi.si.seart.analyzer.predicate.JavaTestFilePredicate; import usi.si.seart.analyzer.query.JavaSingleCaptureQueries; import usi.si.seart.analyzer.traverser.PreviousCommentTraverser; +import usi.si.seart.analyzer.traverser.Traverser; import usi.si.seart.analyzer.util.stream.DelimiterSuffixedStringCollector; import usi.si.seart.model.code.Function; import usi.si.seart.treesitter.Language; @@ -14,6 +15,8 @@ public class JavaAnalyzer extends AbstractAnalyzer { + protected Traverser> previousCommentTraverser; + public JavaAnalyzer(LocalClone localClone, Path path) { super(localClone, path, Language.JAVA); this.testFilePredicate = new JavaTestFilePredicate(); From a19dc23d169a36f41343407108ac99b8acce2f32 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 18 Jan 2023 17:02:49 +0100 Subject: [PATCH 0049/1089] Added another layer of abstraction: `PreviousCommentsAnalyzer` Terrible name for a class. Was never good with naming things. Don't be surprised if this gets changed down the line. Anyway, this new abstract class isolates function extraction logic that will be specific to languages whose comments and documentation are defined as extras that by convention precede the declaration. In other words the existing `JavaAnalyzer` as well as those that will be written for C, C++ and JavaScript. Python is (un?)fortunately a completely different can of worms. --- .../usi/si/seart/analyzer/JavaAnalyzer.java | 52 +--------------- .../analyzer/PreviousCommentsAnalyzer.java | 61 +++++++++++++++++++ 2 files changed, 62 insertions(+), 51 deletions(-) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PreviousCommentsAnalyzer.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java index eca7a7d1..9aa2b135 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java @@ -3,66 +3,16 @@ import usi.si.seart.analyzer.enumerator.JavaBoilerplateEnumerator; import usi.si.seart.analyzer.predicate.JavaTestFilePredicate; import usi.si.seart.analyzer.query.JavaSingleCaptureQueries; -import usi.si.seart.analyzer.traverser.PreviousCommentTraverser; -import usi.si.seart.analyzer.traverser.Traverser; -import usi.si.seart.analyzer.util.stream.DelimiterSuffixedStringCollector; -import usi.si.seart.model.code.Function; import usi.si.seart.treesitter.Language; -import usi.si.seart.treesitter.Node; import java.nio.file.Path; -import java.util.List; -public class JavaAnalyzer extends AbstractAnalyzer { - - protected Traverser> previousCommentTraverser; +public class JavaAnalyzer extends PreviousCommentsAnalyzer { public JavaAnalyzer(LocalClone localClone, Path path) { super(localClone, path, Language.JAVA); this.testFilePredicate = new JavaTestFilePredicate(); this.queries = new JavaSingleCaptureQueries(); this.boilerplateEnumerator = new JavaBoilerplateEnumerator(this::getSourceBytes); - this.previousCommentTraverser = new PreviousCommentTraverser(); - } - - @Override - protected Function extractFunctionEntity(Node node) { - List comments = previousCommentTraverser.getNodes(node); - String doc = comments.stream() - .map(comment -> nodePrinter.print(comment)) - .collect(new DelimiterSuffixedStringCollector("\n")); - String docAst = comments.stream() - .map(comment -> syntaxTreePrinter.print(comment)) - .collect(new DelimiterSuffixedStringCollector("\n")); - String docSExpression = comments.stream() - .map(comment -> sExpressionPrinter.print(comment)) - .collect(new DelimiterSuffixedStringCollector(" ")); - Long docLines = comments.stream() - .mapToLong(comment -> lineCounter.count(comment)) - .sum(); - Long docTotalTokens = comments.stream() - .mapToLong(comment -> totalTokenCounter.count(comment)) - .sum(); - Long docCharacters = comments.stream() - .mapToLong(comment -> characterCounter.count(comment)) - .sum(); - boolean docContainsNonAscii = comments.stream() - .anyMatch(comment -> containsNonAscii.test(comment)); - - return Function.builder() - .repo(localClone.getGitRepo()) - .content(doc + nodePrinter.print(node)) - .contentHash(contentHasher.hash(node)) - .ast(docAst + syntaxTreePrinter.print(node)) - .astHash(syntaxTreeHasher.hash(node)) - .sExpression("(sexp " + docSExpression + sExpressionPrinter.print(node)+")") - .totalTokens(docTotalTokens + totalTokenCounter.count(node)) - .codeTokens(codeTokenCounter.count(node)) - .lines(docLines + lineCounter.count(node)) - .characters(docCharacters + characterCounter.count(node)) - .containsNonAscii(docContainsNonAscii || containsNonAscii.test(node)) - .containsError(containsError.test(node)) - .boilerplateType(boilerplateEnumerator.asEnum(node)) - .build(); } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PreviousCommentsAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PreviousCommentsAnalyzer.java new file mode 100644 index 00000000..d11e94bb --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PreviousCommentsAnalyzer.java @@ -0,0 +1,61 @@ +package usi.si.seart.analyzer; + +import usi.si.seart.analyzer.traverser.PreviousCommentTraverser; +import usi.si.seart.analyzer.traverser.Traverser; +import usi.si.seart.analyzer.util.stream.DelimiterSuffixedStringCollector; +import usi.si.seart.model.code.Function; +import usi.si.seart.treesitter.Language; +import usi.si.seart.treesitter.Node; + +import java.nio.file.Path; +import java.util.List; + +public abstract class PreviousCommentsAnalyzer extends AbstractAnalyzer { + + protected Traverser> previousCommentTraverser = new PreviousCommentTraverser(); + + protected PreviousCommentsAnalyzer(LocalClone localClone, Path path, Language language) { + super(localClone, path, language); + } + + @Override + protected Function extractFunctionEntity(Node node) { + List comments = previousCommentTraverser.getNodes(node); + String doc = comments.stream() + .map(comment -> nodePrinter.print(comment)) + .collect(new DelimiterSuffixedStringCollector("\n")); + String docAst = comments.stream() + .map(comment -> syntaxTreePrinter.print(comment)) + .collect(new DelimiterSuffixedStringCollector("\n")); + String docSExpression = comments.stream() + .map(comment -> sExpressionPrinter.print(comment)) + .collect(new DelimiterSuffixedStringCollector(" ")); + Long docLines = comments.stream() + .mapToLong(comment -> lineCounter.count(comment)) + .sum(); + Long docTotalTokens = comments.stream() + .mapToLong(comment -> totalTokenCounter.count(comment)) + .sum(); + Long docCharacters = comments.stream() + .mapToLong(comment -> characterCounter.count(comment)) + .sum(); + boolean docContainsNonAscii = comments.stream() + .anyMatch(comment -> containsNonAscii.test(comment)); + + return Function.builder() + .repo(localClone.getGitRepo()) + .content(doc + nodePrinter.print(node)) + .contentHash(contentHasher.hash(node)) + .ast(docAst + syntaxTreePrinter.print(node)) + .astHash(syntaxTreeHasher.hash(node)) + .sExpression("(sexp " + docSExpression + sExpressionPrinter.print(node)+")") + .totalTokens(docTotalTokens + totalTokenCounter.count(node)) + .codeTokens(codeTokenCounter.count(node)) + .lines(docLines + lineCounter.count(node)) + .characters(docCharacters + characterCounter.count(node)) + .containsNonAscii(docContainsNonAscii || containsNonAscii.test(node)) + .containsError(containsError.test(node)) + .boilerplateType(boilerplateEnumerator.asEnum(node)) + .build(); + } +} From 17084ae766d818dbd82126a221a53f8f70246904 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 19 Jan 2023 10:35:51 +0100 Subject: [PATCH 0050/1089] Updates to `Node` documentation, clarifying previous ambiguities --- .../main/java/usi/si/seart/treesitter/Node.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java index eec532bf..d8d1c00c 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java @@ -22,7 +22,7 @@ public class Node implements Iterable { /** * Get the node's child at the given index, where zero represents the first child. * - * @param child The zero-indexed child + * @param child The zero-indexed child position * @return The Node's child at the given index */ public Node getChild(int child) { @@ -30,7 +30,7 @@ public Node getChild(int child) { } /** - * @param name The node field name. + * @param name The child field name. * @return The node's child with the given field name. */ public Node getChildByFieldName(String name) { @@ -68,7 +68,9 @@ public Point getEndPoint() { } /** - * @return The field name for node's child at the given index, where zero represents the first child. + * @return + * The field name for node's child at the given index, + * with zero representing the first child. * Returns NULL, if no field is found. */ public String getFieldNameForChild(int child) { @@ -92,8 +94,6 @@ public Node getFirstNamedChildForByte(int offset) { } /** - * This string is allocated with malloc and the caller is responsible for freeing it using free. - * * @return An S-expression representing the node as a string. */ public String getNodeString() { @@ -135,6 +135,9 @@ public Node getParent() { return TreeSitter.nodeParent(this); } + /** + * @return The node's range, indicating its byte and file position span. + */ public Range getRange() { return new Range(this); } @@ -154,7 +157,7 @@ public Point getStartPoint() { } /** - * @return The node's type as a null-terminated string + * @return The node's type as a string */ public String getType() { return TreeSitter.nodeType(this); From d1ee97ceaaa8d4f4d1d3fe0f4682dae9e69d4442 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 19 Jan 2023 10:46:13 +0100 Subject: [PATCH 0051/1089] Minor refactoring of `NodeTest`, feel free to ignore this --- .../usi/si/seart/treesitter/NodeTest.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java index ea6ae62c..b047b409 100644 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java @@ -12,7 +12,7 @@ class NodeTest extends TestBase { private static final String source = "def foo(bar, baz):\n print(bar)\n print(baz)"; @Test - @SneakyThrows({UnsupportedEncodingException.class}) + @SneakyThrows(UnsupportedEncodingException.class) void testGetChild() { @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString(source); @@ -28,7 +28,7 @@ void testGetChild() { } @Test - @SneakyThrows({UnsupportedEncodingException.class}) + @SneakyThrows(UnsupportedEncodingException.class) void testGetChildByFieldName() { @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString(source); @@ -39,7 +39,7 @@ void testGetChildByFieldName() { } @Test - @SneakyThrows({UnsupportedEncodingException.class}) + @SneakyThrows(UnsupportedEncodingException.class) void testGetDescendantForByteRange() { @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString(source); @@ -58,7 +58,7 @@ void testGetDescendantForByteRange() { } @Test - @SneakyThrows({UnsupportedEncodingException.class}) + @SneakyThrows(UnsupportedEncodingException.class) void testGetFieldNameForChild() { @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString(source); @@ -72,7 +72,7 @@ void testGetFieldNameForChild() { } @Test - @SneakyThrows({UnsupportedEncodingException.class}) + @SneakyThrows(UnsupportedEncodingException.class) void testGetFirstChildForByte() { @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString(source); @@ -91,7 +91,7 @@ void testGetFirstChildForByte() { } @Test - @SneakyThrows({UnsupportedEncodingException.class}) + @SneakyThrows(UnsupportedEncodingException.class) void testGetFirstNamedChildForByte() { @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString(source); @@ -110,7 +110,7 @@ void testGetFirstNamedChildForByte() { } @Test - @SneakyThrows({UnsupportedEncodingException.class}) + @SneakyThrows(UnsupportedEncodingException.class) void testGetParent() { @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString(source); @@ -120,7 +120,7 @@ void testGetParent() { } @Test - @SneakyThrows({UnsupportedEncodingException.class}) + @SneakyThrows(UnsupportedEncodingException.class) void testGetNextNamedSibling() { @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString(source); @@ -133,7 +133,7 @@ void testGetNextNamedSibling() { } @Test - @SneakyThrows({UnsupportedEncodingException.class}) + @SneakyThrows(UnsupportedEncodingException.class) void testGetNextSibling() { @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString(source); @@ -146,7 +146,7 @@ void testGetNextSibling() { } @Test - @SneakyThrows({UnsupportedEncodingException.class}) + @SneakyThrows(UnsupportedEncodingException.class) void testGetPrevNamedSibling() { @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString(source); @@ -159,7 +159,7 @@ void testGetPrevNamedSibling() { } @Test - @SneakyThrows({UnsupportedEncodingException.class}) + @SneakyThrows(UnsupportedEncodingException.class) void testGetPrevSibling() { @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString(source); @@ -172,7 +172,7 @@ void testGetPrevSibling() { } @Test - @SneakyThrows({UnsupportedEncodingException.class}) + @SneakyThrows(UnsupportedEncodingException.class) void testHasError() { @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString("def foo(bar, baz):\n print(bar.)"); @@ -185,7 +185,7 @@ void testHasError() { } @Test - @SneakyThrows({UnsupportedEncodingException.class}) + @SneakyThrows(UnsupportedEncodingException.class) void testIsExtra() { @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString("# this is just a comment"); @@ -196,7 +196,7 @@ void testIsExtra() { } @Test - @SneakyThrows({UnsupportedEncodingException.class}) + @SneakyThrows(UnsupportedEncodingException.class) void testIsMissing() { @Cleanup Parser parser = new Parser(Language.JAVA); @Cleanup Tree tree = parser.parseString("class C { public static final int i = 6 }"); @@ -210,7 +210,7 @@ void testIsMissing() { } @Test - @SneakyThrows({UnsupportedEncodingException.class}) + @SneakyThrows(UnsupportedEncodingException.class) void testIsNamed() { @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString(source); From ed6dac89477e66a97196fe3c57e627226ae7bd40 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 19 Jan 2023 10:47:10 +0100 Subject: [PATCH 0052/1089] Minor improvement to `QueryCursorTest`, feel free to ignore this --- .../test/java/usi/si/seart/treesitter/QueryCursorTest.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryCursorTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryCursorTest.java index 48772263..49b48f56 100644 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryCursorTest.java +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryCursorTest.java @@ -1,6 +1,7 @@ package usi.si.seart.treesitter; import lombok.Cleanup; +import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -9,7 +10,8 @@ class QueryCursorTest extends TestBase { @Test - void testExecSimpleQuery() throws UnsupportedEncodingException { + @SneakyThrows(UnsupportedEncodingException.class) + void testExecSimpleQuery() { @Cleanup Parser parser = new Parser(Language.JAVA); @Cleanup Tree tree = parser.parseString("class Hello {}"); @Cleanup Query query = new Query(Language.JAVA, "(class_body) @test"); @@ -21,7 +23,8 @@ void testExecSimpleQuery() throws UnsupportedEncodingException { } @Test - void testExecNoResultQuery() throws UnsupportedEncodingException { + @SneakyThrows(UnsupportedEncodingException.class) + void testExecNoResultQuery() { @Cleanup Parser parser = new Parser(Language.JAVA); @Cleanup Tree tree = parser.parseString("class Hello {}"); @Cleanup Query query = new Query(Language.JAVA, "(method_declaration) @method"); From 5f3d9bb71f89922b566c51da8c6ee2c86db3ab64 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 19 Jan 2023 10:53:59 +0100 Subject: [PATCH 0053/1089] `Query` internal pointer access now restricted to package-private level --- .../src/main/java/usi/si/seart/treesitter/Query.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java index e1a412ff..3ed98287 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java @@ -24,7 +24,7 @@ * * @apiNote The underlying query value is immutable and can be safely shared between threads. */ -@Getter +@Getter(value = AccessLevel.PACKAGE) @AllArgsConstructor(access = AccessLevel.PACKAGE) public class Query implements AutoCloseable { From 256b2f173dc132499936cb06f97ded4de2c84ec5 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 19 Jan 2023 10:55:21 +0100 Subject: [PATCH 0054/1089] Added internal pointer nullability check to `Query` --- .../src/main/java/usi/si/seart/treesitter/Query.java | 4 ++++ .../src/test/java/usi/si/seart/treesitter/QueryTest.java | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java index 3ed98287..ff3b0278 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java @@ -41,4 +41,8 @@ public Query(Language language, String source) { public void close() { TreeSitter.queryDelete(pointer); } + + public boolean isNull() { + return pointer == 0; + } } diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java index ea800ac4..7da406f7 100644 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java @@ -9,12 +9,12 @@ class QueryTest extends TestBase { @Test void testQuery() { @Cleanup Query query = new Query(Language.JAVA, "(class_declaration)"); - Assertions.assertNotEquals(0, query.getPointer(), "Pointer is not null"); + Assertions.assertFalse(query.isNull(), "Pointer is not null"); } @Test void testInvalidQuery() { @Cleanup Query query = new Query(Language.JAVA, "(class_declaration"); - Assertions.assertEquals(0, query.getPointer(), "Pointer is null"); + Assertions.assertTrue(query.isNull(), "Pointer is null"); } } From 9a5546305c1accd02707f37ad20d7f2f94d11c20 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 19 Jan 2023 11:03:36 +0100 Subject: [PATCH 0055/1089] Added null checks to `QueryCursor`, `Tree`, `TreeCursor` and `Parser` Tests will soon follow --- .../src/main/java/usi/si/seart/treesitter/Parser.java | 4 ++++ .../src/main/java/usi/si/seart/treesitter/QueryCursor.java | 4 ++++ .../src/main/java/usi/si/seart/treesitter/Tree.java | 4 ++++ .../src/main/java/usi/si/seart/treesitter/TreeCursor.java | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java index fc5a25e7..c9112b07 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java @@ -22,6 +22,10 @@ public Parser(Language language) { this.setLanguage(language); } + public boolean isNull() { + return pointer == 0; + } + /** * Set the language that the parser should use for parsing. * diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCursor.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCursor.java index 6c5c9e6f..f1654e40 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCursor.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCursor.java @@ -27,6 +27,10 @@ public void execQuery(Query query, Node node) { TreeSitter.queryCursorExec(pointer, query.getPointer(), node); } + public boolean isNull() { + return pointer == 0; + } + /** * Advance to the next match of the currently running query. * diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java index c4f5fd19..59da1b04 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java @@ -46,4 +46,8 @@ public Node getRootNode() { public Iterator iterator() { return getRootNode().iterator(); } + + public boolean isNull() { + return pointer == 0; + } } diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursor.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursor.java index 6bb4b849..2e72db5e 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursor.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursor.java @@ -74,6 +74,10 @@ public boolean gotoParent() { return TreeSitter.treeCursorGotoParent(pointer); } + public boolean isNull() { + return pointer == 0; + } + /** * Iteratively traverse over the parse tree, applying a callback to the nodes before they are visited. * From f6bc92b3d283a3895d221dc0c965c55587b4f2c5 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 19 Jan 2023 11:47:10 +0100 Subject: [PATCH 0056/1089] Added `External` supertype The `QueryCursor`, `Tree`, `TreeCursor` and `Parser` classes now share a common superclass called `External`. As the name suggests, this abstract class signifies that its concrete descendants are not pure Java classes. What this means is that each subclass is direct mapping to a C struct. Such classes are defined by a common set of characteristics: - Each has a pointer that is used to directly access the struct - This pointer is `final`, as it should never be changed - Null instances are defined by a 0 pointer value - All instances can be checked if they are null `External` itself is defined as package private, as this is a rare case where the substitution principle is not desired. This may be subject to change in the future, provided that different needs arise. For instance, we may keep references of all `External` instances in an ordered collection and then free the memory associated with then en-masse. --- .../usi/si/seart/treesitter/External.java | 16 ++++++++++++++ .../java/usi/si/seart/treesitter/Parser.java | 12 +++++----- .../java/usi/si/seart/treesitter/Query.java | 22 ++++++++----------- .../usi/si/seart/treesitter/QueryCursor.java | 14 ++---------- .../java/usi/si/seart/treesitter/Tree.java | 15 ++++--------- .../usi/si/seart/treesitter/TreeCursor.java | 14 +++++------- 6 files changed, 41 insertions(+), 52 deletions(-) create mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/External.java diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/External.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/External.java new file mode 100644 index 00000000..064dcefa --- /dev/null +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/External.java @@ -0,0 +1,16 @@ +package usi.si.seart.treesitter; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter(value = AccessLevel.PACKAGE) +@AllArgsConstructor(access = AccessLevel.PROTECTED) +abstract class External implements AutoCloseable { + + protected final long pointer; + + public final boolean isNull() { + return pointer == 0; + } +} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java index c9112b07..c17084ad 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java @@ -12,18 +12,16 @@ * Parsers are stateful objects that can be assigned a language and used to produce a * {@link Tree Tree} based on some source code. */ -public class Parser implements AutoCloseable { - - private final long pointer; +public class Parser extends External { public Parser(Language language) { - Objects.requireNonNull(language, "Language must not be null!"); - this.pointer = TreeSitter.parserNew(); + super(createIfValid(language)); this.setLanguage(language); } - public boolean isNull() { - return pointer == 0; + private static long createIfValid(Language language) { + Objects.requireNonNull(language, "Language must not be null!"); + return TreeSitter.parserNew(); } /** diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java index ff3b0278..7980e255 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java @@ -1,8 +1,6 @@ package usi.si.seart.treesitter; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Getter; +import java.util.Objects; /** * A query consists of one or more patterns, where each pattern is an S-expression that matches a certain set of nodes @@ -24,14 +22,16 @@ * * @apiNote The underlying query value is immutable and can be safely shared between threads. */ -@Getter(value = AccessLevel.PACKAGE) -@AllArgsConstructor(access = AccessLevel.PACKAGE) -public class Query implements AutoCloseable { - - private final long pointer; +public class Query extends External { public Query(Language language, String source) { - this(TreeSitter.queryNew(language.getId(), source)); + super(createIfValid(language, source)); + } + + private static long createIfValid(Language language, String source) { + Objects.requireNonNull(language, "Language must not be null!"); + Objects.requireNonNull(source, "Source must not be null!"); + return TreeSitter.queryNew(language.getId(), source); } /** @@ -41,8 +41,4 @@ public Query(Language language, String source) { public void close() { TreeSitter.queryDelete(pointer); } - - public boolean isNull() { - return pointer == 0; - } } diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCursor.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCursor.java index f1654e40..1f8e1437 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCursor.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCursor.java @@ -1,20 +1,14 @@ package usi.si.seart.treesitter; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; - /** * Cursor used for executing queries, carrying the state needed to process them. * * @apiNote The query cursor should not be shared between threads, but can be reused for many query executions. */ -@AllArgsConstructor(access = AccessLevel.PACKAGE) -public class QueryCursor implements AutoCloseable { - - private final long pointer; +public class QueryCursor extends External { public QueryCursor() { - this(TreeSitter.queryCursorNew()); + super(TreeSitter.queryCursorNew()); } /** @@ -27,10 +21,6 @@ public void execQuery(Query query, Node node) { TreeSitter.queryCursorExec(pointer, query.getPointer(), node); } - public boolean isNull() { - return pointer == 0; - } - /** * Advance to the next match of the currently running query. * diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java index 59da1b04..60526e68 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java @@ -1,19 +1,16 @@ package usi.si.seart.treesitter; -import lombok.AllArgsConstructor; -import lombok.Getter; - import java.util.Iterator; /** * A Tree represents the syntax tree of an entire source code file. It contains {@link Node Node} * instances that indicate the structure of the source code. */ -@Getter -@AllArgsConstructor -public class Tree implements AutoCloseable, Iterable { +public class Tree extends External implements Iterable { - private final long pointer; + Tree(long pointer) { + super(pointer); + } /** * Delete the syntax tree, freeing all the memory that it used. @@ -46,8 +43,4 @@ public Node getRootNode() { public Iterator iterator() { return getRootNode().iterator(); } - - public boolean isNull() { - return pointer == 0; - } } diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursor.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursor.java index 2e72db5e..628484cc 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursor.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursor.java @@ -1,21 +1,21 @@ package usi.si.seart.treesitter; -import lombok.RequiredArgsConstructor; - import java.util.function.Consumer; /** * A tree cursor is a stateful object that allows you to walk a syntax tree with maximum efficiency. */ -@RequiredArgsConstructor -public class TreeCursor implements AutoCloseable { +public class TreeCursor extends External { - private final long pointer; private int context0; private int context1; private long id; private long tree; + TreeCursor(long pointer) { + super(pointer); + } + /** * Delete the tree cursor, freeing all the memory that it used. */ @@ -74,10 +74,6 @@ public boolean gotoParent() { return TreeSitter.treeCursorGotoParent(pointer); } - public boolean isNull() { - return pointer == 0; - } - /** * Iteratively traverse over the parse tree, applying a callback to the nodes before they are visited. * From 2243edc283c6bf45428c5bd6680a3605fbd11eab Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 19 Jan 2023 11:55:59 +0100 Subject: [PATCH 0057/1089] Added `isNull` method to `Node` I can't believe I forgot to add this one. This method will be extremely useful in preventing SIGSEGV crashes during JNI calls. The following commits will introduce null checks as preconditions to various methods. --- .../lib/usi_si_seart_treesitter_TreeSitter.cc | 5 +++++ .../lib/usi_si_seart_treesitter_TreeSitter.h | 8 ++++++++ .../src/main/java/usi/si/seart/treesitter/Node.java | 11 +++++++++++ .../java/usi/si/seart/treesitter/TreeSitter.java | 2 ++ .../test/java/usi/si/seart/treesitter/NodeTest.java | 13 +++++++++++++ 5 files changed, 39 insertions(+) diff --git a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc index c90934e1..b8b8473e 100644 --- a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc +++ b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc @@ -309,6 +309,11 @@ JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeIsNamed( return (jboolean) ts_node_is_named(_unmarshalNode(env, node)); } +JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeIsNull( + JNIEnv* env, jclass self, jobject node) { + return (jboolean) ts_node_is_null(_unmarshalNode(env, node)); +} + JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeParent( JNIEnv* env, jclass self, jobject node) { TSNode parent = ts_node_parent(_unmarshalNode(env, node)); diff --git a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.h b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.h index 29c3c426..40f2d3aa 100644 --- a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.h +++ b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.h @@ -119,6 +119,14 @@ JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeIsMissing JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeIsNamed (JNIEnv *, jclass, jobject); +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: nodeIsNull + * Signature: (Lusi/si/seart/treesitter/Node;)Z + */ +JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeIsNull + (JNIEnv *, jclass, jobject); + /* * Class: usi_si_seart_treesitter_TreeSitter * Method: nodeParent diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java index d8d1c00c..44b923dc 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java @@ -200,6 +200,17 @@ public boolean isNamed() { return TreeSitter.nodeIsNamed(this); } + /** + * Check if the node is null. Methods such as {@link #getChild(int) getChild} and + * {@link #getNextSibling() getNextSibling} will return a null node to indicate that no such node + * was found. + * + * @return true if the current node is a null node, false otherwise + */ + public boolean isNull() { + return TreeSitter.nodeIsNull(this); + } + /** * A tree cursor allows you to walk a syntax tree more efficiently than is possible using the TSNode functions. * It is a mutable object that is always on a certain syntax node, and can be moved imperatively to different nodes. diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitter.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitter.java index ff95245d..98acf22d 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitter.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitter.java @@ -33,6 +33,8 @@ class TreeSitter { static native boolean nodeIsNamed(Node node); + static native boolean nodeIsNull(Node node); + static native Node nodeParent(Node node); static native Node nodePrevNamedSibling(Node node); diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java index b047b409..3b297cb2 100644 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java @@ -221,4 +221,17 @@ void testIsNamed() { Assertions.assertFalse(def.isNamed()); Assertions.assertTrue(identifier.isNamed()); } + + @Test + @SneakyThrows(UnsupportedEncodingException.class) + void testIsNull() { + @Cleanup Parser parser = new Parser(Language.PYTHON); + @Cleanup Tree tree = parser.parseString(source); + Node root = tree.getRootNode(); + Assertions.assertFalse(root.isNull()); + Node function = root.getChild(0); + Node nullNode = root.getChild(1); + Assertions.assertFalse(function.isNull()); + Assertions.assertTrue(nullNode.isNull()); + } } From 2bef46887b18d761f0bf7c95564c2b0986c1b2a4 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 19 Jan 2023 12:07:01 +0100 Subject: [PATCH 0058/1089] Added missing package-level constructor restriction for certain classes List of classes affected: - `Node` - `TreeCursorNode` - `QueryMatch` - `QueryCapture` These classes should never be instantiated by the client, but rather created through their respective methods. --- .../src/main/java/usi/si/seart/treesitter/Node.java | 4 +++- .../src/main/java/usi/si/seart/treesitter/QueryCapture.java | 2 +- .../src/main/java/usi/si/seart/treesitter/QueryMatch.java | 2 +- .../src/main/java/usi/si/seart/treesitter/TreeCursorNode.java | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java index 44b923dc..0e3c9657 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java @@ -1,5 +1,6 @@ package usi.si.seart.treesitter; +import lombok.AccessLevel; import lombok.NoArgsConstructor; import java.util.Iterator; @@ -10,8 +11,9 @@ * A Node represents a single node in the syntax tree. It tracks its start and end positions in the source code, * as well as its relation to other nodes like its parent, siblings and children. */ -@NoArgsConstructor +@NoArgsConstructor(access = AccessLevel.PACKAGE) public class Node implements Iterable { + private int context0; private int context1; private int context2; diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCapture.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCapture.java index 3f47e89b..bfa8fb03 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCapture.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCapture.java @@ -6,7 +6,7 @@ import lombok.experimental.FieldDefaults; @Getter -@AllArgsConstructor +@AllArgsConstructor(access = AccessLevel.PACKAGE) @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class QueryCapture { diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryMatch.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryMatch.java index dc4826e0..2c19428a 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryMatch.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryMatch.java @@ -6,7 +6,7 @@ import lombok.experimental.FieldDefaults; @Getter -@AllArgsConstructor +@AllArgsConstructor(access = AccessLevel.PACKAGE) @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class QueryMatch { diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursorNode.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursorNode.java index eac4b480..2d0e449a 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursorNode.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursorNode.java @@ -6,7 +6,7 @@ import lombok.experimental.FieldDefaults; @Getter -@AllArgsConstructor +@AllArgsConstructor(access = AccessLevel.PACKAGE) @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class TreeCursorNode { From 8c055057e19f33ee98fa8060f57ad5600164e147 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 19 Jan 2023 12:10:36 +0100 Subject: [PATCH 0059/1089] More creation options for `SyntaxTreePrinter` --- .../usi/si/seart/treesitter/SyntaxTreePrinter.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/SyntaxTreePrinter.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/SyntaxTreePrinter.java index 271b2147..610ef6cc 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/SyntaxTreePrinter.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/SyntaxTreePrinter.java @@ -1,6 +1,7 @@ package usi.si.seart.treesitter; import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.Cleanup; import lombok.RequiredArgsConstructor; import lombok.experimental.FieldDefaults; @@ -8,12 +9,14 @@ /** * Utility used for pretty-printing entire syntax trees, as well as their subtrees. */ +@AllArgsConstructor @RequiredArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE) public class SyntaxTreePrinter { - int indentLevel = 0; final Node node; + String indentation = " "; + int currentLevel = 0; /** * @return A string representation of the subtree. Consists only of named nodes. @@ -41,7 +44,7 @@ private String printTreeNode(TreeCursorNode treeCursorNode) { Point startPoint = treeCursorNode.getStartPoint(); Point endPoint = treeCursorNode.getEndPoint(); return String.format("%s%s%s [%s] - [%s]%n", - " ".repeat(this.indentLevel), + indentation.repeat(currentLevel), (name != null) ? name + ": " : "", type, startPoint, endPoint ); @@ -56,14 +59,14 @@ private TreePrinterCursor(Node node) { @Override public boolean gotoFirstChild() { boolean success = super.gotoFirstChild(); - if (success) indentLevel++; + if (success) currentLevel++; return success; } @Override public boolean gotoParent() { boolean success = super.gotoParent(); - if (success) indentLevel--; + if (success) currentLevel--; return success; } } From c093bd5773c6839ad51d45b146209c36121a056d Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 19 Jan 2023 12:31:33 +0100 Subject: [PATCH 0060/1089] Added `equals` and `hashCode` implementations for `External` Just check the pointer value. Simple as. --- .../main/java/usi/si/seart/treesitter/External.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/External.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/External.java index 064dcefa..0d723015 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/External.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/External.java @@ -13,4 +13,17 @@ abstract class External implements AutoCloseable { public final boolean isNull() { return pointer == 0; } + + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + if (obj == null || getClass() != obj.getClass()) return false; + External other = (External) obj; + return pointer == other.pointer; + } + + @Override + public int hashCode() { + return Long.hashCode(pointer); + } } From 0c2580b05810b6ad57b513d6322ee42b4f41a421 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 19 Jan 2023 14:41:32 +0100 Subject: [PATCH 0061/1089] Use conditional to avoid conversion from bool to jboolean --- .../lib/usi_si_seart_treesitter_TreeSitter.cc | 31 ++++++++----------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc index b8b8473e..12bc3367 100644 --- a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc +++ b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc @@ -291,27 +291,27 @@ JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeEndPoint( JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeHasError( JNIEnv* env, jclass self, jobject node) { - return (jboolean) ts_node_has_error(_unmarshalNode(env, node)); + return ts_node_has_error(_unmarshalNode(env, node)) ? JNI_TRUE : JNI_FALSE; } JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeIsExtra( JNIEnv* env, jclass self, jobject node) { - return (jboolean) ts_node_is_extra(_unmarshalNode(env, node)); + return ts_node_is_extra(_unmarshalNode(env, node)) ? JNI_TRUE : JNI_FALSE; } JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeIsMissing( JNIEnv* env, jclass self, jobject node) { - return (jboolean) ts_node_is_missing(_unmarshalNode(env, node)); + return ts_node_is_missing(_unmarshalNode(env, node)) ? JNI_TRUE : JNI_FALSE; } JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeIsNamed( JNIEnv* env, jclass self, jobject node) { - return (jboolean) ts_node_is_named(_unmarshalNode(env, node)); + return ts_node_is_named(_unmarshalNode(env, node)) ? JNI_TRUE : JNI_FALSE; } JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeIsNull( JNIEnv* env, jclass self, jobject node) { - return (jboolean) ts_node_is_null(_unmarshalNode(env, node)); + return ts_node_is_null(_unmarshalNode(env, node)) ? JNI_TRUE : JNI_FALSE; } JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeParent( @@ -437,22 +437,19 @@ JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorNew( return (jlong)cursor; } -JNIEXPORT jstring JNICALL -Java_usi_si_seart_treesitter_TreeSitter_treeCursorCurrentFieldName( +JNIEXPORT jstring JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorCurrentFieldName( JNIEnv* env, jclass self, jlong cursor) { const char* name = ts_tree_cursor_current_field_name((TSTreeCursor*)cursor); jstring result = env->NewStringUTF(name); return result; } -JNIEXPORT jobject JNICALL -Java_usi_si_seart_treesitter_TreeSitter_treeCursorCurrentNode( +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorCurrentNode( JNIEnv* env, jclass self, jlong cursor) { return _marshalNode(env, ts_tree_cursor_current_node((TSTreeCursor*)cursor)); } -JNIEXPORT jobject JNICALL -Java_usi_si_seart_treesitter_TreeSitter_treeCursorCurrentTreeCursorNode( +JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorCurrentTreeCursorNode( JNIEnv* env, jclass self, jlong cursor) { TSNode node = ts_tree_cursor_current_node((TSTreeCursor*)cursor); return _marshalTreeCursorNode( @@ -474,21 +471,19 @@ JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorDelete( delete (TSTreeCursor*)cursor; } -JNIEXPORT jboolean JNICALL -Java_usi_si_seart_treesitter_TreeSitter_treeCursorGotoFirstChild( +JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorGotoFirstChild( JNIEnv* env, jclass self, jlong cursor) { - return (jboolean)ts_tree_cursor_goto_first_child((TSTreeCursor*)cursor); + return ts_tree_cursor_goto_first_child((TSTreeCursor*)cursor) ? JNI_TRUE : JNI_FALSE; } JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorGotoNextSibling( JNIEnv* env, jclass self, jlong cursor) { - return (jboolean)ts_tree_cursor_goto_next_sibling((TSTreeCursor*)cursor); + return ts_tree_cursor_goto_next_sibling((TSTreeCursor*)cursor) ? JNI_TRUE : JNI_FALSE; } -JNIEXPORT jboolean JNICALL -Java_usi_si_seart_treesitter_TreeSitter_treeCursorGotoParent( +JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorGotoParent( JNIEnv* env, jclass self, jlong cursor) { - return (jboolean)ts_tree_cursor_goto_parent((TSTreeCursor*)cursor); + return ts_tree_cursor_goto_parent((TSTreeCursor*)cursor) ? JNI_TRUE : JNI_FALSE; } JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeDelete( From eb223aa8ec9e028882a72fd23d0d8c6979a2e75d Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 19 Jan 2023 17:38:48 +0100 Subject: [PATCH 0062/1089] Improved the `LibraryLoader` internal logic Will now work both in local IDE, and JAR runs --- .../si/seart/treesitter/LibraryLoader.java | 84 ++++++++++++------- 1 file changed, 54 insertions(+), 30 deletions(-) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/LibraryLoader.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/LibraryLoader.java index 1749d608..12884e66 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/LibraryLoader.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/LibraryLoader.java @@ -1,47 +1,71 @@ package usi.si.seart.treesitter; +import lombok.AccessLevel; +import lombok.Cleanup; +import lombok.experimental.FieldDefaults; import lombok.experimental.UtilityClass; -import java.io.FileNotFoundException; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.net.URL; @UtilityClass public class LibraryLoader { + @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) + private static final class SystemResource { + + URL url; + String name; + + private SystemResource(String name) { + this.url = ClassLoader.getSystemResource(name); + this.name = name; + } + } + public void load() { - String format = "libjava-tree-sitter.%s"; - String filename; - switch (currentOS()) { - case MACOS: - filename = String.format(format, "dylib"); - break; - case LINUX: - filename = String.format(format, "so"); - break; + String name = "libjava-tree-sitter"; + String extension = getExtension(); + String filename = name + "." + extension; + SystemResource systemResource = new SystemResource(filename); + String libPath = getLibPath(systemResource); + System.load(libPath); + } + + private String getLibPath(SystemResource systemResource) { + String protocol = systemResource.url.getProtocol(); + switch (protocol) { + case "file": + return systemResource.url.getPath(); + case "jar": + try { + @Cleanup InputStream input = systemResource.url.openStream(); + String tmpdir = System.getProperty("java.io.tmpdir"); + File temporary = new File(tmpdir, systemResource.name); + temporary.deleteOnExit(); + @Cleanup OutputStream output = new FileOutputStream(temporary, false); + input.transferTo(output); + return temporary.getPath(); + } catch (IOException cause) { + throw new TreeSitterException(cause); + } default: - throw new TreeSitterException("tree-sitter library was not compiled for this platform!"); - } - URL libURL = ClassLoader.getSystemResource(filename); - if (libURL != null) { - String libPath = libURL.getPath(); - System.load(libPath); - } else { - Exception cause = new FileNotFoundException("Resource could not be found!"); - throw new TreeSitterException(cause); + Exception cause = new UnsupportedOperationException("Unsupported protocol: " + protocol); + throw new TreeSitterException(cause); } } - private OS currentOS() { - String osName = System.getProperty("os.name").toLowerCase(); - if (osName.contains("nix") || osName.contains("nux") || osName.contains("aix")) - return OS.LINUX; - else if (osName.contains("mac") || osName.contains("darwin")) - return OS.MACOS; + private String getExtension() { + String platform = System.getProperty("os.name").toLowerCase(); + if (platform.contains("nix") || platform.contains("nux") || platform.contains("aix")) + return "so"; + else if (platform.contains("mac") || platform.contains("darwin")) + return "dylib"; else - return OS.UNSUPPORTED; - } - - private enum OS { - MACOS, LINUX, UNSUPPORTED + throw new TreeSitterException("The tree-sitter library was not compiled for this platform: " + platform); } } From 4260b281799dc6b4a8c040d23c9febf509138b21 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 19 Jan 2023 22:16:22 +0100 Subject: [PATCH 0063/1089] Added exception-triggering preconditions to certain `Node` method calls Includes tests --- .../java/usi/si/seart/treesitter/Node.java | 21 +++++++++++++++++++ .../usi/si/seart/treesitter/NodeTest.java | 9 ++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java index 0e3c9657..7cb7796a 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java @@ -5,6 +5,7 @@ import java.util.Iterator; import java.util.NoSuchElementException; +import java.util.Objects; import java.util.Stack; /** @@ -26,16 +27,23 @@ public class Node implements Iterable { * * @param child The zero-indexed child position * @return The Node's child at the given index + * @throws IndexOutOfBoundsException + * if the index is a negative number */ public Node getChild(int child) { + if (child < 0) + throw new IndexOutOfBoundsException("Child index must not be negative!"); return TreeSitter.nodeChild(this, child); } /** * @param name The child field name. * @return The node's child with the given field name. + * @throws NullPointerException + * if the field name is null */ public Node getChildByFieldName(String name) { + Objects.requireNonNull(name, "Field name must not be null!"); return TreeSitter.nodeChildByFieldName(this, name); } @@ -50,8 +58,11 @@ public int getChildCount() { * @param startByte The starting byte of the range * @param endByte The ending byte of the range * @return The smallest node within this node that spans the given range of bytes + * @throws IllegalArgumentException if {@code startByte} > {@code endByte} */ public Node getDescendantForByteRange(int startByte, int endByte) { + if (startByte > endByte) + throw new IllegalArgumentException("The starting byte of the range must not be greater than the ending byte!"); return TreeSitter.nodeDescendantForByteRange(this, startByte, endByte); } @@ -74,24 +85,34 @@ public Point getEndPoint() { * The field name for node's child at the given index, * with zero representing the first child. * Returns NULL, if no field is found. + * @throws IndexOutOfBoundsException + * if the index is a negative number */ public String getFieldNameForChild(int child) { + if (child < 0) + throw new IndexOutOfBoundsException("Child index must not be negative!"); return TreeSitter.nodeFieldNameForChild(this, child); } /** * @param offset The offset in bytes. * @return The node's first child that extends beyond the given byte offset. + * @throws IndexOutOfBoundsException if the offset is a negative number */ public Node getFirstChildForByte(int offset) { + if (offset < 0) + throw new IndexOutOfBoundsException("Byte offset must not be negative!"); return TreeSitter.nodeFirstChildForByte(this, offset); } /** * @param offset The offset in bytes. * @return The node's first named child that extends beyond the given byte offset. + * @throws IndexOutOfBoundsException if the offset is a negative number */ public Node getFirstNamedChildForByte(int offset) { + if (offset < 0) + throw new IndexOutOfBoundsException("Byte offset must not be negative!"); return TreeSitter.nodeFirstNamedChildForByte(this, offset); } diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java index 3b297cb2..9283fb18 100644 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java @@ -17,14 +17,14 @@ void testGetChild() { @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString(source); Node root = tree.getRootNode(); + Node function = root.getChild(0); Assertions.assertEquals(1, root.getChildCount()); Assertions.assertEquals("module", root.getType()); Assertions.assertEquals(0, root.getStartByte()); Assertions.assertEquals(44, root.getEndByte()); - - Node function = root.getChild(0); Assertions.assertEquals("function_definition", function.getType()); Assertions.assertEquals(5, function.getChildCount()); + Assertions.assertThrows(IndexOutOfBoundsException.class, () -> root.getChild(-1)); } @Test @@ -36,6 +36,7 @@ void testGetChildByFieldName() { Node function = root.getChild(0); Node identifier = function.getChild(1); Assertions.assertEquals(identifier, function.getChildByFieldName("name")); + Assertions.assertThrows(NullPointerException.class, () -> root.getChildByFieldName(null)); } @Test @@ -55,6 +56,7 @@ void testGetDescendantForByteRange() { Assertions.assertEquals(parameters, root.getDescendantForByteRange(parameters.getStartByte(), parameters.getEndByte())); Assertions.assertEquals(colon, root.getDescendantForByteRange(colon.getStartByte(), colon.getEndByte())); Assertions.assertEquals(body, root.getDescendantForByteRange(body.getStartByte(), body.getEndByte())); + Assertions.assertThrows(IllegalArgumentException.class, () -> root.getDescendantForByteRange(2, 0)); } @Test @@ -69,6 +71,7 @@ void testGetFieldNameForChild() { Assertions.assertEquals("parameters", function.getFieldNameForChild(2)); // "parameters" Assertions.assertNull(function.getFieldNameForChild(3)); // `:` Assertions.assertEquals("body", function.getFieldNameForChild(4)); // "body" + Assertions.assertThrows(IndexOutOfBoundsException.class, () -> root.getFieldNameForChild(-1)); } @Test @@ -88,6 +91,7 @@ void testGetFirstChildForByte() { Assertions.assertEquals(parameters, function.getFirstChildForByte(parameters.getStartByte())); Assertions.assertEquals(colon, function.getFirstChildForByte(colon.getStartByte())); Assertions.assertEquals(body, function.getFirstChildForByte(body.getStartByte())); + Assertions.assertThrows(IndexOutOfBoundsException.class, () -> root.getFirstChildForByte(-1)); } @Test @@ -107,6 +111,7 @@ void testGetFirstNamedChildForByte() { Assertions.assertEquals(parameters, function.getFirstNamedChildForByte(parameters.getStartByte())); Assertions.assertEquals(body, function.getFirstNamedChildForByte(colon.getStartByte())); Assertions.assertEquals(body, function.getFirstNamedChildForByte(body.getStartByte())); + Assertions.assertThrows(IndexOutOfBoundsException.class, () -> root.getFirstNamedChildForByte(-1)); } @Test From e55deba0ba27cc2372d6a5e11ebabe0654ae305c Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 20 Jan 2023 12:20:51 +0100 Subject: [PATCH 0064/1089] Added the "invalid" `Language` option Will only be used for testing purposes --- .../src/main/java/usi/si/seart/treesitter/Language.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Language.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Language.java index 83a44671..f9070044 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Language.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Language.java @@ -6,6 +6,7 @@ public enum Language { + _INVALID_(), AGDA(Languages::agda), BASH(Languages::bash), C(Languages::c), @@ -43,6 +44,10 @@ public enum Language { @Getter private final long id; + Language() { + this.id = 0L; + } + Language(LongSupplier supplier) { long id = 0L; try { From a6de9b9ca68954e2cd78a6ad4312e7ce6f45da55 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 20 Jan 2023 13:33:00 +0100 Subject: [PATCH 0065/1089] Native `parserSetLanguage` method now returns boolean This will be used as a means for detecting when the `Parser` language could not be set. As of right now, the method result is ignored. The coming commits will introduce further improvements to `Parser` instance construction. --- dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc | 4 ++-- dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.h | 4 ++-- .../src/main/java/usi/si/seart/treesitter/TreeSitter.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc index 12bc3367..571afa7d 100644 --- a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc +++ b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc @@ -366,9 +366,9 @@ JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_parserDelete( ts_parser_delete((TSParser*)parser); } -JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_parserSetLanguage( +JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_parserSetLanguage( JNIEnv* env, jclass self, jlong parser, jlong language) { - ts_parser_set_language((TSParser*)parser, (TSLanguage*)language); + return ts_parser_set_language((TSParser*)parser, (TSLanguage*)language) ? JNI_TRUE : JNI_FALSE; } JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_parserParseBytes( diff --git a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.h b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.h index 40f2d3aa..dfd466bc 100644 --- a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.h +++ b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.h @@ -218,9 +218,9 @@ JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_parserDelete /* * Class: usi_si_seart_treesitter_TreeSitter * Method: parserSetLanguage - * Signature: (JJ)V + * Signature: (JJ)Z */ -JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_parserSetLanguage +JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_parserSetLanguage (JNIEnv *, jclass, jlong, jlong); /* diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitter.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitter.java index 98acf22d..9786d5e7 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitter.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitter.java @@ -57,7 +57,7 @@ class TreeSitter { static native void parserDelete(long parser); - static native void parserSetLanguage(long parser, long language); + static native boolean parserSetLanguage(long parser, long language); static native long parserParseBytes(long parser, byte[] source, int length); From 04089909ff8d45e2c3d246ca370174e0c090bea2 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 20 Jan 2023 13:38:23 +0100 Subject: [PATCH 0066/1089] Updated `TreeSitterException` documentation --- .../main/java/usi/si/seart/treesitter/TreeSitterException.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitterException.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitterException.java index 25453e17..013f16cb 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitterException.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitterException.java @@ -2,6 +2,9 @@ import lombok.experimental.StandardException; +/** + * The base exception type for all tree-sitter exceptions. + */ @StandardException public class TreeSitterException extends RuntimeException { } From fa3f174111d1cf1ef86fae6dd45237f0dec9587f Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 20 Jan 2023 13:42:27 +0100 Subject: [PATCH 0067/1089] Added `ABIVersionMismatch` More specific subtype of `TreeSitterException` which will be thrown whenever a language can not be assigned to a parser due to ABI version incompatibilities. --- .../usi/si/seart/treesitter/ABIVersionMismatch.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/ABIVersionMismatch.java diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/ABIVersionMismatch.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/ABIVersionMismatch.java new file mode 100644 index 00000000..b2792929 --- /dev/null +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/ABIVersionMismatch.java @@ -0,0 +1,13 @@ +package usi.si.seart.treesitter; + +import lombok.experimental.StandardException; + +/** + * An exception thrown whenever there is an ABI version mismatch. + *

+ * These are usually raised as a result of a language being + * generated with an incompatible version of the Tree-sitter CLI. + */ +@StandardException +public class ABIVersionMismatch extends TreeSitterException { +} From 2fd7bac1dbb26c794ada5014d3b90cbd48009288 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 20 Jan 2023 13:51:09 +0100 Subject: [PATCH 0068/1089] Added more safety measures to `Parser` instantiation As of now, parser instances will not be created if certain criteria are not met. These include: - The language not being specified (i.e. null); - The language not being properly linked to the system library; - The language not having a matching ABI version with tree-sitter. --- .../java/usi/si/seart/treesitter/Parser.java | 53 ++++++++++++++++--- .../usi/si/seart/treesitter/ParserTest.java | 25 +++++++-- 2 files changed, 68 insertions(+), 10 deletions(-) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java index c17084ad..055bced3 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java @@ -9,29 +9,70 @@ import java.util.Objects; /** - * Parsers are stateful objects that can be assigned a language and used to produce a - * {@link Tree Tree} based on some source code. + * Parsers are stateful objects that can be assigned a language + * and used to produce a {@link Tree Tree} based on some source code. + * Instances of this class can not be created + * without an initially set language. */ public class Parser extends External { + /** + * @param language The language used for parsing. + * @throws NullPointerException + * if the specified language is null + * @throws UnsatisfiedLinkError + * if the specified language has not + * been linked to the system library + * @throws ABIVersionMismatch + * if there was an ABI version mismatch + */ public Parser(Language language) { super(createIfValid(language)); - this.setLanguage(language); } + /* + * Constructor precondition for creating a parser. + * In essence, we should never allocate memory to + * these structures if the language: + * - Has not been specified (i.e. is null) + * - Has not been linked to the system library + */ private static long createIfValid(Language language) { + validateLanguage(language); + long pointer = TreeSitter.parserNew(); + setLanguage(pointer, language); + return pointer; + } + + private static void validateLanguage(Language language) { Objects.requireNonNull(language, "Language must not be null!"); - return TreeSitter.parserNew(); + long id = language.getId(); + if (id == 0L) throw new UnsatisfiedLinkError( + "Language binding has not been included for: " + language.name().toLowerCase() + ); } /** * Set the language that the parser should use for parsing. * * @param language The language used for parsing. + * @throws NullPointerException + * if the specified language is null + * @throws UnsatisfiedLinkError + * if the specified language has not + * been linked to the system library + * @throws ABIVersionMismatch + * if there was an ABI version mismatch */ public void setLanguage(Language language) { - Objects.requireNonNull(language, "Language must not be null!"); - TreeSitter.parserSetLanguage(pointer, language.getId()); + validateLanguage(language); + setLanguage(pointer, language); + } + + private static void setLanguage(long pointer, Language language) { + boolean success = TreeSitter.parserSetLanguage(pointer, language.getId()); + if (!success) + throw new ABIVersionMismatch("Language could not be assigned to parser!"); } /** diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/ParserTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/ParserTest.java index ea5c3baf..e80f2155 100644 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/ParserTest.java +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/ParserTest.java @@ -1,6 +1,8 @@ package usi.si.seart.treesitter; import lombok.Cleanup; +import lombok.SneakyThrows; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -17,6 +19,8 @@ class ParserTest extends TestBase { static Path tmp; static Path tmpFile; + static Parser parser; + static final String source = "print(\"hi\")\n"; static final String nodeString = "(module (expression_statement (call function: (identifier) arguments: (argument_list (string)))))"; @@ -25,19 +29,32 @@ class ParserTest extends TestBase { static void beforeAll() throws IOException { tmpFile = Files.createFile(tmp.resolve("print.py")); Files.writeString(tmpFile, source); + parser = new Parser(Language.PYTHON); + } + + @AfterAll + static void afterAll() { + parser.close(); } @Test - void testParseString() throws UnsupportedEncodingException { - @Cleanup Parser parser = new Parser(Language.PYTHON); + @SneakyThrows(UnsupportedEncodingException.class) + void testParseString() { @Cleanup Tree tree = parser.parseString(source); Assertions.assertEquals(nodeString, tree.getRootNode().getNodeString()); } @Test - void testParseFile() throws IOException { - @Cleanup Parser parser = new Parser(Language.PYTHON); + @SneakyThrows(IOException.class) + void testParseFile() { @Cleanup Tree tree = parser.parseFile(tmpFile); Assertions.assertEquals(nodeString, tree.getRootNode().getNodeString()); } + + @Test + @SuppressWarnings("resource") + void testParserThrows() { + Assertions.assertThrows(NullPointerException.class, () -> new Parser(null)); + Assertions.assertThrows(UnsatisfiedLinkError.class, () -> new Parser(Language._INVALID_)); + } } From f7505df1cbbc57b61db5838992f779e1959affa5 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 20 Jan 2023 14:54:16 +0100 Subject: [PATCH 0069/1089] Extracting invalid language pointer value to a static variable --- .../src/main/java/usi/si/seart/treesitter/Language.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Language.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Language.java index f9070044..cd4bb446 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Language.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Language.java @@ -44,12 +44,14 @@ public enum Language { @Getter private final long id; + static final long INVALID = 0L; + Language() { - this.id = 0L; + this.id = INVALID; } Language(LongSupplier supplier) { - long id = 0L; + long id = INVALID; try { id = supplier.getAsLong(); } catch (UnsatisfiedLinkError ignored) { From 34a71aad198a8799728e64d89ebe6e43e192fe41 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 20 Jan 2023 14:56:52 +0100 Subject: [PATCH 0070/1089] Moved `Language` validation to `Languages` --- .../java/usi/si/seart/treesitter/Languages.java | 10 ++++++++++ .../java/usi/si/seart/treesitter/Parser.java | 16 +++------------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Languages.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Languages.java index 383ee50a..c544c679 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Languages.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Languages.java @@ -2,6 +2,8 @@ import lombok.experimental.UtilityClass; +import java.util.Objects; + @UtilityClass class Languages { static native long agda(); @@ -37,4 +39,12 @@ class Languages { static native long vue(); static native long yaml(); static native long wasm(); + + static void validate(Language language) { + Objects.requireNonNull(language, "Language must not be null!"); + long id = language.getId(); + if (id == Language.INVALID) throw new UnsatisfiedLinkError( + "Language binding has not been defined for: " + language.name().toLowerCase() + ); + } } diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java index 055bced3..3f3b689f 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java @@ -6,7 +6,6 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Objects; /** * Parsers are stateful objects that can be assigned a language @@ -38,20 +37,12 @@ public Parser(Language language) { * - Has not been linked to the system library */ private static long createIfValid(Language language) { - validateLanguage(language); + Languages.validate(language); long pointer = TreeSitter.parserNew(); setLanguage(pointer, language); return pointer; } - private static void validateLanguage(Language language) { - Objects.requireNonNull(language, "Language must not be null!"); - long id = language.getId(); - if (id == 0L) throw new UnsatisfiedLinkError( - "Language binding has not been included for: " + language.name().toLowerCase() - ); - } - /** * Set the language that the parser should use for parsing. * @@ -65,14 +56,13 @@ private static void validateLanguage(Language language) { * if there was an ABI version mismatch */ public void setLanguage(Language language) { - validateLanguage(language); + Languages.validate(language); setLanguage(pointer, language); } private static void setLanguage(long pointer, Language language) { boolean success = TreeSitter.parserSetLanguage(pointer, language.getId()); - if (!success) - throw new ABIVersionMismatch("Language could not be assigned to parser!"); + if (!success) throw new ABIVersionMismatch("Language could not be assigned to parser!"); } /** From 3b20de085a59686cf9a42da927f3d05c98ccbcb2 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 20 Jan 2023 16:51:15 +0100 Subject: [PATCH 0071/1089] Added preconditions for `QueryCursor` execute method --- .../src/main/java/usi/si/seart/treesitter/QueryCursor.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCursor.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCursor.java index 1f8e1437..45a6367e 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCursor.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCursor.java @@ -1,5 +1,7 @@ package usi.si.seart.treesitter; +import java.util.Objects; + /** * Cursor used for executing queries, carrying the state needed to process them. * @@ -18,6 +20,8 @@ public QueryCursor() { * @param node The node which the query will be executed on. */ public void execQuery(Query query, Node node) { + Objects.requireNonNull(node, "Node must not be null!"); + Objects.requireNonNull(query, "Query must not be null!"); TreeSitter.queryCursorExec(pointer, query.getPointer(), node); } From e2e24a2ec6084760be60e2e3e14ee3aa19c4ae50 Mon Sep 17 00:00:00 2001 From: dabico Date: Sat, 21 Jan 2023 12:05:58 +0100 Subject: [PATCH 0072/1089] Simplified `isNull` test --- .../src/test/java/usi/si/seart/treesitter/NodeTest.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java index 9283fb18..224102a6 100644 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java @@ -234,9 +234,6 @@ void testIsNull() { @Cleanup Tree tree = parser.parseString(source); Node root = tree.getRootNode(); Assertions.assertFalse(root.isNull()); - Node function = root.getChild(0); - Node nullNode = root.getChild(1); - Assertions.assertFalse(function.isNull()); - Assertions.assertTrue(nullNode.isNull()); + Assertions.assertTrue(new Node().isNull()); } } From ef93a63b7d20dd6e6bc81d92cbd5fade3b45a820 Mon Sep 17 00:00:00 2001 From: dabico Date: Sat, 21 Jan 2023 12:11:06 +0100 Subject: [PATCH 0073/1089] Improved `NodeTest` by introducing `beforeAll` and `afterAll` methods --- .../usi/si/seart/treesitter/NodeTest.java | 73 +++++-------------- 1 file changed, 19 insertions(+), 54 deletions(-) diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java index 224102a6..c8c7940f 100644 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java @@ -2,7 +2,9 @@ import lombok.Cleanup; import lombok.SneakyThrows; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import java.io.UnsupportedEncodingException; @@ -10,13 +12,26 @@ class NodeTest extends TestBase { private static final String source = "def foo(bar, baz):\n print(bar)\n print(baz)"; + private static Parser parser; + private static Tree tree; + private static Node root; - @Test + @BeforeAll @SneakyThrows(UnsupportedEncodingException.class) + static void beforeAll() { + parser = new Parser(Language.PYTHON); + tree = parser.parseString(source); + root = tree.getRootNode(); + } + + @AfterAll + static void afterAll() { + tree.close(); + parser.close(); + } + + @Test void testGetChild() { - @Cleanup Parser parser = new Parser(Language.PYTHON); - @Cleanup Tree tree = parser.parseString(source); - Node root = tree.getRootNode(); Node function = root.getChild(0); Assertions.assertEquals(1, root.getChildCount()); Assertions.assertEquals("module", root.getType()); @@ -28,11 +43,7 @@ void testGetChild() { } @Test - @SneakyThrows(UnsupportedEncodingException.class) void testGetChildByFieldName() { - @Cleanup Parser parser = new Parser(Language.PYTHON); - @Cleanup Tree tree = parser.parseString(source); - Node root = tree.getRootNode(); Node function = root.getChild(0); Node identifier = function.getChild(1); Assertions.assertEquals(identifier, function.getChildByFieldName("name")); @@ -40,11 +51,7 @@ void testGetChildByFieldName() { } @Test - @SneakyThrows(UnsupportedEncodingException.class) void testGetDescendantForByteRange() { - @Cleanup Parser parser = new Parser(Language.PYTHON); - @Cleanup Tree tree = parser.parseString(source); - Node root = tree.getRootNode(); Node function = root.getChild(0); Node def = function.getChild(0); Node identifier = function.getChild(1); @@ -60,11 +67,7 @@ void testGetDescendantForByteRange() { } @Test - @SneakyThrows(UnsupportedEncodingException.class) void testGetFieldNameForChild() { - @Cleanup Parser parser = new Parser(Language.PYTHON); - @Cleanup Tree tree = parser.parseString(source); - Node root = tree.getRootNode(); Node function = root.getChild(0); Assertions.assertNull(function.getFieldNameForChild(0)); // `def` Assertions.assertEquals("name", function.getFieldNameForChild(1)); // "name" @@ -75,11 +78,7 @@ void testGetFieldNameForChild() { } @Test - @SneakyThrows(UnsupportedEncodingException.class) void testGetFirstChildForByte() { - @Cleanup Parser parser = new Parser(Language.PYTHON); - @Cleanup Tree tree = parser.parseString(source); - Node root = tree.getRootNode(); Node function = root.getChild(0); Node def = function.getChild(0); Node identifier = function.getChild(1); @@ -95,11 +94,7 @@ void testGetFirstChildForByte() { } @Test - @SneakyThrows(UnsupportedEncodingException.class) void testGetFirstNamedChildForByte() { - @Cleanup Parser parser = new Parser(Language.PYTHON); - @Cleanup Tree tree = parser.parseString(source); - Node root = tree.getRootNode(); Node function = root.getChild(0); Node def = function.getChild(0); Node identifier = function.getChild(1); @@ -115,21 +110,13 @@ void testGetFirstNamedChildForByte() { } @Test - @SneakyThrows(UnsupportedEncodingException.class) void testGetParent() { - @Cleanup Parser parser = new Parser(Language.PYTHON); - @Cleanup Tree tree = parser.parseString(source); - Node root = tree.getRootNode(); Assertions.assertNull(root.getParent()); Assertions.assertEquals(root, root.getChild(0).getParent()); } @Test - @SneakyThrows(UnsupportedEncodingException.class) void testGetNextNamedSibling() { - @Cleanup Parser parser = new Parser(Language.PYTHON); - @Cleanup Tree tree = parser.parseString(source); - Node root = tree.getRootNode(); Node function = root.getChild(0); Node def = function.getChild(0); Node identifier = function.getChild(1); @@ -138,11 +125,7 @@ void testGetNextNamedSibling() { } @Test - @SneakyThrows(UnsupportedEncodingException.class) void testGetNextSibling() { - @Cleanup Parser parser = new Parser(Language.PYTHON); - @Cleanup Tree tree = parser.parseString(source); - Node root = tree.getRootNode(); Node function = root.getChild(0); Node def = function.getChild(0); Node identifier = function.getChild(1); @@ -151,11 +134,7 @@ void testGetNextSibling() { } @Test - @SneakyThrows(UnsupportedEncodingException.class) void testGetPrevNamedSibling() { - @Cleanup Parser parser = new Parser(Language.PYTHON); - @Cleanup Tree tree = parser.parseString(source); - Node root = tree.getRootNode(); Node function = root.getChild(0); Node identifier = function.getChild(1); Node parameters = function.getChild(2); @@ -164,11 +143,7 @@ void testGetPrevNamedSibling() { } @Test - @SneakyThrows(UnsupportedEncodingException.class) void testGetPrevSibling() { - @Cleanup Parser parser = new Parser(Language.PYTHON); - @Cleanup Tree tree = parser.parseString(source); - Node root = tree.getRootNode(); Node function = root.getChild(0); Node def = function.getChild(0); Node identifier = function.getChild(1); @@ -179,7 +154,6 @@ void testGetPrevSibling() { @Test @SneakyThrows(UnsupportedEncodingException.class) void testHasError() { - @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString("def foo(bar, baz):\n print(bar.)"); Node root = tree.getRootNode(); Node function = root.getChild(0); @@ -192,7 +166,6 @@ void testHasError() { @Test @SneakyThrows(UnsupportedEncodingException.class) void testIsExtra() { - @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString("# this is just a comment"); Node root = tree.getRootNode(); Node comment = root.getChild(0); @@ -215,11 +188,7 @@ void testIsMissing() { } @Test - @SneakyThrows(UnsupportedEncodingException.class) void testIsNamed() { - @Cleanup Parser parser = new Parser(Language.PYTHON); - @Cleanup Tree tree = parser.parseString(source); - Node root = tree.getRootNode(); Node function = root.getChild(0); Node def = function.getChild(0); Node identifier = function.getChild(1); @@ -228,11 +197,7 @@ void testIsNamed() { } @Test - @SneakyThrows(UnsupportedEncodingException.class) void testIsNull() { - @Cleanup Parser parser = new Parser(Language.PYTHON); - @Cleanup Tree tree = parser.parseString(source); - Node root = tree.getRootNode(); Assertions.assertFalse(root.isNull()); Assertions.assertTrue(new Node().isNull()); } From 0485511552430144c15d6cc3ea03f6a7fc2ea661 Mon Sep 17 00:00:00 2001 From: dabico Date: Sat, 21 Jan 2023 12:11:56 +0100 Subject: [PATCH 0074/1089] Added missing `private` access modifier to `ParserTest` static fields --- .../test/java/usi/si/seart/treesitter/ParserTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/ParserTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/ParserTest.java index e80f2155..67b06121 100644 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/ParserTest.java +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/ParserTest.java @@ -16,13 +16,13 @@ class ParserTest extends TestBase { @TempDir - static Path tmp; - static Path tmpFile; + private static Path tmp; + private static Path tmpFile; - static Parser parser; + private static Parser parser; - static final String source = "print(\"hi\")\n"; - static final String nodeString = + private static final String source = "print(\"hi\")\n"; + private static final String nodeString = "(module (expression_statement (call function: (identifier) arguments: (argument_list (string)))))"; @BeforeAll From 34919cfc17281097f8ed574790eea044b111866c Mon Sep 17 00:00:00 2001 From: dabico Date: Sat, 21 Jan 2023 12:21:40 +0100 Subject: [PATCH 0075/1089] Improved `QueryCursorTest` just like `NodeTest` --- .../si/seart/treesitter/QueryCursorTest.java | 40 +++++++++++++------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryCursorTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryCursorTest.java index 49b48f56..f77a5c00 100644 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryCursorTest.java +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryCursorTest.java @@ -2,34 +2,50 @@ import lombok.Cleanup; import lombok.SneakyThrows; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import java.io.UnsupportedEncodingException; class QueryCursorTest extends TestBase { - @Test + private static final String source = "class Hello {}"; + private static final Language language = Language.JAVA; + private static Parser parser; + private static Tree tree; + private static Node root; + + @BeforeAll @SneakyThrows(UnsupportedEncodingException.class) + static void beforeAll() { + parser = new Parser(language); + tree = parser.parseString(source); + root = tree.getRootNode(); + } + + @AfterAll + static void afterAll() { + tree.close(); + parser.close(); + } + + @Test void testExecSimpleQuery() { - @Cleanup Parser parser = new Parser(Language.JAVA); - @Cleanup Tree tree = parser.parseString("class Hello {}"); - @Cleanup Query query = new Query(Language.JAVA, "(class_body) @test"); + @Cleanup Query query = new Query(language, "(class_body) @test"); @Cleanup QueryCursor cursor = new QueryCursor(); - cursor.execQuery(query, tree.getRootNode()); + cursor.execQuery(query, root); int numMatches = 0; while (cursor.nextMatch() != null) numMatches++; - Assertions.assertEquals(1, numMatches, "Finds one match"); + Assertions.assertEquals(1, numMatches, "Must find one match!"); } @Test - @SneakyThrows(UnsupportedEncodingException.class) void testExecNoResultQuery() { - @Cleanup Parser parser = new Parser(Language.JAVA); - @Cleanup Tree tree = parser.parseString("class Hello {}"); - @Cleanup Query query = new Query(Language.JAVA, "(method_declaration) @method"); + @Cleanup Query query = new Query(language, "(method_declaration) @method"); @Cleanup QueryCursor cursor = new QueryCursor(); - cursor.execQuery(query, tree.getRootNode()); - Assertions.assertNull(cursor.nextMatch()); + cursor.execQuery(query, root); + Assertions.assertNull(cursor.nextMatch(), "Must find no matches!"); } } From b68c63a4b9afc28ffacd63200d28d220001334f4 Mon Sep 17 00:00:00 2001 From: dabico Date: Sat, 21 Jan 2023 12:24:05 +0100 Subject: [PATCH 0076/1089] Suppressing throws --- .../src/test/java/usi/si/seart/treesitter/TreeCursorTest.java | 4 +++- .../src/test/java/usi/si/seart/treesitter/TreeTest.java | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeCursorTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeCursorTest.java index b1fad3cb..2ae8d48d 100644 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeCursorTest.java +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeCursorTest.java @@ -1,6 +1,7 @@ package usi.si.seart.treesitter; import lombok.Cleanup; +import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -9,7 +10,8 @@ class TreeCursorTest extends TestBase { @Test - void testWalk() throws UnsupportedEncodingException { + @SneakyThrows(UnsupportedEncodingException.class) + void testWalk() { @Cleanup Parser parser = new Parser(Language.PYTHON); @Cleanup Tree tree = parser.parseString("def foo(bar, baz):\n print(bar)\n print(baz)"); @Cleanup TreeCursor cursor = tree.getRootNode().walk(); diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeTest.java index ecdd6ef7..b2d86dd7 100644 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeTest.java +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeTest.java @@ -1,6 +1,7 @@ package usi.si.seart.treesitter; import lombok.Cleanup; +import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -9,7 +10,8 @@ class TreeTest extends TestBase { @Test - void testTreeEdit() throws UnsupportedEncodingException { + @SneakyThrows(UnsupportedEncodingException.class) + void testTreeEdit() { @Cleanup Parser parser = new Parser(Language.JAVA); Tree tree = parser.parseString("class Main {\n // This is a line comment\n}"); From 7bb7adbd8a9817bf051a0ad0defd3ca423580ca7 Mon Sep 17 00:00:00 2001 From: dabico Date: Sat, 21 Jan 2023 18:41:11 +0100 Subject: [PATCH 0077/1089] `QueryCursor` now defined as an implementation of `Iterable` Will greatly simplify client code depending on it. Since the class now offers a `Iterator`, accessing query results is straightforward. Major API changes: - Class instance fields for `Language` and `Query` - Lazy execution through the `execute` method - `QueryCursor` in enhanced for loops and Streams Test have been expanded to support the new additions. --- .../analyzer/query/SingleCaptureQueries.java | 14 ++-- .../usi/si/seart/treesitter/QueryCursor.java | 67 ++++++++++++++++--- .../si/seart/treesitter/QueryCursorTest.java | 60 ++++++++++++++--- 3 files changed, 114 insertions(+), 27 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/SingleCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/SingleCaptureQueries.java index 74e1c944..5f29ae00 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/SingleCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/SingleCaptureQueries.java @@ -10,10 +10,11 @@ import usi.si.seart.treesitter.QueryCursor; import usi.si.seart.treesitter.QueryMatch; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; @AllArgsConstructor(access = AccessLevel.PROTECTED) public abstract class SingleCaptureQueries implements Queries>, Validated { @@ -28,14 +29,9 @@ public List getNodes(Node node) { protected List execute(Node node, String sExpr) { validate(sExpr, "Queries must contain at least one capture!"); @Cleanup Query query = new Query(this.language, sExpr); - @Cleanup QueryCursor cursor = new QueryCursor(); - cursor.execQuery(query, node); - List matches = new ArrayList<>(); - QueryMatch match; - while ((match = cursor.nextMatch()) != null) - matches.add(match); - return matches.stream() - .map(QueryMatch::getCaptures) + @Cleanup QueryCursor cursor = new QueryCursor(node, query); + Stream matches = StreamSupport.stream(cursor.spliterator(), false); + return matches.map(QueryMatch::getCaptures) .flatMap(Arrays::stream) .map(QueryCapture::getNode) .collect(Collectors.toList()); diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCursor.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCursor.java index 45a6367e..6a4996d2 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCursor.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCursor.java @@ -1,5 +1,11 @@ package usi.si.seart.treesitter; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; +import lombok.experimental.NonFinal; + +import java.util.Iterator; +import java.util.NoSuchElementException; import java.util.Objects; /** @@ -7,30 +13,46 @@ * * @apiNote The query cursor should not be shared between threads, but can be reused for many query executions. */ -public class QueryCursor extends External { +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +public class QueryCursor extends External implements Iterable { + + Node node; + Query query; + + @NonFinal + boolean executed = false; - public QueryCursor() { - super(TreeSitter.queryCursorNew()); + public QueryCursor(Node node, Query query) { + super(createIfValid(node, query)); + this.node = node; + this.query = query; + } + + private static long createIfValid(Node node, Query query) { + Objects.requireNonNull(node, "Node must not be null!"); + Objects.requireNonNull(query, "Query must not be null!"); + return TreeSitter.queryCursorNew(); } /** * Start running a given query on a given node. - * - * @param query The query to execute. - * @param node The node which the query will be executed on. + * Successive calls to this method are ignored. */ - public void execQuery(Query query, Node node) { - Objects.requireNonNull(node, "Node must not be null!"); - Objects.requireNonNull(query, "Query must not be null!"); - TreeSitter.queryCursorExec(pointer, query.getPointer(), node); + public void execute() { + if (executed) return; + TreeSitter.queryCursorExec(pointer, query.pointer, node); + this.executed = true; } /** * Advance to the next match of the currently running query. * * @return A match if there is one, null otherwise. + * @throws IllegalStateException + * if {@code queryExec()} was not called beforehand */ public QueryMatch nextMatch() { + if (!executed) throw new IllegalStateException("Query was not executed on node!"); return TreeSitter.queryCursorNextMatch(pointer); } @@ -41,4 +63,29 @@ public QueryMatch nextMatch() { public void close() { TreeSitter.queryCursorDelete(pointer); } + + /** + * @return An iterator over the query cursor matches, starting from the first match. + */ + @Override + public Iterator iterator() { + execute(); + return new Iterator<>() { + + private QueryMatch current = nextMatch(); + + @Override + public boolean hasNext() { + return current != null; + } + + @Override + public QueryMatch next() { + if (!hasNext()) throw new NoSuchElementException(); + QueryMatch match = current; + current = nextMatch(); + return match; + } + }; + } } diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryCursorTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryCursorTest.java index f77a5c00..d71c9463 100644 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryCursorTest.java +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryCursorTest.java @@ -8,10 +8,15 @@ import org.junit.jupiter.api.Test; import java.io.UnsupportedEncodingException; +import java.util.Iterator; +import java.util.Spliterator; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; class QueryCursorTest extends TestBase { - private static final String source = "class Hello {}"; + private static final String source = "class Hello { /* Comment 1 */ /* Comment 2 */ /* Comment 3 */ }"; private static final Language language = Language.JAVA; private static Parser parser; private static Tree tree; @@ -32,20 +37,59 @@ static void afterAll() { } @Test - void testExecSimpleQuery() { - @Cleanup Query query = new Query(language, "(class_body) @test"); - @Cleanup QueryCursor cursor = new QueryCursor(); - cursor.execQuery(query, root); + void testExecWithFor() { + @Cleanup Query query = new Query(language, "(block_comment) @comment"); + @Cleanup QueryCursor cursor = new QueryCursor(root, query); + int numMatches = 0; + for (QueryMatch ignored: cursor) numMatches++; + Assertions.assertEquals(3, numMatches, "Must find three matches!"); + } + + @Test + void testExecWithWhile() { + @Cleanup Query query = new Query(language, "(block_comment) @comment"); + @Cleanup QueryCursor cursor = new QueryCursor(root, query); + cursor.execute(); int numMatches = 0; while (cursor.nextMatch() != null) numMatches++; - Assertions.assertEquals(1, numMatches, "Must find one match!"); + Assertions.assertEquals(3, numMatches, "Must find three matches!"); + } + + @Test + void testExecWithIterator() { + @Cleanup Query query = new Query(language, "(block_comment) @comment"); + @Cleanup QueryCursor cursor = new QueryCursor(root, query); + AtomicInteger numMatches = new AtomicInteger(); + Iterator iterator = cursor.iterator(); + iterator.forEachRemaining(ignored -> numMatches.incrementAndGet()); + Assertions.assertEquals(3, numMatches.get(), "Must find three matches!"); + } + + @Test + void testExecWithStream() { + @Cleanup Query query = new Query(language, "(block_comment) @comment"); + @Cleanup QueryCursor cursor = new QueryCursor(root, query); + Spliterator spliterator = cursor.spliterator(); + Stream stream = StreamSupport.stream(spliterator, false); + Assertions.assertEquals(3, stream.count(), "Must find three matches!"); } @Test void testExecNoResultQuery() { @Cleanup Query query = new Query(language, "(method_declaration) @method"); - @Cleanup QueryCursor cursor = new QueryCursor(); - cursor.execQuery(query, root); + @Cleanup QueryCursor cursor = new QueryCursor(root, query); + cursor.execute(); Assertions.assertNull(cursor.nextMatch(), "Must find no matches!"); } + + @Test + void testMultipleExecCalls() { + @Cleanup Query query = new Query(language, "(class_body) @test"); + @Cleanup QueryCursor cursor = new QueryCursor(root, query); + cursor.execute(); + cursor.execute(); + QueryMatch match = cursor.nextMatch(); + Assertions.assertNotNull(match); + Assertions.assertNull(cursor.nextMatch()); + } } From c78156416056e227597ec96a4ee6c2636806d0dd Mon Sep 17 00:00:00 2001 From: dabico Date: Sat, 21 Jan 2023 19:29:02 +0100 Subject: [PATCH 0078/1089] Construction of `Query` instances now made safer --- .../analyzer/query/SingleCaptureQueries.java | 2 +- .../main/java/usi/si/seart/treesitter/Query.java | 14 ++++++++------ .../treesitter/SymbolicExpressionException.java | 10 ++++++++++ .../java/usi/si/seart/treesitter/QueryTest.java | 16 ++++++++-------- 4 files changed, 27 insertions(+), 15 deletions(-) create mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/SymbolicExpressionException.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/SingleCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/SingleCaptureQueries.java index 5f29ae00..26c6e120 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/SingleCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/SingleCaptureQueries.java @@ -28,7 +28,7 @@ public List getNodes(Node node) { protected List execute(Node node, String sExpr) { validate(sExpr, "Queries must contain at least one capture!"); - @Cleanup Query query = new Query(this.language, sExpr); + @Cleanup Query query = new Query(language, sExpr); @Cleanup QueryCursor cursor = new QueryCursor(node, query); Stream matches = StreamSupport.stream(cursor.spliterator(), false); return matches.map(QueryMatch::getCaptures) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java index 7980e255..40e44c5d 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java @@ -24,14 +24,16 @@ */ public class Query extends External { - public Query(Language language, String source) { - super(createIfValid(language, source)); + public Query(Language language, String sExpr) { + super(createIfValid(language, sExpr)); } - private static long createIfValid(Language language, String source) { - Objects.requireNonNull(language, "Language must not be null!"); - Objects.requireNonNull(source, "Source must not be null!"); - return TreeSitter.queryNew(language.getId(), source); + private static long createIfValid(Language language, String sExpr) { + Languages.validate(language); + Objects.requireNonNull(sExpr, "Pattern must not be null!"); + long pointer = TreeSitter.queryNew(language.getId(), sExpr); + if (pointer != 0L) return pointer; + else throw new SymbolicExpressionException("Invalid S-Expression pattern: " + sExpr); } /** diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/SymbolicExpressionException.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/SymbolicExpressionException.java new file mode 100644 index 00000000..17323d69 --- /dev/null +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/SymbolicExpressionException.java @@ -0,0 +1,10 @@ +package usi.si.seart.treesitter; + +import lombok.experimental.StandardException; + +/** + * The base exception type for all exceptions related to symbolic expressions (s-expressions). + */ +@StandardException +public class SymbolicExpressionException extends TreeSitterException { +} diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java index 7da406f7..533d8e0b 100644 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java @@ -7,14 +7,14 @@ class QueryTest extends TestBase { @Test + @SuppressWarnings("resource") void testQuery() { - @Cleanup Query query = new Query(Language.JAVA, "(class_declaration)"); - Assertions.assertFalse(query.isNull(), "Pointer is not null"); - } - - @Test - void testInvalidQuery() { - @Cleanup Query query = new Query(Language.JAVA, "(class_declaration"); - Assertions.assertTrue(query.isNull(), "Pointer is null"); + @Cleanup Query query = new Query(Language.JAVA, "(_)"); + Assertions.assertNotNull(query, "Query is not null"); + Assertions.assertThrows(NullPointerException.class, () -> new Query(null, null)); + Assertions.assertThrows(NullPointerException.class, () -> new Query(Language.JAVA, null)); + Assertions.assertThrows(NullPointerException.class, () -> new Query(null, "(_)")); + Assertions.assertThrows(UnsatisfiedLinkError.class, () -> new Query(Language._INVALID_, "(_)")); + Assertions.assertThrows(SymbolicExpressionException.class, () -> new Query(Language.JAVA, "()")); } } From c74630ae8abb46058c512d2a131842e85224c375 Mon Sep 17 00:00:00 2001 From: dabico Date: Sat, 21 Jan 2023 19:34:45 +0100 Subject: [PATCH 0079/1089] `ABIVersionMismatch` renamed to `ABIVersionError` These should not be caught in my opinion --- .../usi/si/seart/treesitter/ABIVersionError.java | 13 +++++++++++++ .../usi/si/seart/treesitter/ABIVersionMismatch.java | 13 ------------- .../main/java/usi/si/seart/treesitter/Parser.java | 6 +----- 3 files changed, 14 insertions(+), 18 deletions(-) create mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/ABIVersionError.java delete mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/ABIVersionMismatch.java diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/ABIVersionError.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/ABIVersionError.java new file mode 100644 index 00000000..a5dd1103 --- /dev/null +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/ABIVersionError.java @@ -0,0 +1,13 @@ +package usi.si.seart.treesitter; + +import lombok.experimental.StandardException; + +/** + * An error raised whenever there is an ABI version mismatch. + *

+ * These usually occur as a result of a language being generated + * with an incompatible version of the Tree-sitter CLI. + */ +@StandardException +public class ABIVersionError extends Error { +} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/ABIVersionMismatch.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/ABIVersionMismatch.java deleted file mode 100644 index b2792929..00000000 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/ABIVersionMismatch.java +++ /dev/null @@ -1,13 +0,0 @@ -package usi.si.seart.treesitter; - -import lombok.experimental.StandardException; - -/** - * An exception thrown whenever there is an ABI version mismatch. - *

- * These are usually raised as a result of a language being - * generated with an incompatible version of the Tree-sitter CLI. - */ -@StandardException -public class ABIVersionMismatch extends TreeSitterException { -} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java index 3f3b689f..ffb841ed 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java @@ -22,8 +22,6 @@ public class Parser extends External { * @throws UnsatisfiedLinkError * if the specified language has not * been linked to the system library - * @throws ABIVersionMismatch - * if there was an ABI version mismatch */ public Parser(Language language) { super(createIfValid(language)); @@ -52,8 +50,6 @@ private static long createIfValid(Language language) { * @throws UnsatisfiedLinkError * if the specified language has not * been linked to the system library - * @throws ABIVersionMismatch - * if there was an ABI version mismatch */ public void setLanguage(Language language) { Languages.validate(language); @@ -62,7 +58,7 @@ public void setLanguage(Language language) { private static void setLanguage(long pointer, Language language) { boolean success = TreeSitter.parserSetLanguage(pointer, language.getId()); - if (!success) throw new ABIVersionMismatch("Language could not be assigned to parser!"); + if (!success) throw new ABIVersionError("Language could not be assigned to parser!"); } /** From 0fe6364ee29dc9b55d5bb320a6a11b34a8ff0a0d Mon Sep 17 00:00:00 2001 From: dabico Date: Sun, 22 Jan 2023 15:15:47 +0100 Subject: [PATCH 0080/1089] Added `toString` method for `TreeCursorNode` --- .../main/java/usi/si/seart/treesitter/TreeCursorNode.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursorNode.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursorNode.java index 2d0e449a..3a986c5e 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursorNode.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursorNode.java @@ -17,4 +17,10 @@ public class TreeCursorNode { Point startPoint; Point endPoint; boolean isNamed; + + @Override + public String toString() { + String field = (name != null) ? name + ": " : ""; + return String.format("%s%s [%s] - [%s]", field, type, startPoint, endPoint); + } } From 577dd36cc74feb6913601a76a50cff3ffb41b56a Mon Sep 17 00:00:00 2001 From: dabico Date: Sun, 22 Jan 2023 15:16:57 +0100 Subject: [PATCH 0081/1089] Simplified implementation of `SyntaxTreePrinter` --- .../seart/treesitter/SyntaxTreePrinter.java | 32 ++++++------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/SyntaxTreePrinter.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/SyntaxTreePrinter.java index 610ef6cc..e14fc1db 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/SyntaxTreePrinter.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/SyntaxTreePrinter.java @@ -1,7 +1,6 @@ package usi.si.seart.treesitter; import lombok.AccessLevel; -import lombok.AllArgsConstructor; import lombok.Cleanup; import lombok.RequiredArgsConstructor; import lombok.experimental.FieldDefaults; @@ -9,14 +8,12 @@ /** * Utility used for pretty-printing entire syntax trees, as well as their subtrees. */ -@AllArgsConstructor @RequiredArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE) public class SyntaxTreePrinter { + int depth = 0; final Node node; - String indentation = " "; - int currentLevel = 0; /** * @return A string representation of the subtree. Consists only of named nodes. @@ -26,10 +23,13 @@ public String printSubtree() { StringBuilder stringBuilder = new StringBuilder(); @Cleanup TreeCursor cursor = new TreePrinterCursor(node); for (;;) { - TreeCursorNode treeCursorNode = cursor.getCurrentTreeCursorNode(); - if (treeCursorNode.isNamed()) { - String treeNode = printTreeNode(treeCursorNode); - stringBuilder.append(treeNode); + TreeCursorNode cursorNode = cursor.getCurrentTreeCursorNode(); + if (cursorNode.isNamed()) { + String indentation = " ".repeat(depth); + stringBuilder + .append(indentation) + .append(cursorNode) + .append("\n"); } if (cursor.gotoFirstChild() || cursor.gotoNextSibling()) continue; do { @@ -38,18 +38,6 @@ public String printSubtree() { } } - private String printTreeNode(TreeCursorNode treeCursorNode) { - String name = treeCursorNode.getName(); - String type = treeCursorNode.getType(); - Point startPoint = treeCursorNode.getStartPoint(); - Point endPoint = treeCursorNode.getEndPoint(); - return String.format("%s%s%s [%s] - [%s]%n", - indentation.repeat(currentLevel), - (name != null) ? name + ": " : "", - type, startPoint, endPoint - ); - } - private final class TreePrinterCursor extends TreeCursor { private TreePrinterCursor(Node node) { @@ -59,14 +47,14 @@ private TreePrinterCursor(Node node) { @Override public boolean gotoFirstChild() { boolean success = super.gotoFirstChild(); - if (success) currentLevel++; + if (success) depth++; return success; } @Override public boolean gotoParent() { boolean success = super.gotoParent(); - if (success) currentLevel--; + if (success) depth--; return success; } } From b185ff57b0cb6b15e60cb813516969c6cdf2d7b3 Mon Sep 17 00:00:00 2001 From: dabico Date: Sun, 22 Jan 2023 17:05:46 +0100 Subject: [PATCH 0082/1089] Added fields to `Query` and `Parser` Previously, the information used to construct instances of the two objects was discarded after they were created. This is no longer the case, and we may see more cohesion among classes of the package. --- .../src/main/java/usi/si/seart/treesitter/Parser.java | 9 +++++++++ .../src/main/java/usi/si/seart/treesitter/Query.java | 11 +++++++++++ 2 files changed, 20 insertions(+) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java index ffb841ed..6bc0263e 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java @@ -1,5 +1,9 @@ package usi.si.seart.treesitter; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.experimental.FieldDefaults; + import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -13,8 +17,12 @@ * Instances of this class can not be created * without an initially set language. */ +@Getter +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class Parser extends External { + Language language; + /** * @param language The language used for parsing. * @throws NullPointerException @@ -25,6 +33,7 @@ public class Parser extends External { */ public Parser(Language language) { super(createIfValid(language)); + this.language = language; } /* diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java index 40e44c5d..4ee5d6e8 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java @@ -1,5 +1,9 @@ package usi.si.seart.treesitter; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.experimental.FieldDefaults; + import java.util.Objects; /** @@ -22,10 +26,17 @@ * * @apiNote The underlying query value is immutable and can be safely shared between threads. */ +@Getter +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class Query extends External { + Language language; + String sExpr; + public Query(Language language, String sExpr) { super(createIfValid(language, sExpr)); + this.language = language; + this.sExpr = sExpr; } private static long createIfValid(Language language, String sExpr) { From e7772d7d74f280f3e813e10358f9c855093ea99c Mon Sep 17 00:00:00 2001 From: dabico Date: Sun, 22 Jan 2023 17:13:20 +0100 Subject: [PATCH 0083/1089] Added language information to constructed trees --- .../src/main/java/usi/si/seart/treesitter/Parser.java | 6 ++++-- .../src/main/java/usi/si/seart/treesitter/Tree.java | 11 ++++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java index 6bc0263e..b0835afa 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java @@ -78,7 +78,8 @@ private static void setLanguage(long pointer, Language language) { */ public Tree parseString(String source) throws UnsupportedEncodingException { byte[] bytes = source.getBytes(StandardCharsets.UTF_16LE); - return new Tree(TreeSitter.parserParseBytes(pointer, bytes, bytes.length)); + long treePointer = TreeSitter.parserParseBytes(pointer, bytes, bytes.length); + return new Tree(treePointer, language); } /** @@ -91,7 +92,8 @@ public Tree parseString(String source) throws UnsupportedEncodingException { */ public Tree parseString(Tree oldTree, String source) throws UnsupportedEncodingException { byte[] bytes = source.getBytes(StandardCharsets.UTF_16LE); - return new Tree(TreeSitter.parserIncrementalParseBytes(pointer, oldTree.getPointer(), bytes, bytes.length)); + long treePointer = TreeSitter.parserIncrementalParseBytes(pointer, oldTree.getPointer(), bytes, bytes.length); + return new Tree(treePointer, language); } /** diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java index 60526e68..45debfb1 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java @@ -1,15 +1,24 @@ package usi.si.seart.treesitter; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.experimental.FieldDefaults; + import java.util.Iterator; /** * A Tree represents the syntax tree of an entire source code file. It contains {@link Node Node} * instances that indicate the structure of the source code. */ +@Getter +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class Tree extends External implements Iterable { - Tree(long pointer) { + Language language; + + Tree(long pointer, Language language) { super(pointer); + this.language = language; } /** From 00f3bfae04b8d75b6c4811f103fabbba7f060332 Mon Sep 17 00:00:00 2001 From: dabico Date: Sun, 22 Jan 2023 17:22:45 +0100 Subject: [PATCH 0084/1089] Introduced unique `toString` implementations to almost all classes --- .../src/main/java/usi/si/seart/treesitter/Node.java | 5 +++++ .../src/main/java/usi/si/seart/treesitter/Parser.java | 5 +++++ .../src/main/java/usi/si/seart/treesitter/Query.java | 5 +++++ .../java/usi/si/seart/treesitter/QueryCapture.java | 5 +++++ .../java/usi/si/seart/treesitter/QueryCursor.java | 5 +++++ .../main/java/usi/si/seart/treesitter/QueryMatch.java | 11 +++++++++++ .../src/main/java/usi/si/seart/treesitter/Range.java | 5 +++++ .../src/main/java/usi/si/seart/treesitter/Tree.java | 5 +++++ .../main/java/usi/si/seart/treesitter/TreeCursor.java | 5 +++++ 9 files changed, 51 insertions(+) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java index 7cb7796a..d71a6813 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java @@ -257,6 +257,11 @@ public int hashCode() { return Long.hashCode(id); } + @Override + public String toString() { + return "Node(id: "+id+", tree: "+tree+")"; + } + /** * @return An iterator over the node subtree, starting from the current node. */ diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java index b0835afa..4344f38d 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java @@ -125,4 +125,9 @@ public Tree parseFile(File file) throws IOException { public void close() { TreeSitter.parserDelete(pointer); } + + @Override + public String toString() { + return "Parser(id: "+pointer+", language: "+language.name()+")"; + } } diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java index 4ee5d6e8..65e8940c 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java @@ -54,4 +54,9 @@ private static long createIfValid(Language language, String sExpr) { public void close() { TreeSitter.queryDelete(pointer); } + + @Override + public String toString() { + return "Query(language: "+language.name()+", expression: '"+sExpr+"')"; + } } diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCapture.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCapture.java index bfa8fb03..e0096f35 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCapture.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCapture.java @@ -12,4 +12,9 @@ public class QueryCapture { Node node; int index; + + @Override + public String toString() { + return "QueryCapture(index: "+index+", node: "+node+")"; + } } diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCursor.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCursor.java index 6a4996d2..6a828ead 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCursor.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCursor.java @@ -88,4 +88,9 @@ public QueryMatch next() { } }; } + + @Override + public String toString() { + return "QueryCursor(node: "+node+", query: "+query+")"; + } } diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryMatch.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryMatch.java index 2c19428a..c571ef99 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryMatch.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryMatch.java @@ -5,6 +5,9 @@ import lombok.Getter; import lombok.experimental.FieldDefaults; +import java.util.stream.Collectors; +import java.util.stream.Stream; + @Getter @AllArgsConstructor(access = AccessLevel.PACKAGE) @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) @@ -13,4 +16,12 @@ public class QueryMatch { int id; int pattern_index; QueryCapture[] captures; + + @Override + public String toString() { + String joined = Stream.of(captures) + .map(QueryCapture::toString) + .collect(Collectors.joining(", ")); + return String.format("QueryMatch(id: %d, pattern: %d, captures: [%s])", id, pattern_index, joined); + } } diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Range.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Range.java index 94124908..f92a6f02 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Range.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Range.java @@ -18,4 +18,9 @@ public class Range { public Range(Node node) { this(node.getStartByte(), node.getEndByte(), node.getStartPoint(), node.getEndPoint()); } + + @Override + public String toString() { + return "["+startPoint+"] - ["+endPoint+"]"; + } } diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java index 45debfb1..464bab8e 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java @@ -52,4 +52,9 @@ public Node getRootNode() { public Iterator iterator() { return getRootNode().iterator(); } + + @Override + public String toString() { + return "Tree(id: "+pointer+", language: "+language.name()+")"; + } } diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursor.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursor.java index 628484cc..232aa19b 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursor.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursor.java @@ -90,4 +90,9 @@ public void preorderTraversal(Consumer callback) { } while (!this.gotoNextSibling()); } } + + @Override + public String toString() { + return "TreeCursor(id: "+id+", tree: "+tree+")"; + } } From 21d758aa15064dc0f13c5bc1da6c0e6634c8768b Mon Sep 17 00:00:00 2001 From: dabico Date: Sun, 22 Jan 2023 17:24:30 +0100 Subject: [PATCH 0085/1089] Returning `NULL` instead of a "null" node when marshalling nodes I'd rather deal with a `NullPointerException` than a segfault... --- dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc index 571afa7d..41b9d13a 100644 --- a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc +++ b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc @@ -124,6 +124,7 @@ void JNI_OnUnload(JavaVM* vm, void* reserved) { } jobject _marshalNode(JNIEnv* env, TSNode node) { + if (node.id == 0) return NULL; jobject javaObject = env->AllocObject(_nodeClass); env->SetIntField(javaObject, _nodeContext0Field, node.context[0]); env->SetIntField(javaObject, _nodeContext1Field, node.context[1]); From 75bc8e44a29ad667736b80c111d9a2b5f006d0f5 Mon Sep 17 00:00:00 2001 From: dabico Date: Sun, 22 Jan 2023 17:24:43 +0100 Subject: [PATCH 0086/1089] `Node` documentation update --- .../java/usi/si/seart/treesitter/Node.java | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java index d71a6813..eb90bc7b 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java @@ -9,8 +9,10 @@ import java.util.Stack; /** - * A Node represents a single node in the syntax tree. It tracks its start and end positions in the source code, - * as well as its relation to other nodes like its parent, siblings and children. + * A Node represents a single node in the syntax tree. + * It tracks its start and end positions in the source code, + * as well as its relation to other nodes like its parent, + * siblings and children. */ @NoArgsConstructor(access = AccessLevel.PACKAGE) public class Node implements Iterable { @@ -23,7 +25,8 @@ public class Node implements Iterable { private long tree; /** - * Get the node's child at the given index, where zero represents the first child. + * Get the node's child at the given index, + * where zero represents the first child. * * @param child The zero-indexed child position * @return The Node's child at the given index @@ -194,8 +197,10 @@ public boolean hasError() { } /** - * Check if the node is extra. Extra nodes represent things like comments, - * which are not required the grammar, but can appear anywhere. + * Check if the node is extra. + * Extra nodes represent things like comments, + * which are not required the grammar, + * but can appear anywhere. * * @return true if the node is an extra, false otherwise. */ @@ -204,8 +209,10 @@ public boolean isExtra() { } /** - * Check if the node is missing. Missing nodes are inserted by the parser in order to recover from certain - * kinds of syntax errors. + * Check if the node is missing. + * Missing nodes are inserted by the parser + * in order to recover from certain kinds + * of syntax errors. * * @return true if the node is missing, false otherwise. */ @@ -214,8 +221,10 @@ public boolean isMissing() { } /** - * Check if the node is named. Named nodes correspond to named rules in the grammar, whereas anonymous nodes - * correspond to string literals in the grammar. + * Check if the node is named. + * Named nodes correspond to named rules in the grammar, + * whereas anonymous nodes correspond to string + * literals in the grammar. * * @return true if the node is named, false otherwise. */ @@ -224,19 +233,19 @@ public boolean isNamed() { } /** - * Check if the node is null. Methods such as {@link #getChild(int) getChild} and - * {@link #getNextSibling() getNextSibling} will return a null node to indicate that no such node - * was found. + * Check if the node is null node. * - * @return true if the current node is a null node, false otherwise + * @return true if {@code id == 0}, false otherwise */ public boolean isNull() { return TreeSitter.nodeIsNull(this); } /** - * A tree cursor allows you to walk a syntax tree more efficiently than is possible using the TSNode functions. - * It is a mutable object that is always on a certain syntax node, and can be moved imperatively to different nodes. + * A tree cursor allows you to walk a syntax tree more + * efficiently than is possible using the instance functions. + * It is a mutable object that is always on a certain syntax node, + * and can be moved imperatively to different nodes. * * @return A new tree cursor starting from the given node. */ From 18f48e39cd976856e6edff83a669a7725499115d Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 23 Jan 2023 11:30:34 +0100 Subject: [PATCH 0087/1089] Adding `SingleCaptureQueries` implementation for the Python language --- .../query/PythonSingleCaptureQueries.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/PythonSingleCaptureQueries.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/PythonSingleCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/PythonSingleCaptureQueries.java new file mode 100644 index 00000000..2b9ce091 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/PythonSingleCaptureQueries.java @@ -0,0 +1,38 @@ +package usi.si.seart.analyzer.query; + +import usi.si.seart.treesitter.Language; +import usi.si.seart.treesitter.Node; + +import java.util.List; + +/** + * @see + * + * Query Syntax - Anchors + * + * @see PEP 257 – Docstring Conventions + */ +public class PythonSingleCaptureQueries extends SingleCaptureQueries { + + protected PythonSingleCaptureQueries() { + super(Language.PYTHON); + } + + @Override + public List getComments(Node node) { + return execute( + node, + "[" + + "(_ (comment) @comment)" + + "(module . (expression_statement (string) @comment))" + + "(class_definition body: (block . (expression_statement (string) @comment)))" + + "(function_definition body: (block . (expression_statement (string) @comment)))" + + "]" + ); + } + + @Override + public List getCallableDeclarations(Node node) { + return execute(node, "(function_definition) @definition"); + } +} From 37d847a2990bbaa1f530473c006da315d9d2e741 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 23 Jan 2023 14:18:24 +0100 Subject: [PATCH 0088/1089] Edge case fix Shebangs would lead to module documentation comments not being detected. This is no longer the case, and if they are present they are simply ignored by this query capture. They are still captured by the first part of the query (the one directly matching comments). --- .../usi/si/seart/analyzer/query/PythonSingleCaptureQueries.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/PythonSingleCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/PythonSingleCaptureQueries.java index 2b9ce091..f0827d11 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/PythonSingleCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/PythonSingleCaptureQueries.java @@ -24,7 +24,7 @@ public List getComments(Node node) { node, "[" + "(_ (comment) @comment)" + - "(module . (expression_statement (string) @comment))" + + "(module (comment)? . (expression_statement (string) @comment))" + "(class_definition body: (block . (expression_statement (string) @comment)))" + "(function_definition body: (block . (expression_statement (string) @comment)))" + "]" From 040cd7708e504f6452e2cc16e089707f3a78a1b1 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 23 Jan 2023 15:54:46 +0100 Subject: [PATCH 0089/1089] Added `count` family of methods to `Query` These allow us to obtain the number of patterns, captures and strings. Will be useful for when I introduce multi-capture query support. --- .../lib/usi_si_seart_treesitter_TreeSitter.cc | 15 ++++++++++++ .../lib/usi_si_seart_treesitter_TreeSitter.h | 24 +++++++++++++++++++ .../java/usi/si/seart/treesitter/Query.java | 21 ++++++++++++++++ .../usi/si/seart/treesitter/TreeSitter.java | 6 +++++ .../usi/si/seart/treesitter/QueryTest.java | 23 ++++++++++++++++-- 5 files changed, 87 insertions(+), 2 deletions(-) diff --git a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc index 41b9d13a..32d3eaef 100644 --- a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc +++ b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc @@ -408,6 +408,21 @@ JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryNew( return (jlong) query; } +JNIEXPORT jint JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryPatternCount( + JNIEnv* env, jclass self, jlong query) { + return (jint)ts_query_pattern_count((TSQuery*)query); +} + +JNIEXPORT jint JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryCaptureCount( + JNIEnv* env, jclass self, jlong query) { + return (jint)ts_query_capture_count((TSQuery*)query); +} + +JNIEXPORT jint JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryStringCount( + JNIEnv* env, jclass self, jlong query) { + return (jint)ts_query_string_count((TSQuery*)query); +} + JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryCursorDelete( JNIEnv* env, jclass self, jlong query_cursor) { ts_query_cursor_delete((TSQueryCursor*)query_cursor); diff --git a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.h b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.h index dfd466bc..7c0e5b03 100644 --- a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.h +++ b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.h @@ -255,6 +255,30 @@ JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryDelete JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryNew (JNIEnv *, jclass, jlong, jstring); +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: queryStringCount + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryStringCount + (JNIEnv *, jclass, jlong); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: queryCaptureCount + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryCaptureCount + (JNIEnv *, jclass, jlong); + +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: queryPatternCount + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryPatternCount + (JNIEnv *, jclass, jlong); + /* * Class: usi_si_seart_treesitter_TreeSitter * Method: queryCursorDelete diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java index 65e8940c..aa383531 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java @@ -47,6 +47,27 @@ private static long createIfValid(Language language, String sExpr) { else throw new SymbolicExpressionException("Invalid S-Expression pattern: " + sExpr); } + /** + * @return The number of string literals in this query. + */ + public int countStrings() { + return TreeSitter.queryStringCount(pointer); + } + + /** + * @return The number of captures in this query. + */ + public int countCaptures() { + return TreeSitter.queryCaptureCount(pointer); + } + + /** + * @return The number of patterns in this query. + */ + public int countPatterns() { + return TreeSitter.queryPatternCount(pointer); + } + /** * Delete a query, freeing all the memory that it used. */ diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitter.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitter.java index 9786d5e7..321c8684 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitter.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitter.java @@ -67,6 +67,12 @@ class TreeSitter { static native long queryNew(long language, String source); + static native int queryStringCount(long query); + + static native int queryCaptureCount(long query); + + static native int queryPatternCount(long query); + static native void queryCursorDelete(long query_cursor); static native long queryCursorNew(); diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java index 533d8e0b..4d46d321 100644 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java @@ -1,15 +1,27 @@ package usi.si.seart.treesitter; -import lombok.Cleanup; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; class QueryTest extends TestBase { + static Query query; + + @BeforeAll + static void beforeAll() { + query = new Query(Language.JAVA, "(_) @capture"); + } + + @AfterAll + static void afterAll() { + query.close(); + } + @Test @SuppressWarnings("resource") void testQuery() { - @Cleanup Query query = new Query(Language.JAVA, "(_)"); Assertions.assertNotNull(query, "Query is not null"); Assertions.assertThrows(NullPointerException.class, () -> new Query(null, null)); Assertions.assertThrows(NullPointerException.class, () -> new Query(Language.JAVA, null)); @@ -17,4 +29,11 @@ void testQuery() { Assertions.assertThrows(UnsatisfiedLinkError.class, () -> new Query(Language._INVALID_, "(_)")); Assertions.assertThrows(SymbolicExpressionException.class, () -> new Query(Language.JAVA, "()")); } + + @Test + void testQueryCount() { + Assertions.assertEquals(1, query.countCaptures()); + Assertions.assertEquals(1, query.countPatterns()); + Assertions.assertEquals(0, query.countStrings()); + } } From 4ab616ac3b30e87ffb7e39567746f1e3d5e803cf Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 23 Jan 2023 16:21:04 +0100 Subject: [PATCH 0090/1089] Added `QueryCapture` name retrieval Previously, only the index was available to the client. Through native calls, we are now able to cross-reference indexes with the actual name of the query capture, based on its position in the `Query`. --- .../lib/usi_si_seart_treesitter_TreeSitter.cc | 8 ++++++++ .../lib/usi_si_seart_treesitter_TreeSitter.h | 8 ++++++++ .../src/main/java/usi/si/seart/treesitter/Query.java | 8 ++++++++ .../src/main/java/usi/si/seart/treesitter/TreeSitter.java | 2 ++ .../src/test/java/usi/si/seart/treesitter/QueryTest.java | 6 ++++++ 5 files changed, 32 insertions(+) diff --git a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc index 32d3eaef..ba33b5ac 100644 --- a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc +++ b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc @@ -408,6 +408,14 @@ JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryNew( return (jlong) query; } +JNIEXPORT jstring JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryCaptureName( + JNIEnv* env, jclass self, jlong query, jint index) { + uint32_t* length = new uint32_t; + const char* nameForIndex = ts_query_capture_name_for_id((TSQuery*)query, index, length); + jstring result = env->NewStringUTF(nameForIndex); + return result; +} + JNIEXPORT jint JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryPatternCount( JNIEnv* env, jclass self, jlong query) { return (jint)ts_query_pattern_count((TSQuery*)query); diff --git a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.h b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.h index 7c0e5b03..cff7c456 100644 --- a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.h +++ b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.h @@ -255,6 +255,14 @@ JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryDelete JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryNew (JNIEnv *, jclass, jlong, jstring); +/* + * Class: usi_si_seart_treesitter_TreeSitter + * Method: queryCaptureName + * Signature: (JI)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryCaptureName + (JNIEnv *, jclass, jlong, jint); + /* * Class: usi_si_seart_treesitter_TreeSitter * Method: queryStringCount diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java index aa383531..8514b7d6 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java @@ -68,6 +68,14 @@ public int countPatterns() { return TreeSitter.queryPatternCount(pointer); } + /** + * @param capture The query capture. + * @return The name of the provided query captures. + */ + public String getCaptureName(QueryCapture capture) { + return TreeSitter.queryCaptureName(pointer, capture.getIndex()); + } + /** * Delete a query, freeing all the memory that it used. */ diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitter.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitter.java index 321c8684..f6c7ac4e 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitter.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitter.java @@ -67,6 +67,8 @@ class TreeSitter { static native long queryNew(long language, String source); + static native String queryCaptureName(long pointer, int index); + static native int queryStringCount(long query); static native int queryCaptureCount(long query); diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java index 4d46d321..53a06d63 100644 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java @@ -36,4 +36,10 @@ void testQueryCount() { Assertions.assertEquals(1, query.countPatterns()); Assertions.assertEquals(0, query.countStrings()); } + + @Test + void testQueryCaptureName() { + QueryCapture capture = new QueryCapture(new Node(), 0); + Assertions.assertEquals("capture", query.getCaptureName(capture)); + } } From 4a3067265041f8ca2b7e12ed4a309efa582bb74b Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 24 Jan 2023 10:13:57 +0100 Subject: [PATCH 0091/1089] `Query` now automatically initializes captures on creation As opposed to making JNI calls for every single capture of every match, we only make the necessary JNI calls when the object is first created, and then re-use these results for every subsequent call to `getCaptureName`. Should reduce some overhead, but the performance impact remains to be seen. --- .../java/usi/si/seart/treesitter/Query.java | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java index 8514b7d6..5e5c2ecc 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java @@ -4,6 +4,9 @@ import lombok.Getter; import lombok.experimental.FieldDefaults; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.Objects; /** @@ -31,20 +34,28 @@ public class Query extends External { Language language; - String sExpr; + String pattern; + List captures; - public Query(Language language, String sExpr) { - super(createIfValid(language, sExpr)); + public Query(Language language, String pattern) { + super(createIfValid(language, pattern)); this.language = language; - this.sExpr = sExpr; + this.pattern = pattern; + int capturesCount = TreeSitter.queryCaptureCount(pointer); + List captures = new ArrayList<>(capturesCount); + for (int idx = 0; idx < capturesCount; idx++) { + String capture = TreeSitter.queryCaptureName(pointer, idx); + captures.add(capture); + } + this.captures = Collections.unmodifiableList(captures); } - private static long createIfValid(Language language, String sExpr) { + private static long createIfValid(Language language, String pattern) { Languages.validate(language); - Objects.requireNonNull(sExpr, "Pattern must not be null!"); - long pointer = TreeSitter.queryNew(language.getId(), sExpr); + Objects.requireNonNull(pattern, "Pattern must not be null!"); + long pointer = TreeSitter.queryNew(language.getId(), pattern); if (pointer != 0L) return pointer; - else throw new SymbolicExpressionException("Invalid S-Expression pattern: " + sExpr); + else throw new SymbolicExpressionException("Invalid S-Expression pattern: " + pattern); } /** @@ -73,7 +84,7 @@ public int countPatterns() { * @return The name of the provided query captures. */ public String getCaptureName(QueryCapture capture) { - return TreeSitter.queryCaptureName(pointer, capture.getIndex()); + return captures.get(capture.getIndex()); } /** @@ -86,6 +97,8 @@ public void close() { @Override public String toString() { - return "Query(language: "+language.name()+", expression: '"+sExpr+"')"; + String languageStr = language.name(); + String capturesStr = String.join(", ", captures); + return String.format("Query(language: %s, pattern: '%s', captures: [%s])", languageStr, pattern, capturesStr); } } From 6d672873839cfa0463178cd684a5e9add95496a4 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 24 Jan 2023 10:15:26 +0100 Subject: [PATCH 0092/1089] Added a `toString` method to `Language` This could be useful for an interop with the `Language` class from `model`. May see more adjustments. --- .../usi/si/seart/treesitter/Language.java | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Language.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Language.java index cd4bb446..1b170344 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Language.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Language.java @@ -60,4 +60,55 @@ public enum Language { this.id = id; } } + + + @Override + public String toString() { + switch (this) { + // Unmodified + case C: + case CSS: + case HTML: + case PHP: + case SCSS: + case TOML: + case TSX: + case YAML: + return name(); + + // Capital Case + case AGDA: + case BASH: + case DART: + case ELM: + case ENO: + case GO: + case HASKELL: + case JAVA: + case JULIA: + case KOTLIN: + case LUA: + case MARKDOWN: + case PYTHON: + case RUBY: + case RUST: + case SCALA: + case SWIFT: + case VUE: + return name().charAt(0) + name().substring(1).toLowerCase(); + + // Special Cases + case CSHARP: return "C#"; + case CPP: return "C++"; + case EMBEDDED_TEMPLATE: return "Embedded Template"; + case JAVASCRIPT: return "JavaScript"; + case OCAML: return "OCaml"; + case TYPESCRIPT: return "TypeScript"; + case WASM: return "WebAssembly"; + + // Default / Undefined + default: + return "???"; + } + } } From 6470a510e843e4256612a7fd3a9b457d88c2b4e5 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 24 Jan 2023 11:06:52 +0100 Subject: [PATCH 0093/1089] Moved `TreeSitterException` into the `exception` package As we introduce more exception types, it will be necessary to segregate the code so that it does not intermingle with the rest of the classes. --- .../src/main/java/usi/si/seart/treesitter/LibraryLoader.java | 1 + .../seart/treesitter/{ => exception}/TreeSitterException.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) rename dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/{ => exception}/TreeSitterException.java (82%) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/LibraryLoader.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/LibraryLoader.java index 12884e66..2f2302b3 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/LibraryLoader.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/LibraryLoader.java @@ -4,6 +4,7 @@ import lombok.Cleanup; import lombok.experimental.FieldDefaults; import lombok.experimental.UtilityClass; +import usi.si.seart.treesitter.exception.TreeSitterException; import java.io.File; import java.io.FileOutputStream; diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitterException.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/TreeSitterException.java similarity index 82% rename from dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitterException.java rename to dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/TreeSitterException.java index 013f16cb..58a8323d 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitterException.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/TreeSitterException.java @@ -1,4 +1,4 @@ -package usi.si.seart.treesitter; +package usi.si.seart.treesitter.exception; import lombok.experimental.StandardException; From 8bead945d0b43d0e5562cb617807034f25a8cbf0 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 24 Jan 2023 11:08:49 +0100 Subject: [PATCH 0094/1089] Moved `ABIVersionError` into the `error` package Same as before, though I'm not sure if we will introduce more `error` classes. Still better to move this now and not have to worry later. --- .../src/main/java/usi/si/seart/treesitter/Parser.java | 3 ++- .../usi/si/seart/treesitter/{ => error}/ABIVersionError.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) rename dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/{ => error}/ABIVersionError.java (88%) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java index 4344f38d..c6a90375 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java @@ -3,6 +3,7 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.experimental.FieldDefaults; +import usi.si.seart.treesitter.error.ABIVersionError; import java.io.File; import java.io.IOException; @@ -128,6 +129,6 @@ public void close() { @Override public String toString() { - return "Parser(id: "+pointer+", language: "+language.name()+")"; + return "Parser(id: "+pointer+", language: "+language+")"; } } diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/ABIVersionError.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/error/ABIVersionError.java similarity index 88% rename from dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/ABIVersionError.java rename to dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/error/ABIVersionError.java index a5dd1103..008859ef 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/ABIVersionError.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/error/ABIVersionError.java @@ -1,4 +1,4 @@ -package usi.si.seart.treesitter; +package usi.si.seart.treesitter.error; import lombok.experimental.StandardException; From 23649f06c91b63378a30648f0cb1fc4e93acc91c Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 24 Jan 2023 11:10:02 +0100 Subject: [PATCH 0095/1089] Replacing usages of `name()` with the newly defined `toString()` Much better :) --- .../src/main/java/usi/si/seart/treesitter/Languages.java | 2 +- .../src/main/java/usi/si/seart/treesitter/Query.java | 7 ++++--- .../src/main/java/usi/si/seart/treesitter/Tree.java | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Languages.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Languages.java index c544c679..20668281 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Languages.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Languages.java @@ -44,7 +44,7 @@ static void validate(Language language) { Objects.requireNonNull(language, "Language must not be null!"); long id = language.getId(); if (id == Language.INVALID) throw new UnsatisfiedLinkError( - "Language binding has not been defined for: " + language.name().toLowerCase() + "Language binding has not been defined for: " + language ); } } diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java index 5e5c2ecc..54f930df 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java @@ -97,8 +97,9 @@ public void close() { @Override public String toString() { - String languageStr = language.name(); - String capturesStr = String.join(", ", captures); - return String.format("Query(language: %s, pattern: '%s', captures: [%s])", languageStr, pattern, capturesStr); + return String.format( + "Query(language: %s, pattern: '%s', captures: [%s])", + language, pattern, String.join(", ", captures) + ); } } diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java index 464bab8e..9a2d1459 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java @@ -55,6 +55,6 @@ public Iterator iterator() { @Override public String toString() { - return "Tree(id: "+pointer+", language: "+language.name()+")"; + return "Tree(id: "+pointer+", language: "+language+")"; } } From 1dc0de9364249e035d3a8ca2d55ff1dfd6ee7d43 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 24 Jan 2023 11:14:07 +0100 Subject: [PATCH 0096/1089] Replaced `SymbolicExpressionException` with `QueryException` In the future, we will throw more specific exceptions from the JNI during `Query` construction. --- .../src/main/java/usi/si/seart/treesitter/Query.java | 4 +--- .../seart/treesitter/SymbolicExpressionException.java | 10 ---------- .../main/java/usi/si/seart/treesitter/TreeSitter.java | 3 ++- .../treesitter/exception/query/QueryException.java | 11 +++++++++++ 4 files changed, 14 insertions(+), 14 deletions(-) delete mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/SymbolicExpressionException.java create mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryException.java diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java index 54f930df..eb95bd75 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java @@ -53,9 +53,7 @@ public Query(Language language, String pattern) { private static long createIfValid(Language language, String pattern) { Languages.validate(language); Objects.requireNonNull(pattern, "Pattern must not be null!"); - long pointer = TreeSitter.queryNew(language.getId(), pattern); - if (pointer != 0L) return pointer; - else throw new SymbolicExpressionException("Invalid S-Expression pattern: " + pattern); + return TreeSitter.queryNew(language.getId(), pattern); } /** diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/SymbolicExpressionException.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/SymbolicExpressionException.java deleted file mode 100644 index 17323d69..00000000 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/SymbolicExpressionException.java +++ /dev/null @@ -1,10 +0,0 @@ -package usi.si.seart.treesitter; - -import lombok.experimental.StandardException; - -/** - * The base exception type for all exceptions related to symbolic expressions (s-expressions). - */ -@StandardException -public class SymbolicExpressionException extends TreeSitterException { -} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitter.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitter.java index f6c7ac4e..eb7aa6a7 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitter.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitter.java @@ -1,6 +1,7 @@ package usi.si.seart.treesitter; import lombok.experimental.UtilityClass; +import usi.si.seart.treesitter.exception.query.QueryException; @UtilityClass class TreeSitter { @@ -65,7 +66,7 @@ class TreeSitter { static native void queryDelete(long query); - static native long queryNew(long language, String source); + static native long queryNew(long language, String source) throws QueryException; static native String queryCaptureName(long pointer, int index); diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryException.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryException.java new file mode 100644 index 00000000..60f89773 --- /dev/null +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryException.java @@ -0,0 +1,11 @@ +package usi.si.seart.treesitter.exception.query; + +import lombok.experimental.StandardException; +import usi.si.seart.treesitter.exception.TreeSitterException; + +/** + * The base exception type for all exceptions related to tree-sitter queries. + */ +@StandardException +public abstract class QueryException extends TreeSitterException { +} From 9a404bc1194412a6ffb4e9e49d5df92dd4a76b22 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 24 Jan 2023 11:29:53 +0100 Subject: [PATCH 0097/1089] Introducing `QueryException` subtypes We currently only load these classes to the native code file. We will soon define how and where they are used. --- .../lib/usi_si_seart_treesitter_TreeSitter.cc | 12 ++++++++++++ .../exception/query/QueryCaptureException.java | 7 +++++++ .../exception/query/QueryFieldException.java | 7 +++++++ .../exception/query/QueryNodeTypeException.java | 7 +++++++ .../exception/query/QueryStructureException.java | 7 +++++++ .../exception/query/QuerySyntaxException.java | 7 +++++++ 6 files changed, 47 insertions(+) create mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryCaptureException.java create mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryFieldException.java create mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryNodeTypeException.java create mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryStructureException.java create mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QuerySyntaxException.java diff --git a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc index ba33b5ac..f9f59868 100644 --- a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc +++ b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc @@ -56,6 +56,12 @@ static jfieldID _treeCursorNodeStartPointField; static jfieldID _treeCursorNodeEndPointField; static jfieldID _treeCursorNodeIsNamed; +static jclass _queryCaptureExceptionClass; +static jclass _queryFieldExceptionClass; +static jclass _queryNodeTypeExceptionClass; +static jclass _queryStructureExceptionClass; +static jclass _querySyntaxExceptionClass; + #define _loadClass(VARIABLE, NAME) \ { \ jclass tmp; \ @@ -113,6 +119,12 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) { _loadField(_inputEditOldEndPointField, _inputEditClass, "oldEndPoint", "Lusi/si/seart/treesitter/Point;"); _loadField(_inputEditNewEndPointField, _inputEditClass, "newEndPoint", "Lusi/si/seart/treesitter/Point;"); + _loadClass(_queryCaptureExceptionClass, "usi/si/seart/treesitter/exception/query/QueryCaptureException"); + _loadClass(_queryFieldExceptionClass, "usi/si/seart/treesitter/exception/query/QueryFieldException"); + _loadClass(_queryNodeTypeExceptionClass, "usi/si/seart/treesitter/exception/query/QueryNodeTypeException"); + _loadClass(_queryStructureExceptionClass, "usi/si/seart/treesitter/exception/query/QueryStructureException"); + _loadClass(_querySyntaxExceptionClass, "usi/si/seart/treesitter/exception/query/QuerySyntaxException"); + return JNI_VERSION; } diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryCaptureException.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryCaptureException.java new file mode 100644 index 00000000..fc50310f --- /dev/null +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryCaptureException.java @@ -0,0 +1,7 @@ +package usi.si.seart.treesitter.exception.query; + +import lombok.experimental.StandardException; + +@StandardException +public class QueryCaptureException extends QueryException { +} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryFieldException.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryFieldException.java new file mode 100644 index 00000000..c8ffc842 --- /dev/null +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryFieldException.java @@ -0,0 +1,7 @@ +package usi.si.seart.treesitter.exception.query; + +import lombok.experimental.StandardException; + +@StandardException +public class QueryFieldException extends QueryException { +} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryNodeTypeException.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryNodeTypeException.java new file mode 100644 index 00000000..381b84b8 --- /dev/null +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryNodeTypeException.java @@ -0,0 +1,7 @@ +package usi.si.seart.treesitter.exception.query; + +import lombok.experimental.StandardException; + +@StandardException +public class QueryNodeTypeException extends QueryException { +} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryStructureException.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryStructureException.java new file mode 100644 index 00000000..240b6b66 --- /dev/null +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryStructureException.java @@ -0,0 +1,7 @@ +package usi.si.seart.treesitter.exception.query; + +import lombok.experimental.StandardException; + +@StandardException +public class QueryStructureException extends QueryException { +} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QuerySyntaxException.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QuerySyntaxException.java new file mode 100644 index 00000000..47928679 --- /dev/null +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QuerySyntaxException.java @@ -0,0 +1,7 @@ +package usi.si.seart.treesitter.exception.query; + +import lombok.experimental.StandardException; + +@StandardException +public class QuerySyntaxException extends QueryException { +} From bbc4f1026fc62dbd1ae6d23780227dc1b3ed0c86 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 24 Jan 2023 11:31:34 +0100 Subject: [PATCH 0098/1089] `QueryException` now thrown when `Query` creation fails These are very rudimentary exception throws, not offering any details. We may change that in the next commit. --- .../lib/usi_si_seart_treesitter_TreeSitter.cc | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc index f9f59868..08d522a2 100644 --- a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc +++ b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc @@ -417,7 +417,20 @@ JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryNew( uint32_t* error_offset = new uint32_t; TSQueryError* error_type = new TSQueryError; TSQuery* query = ts_query_new((TSLanguage*) language, c_source, source_length, error_offset, error_type); - return (jlong) query; + switch (*error_type) { + case TSQueryErrorSyntax: + return env->ThrowNew(_querySyntaxExceptionClass, NULL); + case TSQueryErrorNodeType: + return env->ThrowNew(_queryNodeTypeExceptionClass, NULL); + case TSQueryErrorField: + return env->ThrowNew(_queryFieldExceptionClass, NULL); + case TSQueryErrorCapture: + return env->ThrowNew(_queryCaptureExceptionClass, NULL); + case TSQueryErrorStructure: + return env->ThrowNew(_queryStructureExceptionClass, NULL); + default: + return (jlong)query; + } } JNIEXPORT jstring JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryCaptureName( From 69b3c34c7d969b42569e421d8d984abe49cf5668 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 24 Jan 2023 12:07:33 +0100 Subject: [PATCH 0099/1089] Added test cases for all the new exception types in `QueryTest` --- .../test/java/usi/si/seart/treesitter/QueryTest.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java index 53a06d63..98b392c0 100644 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java @@ -4,6 +4,11 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import usi.si.seart.treesitter.exception.query.QueryCaptureException; +import usi.si.seart.treesitter.exception.query.QueryFieldException; +import usi.si.seart.treesitter.exception.query.QueryNodeTypeException; +import usi.si.seart.treesitter.exception.query.QueryStructureException; +import usi.si.seart.treesitter.exception.query.QuerySyntaxException; class QueryTest extends TestBase { @@ -27,7 +32,11 @@ void testQuery() { Assertions.assertThrows(NullPointerException.class, () -> new Query(Language.JAVA, null)); Assertions.assertThrows(NullPointerException.class, () -> new Query(null, "(_)")); Assertions.assertThrows(UnsatisfiedLinkError.class, () -> new Query(Language._INVALID_, "(_)")); - Assertions.assertThrows(SymbolicExpressionException.class, () -> new Query(Language.JAVA, "()")); + Assertions.assertThrows(QueryCaptureException.class, () -> new Query(Language.JAVA, "(#eq? @key @value)")); + Assertions.assertThrows(QueryFieldException.class, () -> new Query(Language.JAVA, "(program unknown: (_))")); + Assertions.assertThrows(QueryNodeTypeException.class, () -> new Query(Language.JAVA, "(null)")); + Assertions.assertThrows(QueryStructureException.class, () -> new Query(Language.JAVA, "(program (program))")); + Assertions.assertThrows(QuerySyntaxException.class, () -> new Query(Language.JAVA, "()")); } @Test From 3697d590a5341faea6b5267a6828ad9fdde60060 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 24 Jan 2023 15:26:26 +0100 Subject: [PATCH 0100/1089] Thrown `QueryException` instances now include additional information --- .../lib/usi_si_seart_treesitter_TreeSitter.cc | 37 +++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc index 08d522a2..be7a5640 100644 --- a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc +++ b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc @@ -1,6 +1,7 @@ #include "usi_si_seart_treesitter_TreeSitter.h" #include +#include #include #include @@ -56,6 +57,8 @@ static jfieldID _treeCursorNodeStartPointField; static jfieldID _treeCursorNodeEndPointField; static jfieldID _treeCursorNodeIsNamed; +static jclass _treeSitterException; + static jclass _queryCaptureExceptionClass; static jclass _queryFieldExceptionClass; static jclass _queryNodeTypeExceptionClass; @@ -119,6 +122,8 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) { _loadField(_inputEditOldEndPointField, _inputEditClass, "oldEndPoint", "Lusi/si/seart/treesitter/Point;"); _loadField(_inputEditNewEndPointField, _inputEditClass, "newEndPoint", "Lusi/si/seart/treesitter/Point;"); + _loadClass(_treeSitterException, "usi/si/seart/treesitter/exception/TreeSitterException"); + _loadClass(_queryCaptureExceptionClass, "usi/si/seart/treesitter/exception/query/QueryCaptureException"); _loadClass(_queryFieldExceptionClass, "usi/si/seart/treesitter/exception/query/QueryFieldException"); _loadClass(_queryNodeTypeExceptionClass, "usi/si/seart/treesitter/exception/query/QueryNodeTypeException"); @@ -416,21 +421,39 @@ JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryNew( c_source = env->GetStringUTFChars(source, NULL); uint32_t* error_offset = new uint32_t; TSQueryError* error_type = new TSQueryError; - TSQuery* query = ts_query_new((TSLanguage*) language, c_source, source_length, error_offset, error_type); + TSQuery* query = ts_query_new((TSLanguage*)language, c_source, source_length, error_offset, error_type); + jclass exceptionClass; + const char* c_pattern; switch (*error_type) { + case TSQueryErrorNone: + return (jlong)query; case TSQueryErrorSyntax: - return env->ThrowNew(_querySyntaxExceptionClass, NULL); + exceptionClass = _querySyntaxExceptionClass; + c_pattern = "Bad syntax at offset %d"; + break; case TSQueryErrorNodeType: - return env->ThrowNew(_queryNodeTypeExceptionClass, NULL); + exceptionClass = _queryNodeTypeExceptionClass; + c_pattern = "Bad node name at offset %d"; + break; case TSQueryErrorField: - return env->ThrowNew(_queryFieldExceptionClass, NULL); + exceptionClass = _queryFieldExceptionClass; + c_pattern = "Bad field name at offset %d"; + break; case TSQueryErrorCapture: - return env->ThrowNew(_queryCaptureExceptionClass, NULL); + exceptionClass = _queryCaptureExceptionClass; + c_pattern = "Bad capture at offset %d"; + break; case TSQueryErrorStructure: - return env->ThrowNew(_queryStructureExceptionClass, NULL); + exceptionClass = _queryStructureExceptionClass; + c_pattern = "Bad pattern structure at offset %d"; + break; default: - return (jlong)query; + return env->ThrowNew(_treeSitterException, NULL); } + int digits = static_cast(floor(log10(*error_offset))) + 1; + char c_message[strlen(c_pattern) + 1 + digits]; + snprintf(c_message, sizeof(c_message), c_pattern, *error_offset); + return env->ThrowNew(exceptionClass, c_message); } JNIEXPORT jstring JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryCaptureName( From 99e75f5ee136a384fd5f9689ca532a675f621b0e Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 25 Jan 2023 09:32:48 +0100 Subject: [PATCH 0101/1089] Added `PythonTestFilePredicate` --- .../predicate/PythonTestFilePredicate.java | 14 +++++++ .../PythonTestFilePredicateTest.java | 38 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/PythonTestFilePredicate.java create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/PythonTestFilePredicateTest.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/PythonTestFilePredicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/PythonTestFilePredicate.java new file mode 100644 index 00000000..d80fc29a --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/PythonTestFilePredicate.java @@ -0,0 +1,14 @@ +package usi.si.seart.analyzer.predicate; + +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.PathMatcher; + +public class PythonTestFilePredicate extends TestFilePredicate { + + @Override + public boolean test(Path path) { + PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:**/*test*.py"); + return super.test(path) || matcher.matches(path); + } +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/PythonTestFilePredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/PythonTestFilePredicateTest.java new file mode 100644 index 00000000..640526d1 --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/PythonTestFilePredicateTest.java @@ -0,0 +1,38 @@ +package usi.si.seart.analyzer.predicate; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; + +import java.nio.file.Path; +import java.util.function.Predicate; +import java.util.stream.Stream; + +class PythonTestFilePredicateTest { + + private static class PythonPathPredicateProvider implements ArgumentsProvider { + + @Override + public Stream provideArguments(ExtensionContext extensionContext) throws Exception { + return Stream.of( + Arguments.of(Path.of("/src", "app.py"), false), + Arguments.of(Path.of("/src", "test", "app.py"), true), + Arguments.of(Path.of("/src", "tests", "app.py"), true), + Arguments.of(Path.of("/src", "latest", "app.py"), false), + Arguments.of(Path.of("/src", "test.py"), true), + Arguments.of(Path.of("/src", "test_app.py"), true), + Arguments.of(Path.of("/src", "app_test.py"), true) + ); + } + } + + @ParameterizedTest + @ArgumentsSource(PythonPathPredicateProvider.class) + void pathPredicateTest(Path path, boolean expected) { + Predicate predicate = new PythonTestFilePredicate(); + Assertions.assertEquals(expected, predicate.test(path)); + } +} \ No newline at end of file From ed61adb5761fa2331fcff524d1e9fe8a23c6097e Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 25 Jan 2023 09:36:40 +0100 Subject: [PATCH 0102/1089] Refined `PythonTestFilePredicate` pattern to be more restrictive --- .../analyzer/predicate/PythonTestFilePredicate.java | 11 ++++++++++- .../predicate/PythonTestFilePredicateTest.java | 3 ++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/PythonTestFilePredicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/PythonTestFilePredicate.java index d80fc29a..b3908092 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/PythonTestFilePredicate.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/PythonTestFilePredicate.java @@ -3,12 +3,21 @@ import java.nio.file.FileSystems; import java.nio.file.Path; import java.nio.file.PathMatcher; +import java.util.Set; +import java.util.stream.Collectors; public class PythonTestFilePredicate extends TestFilePredicate { + private static final Set FILE_PATTERNS = Set.of( + "**/test.py", + "**/*_test.py", + "**/test_*.py" + ); + @Override public boolean test(Path path) { - PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:**/*test*.py"); + String glob = FILE_PATTERNS.stream().collect(Collectors.joining(",", "glob:{", "}")); + PathMatcher matcher = FileSystems.getDefault().getPathMatcher(glob); return super.test(path) || matcher.matches(path); } } diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/PythonTestFilePredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/PythonTestFilePredicateTest.java index 640526d1..ca74c0cd 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/PythonTestFilePredicateTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/PythonTestFilePredicateTest.java @@ -24,7 +24,8 @@ public Stream provideArguments(ExtensionContext extensionCo Arguments.of(Path.of("/src", "latest", "app.py"), false), Arguments.of(Path.of("/src", "test.py"), true), Arguments.of(Path.of("/src", "test_app.py"), true), - Arguments.of(Path.of("/src", "app_test.py"), true) + Arguments.of(Path.of("/src", "app_test.py"), true), + Arguments.of(Path.of("/src", "latest.py"), false) ); } } From 8cca4dca91c494c45f8b7b450533c0b9d60f0bd0 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 25 Jan 2023 09:38:30 +0100 Subject: [PATCH 0103/1089] Added `hasCaptures` method to `Query` Only indented as a shorthand, clearer as opposed to calling list methods --- .../src/main/java/usi/si/seart/treesitter/Query.java | 7 +++++++ .../src/test/java/usi/si/seart/treesitter/QueryTest.java | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java index eb95bd75..f0af00ac 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java @@ -85,6 +85,13 @@ public String getCaptureName(QueryCapture capture) { return captures.get(capture.getIndex()); } + /** + * @return true if the query has captures, false otherwise. + */ + public boolean hasCaptures() { + return !captures.isEmpty(); + } + /** * Delete a query, freeing all the memory that it used. */ diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java index 98b392c0..3086e224 100644 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java @@ -1,5 +1,6 @@ package usi.si.seart.treesitter; +import lombok.Cleanup; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; @@ -51,4 +52,11 @@ void testQueryCaptureName() { QueryCapture capture = new QueryCapture(new Node(), 0); Assertions.assertEquals("capture", query.getCaptureName(capture)); } + + @Test + void testQueryHasCaptures() { + Assertions.assertTrue(query.hasCaptures()); + @Cleanup Query query = new Query(Language.JAVA, "(_)"); + Assertions.assertFalse(query.hasCaptures()); + } } From d1e3e33a17d3254308a39c62577c93768530775f Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 25 Jan 2023 09:39:56 +0100 Subject: [PATCH 0104/1089] Added `Tuple` utility class to `dl4se-analyzer` We may also remove this one from the `dl4se-crawler` module in the future. Will be way more useful here. --- .../usi/si/seart/analyzer/util/Tuple.java | 94 +++++++++++++++++++ .../usi/si/seart/analyzer/util/TupleTest.java | 14 +++ 2 files changed, 108 insertions(+) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/util/Tuple.java create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/util/TupleTest.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/util/Tuple.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/util/Tuple.java new file mode 100644 index 00000000..1174993c --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/util/Tuple.java @@ -0,0 +1,94 @@ +package usi.si.seart.analyzer.util; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.experimental.FieldDefaults; + +import java.util.Map; +import java.util.Objects; + +/** + * Simple implementation of a tuple class, + * used as a container for two values of arbitrary types. + * Tuples are immutable, and can only be created through a static factory: + *

{@code
+ *      Tuple t = Tuple.of(1, "Hello!");
+ * }
+ * The left and right side are subsequently accessed through dedicated getters: + *
{@code
+ *      int i = t.getLeft();
+ *      String msg = t.getRight();
+ * }
+ * Instances can also be used in place of {@link Map.Entry}: + *
{@code
+ *      Map = Map.ofEntries(
+ *          Tuple.of(1, 1L),
+ *          Tuple.of(2, ""),
+ *          Tuple.of(3, new Object())
+ *      );
+ * }
+ * Which means that you can also access tuple data as you would a map entry: + *
{@code
+ *      int i = t.getKey();
+ *      String msg = t.getValue();
+ * }
+ * In terms of overall behaviour, it is similar to a {@code UnmodifiableEntry}. + * + * @author dabico + * @param The type of the first value. + * @param The type of the second value. + */ +@Getter +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +public class Tuple implements Map.Entry { + + L left; + R right; + + @Override + public L getKey() { + return left; + } + + @Override + public R getValue() { + return right; + } + + @Override + public R setValue(R value) { + throw new UnsupportedOperationException("Tuple values are not modifiable!"); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Tuple tuple = (Tuple) o; + if (!Objects.equals(left, tuple.left)) return false; + return Objects.equals(right, tuple.right); + } + + @Override + public int hashCode() { + int result = left != null ? left.hashCode() : 0; + result = 31 * result + (right != null ? right.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return String.format("(%s, %s)", left.toString(), right.toString()); + } + + public Tuple invert() { + return new Tuple<>(right, left); + } + + public static Tuple of(L left, R right) { + return new Tuple<>(left, right); + } +} + diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/util/TupleTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/util/TupleTest.java new file mode 100644 index 00000000..c38d37e5 --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/util/TupleTest.java @@ -0,0 +1,14 @@ +package usi.si.seart.analyzer.util; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class TupleTest { + + @Test + void invertTest() { + Tuple tuple = Tuple.of(1, "hello!"); + Tuple elput = Tuple.of("hello!", 1); + Assertions.assertEquals(elput, tuple.invert()); + } +} \ No newline at end of file From 7c52c1934baf73e3392f3f1b39eafd9fd6358317 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 25 Jan 2023 09:56:12 +0100 Subject: [PATCH 0105/1089] HUGE COMMIT, READ MESSAGE BODY! I have begun introducing the `PythonAnalyzer` into the `Analyzer` hierarchy. This implies a number of changes: - `Validated` has been completely removed - `Queries` now offers only a `validate` and abstract `execute` methods - Implementations have been divided into single- and multi-capture - `PreviousCommentsAnalyzer` has been completely removed Q: What is the difference between single- and multi-capture `Queries`? A: Single-capture `Queries` will be used to locate independent source nodes like comments, while multi-capture `Queries` will be used to locate nodes whose immediate neighbors will also be stored along with the node itself. In the case of Java, comments preceding callable declarations will be extracted alongside the declaration, while in the case of Python, all decorators preceding the function definition will also be extracted. Q: Why was `Validated` removed? A: Thanks to the introduction of "count" methods to the `Query` class, as well as the inclusion exceptions during construction, I believe that the interface is no longer needed, and the logic can be extracted to the common ancestor of the implementing classes, which in this case is `Queries`. Q: Does this also mean that we will remove `Traverser`? A: No, it may be useful for the `PythonBoilerplateEnumerator`, which I have yet to implement. Doing so requires first a discussion on what constitutes "boilerplate" in Python. Q: Why was `PreviousCommentsAnalyzer` removed? A: Thanks to the introduction of multi-capture queries, the middleman is no longer required. This query type will now always be used for the extraction of callable declarations from files, so the logic it introduced has been hoisted up into the parent. --- .../si/seart/analyzer/AbstractAnalyzer.java | 100 ++++++++++++++---- .../usi/si/seart/analyzer/JavaAnalyzer.java | 8 +- .../analyzer/PreviousCommentsAnalyzer.java | 61 ----------- .../usi/si/seart/analyzer/PythonAnalyzer.java | 19 ++++ .../usi/si/seart/analyzer/query/Queries.java | 18 +++- .../si/seart/analyzer/query/Validated.java | 21 ---- .../query/multi/JavaMultiCaptureQueries.java | 37 +++++++ .../query/multi/MultiCaptureQueries.java | 45 ++++++++ .../multi/PythonMultiCaptureQueries.java | 26 +++++ .../JavaSingleCaptureQueries.java | 13 +-- .../PythonSingleCaptureQueries.java | 17 +-- .../{ => single}/SingleCaptureQueries.java | 21 ++-- 12 files changed, 248 insertions(+), 138 deletions(-) delete mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PreviousCommentsAnalyzer.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java delete mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/Validated.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/JavaMultiCaptureQueries.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/PythonMultiCaptureQueries.java rename dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/{ => single}/JavaSingleCaptureQueries.java (65%) rename dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/{ => single}/PythonSingleCaptureQueries.java (71%) rename dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/{ => single}/SingleCaptureQueries.java (68%) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java index e5441395..fa2f87b1 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java @@ -19,13 +19,17 @@ import usi.si.seart.analyzer.printer.Printer; import usi.si.seart.analyzer.printer.SExpressionPrinter; import usi.si.seart.analyzer.printer.SyntaxTreePrinter; -import usi.si.seart.analyzer.query.Queries; +import usi.si.seart.analyzer.query.multi.MultiCaptureQueries; +import usi.si.seart.analyzer.query.single.SingleCaptureQueries; +import usi.si.seart.analyzer.util.Tuple; +import usi.si.seart.analyzer.util.stream.DelimiterSuffixedStringCollector; import usi.si.seart.model.code.Boilerplate; import usi.si.seart.model.code.File; import usi.si.seart.model.code.Function; import usi.si.seart.treesitter.Language; import usi.si.seart.treesitter.Node; import usi.si.seart.treesitter.Parser; +import usi.si.seart.treesitter.Query; import usi.si.seart.treesitter.Tree; import java.io.IOException; @@ -33,6 +37,7 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import java.util.NoSuchElementException; import java.util.function.Predicate; @FieldDefaults(level = AccessLevel.PROTECTED) @@ -63,10 +68,9 @@ public abstract class AbstractAnalyzer implements Analyzer { Printer syntaxTreePrinter = new SyntaxTreePrinter(); Printer sExpressionPrinter = new SExpressionPrinter(); - Queries> queries = new Queries<>() { + SingleCaptureQueries singleCaptureQueries = new SingleCaptureQueries(null) { @Override - public List getNodes(Node node) { - return List.of(); + public void verify(Query query) { } @Override @@ -75,7 +79,23 @@ public List getComments(Node node) { } @Override - public List getCallableDeclarations(Node node) { + public List execute(Node node, String pattern) { + return List.of(); + } + }; + + MultiCaptureQueries multiCaptureQueries = new MultiCaptureQueries(null) { + @Override + public void verify(Query query) { + } + + @Override + public List>> getCallableDeclarations(Node node) { + return List.of(); + } + + @Override + public List>> execute(Node node, String pattern) { return List.of(); } }; @@ -136,10 +156,10 @@ protected File extractFileEntity() { } protected List extractFunctionEntities(File file) { - List targets = queries.getCallableDeclarations(tree.getRootNode()); + List>> targets = multiCaptureQueries.getCallableDeclarations(tree.getRootNode()); List functions = new ArrayList<>(targets.size()); - for (Node node: targets) { - Function function = extractFunctionEntity(node); + for (List> nodes: targets) { + Function function = extractFunctionEntity(nodes); // These operations are invariant by // nature and should not be overridden function.setFile(file); @@ -149,21 +169,59 @@ protected List extractFunctionEntities(File file) { return functions; } - protected Function extractFunctionEntity(Node node) { + protected Function extractFunctionEntity(List> nodes) { + Node target = nodes.stream() + .filter(tuple -> tuple.getKey().equals("target")) + .map(Tuple::getValue) + .findFirst() + .orElseThrow(NoSuchElementException::new); + String content = nodes.stream() + .map(Tuple::getValue) + .map(node -> nodePrinter.print(node)) + .collect(new DelimiterSuffixedStringCollector("\n")); + String ast = nodes.stream() + .map(Tuple::getValue) + .map(node -> syntaxTreePrinter.print(node)) + .collect(new DelimiterSuffixedStringCollector("\n")); + String sExp = nodes.stream() + .map(Tuple::getValue) + .map(node -> sExpressionPrinter.print(node)) + .collect(new DelimiterSuffixedStringCollector(" ")); + + Long sumCodeTokens = nodes.stream() + .map(Tuple::getValue) + .mapToLong(node -> codeTokenCounter.count(node)) + .sum(); + Long sumTotalTokens = nodes.stream() + .map(Tuple::getValue) + .mapToLong(node -> totalTokenCounter.count(node)) + .sum(); + Long sumLines = nodes.stream() + .map(Tuple::getValue) + .mapToLong(node -> lineCounter.count(node)) + .sum(); + Long sumCharacters = nodes.stream() + .map(Tuple::getValue) + .mapToLong(node -> characterCounter.count(node)) + .sum(); + boolean anyContainsNonAscii = nodes.stream() + .map(Tuple::getValue) + .anyMatch(node -> containsNonAscii.test(node)); + return Function.builder() .repo(localClone.getGitRepo()) - .content(nodePrinter.print(node)) - .contentHash(contentHasher.hash(node)) - .ast(syntaxTreePrinter.print(node)) - .astHash(syntaxTreeHasher.hash(node)) - .sExpression("(sexp " + sExpressionPrinter.print(node) + ")") - .totalTokens(totalTokenCounter.count(node)) - .codeTokens(codeTokenCounter.count(node)) - .lines(lineCounter.count(node)) - .characters(characterCounter.count(node)) - .containsNonAscii(containsNonAscii.test(node)) - .containsError(containsError.test(node)) - .boilerplateType(boilerplateEnumerator.asEnum(node)) + .ast(ast) + .content(content) + .astHash(syntaxTreeHasher.hash(target)) + .contentHash(contentHasher.hash(target)) + .sExpression("(sexp " + sExp + ")") + .totalTokens(sumTotalTokens) + .codeTokens(sumCodeTokens) + .lines(sumLines) + .characters(sumCharacters) + .containsNonAscii(anyContainsNonAscii) + .containsError(containsError.test(target)) + .boilerplateType(boilerplateEnumerator.asEnum(target)) .build(); } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java index 9aa2b135..5426bbe7 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java @@ -2,17 +2,19 @@ import usi.si.seart.analyzer.enumerator.JavaBoilerplateEnumerator; import usi.si.seart.analyzer.predicate.JavaTestFilePredicate; -import usi.si.seart.analyzer.query.JavaSingleCaptureQueries; +import usi.si.seart.analyzer.query.multi.JavaMultiCaptureQueries; +import usi.si.seart.analyzer.query.single.JavaSingleCaptureQueries; import usi.si.seart.treesitter.Language; import java.nio.file.Path; -public class JavaAnalyzer extends PreviousCommentsAnalyzer { +public class JavaAnalyzer extends AbstractAnalyzer { public JavaAnalyzer(LocalClone localClone, Path path) { super(localClone, path, Language.JAVA); this.testFilePredicate = new JavaTestFilePredicate(); - this.queries = new JavaSingleCaptureQueries(); + this.singleCaptureQueries = new JavaSingleCaptureQueries(); + this.multiCaptureQueries = new JavaMultiCaptureQueries(); this.boilerplateEnumerator = new JavaBoilerplateEnumerator(this::getSourceBytes); } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PreviousCommentsAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PreviousCommentsAnalyzer.java deleted file mode 100644 index d11e94bb..00000000 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PreviousCommentsAnalyzer.java +++ /dev/null @@ -1,61 +0,0 @@ -package usi.si.seart.analyzer; - -import usi.si.seart.analyzer.traverser.PreviousCommentTraverser; -import usi.si.seart.analyzer.traverser.Traverser; -import usi.si.seart.analyzer.util.stream.DelimiterSuffixedStringCollector; -import usi.si.seart.model.code.Function; -import usi.si.seart.treesitter.Language; -import usi.si.seart.treesitter.Node; - -import java.nio.file.Path; -import java.util.List; - -public abstract class PreviousCommentsAnalyzer extends AbstractAnalyzer { - - protected Traverser> previousCommentTraverser = new PreviousCommentTraverser(); - - protected PreviousCommentsAnalyzer(LocalClone localClone, Path path, Language language) { - super(localClone, path, language); - } - - @Override - protected Function extractFunctionEntity(Node node) { - List comments = previousCommentTraverser.getNodes(node); - String doc = comments.stream() - .map(comment -> nodePrinter.print(comment)) - .collect(new DelimiterSuffixedStringCollector("\n")); - String docAst = comments.stream() - .map(comment -> syntaxTreePrinter.print(comment)) - .collect(new DelimiterSuffixedStringCollector("\n")); - String docSExpression = comments.stream() - .map(comment -> sExpressionPrinter.print(comment)) - .collect(new DelimiterSuffixedStringCollector(" ")); - Long docLines = comments.stream() - .mapToLong(comment -> lineCounter.count(comment)) - .sum(); - Long docTotalTokens = comments.stream() - .mapToLong(comment -> totalTokenCounter.count(comment)) - .sum(); - Long docCharacters = comments.stream() - .mapToLong(comment -> characterCounter.count(comment)) - .sum(); - boolean docContainsNonAscii = comments.stream() - .anyMatch(comment -> containsNonAscii.test(comment)); - - return Function.builder() - .repo(localClone.getGitRepo()) - .content(doc + nodePrinter.print(node)) - .contentHash(contentHasher.hash(node)) - .ast(docAst + syntaxTreePrinter.print(node)) - .astHash(syntaxTreeHasher.hash(node)) - .sExpression("(sexp " + docSExpression + sExpressionPrinter.print(node)+")") - .totalTokens(docTotalTokens + totalTokenCounter.count(node)) - .codeTokens(codeTokenCounter.count(node)) - .lines(docLines + lineCounter.count(node)) - .characters(docCharacters + characterCounter.count(node)) - .containsNonAscii(docContainsNonAscii || containsNonAscii.test(node)) - .containsError(containsError.test(node)) - .boilerplateType(boilerplateEnumerator.asEnum(node)) - .build(); - } -} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java new file mode 100644 index 00000000..321d9445 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java @@ -0,0 +1,19 @@ +package usi.si.seart.analyzer; + +import usi.si.seart.analyzer.predicate.PythonTestFilePredicate; +import usi.si.seart.analyzer.query.multi.PythonMultiCaptureQueries; +import usi.si.seart.analyzer.query.single.PythonSingleCaptureQueries; +import usi.si.seart.treesitter.Language; + +import java.nio.file.Path; + +public class PythonAnalyzer extends AbstractAnalyzer { + + public PythonAnalyzer(LocalClone localClone, Path path) { + super(localClone, path, Language.PYTHON); + this.testFilePredicate = new PythonTestFilePredicate(); + this.singleCaptureQueries = new PythonSingleCaptureQueries(); + this.multiCaptureQueries = new PythonMultiCaptureQueries(); + // this.boilerplateEnumerator = new PythonBoilerplateEnumerator(this::getSourceBytes); + } +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/Queries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/Queries.java index 812d0157..8c6bfb4e 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/Queries.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/Queries.java @@ -1,11 +1,19 @@ package usi.si.seart.analyzer.query; import usi.si.seart.treesitter.Node; +import usi.si.seart.treesitter.Query; -import java.util.Collection; +import java.util.List; -public interface Queries> { - C getNodes(Node node); - C getComments(Node node); - C getCallableDeclarations(Node node); +public interface Queries> { + + default void verify(Query query) { + if (!query.hasCaptures()) { + throw new IllegalArgumentException( + "Queries must contain at least one capture!" + ); + } + } + + C execute(Node node, String pattern); } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/Validated.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/Validated.java deleted file mode 100644 index c69833d2..00000000 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/Validated.java +++ /dev/null @@ -1,21 +0,0 @@ -package usi.si.seart.analyzer.query; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public interface Validated { - - Pattern CAPTURE_PATTERN = Pattern.compile("@[A-Za-z0-9_]+"); - - default void validate(String sExpr, String message) { - int count = 0; - Matcher matcher = CAPTURE_PATTERN.matcher(sExpr); - while (matcher.find()) count++; - if (!isPastThreshold(count)) - throw new IllegalArgumentException(message); - } - - default boolean isPastThreshold(int count) { - return count >= 0; - } -} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/JavaMultiCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/JavaMultiCaptureQueries.java new file mode 100644 index 00000000..1cb7889e --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/JavaMultiCaptureQueries.java @@ -0,0 +1,37 @@ +package usi.si.seart.analyzer.query.multi; + +import usi.si.seart.analyzer.util.Tuple; +import usi.si.seart.treesitter.Language; +import usi.si.seart.treesitter.Node; + +import java.util.List; + +/** + * @see + * + * Query Syntax - Alternations + * + * @see + * + * Query Syntax - Anchors + * + */ +public class JavaMultiCaptureQueries extends MultiCaptureQueries { + + public JavaMultiCaptureQueries() { + super(Language.JAVA); + } + + @Override + public List>> getCallableDeclarations(Node node) { + return execute( + node, + "(" + + "[(line_comment)(block_comment)]* @additional . (method_declaration) @target" + + ")" + + "(" + + "[(line_comment)(block_comment)]* @additional . (constructor_declaration) @target" + + ")" + ); + } +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java new file mode 100644 index 00000000..6206c666 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java @@ -0,0 +1,45 @@ +package usi.si.seart.analyzer.query.multi; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Cleanup; +import usi.si.seart.analyzer.query.Queries; +import usi.si.seart.analyzer.util.Tuple; +import usi.si.seart.treesitter.Language; +import usi.si.seart.treesitter.Node; +import usi.si.seart.treesitter.Query; +import usi.si.seart.treesitter.QueryCapture; +import usi.si.seart.treesitter.QueryCursor; +import usi.si.seart.treesitter.QueryMatch; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +@AllArgsConstructor(access = AccessLevel.PROTECTED) +public abstract class MultiCaptureQueries implements Queries>>> { + + private final Language language; + + public abstract List>> getCallableDeclarations(Node node); + + public List>> execute(Node node, String pattern) { + @Cleanup Query query = new Query(language, pattern); + verify(query); + @Cleanup QueryCursor cursor = new QueryCursor(node, query); + Stream matches = StreamSupport.stream(cursor.spliterator(), false); + return matches.map(match -> { + QueryCapture[] captures = match.getCaptures(); + List> tuples = new ArrayList<>(captures.length); + for (QueryCapture capture: captures) { + Node capturedNode = capture.getNode(); + String captureName = query.getCaptureName(capture); + Tuple tuple = Tuple.of(captureName, capturedNode); + tuples.add(tuple); + } + return tuples; + }).collect(Collectors.toList()); + } +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/PythonMultiCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/PythonMultiCaptureQueries.java new file mode 100644 index 00000000..d48c1044 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/PythonMultiCaptureQueries.java @@ -0,0 +1,26 @@ +package usi.si.seart.analyzer.query.multi; + +import usi.si.seart.analyzer.util.Tuple; +import usi.si.seart.treesitter.Language; +import usi.si.seart.treesitter.Node; + +import java.util.List; + +/** + * @see + * + * Query Syntax - Wildcard Node + * + * @see PEP 318 - Decorators for Functions and Methods + */ +public class PythonMultiCaptureQueries extends MultiCaptureQueries { + + public PythonMultiCaptureQueries() { + super(Language.PYTHON); + } + + @Override + public List>> getCallableDeclarations(Node node) { + return execute(node, "(_ (decorator)* @additional (function_definition) @target)"); + } +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/JavaSingleCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/JavaSingleCaptureQueries.java similarity index 65% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/JavaSingleCaptureQueries.java rename to dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/JavaSingleCaptureQueries.java index 9e8d3e03..7efffa00 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/JavaSingleCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/JavaSingleCaptureQueries.java @@ -1,10 +1,16 @@ -package usi.si.seart.analyzer.query; +package usi.si.seart.analyzer.query.single; import usi.si.seart.treesitter.Language; import usi.si.seart.treesitter.Node; import java.util.List; +/** + * @see + * + * Query Syntax - Alternations + * + */ public class JavaSingleCaptureQueries extends SingleCaptureQueries { public JavaSingleCaptureQueries() { @@ -15,9 +21,4 @@ public JavaSingleCaptureQueries() { public List getComments(Node node) { return execute(node, "[(line_comment) (block_comment)] @comment"); } - - @Override - public List getCallableDeclarations(Node node) { - return execute(node, "[(constructor_declaration) (method_declaration)] @declaration"); - } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/PythonSingleCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/PythonSingleCaptureQueries.java similarity index 71% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/PythonSingleCaptureQueries.java rename to dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/PythonSingleCaptureQueries.java index f0827d11..69a9a98f 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/PythonSingleCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/PythonSingleCaptureQueries.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.query; +package usi.si.seart.analyzer.query.single; import usi.si.seart.treesitter.Language; import usi.si.seart.treesitter.Node; @@ -6,15 +6,23 @@ import java.util.List; /** + * @see + * + * Query Syntax - Alternations + * * @see * * Query Syntax - Anchors * + * @see + * + * Query Syntax - Wildcard Node + * * @see PEP 257 – Docstring Conventions */ public class PythonSingleCaptureQueries extends SingleCaptureQueries { - protected PythonSingleCaptureQueries() { + public PythonSingleCaptureQueries() { super(Language.PYTHON); } @@ -30,9 +38,4 @@ public List getComments(Node node) { "]" ); } - - @Override - public List getCallableDeclarations(Node node) { - return execute(node, "(function_definition) @definition"); - } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/SingleCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/SingleCaptureQueries.java similarity index 68% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/SingleCaptureQueries.java rename to dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/SingleCaptureQueries.java index 26c6e120..ed98569a 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/SingleCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/SingleCaptureQueries.java @@ -1,8 +1,9 @@ -package usi.si.seart.analyzer.query; +package usi.si.seart.analyzer.query.single; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Cleanup; +import usi.si.seart.analyzer.query.Queries; import usi.si.seart.treesitter.Language; import usi.si.seart.treesitter.Node; import usi.si.seart.treesitter.Query; @@ -17,18 +18,15 @@ import java.util.stream.StreamSupport; @AllArgsConstructor(access = AccessLevel.PROTECTED) -public abstract class SingleCaptureQueries implements Queries>, Validated { +public abstract class SingleCaptureQueries implements Queries> { private final Language language; - @Override - public List getNodes(Node node) { - return execute(node, "(_) @node"); - } + public abstract List getComments(Node node); - protected List execute(Node node, String sExpr) { - validate(sExpr, "Queries must contain at least one capture!"); - @Cleanup Query query = new Query(language, sExpr); + public List execute(Node node, String pattern) { + @Cleanup Query query = new Query(language, pattern); + verify(query); @Cleanup QueryCursor cursor = new QueryCursor(node, query); Stream matches = StreamSupport.stream(cursor.spliterator(), false); return matches.map(QueryMatch::getCaptures) @@ -36,9 +34,4 @@ protected List execute(Node node, String sExpr) { .map(QueryCapture::getNode) .collect(Collectors.toList()); } - - @Override - public boolean isPastThreshold(int count) { - return count >= 1; - } } From 68b4556114468f057fa2243abba4c7c1e718fb2c Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 25 Jan 2023 11:07:09 +0100 Subject: [PATCH 0106/1089] All matched nodes are now checked for errors Although this is not necessary in Java, in Python this is necessary for cases such as: ```python @start_date. @start_date.setter def start_date(self, value): self._start_date = date.fromisoformat(value) ``` The previous version would only check for errors in the definition, but not the decorators, which are part of the definition. This is no longer the case. --- .../main/java/usi/si/seart/analyzer/AbstractAnalyzer.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java index fa2f87b1..a94e20c9 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java @@ -207,6 +207,9 @@ protected Function extractFunctionEntity(List> nodes) { boolean anyContainsNonAscii = nodes.stream() .map(Tuple::getValue) .anyMatch(node -> containsNonAscii.test(node)); + boolean anyContainsError = nodes.stream() + .map(Tuple::getValue) + .anyMatch(node -> containsError.test(node)); return Function.builder() .repo(localClone.getGitRepo()) @@ -220,7 +223,7 @@ protected Function extractFunctionEntity(List> nodes) { .lines(sumLines) .characters(sumCharacters) .containsNonAscii(anyContainsNonAscii) - .containsError(containsError.test(target)) + .containsError(anyContainsError) .boilerplateType(boilerplateEnumerator.asEnum(target)) .build(); } From 500ea8d548dce52decb9444c79c98a33061acd5d Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 25 Jan 2023 11:48:57 +0100 Subject: [PATCH 0107/1089] `Point` now has a generated `equals` and `hashCode` method --- .../src/main/java/usi/si/seart/treesitter/Point.java | 1 + 1 file changed, 1 insertion(+) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Point.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Point.java index 405ab050..44e81158 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Point.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Point.java @@ -8,6 +8,7 @@ @Getter @AllArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +@EqualsAndHashCode public class Point { int row; From bdb81acff672a266f4db120d89b7c88b1456d238 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 25 Jan 2023 11:57:52 +0100 Subject: [PATCH 0108/1089] Added `isOrigin` method to `Point` --- .../java/usi/si/seart/treesitter/Point.java | 4 ++++ .../usi/si/seart/treesitter/PointTest.java | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/PointTest.java diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Point.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Point.java index 44e81158..c2bc9808 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Point.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Point.java @@ -18,4 +18,8 @@ public class Point { public String toString() { return row + ":" + column; } + + public boolean isOrigin() { + return row == 0 && column == 0; + } } diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/PointTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/PointTest.java new file mode 100644 index 00000000..7a5ca833 --- /dev/null +++ b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/PointTest.java @@ -0,0 +1,18 @@ +package usi.si.seart.treesitter; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class PointTest { + + @Test + void testIsOrigin() { + Assertions.assertTrue(new Point(0, 0).isOrigin()); + Assertions.assertFalse(new Point(1, 0).isOrigin()); + Assertions.assertFalse(new Point(0, 1).isOrigin()); + Assertions.assertFalse(new Point(1, 1).isOrigin()); + Assertions.assertFalse(new Point(-1, 0).isOrigin()); + Assertions.assertFalse(new Point(0, -1).isOrigin()); + Assertions.assertFalse(new Point(-1, -1).isOrigin()); + } +} \ No newline at end of file From 53be1b176f4d3a9dc8baafe2b80ad16c7bc38a3f Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 25 Jan 2023 11:59:40 +0100 Subject: [PATCH 0109/1089] Separated `printTest` of `SyntaxTreePrinterTest` into two cases --- .../seart/analyzer/printer/SyntaxTreePrinterTest.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java index a819b60b..1f5c8c49 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java @@ -8,7 +8,7 @@ class SyntaxTreePrinterTest extends BaseTest { @Test - void printTest() { + void printRootTest() { Printer printer = new SyntaxTreePrinter(); Node root = tree.getRootNode(); String actual = printer.print(root); @@ -45,10 +45,15 @@ void printTest() { " arguments: argument_list [5:26] - [5:43]\n" + " string_literal [5:27] - [5:42]\n"; Assertions.assertEquals(expected, actual); + } + @Test + void printChildTest() { + Printer printer = new SyntaxTreePrinter(); + Node root = tree.getRootNode(); Node method = root.getChild(1).getChildByFieldName("body").getChild(1); - actual = printer.print(method); - expected = + String actual = printer.print(method); + String expected = "method_declaration [3:4] - [6:5]\n" + " modifiers [3:4] - [3:17]\n" + " type: void_type [3:18] - [3:22]\n" + From 38c3e936234282bc0f1bd06c4e8e49ee0444c9d2 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 25 Jan 2023 12:15:09 +0100 Subject: [PATCH 0110/1089] `Point` and `TreeCursorNode` are now mutable at package level --- .../src/main/java/usi/si/seart/treesitter/Point.java | 5 ++++- .../main/java/usi/si/seart/treesitter/TreeCursorNode.java | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Point.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Point.java index c2bc9808..6149be19 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Point.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Point.java @@ -2,12 +2,15 @@ import lombok.AccessLevel; import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; import lombok.Getter; +import lombok.Setter; import lombok.experimental.FieldDefaults; @Getter +@Setter(value = AccessLevel.PACKAGE) @AllArgsConstructor -@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +@FieldDefaults(level = AccessLevel.PRIVATE) @EqualsAndHashCode public class Point { diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursorNode.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursorNode.java index 3a986c5e..16ef6069 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursorNode.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursorNode.java @@ -3,11 +3,13 @@ import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.Setter; import lombok.experimental.FieldDefaults; @Getter +@Setter(value = AccessLevel.PACKAGE) @AllArgsConstructor(access = AccessLevel.PACKAGE) -@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +@FieldDefaults(level = AccessLevel.PRIVATE) public class TreeCursorNode { String type; From b902030983adab135e067dae4abbb4db7751e050 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 25 Jan 2023 12:15:47 +0100 Subject: [PATCH 0111/1089] `SyntaxTreePrinter` now permits offset recalculations --- .../seart/treesitter/SyntaxTreePrinter.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/SyntaxTreePrinter.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/SyntaxTreePrinter.java index e14fc1db..4b57195c 100644 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/SyntaxTreePrinter.java +++ b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/SyntaxTreePrinter.java @@ -14,6 +14,12 @@ public class SyntaxTreePrinter { int depth = 0; final Node node; + Point offset = new Point(0, 0); + + public SyntaxTreePrinter(Node node, Point offset) { + this.node = node; + this.offset = offset; + } /** * @return A string representation of the subtree. Consists only of named nodes. @@ -25,6 +31,7 @@ public String printSubtree() { for (;;) { TreeCursorNode cursorNode = cursor.getCurrentTreeCursorNode(); if (cursorNode.isNamed()) { + recalculatePosition(cursorNode); String indentation = " ".repeat(depth); stringBuilder .append(indentation) @@ -38,6 +45,21 @@ public String printSubtree() { } } + private void recalculatePosition(TreeCursorNode cursorNode) { + if (!offset.isOrigin()) { + Point cursorStartPoint = cursorNode.getStartPoint(); + Point cursorEndPoint = cursorNode.getEndPoint(); + + int rowOffset = offset.getRow(); + cursorStartPoint.setRow(cursorStartPoint.getRow() + rowOffset); + cursorEndPoint.setRow(cursorEndPoint.getRow() + rowOffset); + + int columnOffset = offset.getColumn(); + cursorStartPoint.setColumn(cursorStartPoint.getColumn() + columnOffset); + cursorEndPoint.setColumn(cursorEndPoint.getColumn() + columnOffset); + } + } + private final class TreePrinterCursor extends TreeCursor { private TreePrinterCursor(Node node) { From 941a6df9fbef4ac8907a3f455d1759e86733679d Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 25 Jan 2023 12:16:29 +0100 Subject: [PATCH 0112/1089] Added `OffsetSyntaxTreePrinter` this will be needed when we introduce source wrappers for AST printing --- .../printer/OffsetSyntaxTreePrinter.java | 16 +++++ .../printer/OffsetSyntaxTreePrinterTest.java | 70 +++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinterTest.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java new file mode 100644 index 00000000..61dba03e --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java @@ -0,0 +1,16 @@ +package usi.si.seart.analyzer.printer; + +import lombok.AllArgsConstructor; +import usi.si.seart.treesitter.Node; +import usi.si.seart.treesitter.Point; + +@AllArgsConstructor +public class OffsetSyntaxTreePrinter implements Printer { + + private final Point offset; + + @Override + public String print(Node node) { + return new usi.si.seart.treesitter.SyntaxTreePrinter(node, offset).printSubtree(); + } +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinterTest.java new file mode 100644 index 00000000..a5b0cc5c --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinterTest.java @@ -0,0 +1,70 @@ +package usi.si.seart.analyzer.printer; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import usi.si.seart.analyzer.test.BaseTest; +import usi.si.seart.treesitter.Node; +import usi.si.seart.treesitter.Point; + +class OffsetSyntaxTreePrinterTest extends BaseTest { + + @Test + void idempotencyTest() { + Printer printer = new OffsetSyntaxTreePrinter(new Point(0, 0)); + Node root = tree.getRootNode(); + Node method = root.getChild(1).getChildByFieldName("body").getChild(1); + String actual = printer.print(method); + String expected = + "method_declaration [3:4] - [6:5]\n" + + " modifiers [3:4] - [3:17]\n" + + " type: void_type [3:18] - [3:22]\n" + + " name: identifier [3:23] - [3:27]\n" + + " parameters: formal_parameters [3:27] - [3:42]\n" + + " formal_parameter [3:28] - [3:41]\n" + + " type: array_type [3:28] - [3:36]\n" + + " element: type_identifier [3:28] - [3:34]\n" + + " dimensions: dimensions [3:34] - [3:36]\n" + + " name: identifier [3:37] - [3:41]\n" + + " body: block [3:43] - [6:5]\n" + + " line_comment [4:8] - [4:22]\n" + + " expression_statement [5:8] - [5:44]\n" + + " method_invocation [5:8] - [5:43]\n" + + " object: field_access [5:8] - [5:18]\n" + + " object: identifier [5:8] - [5:14]\n" + + " field: identifier [5:15] - [5:18]\n" + + " name: identifier [5:19] - [5:26]\n" + + " arguments: argument_list [5:26] - [5:43]\n" + + " string_literal [5:27] - [5:42]\n"; + Assertions.assertEquals(expected, actual); + } + + @Test + void offsetTest() { + Printer printer = new OffsetSyntaxTreePrinter(new Point(-1, -2)); + Node root = tree.getRootNode(); + Node method = root.getChild(1).getChildByFieldName("body").getChild(1); + String actual = printer.print(method); + String expected = + "method_declaration [2:2] - [5:3]\n" + + " modifiers [2:2] - [2:15]\n" + + " type: void_type [2:16] - [2:20]\n" + + " name: identifier [2:21] - [2:25]\n" + + " parameters: formal_parameters [2:25] - [2:40]\n" + + " formal_parameter [2:26] - [2:39]\n" + + " type: array_type [2:26] - [2:34]\n" + + " element: type_identifier [2:26] - [2:32]\n" + + " dimensions: dimensions [2:32] - [2:34]\n" + + " name: identifier [2:35] - [2:39]\n" + + " body: block [2:41] - [5:3]\n" + + " line_comment [3:6] - [3:20]\n" + + " expression_statement [4:6] - [4:42]\n" + + " method_invocation [4:6] - [4:41]\n" + + " object: field_access [4:6] - [4:16]\n" + + " object: identifier [4:6] - [4:12]\n" + + " field: identifier [4:13] - [4:16]\n" + + " name: identifier [4:17] - [4:24]\n" + + " arguments: argument_list [4:24] - [4:41]\n" + + " string_literal [4:25] - [4:40]\n"; + Assertions.assertEquals(expected, actual); + } +} \ No newline at end of file From ade47220785f2420d92b0acb2382ec414d098a24 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 25 Jan 2023 17:43:26 +0100 Subject: [PATCH 0113/1089] Expanded list of `Boilerplate` values --- .../enumerator/JavaBoilerplateEnumerator.java | 23 +++- .../JavaBoilerplateEnumeratorTest.java | 58 +++++--- .../java/usi/si/seart/parser/JavaParser.java | 15 ++- .../usi/si/seart/parser/JavaParserTest.java | 8 +- .../usi/si/seart/model/code/Boilerplate.java | 126 +++++++++++++++++- 5 files changed, 194 insertions(+), 36 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumerator.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumerator.java index 43fcc57f..ac064e6c 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumerator.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumerator.java @@ -22,11 +22,24 @@ public Boilerplate asEnum(Node node) { if (name.startsWith("set")) return Boilerplate.SETTER; if (name.startsWith("get")) return Boilerplate.GETTER; switch (name) { - case "builder": return Boilerplate.BUILDER; - case "equals": return Boilerplate.EQUALS; - case "hashCode": return Boilerplate.HASH_CODE; - case "toString": return Boilerplate.TO_STRING; - default: return null; + case "equals": + case "compareTo": + return Boilerplate.COMPARISON; + case "clone": + return Boilerplate.CLONER; + case "finalize": + return Boilerplate.FINALIZER; + case "hashCode": + return Boilerplate.HASHER; + case "readObject": + case "readObjectNoData": + return Boilerplate.DESERIALIZER; + case "toString": + return Boilerplate.STRING_CONVERSION; + case "writeObject": + return Boilerplate.SERIALIZER; + default: + return null; } } } diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java index 5c94a34b..a87518b7 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java @@ -20,10 +20,15 @@ protected String getInput() { " public void getI(int i) {}\n" + " public void setI() {}\n" + " public void setI(int i) {}\n" + - " public void builder() {}\n" + + " public void compareTo() {}\n" + " public void equals() {}\n" + " public void hashCode() {}\n" + " public void toString() {}\n" + + " public void writeObject() {}\n" + + " public void readObject() {}\n" + + " public void readObjectNoData() {}\n" + + " public void clone() {}\n" + + " public void finalize() {}\n" + " public void run() {}\n" + " public static void main(String[] args) {}\n" + "}"; @@ -37,27 +42,38 @@ void asEnumTest() { Node body = clazz.getChildByFieldName("body"); Node constructor_0 = body.getChild(1); Node constructor_1 = body.getChild(2); - Node method_0 = body.getChild(3); - Node method_1 = body.getChild(4); - Node method_2 = body.getChild(5); - Node method_3 = body.getChild(6); - Node method_4 = body.getChild(7); - Node method_5 = body.getChild(8); - Node method_6 = body.getChild(9); - Node method_7 = body.getChild(10); - Node method_8 = body.getChild(11); - Node method_9 = body.getChild(12); + Node method_00 = body.getChild(3); + Node method_01 = body.getChild(4); + Node method_02 = body.getChild(5); + Node method_03 = body.getChild(6); + Node method_04 = body.getChild(7); + Node method_05 = body.getChild(8); + Node method_06 = body.getChild(9); + Node method_07 = body.getChild(10); + Node method_08 = body.getChild(11); + Node method_09 = body.getChild(12); + Node method_10 = body.getChild(13); + Node method_11 = body.getChild(14); + Node method_12 = body.getChild(15); + Node method_13 = body.getChild(16); + Node method_14 = body.getChild(17); + Assertions.assertEquals(Boilerplate.CONSTRUCTOR, enumerator.asEnum(constructor_0)); Assertions.assertEquals(Boilerplate.CONSTRUCTOR, enumerator.asEnum(constructor_1)); - Assertions.assertEquals(Boilerplate.GETTER, enumerator.asEnum(method_0)); - Assertions.assertEquals(Boilerplate.GETTER, enumerator.asEnum(method_1)); - Assertions.assertEquals(Boilerplate.SETTER, enumerator.asEnum(method_2)); - Assertions.assertEquals(Boilerplate.SETTER, enumerator.asEnum(method_3)); - Assertions.assertEquals(Boilerplate.BUILDER, enumerator.asEnum(method_4)); - Assertions.assertEquals(Boilerplate.EQUALS, enumerator.asEnum(method_5)); - Assertions.assertEquals(Boilerplate.HASH_CODE, enumerator.asEnum(method_6)); - Assertions.assertEquals(Boilerplate.TO_STRING, enumerator.asEnum(method_7)); - Assertions.assertNull(enumerator.asEnum(method_8)); - Assertions.assertNull(enumerator.asEnum(method_9)); + Assertions.assertEquals(Boilerplate.GETTER, enumerator.asEnum(method_00)); + Assertions.assertEquals(Boilerplate.GETTER, enumerator.asEnum(method_01)); + Assertions.assertEquals(Boilerplate.SETTER, enumerator.asEnum(method_02)); + Assertions.assertEquals(Boilerplate.SETTER, enumerator.asEnum(method_03)); + Assertions.assertEquals(Boilerplate.COMPARISON, enumerator.asEnum(method_04)); + Assertions.assertEquals(Boilerplate.COMPARISON, enumerator.asEnum(method_05)); + Assertions.assertEquals(Boilerplate.HASHER, enumerator.asEnum(method_06)); + Assertions.assertEquals(Boilerplate.STRING_CONVERSION, enumerator.asEnum(method_07)); + Assertions.assertEquals(Boilerplate.SERIALIZER, enumerator.asEnum(method_08)); + Assertions.assertEquals(Boilerplate.DESERIALIZER, enumerator.asEnum(method_09)); + Assertions.assertEquals(Boilerplate.DESERIALIZER, enumerator.asEnum(method_10)); + Assertions.assertEquals(Boilerplate.CLONER, enumerator.asEnum(method_11)); + Assertions.assertEquals(Boilerplate.FINALIZER, enumerator.asEnum(method_12)); + Assertions.assertNull(enumerator.asEnum(method_13)); + Assertions.assertNull(enumerator.asEnum(method_14)); } } \ No newline at end of file diff --git a/dl4se-crawler/src/main/java/usi/si/seart/parser/JavaParser.java b/dl4se-crawler/src/main/java/usi/si/seart/parser/JavaParser.java index ba38e506..051cf383 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/parser/JavaParser.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/parser/JavaParser.java @@ -196,10 +196,17 @@ static Boilerplate getBoilerplateType(CallableDeclaration node) { if (name.startsWith("set")) return Boilerplate.SETTER; if (name.startsWith("get")) return Boilerplate.GETTER; switch (name) { - case "builder": return Boilerplate.BUILDER; - case "equals": return Boilerplate.EQUALS; - case "hashCode": return Boilerplate.HASH_CODE; - case "toString": return Boilerplate.TO_STRING; + case "equals": + case "compareTo": + return Boilerplate.COMPARISON; + case "clone": return Boilerplate.CLONER; + case "finalize": return Boilerplate.FINALIZER; + case "hashCode": return Boilerplate.HASHER; + case "readObject": + case "readObjectNoData": + return Boilerplate.DESERIALIZER; + case "toString": return Boilerplate.STRING_CONVERSION; + case "writeObject": return Boilerplate.SERIALIZER; default: return null; } } diff --git a/dl4se-crawler/src/test/java/usi/si/seart/parser/JavaParserTest.java b/dl4se-crawler/src/test/java/usi/si/seart/parser/JavaParserTest.java index ef3e7f7a..336469b0 100644 --- a/dl4se-crawler/src/test/java/usi/si/seart/parser/JavaParserTest.java +++ b/dl4se-crawler/src/test/java/usi/si/seart/parser/JavaParserTest.java @@ -52,7 +52,6 @@ private static final class BoilerplateTypeArgumentProvider implements ArgumentsP MethodDeclaration md1 = StaticJavaParser.parseMethodDeclaration("public void method(){}"); MethodDeclaration md2 = StaticJavaParser.parseMethodDeclaration("public void setX(){}"); MethodDeclaration md3 = StaticJavaParser.parseMethodDeclaration("public void getX(){}"); - MethodDeclaration md4 = StaticJavaParser.parseMethodDeclaration("public void builder(){}"); MethodDeclaration md5 = StaticJavaParser.parseMethodDeclaration("public void toString(){}"); MethodDeclaration md6 = StaticJavaParser.parseMethodDeclaration("public void equals(){}"); MethodDeclaration md7 = StaticJavaParser.parseMethodDeclaration("public void hashCode(){}"); @@ -64,10 +63,9 @@ public Stream provideArguments(ExtensionContext context) { Arguments.of(md1, null), Arguments.of(md2, Boilerplate.SETTER), Arguments.of(md3, Boilerplate.GETTER), - Arguments.of(md4, Boilerplate.BUILDER), - Arguments.of(md5, Boilerplate.TO_STRING), - Arguments.of(md6, Boilerplate.EQUALS), - Arguments.of(md7, Boilerplate.HASH_CODE), + Arguments.of(md5, Boilerplate.STRING_CONVERSION), + Arguments.of(md6, Boilerplate.COMPARISON), + Arguments.of(md7, Boilerplate.HASHER), Arguments.of(cd, Boilerplate.CONSTRUCTOR) ); } diff --git a/dl4se-model/src/main/java/usi/si/seart/model/code/Boilerplate.java b/dl4se-model/src/main/java/usi/si/seart/model/code/Boilerplate.java index 93c87efd..92219773 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/code/Boilerplate.java +++ b/dl4se-model/src/main/java/usi/si/seart/model/code/Boilerplate.java @@ -2,8 +2,132 @@ import java.util.Optional; +/** + * @see Comparable#compareTo(Object) + * @see Object#clone() + * @see Object#equals(Object) + * @see Object#hashCode() + * @see Object#toString() + * @see + * + * Interface Serializable + * + * @see + * + * The Python Language Reference - Data model + * + */ public enum Boilerplate { - CONSTRUCTOR, GETTER, SETTER, TO_STRING, EQUALS, HASH_CODE, BUILDER; + + /** + * Methods that create new class instances. + */ + CONSTRUCTOR, + /** + * Methods that initialize member values of new class instances. + */ + INITIALIZER, + /** + * Methods that retrieve instance member values. + */ + GETTER, + /** + * Methods that mutate instance member values. + */ + SETTER, + /** + * Methods that print the instance out as a string. + */ + STRING_CONVERSION, + /** + * Methods that return a string representation of the instance. + */ + STRING_REPRESENTATION, + /** + * Includes implementations of methods that + * return a hash value for an object instance. + */ + HASHER, + /** + * Includes implementations of instance comparison operations: + *
    + *
  • Equality
  • + *
  • Less-than
  • + *
  • Greater-than
  • + *
  • Less-than-or-equal
  • + *
  • Greater-than-or-equal
  • + *
+ * for arbitrary types. + */ + COMPARISON, + /** + * Includes implementations of instance: + *
    + *
  • Round
  • + *
  • Floor
  • + *
  • Ceiling
  • + *
  • Truncation
  • + *
  • Negative
  • + *
  • Positive
  • + *
  • Absolute
  • + *
  • Invert
  • + *
+ * for arbitrary types. + */ + UNARY_ARITHMETIC, + /** + * Includes implementations of instance: + *
    + *
  • Addition
  • + *
  • Subtraction
  • + *
  • Multiplication
  • + *
  • Division
  • + *
  • Modulo
  • + *
  • Power
  • + *
  • Shift
  • + *
  • And
  • + *
  • Xor
  • + *
  • Or
  • + *
+ * for arbitrary types. + */ + BINARY_ARITHMETIC, + /** + * Includes implementations of the following assignment operations: + *
    + *
  • {@code +=}
  • + *
  • {@code -=}
  • + *
  • {@code *=}
  • + *
  • {@code @=}
  • + *
  • {@code /=}
  • + *
  • {@code //=}
  • + *
  • {@code %=}
  • + *
  • {@code **=}
  • + *
  • {@code <<=}
  • + *
  • {@code >>=}
  • + *
  • {@code &=}
  • + *
  • {@code ^=}
  • + *
  • {@code |=}
  • + *
+ * for any arbitrary type. + */ + AUGMENTED_ASSIGNMENT, + /** + * Methods that return copies of the original instance. + */ + CLONER, + /** + * Methods called prior to instance garbage collection. + */ + FINALIZER, + /** + * Methods that convert the instance into a storable format. + */ + SERIALIZER, + /** + * Methods that reverse serialization. + */ + DESERIALIZER,; public static Boilerplate valueOfNullable(Object value) { return Optional.ofNullable(value) From 7e9a7e79a4398f55a70ce45b4d312e095090657b Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 26 Jan 2023 08:57:51 +0100 Subject: [PATCH 0114/1089] Formatting --- .../analyzer/query/multi/JavaMultiCaptureQueries.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/JavaMultiCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/JavaMultiCaptureQueries.java index 1cb7889e..d53f5315 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/JavaMultiCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/JavaMultiCaptureQueries.java @@ -26,12 +26,8 @@ public JavaMultiCaptureQueries() { public List>> getCallableDeclarations(Node node) { return execute( node, - "(" + - "[(line_comment)(block_comment)]* @additional . (method_declaration) @target" + - ")" + - "(" + - "[(line_comment)(block_comment)]* @additional . (constructor_declaration) @target" + - ")" + "([(line_comment)(block_comment)]* @additional . (method_declaration) @target)" + + "([(line_comment)(block_comment)]* @additional . (constructor_declaration) @target)" ); } } From 11aa3ca592f4fbcbc86fe5506f5fc40cc9315c33 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 26 Jan 2023 09:19:53 +0100 Subject: [PATCH 0115/1089] `Hasher` now supports multiple inputs This will be useful primarily in cases like python where we ignore the root nodes like `decorated_definition` --- .../si/seart/analyzer/hash/ContentHasher.java | 5 +---- .../usi/si/seart/analyzer/hash/Hasher.java | 4 ++++ .../si/seart/analyzer/hash/SHA256Hasher.java | 21 +++++++++++++++++++ .../seart/analyzer/hash/SyntaxTreeHasher.java | 6 +----- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java index f754c9ca..ab12abe4 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java @@ -17,7 +17,7 @@ public ContentHasher(NodeMapper mapper) { } @Override - public String hash(Node node) { + protected void update(Node node) { @Cleanup TreeCursor cursor = node.walk(); cursor.preorderTraversal(current -> { boolean leafNode = current.getChildCount() == 0; @@ -27,8 +27,5 @@ public String hash(Node node) { md.update(mapper.getBytesForRange(range)); } }); - - byte[] hash = md.digest(); - return bytesToHex(hash); } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/Hasher.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/Hasher.java index a134e18d..e4af7f98 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/Hasher.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/Hasher.java @@ -2,6 +2,10 @@ import usi.si.seart.treesitter.Node; +import java.util.Collection; + public interface Hasher { String hash(Node node); + String hash(Node... nodes); + String hash(Collection nodes); } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SHA256Hasher.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SHA256Hasher.java index c914f2a0..a8e2cf3a 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SHA256Hasher.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SHA256Hasher.java @@ -1,11 +1,13 @@ package usi.si.seart.analyzer.hash; import lombok.SneakyThrows; +import usi.si.seart.treesitter.Node; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.util.Collection; public abstract class SHA256Hasher implements Hasher { @@ -18,6 +20,25 @@ protected SHA256Hasher() { this.md = MessageDigest.getInstance("SHA-256"); } + protected abstract void update(Node node); + + @Override + public String hash(Node node) { + return hash(new Node[] { node }); + } + + @Override + public String hash(Collection nodes) { + return hash(nodes.toArray(new Node[0])); + } + + @Override + public String hash(Node... nodes) { + for (Node node: nodes) update(node); + byte[] hash = md.digest(); + return bytesToHex(hash); + } + static String bytesToHex(byte[] bytes) { StringBuilder hexBuilder = new StringBuilder(2 * bytes.length); for (byte b : bytes) { diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SyntaxTreeHasher.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SyntaxTreeHasher.java index d8e66ed9..af71f138 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SyntaxTreeHasher.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SyntaxTreeHasher.java @@ -10,8 +10,7 @@ public SyntaxTreeHasher() { super(); } - @Override - public String hash(Node node) { + protected void update(Node node) { @Cleanup TreeCursor cursor = node.walk(); cursor.preorderTraversal(current -> { boolean leafNode = current.getChildCount() == 0; @@ -22,8 +21,5 @@ public String hash(Node node) { md.update(bytes); } }); - - byte[] hash = md.digest(); - return bytesToHex(hash); } } From a262e4bca07c400f0a46207bed7dd7779ba194f4 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 26 Jan 2023 09:26:16 +0100 Subject: [PATCH 0116/1089] Variable renaming in favor of clarity --- .../si/seart/analyzer/AbstractAnalyzer.java | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java index a94e20c9..a0de014c 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java @@ -156,10 +156,10 @@ protected File extractFileEntity() { } protected List extractFunctionEntities(File file) { - List>> targets = multiCaptureQueries.getCallableDeclarations(tree.getRootNode()); - List functions = new ArrayList<>(targets.size()); - for (List> nodes: targets) { - Function function = extractFunctionEntity(nodes); + List>> matches = multiCaptureQueries.getCallableDeclarations(tree.getRootNode()); + List functions = new ArrayList<>(matches.size()); + for (List> match: matches) { + Function function = extractFunctionEntity(match); // These operations are invariant by // nature and should not be overridden function.setFile(file); @@ -169,45 +169,45 @@ protected List extractFunctionEntities(File file) { return functions; } - protected Function extractFunctionEntity(List> nodes) { - Node target = nodes.stream() + protected Function extractFunctionEntity(List> match) { + Node function = match.stream() .filter(tuple -> tuple.getKey().equals("target")) .map(Tuple::getValue) .findFirst() .orElseThrow(NoSuchElementException::new); - String content = nodes.stream() + String content = match.stream() .map(Tuple::getValue) .map(node -> nodePrinter.print(node)) .collect(new DelimiterSuffixedStringCollector("\n")); - String ast = nodes.stream() + String ast = match.stream() .map(Tuple::getValue) .map(node -> syntaxTreePrinter.print(node)) .collect(new DelimiterSuffixedStringCollector("\n")); - String sExp = nodes.stream() + String sExp = match.stream() .map(Tuple::getValue) .map(node -> sExpressionPrinter.print(node)) .collect(new DelimiterSuffixedStringCollector(" ")); - Long sumCodeTokens = nodes.stream() + Long sumCodeTokens = match.stream() .map(Tuple::getValue) .mapToLong(node -> codeTokenCounter.count(node)) .sum(); - Long sumTotalTokens = nodes.stream() + Long sumTotalTokens = match.stream() .map(Tuple::getValue) .mapToLong(node -> totalTokenCounter.count(node)) .sum(); - Long sumLines = nodes.stream() + Long sumLines = match.stream() .map(Tuple::getValue) .mapToLong(node -> lineCounter.count(node)) .sum(); - Long sumCharacters = nodes.stream() + Long sumCharacters = match.stream() .map(Tuple::getValue) .mapToLong(node -> characterCounter.count(node)) .sum(); - boolean anyContainsNonAscii = nodes.stream() + boolean anyContainsNonAscii = match.stream() .map(Tuple::getValue) .anyMatch(node -> containsNonAscii.test(node)); - boolean anyContainsError = nodes.stream() + boolean anyContainsError = match.stream() .map(Tuple::getValue) .anyMatch(node -> containsError.test(node)); @@ -215,8 +215,8 @@ protected Function extractFunctionEntity(List> nodes) { .repo(localClone.getGitRepo()) .ast(ast) .content(content) - .astHash(syntaxTreeHasher.hash(target)) - .contentHash(contentHasher.hash(target)) + .astHash(syntaxTreeHasher.hash(function)) + .contentHash(contentHasher.hash(function)) .sExpression("(sexp " + sExp + ")") .totalTokens(sumTotalTokens) .codeTokens(sumCodeTokens) @@ -224,7 +224,7 @@ protected Function extractFunctionEntity(List> nodes) { .characters(sumCharacters) .containsNonAscii(anyContainsNonAscii) .containsError(anyContainsError) - .boilerplateType(boilerplateEnumerator.asEnum(target)) + .boilerplateType(boilerplateEnumerator.asEnum(function)) .build(); } } From e8d82f46a8febb8cc1e1760af092ca9478f9b192 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 26 Jan 2023 10:09:32 +0100 Subject: [PATCH 0117/1089] Like `Hasher` before it, `Printer` now also supports multiple inputs --- .../seart/analyzer/printer/NodePrinter.java | 5 ++ .../si/seart/analyzer/printer/Printer.java | 21 ++++++++ .../analyzer/printer/SExpressionPrinter.java | 8 +++ .../analyzer/printer/NodePrinterTest.java | 31 +++++++++-- .../printer/SExpressionPrinterTest.java | 54 +++++++++++++++++-- .../printer/SyntaxTreePrinterTest.java | 41 ++++++++++++++ 6 files changed, 154 insertions(+), 6 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java index 64951fad..a2e277ac 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java @@ -5,6 +5,7 @@ import usi.si.seart.treesitter.Range; import java.util.List; +import java.util.stream.Collector; import java.util.stream.Collectors; public class NodePrinter extends ContentPrinter { @@ -27,4 +28,8 @@ public String print(Node node) { return String.join("\n", lines); } + @Override + public Collector resultCollector() { + return Collectors.joining("\n"); + } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/Printer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/Printer.java index 93f51fe6..e8ff16a5 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/Printer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/Printer.java @@ -2,6 +2,27 @@ import usi.si.seart.treesitter.Node; +import java.util.Collection; +import java.util.stream.Collector; +import java.util.stream.Collectors; +import java.util.stream.Stream; + public interface Printer { String print(Node node); + + default String print(Node... nodes) { + return Stream.of(nodes) + .map(this::print) + .collect(resultCollector()); + } + + default String print(Collection nodes) { + return nodes.stream() + .map(this::print) + .collect(resultCollector()); + } + + default Collector resultCollector() { + return Collectors.joining(); + } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SExpressionPrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SExpressionPrinter.java index d16ddeff..7675f478 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SExpressionPrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SExpressionPrinter.java @@ -2,10 +2,18 @@ import usi.si.seart.treesitter.Node; +import java.util.stream.Collector; +import java.util.stream.Collectors; + public class SExpressionPrinter implements Printer { @Override public String print(Node node) { return node.getNodeString(); } + + @Override + public Collector resultCollector() { + return Collectors.joining(" "); + } } diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java index 86b15f6e..8cbda976 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java @@ -8,20 +8,45 @@ class NodePrinterTest extends BaseTest { @Test - void printTest() { + void printRootTest() { Printer printer = new NodePrinter(getNodeMapper()); Node root = tree.getRootNode(); String actual = printer.print(root); String expected = getInput(); Assertions.assertEquals(expected, actual); + } + @Test + void printChildTest() { + Printer printer = new NodePrinter(getNodeMapper()); + Node root = tree.getRootNode(); Node method = root.getChild(1).getChildByFieldName("body").getChild(1); - actual = printer.print(method); - expected = + String actual = printer.print(method); + String expected = "public static void main(String[] args) {\n" + " //line comment\n" + " System.out.println(\"Hello, World!\");\n" + "}"; Assertions.assertEquals(expected, actual); } + + @Test + void printMultipleTest() { + Printer printer = new NodePrinter(getNodeMapper()); + Node root = tree.getRootNode(); + Node package_declaration = root.getChild(0); + Node class_declaration = root.getChild(1); + String actual = printer.print(package_declaration, class_declaration); + // Extra newline is removed because information + // about spaces between nodes is not maintained + String expected = + "package ch.usi.si;\n" + + "public class Main {\n" + + " public static void main(String[] args) {\n" + + " //line comment\n" + + " System.out.println(\"Hello, World!\");\n" + + " }\n" + + "}"; + Assertions.assertEquals(expected, actual); + } } \ No newline at end of file diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SExpressionPrinterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SExpressionPrinterTest.java index 2817e0e1..a732f766 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SExpressionPrinterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SExpressionPrinterTest.java @@ -8,7 +8,7 @@ class SExpressionPrinterTest extends BaseTest { @Test - void printTest() { + void printRootTest() { Printer printer = new SExpressionPrinter(); Node root = tree.getRootNode(); String actual = printer.print(root); @@ -45,10 +45,15 @@ void printTest() { "arguments: (argument_list " + "(string_literal)))))))))"; Assertions.assertEquals(expected, actual); + } + @Test + void printChildTest() { + Printer printer = new SExpressionPrinter(); + Node root = tree.getRootNode(); Node method = root.getChild(1).getChildByFieldName("body").getChild(1); - actual = printer.print(method); - expected = + String actual = printer.print(method); + String expected = "(method_declaration " + "(modifiers) " + "type: (void_type) " + @@ -71,4 +76,47 @@ void printTest() { "(string_literal))))))"; Assertions.assertEquals(expected, actual); } + + @Test + void printMultipleTest() { + Printer printer = new SExpressionPrinter(); + Node root = tree.getRootNode(); + Node package_declaration = root.getChild(0); + Node class_declaration = root.getChild(1); + String actual = printer.print(package_declaration, class_declaration); + // The "program" root node is removed because + // we are printing its children individually + String expected = + "(package_declaration " + + "(scoped_identifier " + + "scope: (scoped_identifier " + + "scope: (identifier) " + + "name: (identifier)) " + + "name: (identifier))) " + + "(class_declaration " + + "(modifiers) " + + "name: (identifier) " + + "body: (class_body " + + "(method_declaration " + + "(modifiers) " + + "type: (void_type) " + + "name: (identifier) " + + "parameters: (formal_parameters " + + "(formal_parameter " + + "type: (array_type " + + "element: (type_identifier) " + + "dimensions: (dimensions)) " + + "name: (identifier))) " + + "body: (block " + + "(line_comment) " + + "(expression_statement " + + "(method_invocation " + + "object: (field_access " + + "object: (identifier) " + + "field: (identifier)) " + + "name: (identifier) " + + "arguments: (argument_list " + + "(string_literal))))))))"; + Assertions.assertEquals(expected, actual); + } } \ No newline at end of file diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java index 1f5c8c49..17080b76 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java @@ -76,4 +76,45 @@ void printChildTest() { " string_literal [5:27] - [5:42]\n"; Assertions.assertEquals(expected, actual); } + + @Test + void printMultipleTest() { + Printer printer = new SyntaxTreePrinter(); + Node root = tree.getRootNode(); + Node package_declaration = root.getChild(0); + Node class_declaration = root.getChild(1); + String actual = printer.print(package_declaration, class_declaration); + String expected = + "package_declaration [0:0] - [0:18]\n" + + " scoped_identifier [0:8] - [0:17]\n" + + " scope: scoped_identifier [0:8] - [0:14]\n" + + " scope: identifier [0:8] - [0:10]\n" + + " name: identifier [0:11] - [0:14]\n" + + " name: identifier [0:15] - [0:17]\n" + + "class_declaration [2:0] - [7:1]\n" + + " modifiers [2:0] - [2:6]\n" + + " name: identifier [2:13] - [2:17]\n" + + " body: class_body [2:18] - [7:1]\n" + + " method_declaration [3:4] - [6:5]\n" + + " modifiers [3:4] - [3:17]\n" + + " type: void_type [3:18] - [3:22]\n" + + " name: identifier [3:23] - [3:27]\n" + + " parameters: formal_parameters [3:27] - [3:42]\n" + + " formal_parameter [3:28] - [3:41]\n" + + " type: array_type [3:28] - [3:36]\n" + + " element: type_identifier [3:28] - [3:34]\n" + + " dimensions: dimensions [3:34] - [3:36]\n" + + " name: identifier [3:37] - [3:41]\n" + + " body: block [3:43] - [6:5]\n" + + " line_comment [4:8] - [4:22]\n" + + " expression_statement [5:8] - [5:44]\n" + + " method_invocation [5:8] - [5:43]\n" + + " object: field_access [5:8] - [5:18]\n" + + " object: identifier [5:8] - [5:14]\n" + + " field: identifier [5:15] - [5:18]\n" + + " name: identifier [5:19] - [5:26]\n" + + " arguments: argument_list [5:26] - [5:43]\n" + + " string_literal [5:27] - [5:42]\n"; + Assertions.assertEquals(expected, actual); + } } \ No newline at end of file From bcf1b85ff3ac0feee9b6224ed55854015559b6d1 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 26 Jan 2023 10:32:40 +0100 Subject: [PATCH 0118/1089] Improved `Printer` hierarchy by introducing top-level abstract class All concrete `Printer` implementations _must_ extend this abstract class, as it provides the implementation for the multi-target methods, as well as the protected `resultCollector` method. Why not leave the implementation as it was? I do not want the collector getter method to be part of the public API. --- .../analyzer/printer/AbstractPrinter.java | 29 +++++++++++++++++++ .../analyzer/printer/ContentPrinter.java | 2 +- .../printer/OffsetSyntaxTreePrinter.java | 2 +- .../si/seart/analyzer/printer/Printer.java | 21 ++------------ .../analyzer/printer/SExpressionPrinter.java | 2 +- .../analyzer/printer/SyntaxTreePrinter.java | 2 +- 6 files changed, 35 insertions(+), 23 deletions(-) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/AbstractPrinter.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/AbstractPrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/AbstractPrinter.java new file mode 100644 index 00000000..883d20e9 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/AbstractPrinter.java @@ -0,0 +1,29 @@ +package usi.si.seart.analyzer.printer; + +import usi.si.seart.treesitter.Node; + +import java.util.Collection; +import java.util.stream.Collector; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public abstract class AbstractPrinter implements Printer { + + @Override + public String print(Node... nodes) { + return Stream.of(nodes) + .map(this::print) + .collect(resultCollector()); + } + + @Override + public String print(Collection nodes) { + return nodes.stream() + .map(this::print) + .collect(resultCollector()); + } + + protected Collector resultCollector() { + return Collectors.joining(); + } +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/ContentPrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/ContentPrinter.java index 76cff436..50b6611d 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/ContentPrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/ContentPrinter.java @@ -2,7 +2,7 @@ import usi.si.seart.analyzer.NodeMapper; -public abstract class ContentPrinter implements Printer { +public abstract class ContentPrinter extends AbstractPrinter { protected final NodeMapper mapper; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java index 61dba03e..302c660e 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java @@ -5,7 +5,7 @@ import usi.si.seart.treesitter.Point; @AllArgsConstructor -public class OffsetSyntaxTreePrinter implements Printer { +public class OffsetSyntaxTreePrinter extends AbstractPrinter { private final Point offset; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/Printer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/Printer.java index e8ff16a5..d4e6a967 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/Printer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/Printer.java @@ -3,26 +3,9 @@ import usi.si.seart.treesitter.Node; import java.util.Collection; -import java.util.stream.Collector; -import java.util.stream.Collectors; -import java.util.stream.Stream; public interface Printer { String print(Node node); - - default String print(Node... nodes) { - return Stream.of(nodes) - .map(this::print) - .collect(resultCollector()); - } - - default String print(Collection nodes) { - return nodes.stream() - .map(this::print) - .collect(resultCollector()); - } - - default Collector resultCollector() { - return Collectors.joining(); - } + String print(Node... nodes); + String print(Collection nodes); } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SExpressionPrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SExpressionPrinter.java index 7675f478..20058961 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SExpressionPrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SExpressionPrinter.java @@ -5,7 +5,7 @@ import java.util.stream.Collector; import java.util.stream.Collectors; -public class SExpressionPrinter implements Printer { +public class SExpressionPrinter extends AbstractPrinter { @Override public String print(Node node) { diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java index e48e90fc..cbe21431 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java @@ -2,7 +2,7 @@ import usi.si.seart.treesitter.Node; -public class SyntaxTreePrinter implements Printer { +public class SyntaxTreePrinter extends AbstractPrinter { @Override public String print(Node node) { From 5ed04cfeb88fc4cedecdf692cb9805f12d772e13 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 26 Jan 2023 10:48:16 +0100 Subject: [PATCH 0119/1089] `Counter` now supports multi-node inputs like `Hasher` and `Printer` --- .../java/usi/si/seart/analyzer/count/Counter.java | 11 +++++++++++ .../seart/analyzer/count/CharacterCounterTest.java | 13 ++++++++++++- .../seart/analyzer/count/CodeTokenCounterTest.java | 13 ++++++++++++- .../si/seart/analyzer/count/LineCounterTest.java | 14 +++++++++++++- .../si/seart/analyzer/count/TokenCounterTest.java | 13 ++++++++++++- 5 files changed, 60 insertions(+), 4 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/Counter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/Counter.java index 24ef3463..e89ffd13 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/Counter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/Counter.java @@ -2,6 +2,17 @@ import usi.si.seart.treesitter.Node; +import java.util.Collection; +import java.util.stream.Stream; + public interface Counter { Long count(Node node); + + default Long count(Node... nodes) { + return Stream.of(nodes).mapToLong(this::count).sum(); + } + + default Long count(Collection nodes) { + return nodes.stream().mapToLong(this::count).sum(); + } } diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CharacterCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CharacterCounterTest.java index c3ef92ef..a8edff2c 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CharacterCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CharacterCounterTest.java @@ -3,11 +3,12 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import usi.si.seart.analyzer.test.BaseTest; +import usi.si.seart.treesitter.Node; class CharacterCounterTest extends BaseTest { @Test - void countTest(){ + void countRootTest(){ Counter counter = new CharacterCounter(getNodeMapper()); Long actual = counter.count(tree.getRootNode()); // Remove 2 for the space in string and comment @@ -16,4 +17,14 @@ void countTest(){ "Total number of characters should be equal to the joined tree string without spaces!" ); } + + @Test + void countChildrenTest() { + Counter counter = new CharacterCounter(getNodeMapper()); + Node root = tree.getRootNode(); + Node package_declaration = root.getChild(0); + Node class_declaration = root.getChild(1); + Long actual = counter.count(package_declaration, class_declaration); + Assertions.assertEquals(getJoinedTokens().length() - 2, actual); + } } \ No newline at end of file diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CodeTokenCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CodeTokenCounterTest.java index 5ef1c07b..3ea919b8 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CodeTokenCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CodeTokenCounterTest.java @@ -3,11 +3,12 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import usi.si.seart.analyzer.test.BaseTest; +import usi.si.seart.treesitter.Node; class CodeTokenCounterTest extends BaseTest { @Test - void countTest() { + void countRootTest() { Counter counter = new CodeTokenCounter(); Long actual = counter.count(tree.getRootNode()); // Remove 1 for the comment node @@ -16,4 +17,14 @@ void countTest() { "Total number of code tokens should be equal to the number of input tokens without the comments!" ); } + + @Test + void countChildrenTest() { + Counter counter = new CodeTokenCounter(); + Node root = tree.getRootNode(); + Node package_declaration = root.getChild(0); + Node class_declaration = root.getChild(1); + Long actual = counter.count(package_declaration, class_declaration); + Assertions.assertEquals(getNodes().size() - 1, actual, actual); + } } \ No newline at end of file diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/LineCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/LineCounterTest.java index 29de27a0..a61341e1 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/LineCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/LineCounterTest.java @@ -3,11 +3,12 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import usi.si.seart.analyzer.test.BaseTest; +import usi.si.seart.treesitter.Node; class LineCounterTest extends BaseTest { @Test - void countTest() { + void countRootTest() { Counter counter = new LineCounter(); Long actual = counter.count(tree.getRootNode()); Assertions.assertEquals( @@ -15,4 +16,15 @@ void countTest() { "Total number of lines should be equal to the number of lines reported by String method" ); } + + @Test + void countChildrenTest() { + Counter counter = new LineCounter(); + Node root = tree.getRootNode(); + Node package_declaration = root.getChild(0); + Node class_declaration = root.getChild(1); + Long actual = counter.count(package_declaration, class_declaration); + // Subtract one for the lost space between package and class + Assertions.assertEquals(getInput().lines().count() - 1, actual); + } } \ No newline at end of file diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/TokenCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/TokenCounterTest.java index 660b0433..d4f4d14e 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/TokenCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/TokenCounterTest.java @@ -3,11 +3,12 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import usi.si.seart.analyzer.test.BaseTest; +import usi.si.seart.treesitter.Node; class TokenCounterTest extends BaseTest { @Test - void countTest() { + void countRootTest() { Counter counter = new TokenCounter(getNodeMapper()); Long actual = counter.count(tree.getRootNode()); // Add 1 for the extra comment word @@ -16,4 +17,14 @@ void countTest() { "Total number of tokens should be equal to the number of input tokens including comment tokens (words)!" ); } + + @Test + void countChildrenTest() { + Counter counter = new TokenCounter(getNodeMapper()); + Node root = tree.getRootNode(); + Node package_declaration = root.getChild(0); + Node class_declaration = root.getChild(1); + Long actual = counter.count(package_declaration, class_declaration); + Assertions.assertEquals(getNodes().size() + 2, actual); + } } \ No newline at end of file From b09d1db33f1ca0938e7c15795788bbaab78e9b29 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 26 Jan 2023 11:00:30 +0100 Subject: [PATCH 0120/1089] Moved `TestFilePredicate` implementations into separate package --- .../analyzer/predicate/{ => path}/JavaTestFilePredicate.java | 2 +- .../analyzer/predicate/{ => path}/PythonTestFilePredicate.java | 2 +- .../seart/analyzer/predicate/{ => path}/TestFilePredicate.java | 2 +- .../predicate/{ => path}/JavaTestFilePredicateTest.java | 2 +- .../predicate/{ => path}/PythonTestFilePredicateTest.java | 2 +- .../analyzer/predicate/{ => path}/TestFilePredicateTest.java | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) rename dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/{ => path}/JavaTestFilePredicate.java (94%) rename dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/{ => path}/PythonTestFilePredicate.java (93%) rename dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/{ => path}/TestFilePredicate.java (90%) rename dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/{ => path}/JavaTestFilePredicateTest.java (97%) rename dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/{ => path}/PythonTestFilePredicateTest.java (97%) rename dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/{ => path}/TestFilePredicateTest.java (96%) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/JavaTestFilePredicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/path/JavaTestFilePredicate.java similarity index 94% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/JavaTestFilePredicate.java rename to dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/path/JavaTestFilePredicate.java index b2d8c19f..bd9515e9 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/JavaTestFilePredicate.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/path/JavaTestFilePredicate.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.predicate; +package usi.si.seart.analyzer.predicate.path; import java.nio.file.FileSystems; import java.nio.file.Path; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/PythonTestFilePredicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/path/PythonTestFilePredicate.java similarity index 93% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/PythonTestFilePredicate.java rename to dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/path/PythonTestFilePredicate.java index b3908092..b543dcf0 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/PythonTestFilePredicate.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/path/PythonTestFilePredicate.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.predicate; +package usi.si.seart.analyzer.predicate.path; import java.nio.file.FileSystems; import java.nio.file.Path; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/TestFilePredicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/path/TestFilePredicate.java similarity index 90% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/TestFilePredicate.java rename to dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/path/TestFilePredicate.java index 65c22e0f..64418cd8 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/TestFilePredicate.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/path/TestFilePredicate.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.predicate; +package usi.si.seart.analyzer.predicate.path; import java.nio.file.FileSystems; import java.nio.file.Path; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/JavaTestFilePredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/JavaTestFilePredicateTest.java similarity index 97% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/JavaTestFilePredicateTest.java rename to dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/JavaTestFilePredicateTest.java index bae7f094..6ce068b9 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/JavaTestFilePredicateTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/JavaTestFilePredicateTest.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.predicate; +package usi.si.seart.analyzer.predicate.path; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.extension.ExtensionContext; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/PythonTestFilePredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/PythonTestFilePredicateTest.java similarity index 97% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/PythonTestFilePredicateTest.java rename to dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/PythonTestFilePredicateTest.java index ca74c0cd..9459ddb5 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/PythonTestFilePredicateTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/PythonTestFilePredicateTest.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.predicate; +package usi.si.seart.analyzer.predicate.path; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.extension.ExtensionContext; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/TestFilePredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/TestFilePredicateTest.java similarity index 96% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/TestFilePredicateTest.java rename to dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/TestFilePredicateTest.java index bac724b9..dabb4c88 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/TestFilePredicateTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/TestFilePredicateTest.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.predicate; +package usi.si.seart.analyzer.predicate.path; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.extension.ExtensionContext; From f96cde1cf9fdb598536315ba3facff95a9026e06 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 26 Jan 2023 11:58:49 +0100 Subject: [PATCH 0121/1089] Introducing `NodePredicate` class This allows us to define methods for testing multiple nodes at a time. Note that by default, the results for individual matches are combined using `anyMatch`. --- .../predicate/ContainsErrorPredicate.java | 4 +-- .../predicate/ContainsNonAsciiPredicate.java | 2 +- .../analyzer/predicate/ContentPredicate.java | 15 ----------- .../predicate/NodeContentPredicate.java | 12 +++++++++ .../analyzer/predicate/NodePredicate.java | 19 +++++++++++++ .../predicate/ContainsErrorPredicateTest.java | 24 ++++++++++++----- .../ContainsNonAsciiPredicateTest.java | 27 ++++++++++++------- 7 files changed, 69 insertions(+), 34 deletions(-) delete mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContentPredicate.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/NodeContentPredicate.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/NodePredicate.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsErrorPredicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsErrorPredicate.java index 7e5adeb6..894fd0cd 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsErrorPredicate.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsErrorPredicate.java @@ -2,9 +2,7 @@ import usi.si.seart.treesitter.Node; -import java.util.function.Predicate; - -public class ContainsErrorPredicate implements Predicate { +public class ContainsErrorPredicate extends NodePredicate { @Override public boolean test(Node node) { diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiPredicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiPredicate.java index c6aa1a2b..0a857430 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiPredicate.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiPredicate.java @@ -4,7 +4,7 @@ import usi.si.seart.treesitter.Node; import usi.si.seart.treesitter.Range; -public class ContainsNonAsciiPredicate extends ContentPredicate { +public class ContainsNonAsciiPredicate extends NodeContentPredicate { public ContainsNonAsciiPredicate(NodeMapper mapper) { super(mapper); diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContentPredicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContentPredicate.java deleted file mode 100644 index fdad4e3c..00000000 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContentPredicate.java +++ /dev/null @@ -1,15 +0,0 @@ -package usi.si.seart.analyzer.predicate; - -import usi.si.seart.analyzer.NodeMapper; -import usi.si.seart.treesitter.Node; - -import java.util.function.Predicate; - -public abstract class ContentPredicate implements Predicate { - - protected final NodeMapper mapper; - - protected ContentPredicate(NodeMapper mapper) { - this.mapper = mapper; - } -} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/NodeContentPredicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/NodeContentPredicate.java new file mode 100644 index 00000000..52dcfe7b --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/NodeContentPredicate.java @@ -0,0 +1,12 @@ +package usi.si.seart.analyzer.predicate; + +import usi.si.seart.analyzer.NodeMapper; + +public abstract class NodeContentPredicate extends NodePredicate { + + protected final NodeMapper mapper; + + protected NodeContentPredicate(NodeMapper mapper) { + this.mapper = mapper; + } +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/NodePredicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/NodePredicate.java new file mode 100644 index 00000000..95b8da4b --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/NodePredicate.java @@ -0,0 +1,19 @@ +package usi.si.seart.analyzer.predicate; + +import usi.si.seart.treesitter.Node; + +import java.util.Collection; +import java.util.function.Predicate; +import java.util.stream.Stream; + +public abstract class NodePredicate implements Predicate { + public abstract boolean test(Node node); + + public boolean test(Node... nodes) { + return Stream.of(nodes).anyMatch(this); + } + + public boolean test(Collection nodes) { + return nodes.stream().anyMatch(this); + } +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsErrorPredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsErrorPredicateTest.java index 9c9f69cd..f722feba 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsErrorPredicateTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsErrorPredicateTest.java @@ -10,25 +10,37 @@ import usi.si.seart.treesitter.Tree; import java.io.UnsupportedEncodingException; -import java.util.function.Predicate; class ContainsErrorPredicateTest extends PredicateTest { + @Test + void containsNoErrorTest() { + NodePredicate predicate = new ContainsErrorPredicate(); + boolean result = predicate.test(tree.getRootNode()); + Assertions.assertFalse(result); + } + @Test @SneakyThrows(UnsupportedEncodingException.class) void containsErrorTest() { @Cleanup Parser parser = new Parser(Language.C); Tree error = parser.parseString(getInput()); Node root = error.getRootNode(); - Predicate predicate = new ContainsErrorPredicate(); + NodePredicate predicate = new ContainsErrorPredicate(); boolean result = predicate.test(root); Assertions.assertTrue(result); } @Test - void containsNoErrorTest() { - Predicate predicate = new ContainsErrorPredicate(); - boolean result = predicate.test(tree.getRootNode()); - Assertions.assertFalse(result); + @SneakyThrows(UnsupportedEncodingException.class) + void anyContainsErrorTest() { + @Cleanup Parser parser = new Parser(Language.C); + Tree error = parser.parseString(getInput()); + Node root = error.getRootNode(); + Node declaration = root.getChild(0); + Node function_definition = root.getChild(1); + NodePredicate predicate = new ContainsErrorPredicate(); + boolean result = predicate.test(declaration, function_definition); + Assertions.assertTrue(result); } } \ No newline at end of file diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiPredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiPredicateTest.java index 7d80f088..ef93cfae 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiPredicateTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiPredicateTest.java @@ -8,17 +8,9 @@ import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; -import java.util.function.Predicate; class ContainsNonAsciiPredicateTest extends PredicateTest { - @Test - void containsNonAsciiTest() { - Predicate predicate = new ContainsNonAsciiPredicate(getNodeMapper()); - boolean result = predicate.test(tree.getRootNode()); - Assertions.assertTrue(result); - } - @Test @SneakyThrows(UnsupportedEncodingException.class) void containsOnlyAsciiTest() { @@ -35,9 +27,26 @@ void containsOnlyAsciiTest() { " }\n" + "}"; byte[] bytes_2 = input_2.getBytes(StandardCharsets.UTF_16LE); - Predicate predicate = new ContainsNonAsciiPredicate(() -> bytes_2); + NodePredicate predicate = new ContainsNonAsciiPredicate(() -> bytes_2); Tree tree = parser.parseString(input_2); boolean result = predicate.test(tree.getRootNode()); Assertions.assertFalse(result); } + + @Test + void containsNonAsciiTest() { + NodePredicate predicate = new ContainsNonAsciiPredicate(getNodeMapper()); + boolean result = predicate.test(tree.getRootNode()); + Assertions.assertTrue(result); + } + + @Test + void anyContainsNonAscii() { + NodePredicate predicate = new ContainsNonAsciiPredicate(getNodeMapper()); + Node root = tree.getRootNode(); + Node package_declaration = root.getChild(0); + Node class_declaration = root.getChild(1); + boolean result = predicate.test(package_declaration, class_declaration); + Assertions.assertTrue(result); + } } \ No newline at end of file From c3057a3009503cfcc3a209399fa25886595cb4aa Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 26 Jan 2023 12:00:16 +0100 Subject: [PATCH 0122/1089] Moving `NodePredicate` and subclasses into subpackage --- .../analyzer/predicate/{ => node}/ContainsErrorPredicate.java | 2 +- .../predicate/{ => node}/ContainsNonAsciiPredicate.java | 2 +- .../analyzer/predicate/{ => node}/NodeContentPredicate.java | 2 +- .../si/seart/analyzer/predicate/{ => node}/NodePredicate.java | 2 +- .../predicate/{ => node}/ContainsErrorPredicateTest.java | 2 +- .../predicate/{ => node}/ContainsNonAsciiPredicateTest.java | 2 +- .../si/seart/analyzer/predicate/{ => node}/PredicateTest.java | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) rename dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/{ => node}/ContainsErrorPredicate.java (80%) rename dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/{ => node}/ContainsNonAsciiPredicate.java (92%) rename dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/{ => node}/NodeContentPredicate.java (84%) rename dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/{ => node}/NodePredicate.java (90%) rename dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/{ => node}/ContainsErrorPredicateTest.java (97%) rename dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/{ => node}/ContainsNonAsciiPredicateTest.java (97%) rename dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/{ => node}/PredicateTest.java (91%) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsErrorPredicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicate.java similarity index 80% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsErrorPredicate.java rename to dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicate.java index 894fd0cd..a974bdcb 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsErrorPredicate.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicate.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.predicate; +package usi.si.seart.analyzer.predicate.node; import usi.si.seart.treesitter.Node; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiPredicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicate.java similarity index 92% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiPredicate.java rename to dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicate.java index 0a857430..2fe455a2 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiPredicate.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicate.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.predicate; +package usi.si.seart.analyzer.predicate.node; import usi.si.seart.analyzer.NodeMapper; import usi.si.seart.treesitter.Node; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/NodeContentPredicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/NodeContentPredicate.java similarity index 84% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/NodeContentPredicate.java rename to dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/NodeContentPredicate.java index 52dcfe7b..c9306685 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/NodeContentPredicate.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/NodeContentPredicate.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.predicate; +package usi.si.seart.analyzer.predicate.node; import usi.si.seart.analyzer.NodeMapper; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/NodePredicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/NodePredicate.java similarity index 90% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/NodePredicate.java rename to dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/NodePredicate.java index 95b8da4b..d413d4fb 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/NodePredicate.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/NodePredicate.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.predicate; +package usi.si.seart.analyzer.predicate.node; import usi.si.seart.treesitter.Node; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsErrorPredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicateTest.java similarity index 97% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsErrorPredicateTest.java rename to dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicateTest.java index f722feba..94012677 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsErrorPredicateTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicateTest.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.predicate; +package usi.si.seart.analyzer.predicate.node; import lombok.Cleanup; import lombok.SneakyThrows; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiPredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicateTest.java similarity index 97% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiPredicateTest.java rename to dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicateTest.java index ef93cfae..c87b5430 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/ContainsNonAsciiPredicateTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicateTest.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.predicate; +package usi.si.seart.analyzer.predicate.node; import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/PredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/PredicateTest.java similarity index 91% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/PredicateTest.java rename to dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/PredicateTest.java index dbde698f..ac0d42a7 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/PredicateTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/PredicateTest.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.predicate; +package usi.si.seart.analyzer.predicate.node; import usi.si.seart.analyzer.test.BaseTest; From 44acfcef33cd7dd5fe2821dcf6405bf63c5c0b86 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 26 Jan 2023 12:03:50 +0100 Subject: [PATCH 0123/1089] Simplified analysis --- .../si/seart/analyzer/AbstractAnalyzer.java | 78 +++++-------------- .../usi/si/seart/analyzer/JavaAnalyzer.java | 2 +- .../usi/si/seart/analyzer/PythonAnalyzer.java | 3 +- 3 files changed, 24 insertions(+), 59 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java index a0de014c..61ab4c15 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java @@ -12,9 +12,10 @@ import usi.si.seart.analyzer.hash.ContentHasher; import usi.si.seart.analyzer.hash.Hasher; import usi.si.seart.analyzer.hash.SyntaxTreeHasher; -import usi.si.seart.analyzer.predicate.ContainsErrorPredicate; -import usi.si.seart.analyzer.predicate.ContainsNonAsciiPredicate; -import usi.si.seart.analyzer.predicate.TestFilePredicate; +import usi.si.seart.analyzer.predicate.node.ContainsErrorPredicate; +import usi.si.seart.analyzer.predicate.node.ContainsNonAsciiPredicate; +import usi.si.seart.analyzer.predicate.node.NodePredicate; +import usi.si.seart.analyzer.predicate.path.TestFilePredicate; import usi.si.seart.analyzer.printer.NodePrinter; import usi.si.seart.analyzer.printer.Printer; import usi.si.seart.analyzer.printer.SExpressionPrinter; @@ -22,7 +23,6 @@ import usi.si.seart.analyzer.query.multi.MultiCaptureQueries; import usi.si.seart.analyzer.query.single.SingleCaptureQueries; import usi.si.seart.analyzer.util.Tuple; -import usi.si.seart.analyzer.util.stream.DelimiterSuffixedStringCollector; import usi.si.seart.model.code.Boilerplate; import usi.si.seart.model.code.File; import usi.si.seart.model.code.Function; @@ -37,8 +37,7 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; -import java.util.NoSuchElementException; -import java.util.function.Predicate; +import java.util.stream.Collectors; @FieldDefaults(level = AccessLevel.PROTECTED) public abstract class AbstractAnalyzer implements Analyzer { @@ -59,10 +58,10 @@ public abstract class AbstractAnalyzer implements Analyzer { Hasher contentHasher; Hasher syntaxTreeHasher = new SyntaxTreeHasher(); - Predicate containsError = new ContainsErrorPredicate(); - Predicate containsNonAscii; + NodePredicate containsError = new ContainsErrorPredicate(); + NodePredicate containsNonAscii; - Predicate testFilePredicate = new TestFilePredicate() {}; + TestFilePredicate testFilePredicate = new TestFilePredicate() {}; Printer nodePrinter; Printer syntaxTreePrinter = new SyntaxTreePrinter(); @@ -170,60 +169,25 @@ protected List extractFunctionEntities(File file) { } protected Function extractFunctionEntity(List> match) { + List nodes = match.stream().map(Tuple::getValue).collect(Collectors.toList()); Node function = match.stream() .filter(tuple -> tuple.getKey().equals("target")) .map(Tuple::getValue) .findFirst() - .orElseThrow(NoSuchElementException::new); - String content = match.stream() - .map(Tuple::getValue) - .map(node -> nodePrinter.print(node)) - .collect(new DelimiterSuffixedStringCollector("\n")); - String ast = match.stream() - .map(Tuple::getValue) - .map(node -> syntaxTreePrinter.print(node)) - .collect(new DelimiterSuffixedStringCollector("\n")); - String sExp = match.stream() - .map(Tuple::getValue) - .map(node -> sExpressionPrinter.print(node)) - .collect(new DelimiterSuffixedStringCollector(" ")); - - Long sumCodeTokens = match.stream() - .map(Tuple::getValue) - .mapToLong(node -> codeTokenCounter.count(node)) - .sum(); - Long sumTotalTokens = match.stream() - .map(Tuple::getValue) - .mapToLong(node -> totalTokenCounter.count(node)) - .sum(); - Long sumLines = match.stream() - .map(Tuple::getValue) - .mapToLong(node -> lineCounter.count(node)) - .sum(); - Long sumCharacters = match.stream() - .map(Tuple::getValue) - .mapToLong(node -> characterCounter.count(node)) - .sum(); - boolean anyContainsNonAscii = match.stream() - .map(Tuple::getValue) - .anyMatch(node -> containsNonAscii.test(node)); - boolean anyContainsError = match.stream() - .map(Tuple::getValue) - .anyMatch(node -> containsError.test(node)); - + .orElseThrow(IllegalStateException::new); return Function.builder() .repo(localClone.getGitRepo()) - .ast(ast) - .content(content) - .astHash(syntaxTreeHasher.hash(function)) - .contentHash(contentHasher.hash(function)) - .sExpression("(sexp " + sExp + ")") - .totalTokens(sumTotalTokens) - .codeTokens(sumCodeTokens) - .lines(sumLines) - .characters(sumCharacters) - .containsNonAscii(anyContainsNonAscii) - .containsError(anyContainsError) + .ast(syntaxTreePrinter.print(nodes)) + .content(nodePrinter.print(nodes)) + .astHash(syntaxTreeHasher.hash(nodes)) + .contentHash(contentHasher.hash(nodes)) + .sExpression("(sexp " + sExpressionPrinter.print(nodes) + ")") + .totalTokens(totalTokenCounter.count(nodes)) + .codeTokens(codeTokenCounter.count(nodes)) + .lines(lineCounter.count(nodes)) + .characters(characterCounter.count(nodes)) + .containsNonAscii(containsNonAscii.test(nodes)) + .containsError(containsError.test(nodes)) .boilerplateType(boilerplateEnumerator.asEnum(function)) .build(); } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java index 5426bbe7..b61bfa6c 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java @@ -1,7 +1,7 @@ package usi.si.seart.analyzer; import usi.si.seart.analyzer.enumerator.JavaBoilerplateEnumerator; -import usi.si.seart.analyzer.predicate.JavaTestFilePredicate; +import usi.si.seart.analyzer.predicate.path.JavaTestFilePredicate; import usi.si.seart.analyzer.query.multi.JavaMultiCaptureQueries; import usi.si.seart.analyzer.query.single.JavaSingleCaptureQueries; import usi.si.seart.treesitter.Language; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java index 321d9445..fb62b98e 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java @@ -1,6 +1,7 @@ package usi.si.seart.analyzer; -import usi.si.seart.analyzer.predicate.PythonTestFilePredicate; +import usi.si.seart.analyzer.enumerator.PythonBoilerplateEnumerator; +import usi.si.seart.analyzer.predicate.path.PythonTestFilePredicate; import usi.si.seart.analyzer.query.multi.PythonMultiCaptureQueries; import usi.si.seart.analyzer.query.single.PythonSingleCaptureQueries; import usi.si.seart.treesitter.Language; From 4e855a928419b57fe91a26e9aaa0d3096137835e Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 26 Jan 2023 13:01:19 +0100 Subject: [PATCH 0124/1089] Fixed permissive access to protected method --- .../main/java/usi/si/seart/analyzer/printer/NodePrinter.java | 2 +- .../java/usi/si/seart/analyzer/printer/SExpressionPrinter.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java index a2e277ac..e22eebd7 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java @@ -29,7 +29,7 @@ public String print(Node node) { } @Override - public Collector resultCollector() { + protected Collector resultCollector() { return Collectors.joining("\n"); } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SExpressionPrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SExpressionPrinter.java index 20058961..93d070a1 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SExpressionPrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SExpressionPrinter.java @@ -13,7 +13,7 @@ public String print(Node node) { } @Override - public Collector resultCollector() { + protected Collector resultCollector() { return Collectors.joining(" "); } } From c4105a24c1d7cb38bc2412a9dfedb904f3fd5053 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 26 Jan 2023 14:45:59 +0100 Subject: [PATCH 0125/1089] Removed the unnecessary `sexp` prefix when exporting --- .../main/java/usi/si/seart/analyzer/AbstractAnalyzer.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java index 61ab4c15..108a3864 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java @@ -143,7 +143,7 @@ protected File extractFileEntity() { .contentHash(contentHasher.hash(node)) .ast(syntaxTreePrinter.print(node)) .astHash(syntaxTreeHasher.hash(node)) - .sExpression("(sexp " + sExpressionPrinter.print(node) + ")") + .sExpression("(" + sExpressionPrinter.print(node) + ")") .totalTokens(totalTokenCounter.count(node)) .codeTokens(codeTokenCounter.count(node)) .lines(lineCounter.count(node)) @@ -169,7 +169,9 @@ protected List extractFunctionEntities(File file) { } protected Function extractFunctionEntity(List> match) { - List nodes = match.stream().map(Tuple::getValue).collect(Collectors.toList()); + List nodes = match.stream() + .map(Tuple::getValue) + .collect(Collectors.toList()); Node function = match.stream() .filter(tuple -> tuple.getKey().equals("target")) .map(Tuple::getValue) @@ -181,7 +183,7 @@ protected Function extractFunctionEntity(List> match) { .content(nodePrinter.print(nodes)) .astHash(syntaxTreeHasher.hash(nodes)) .contentHash(contentHasher.hash(nodes)) - .sExpression("(sexp " + sExpressionPrinter.print(nodes) + ")") + .sExpression("(" + sExpressionPrinter.print(nodes) + ")") .totalTokens(totalTokenCounter.count(nodes)) .codeTokens(codeTokenCounter.count(nodes)) .lines(lineCounter.count(nodes)) From 3d2090fdc424af3f78e840b212714188df4b57fc Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 26 Jan 2023 15:41:39 +0100 Subject: [PATCH 0126/1089] `SExpressionPrinter` adds a bracket prefix and suffix implicitly The goal of this printing should not be to produce a valid s-expression tree, but rather to give a valid s-expression that can be later used to construct a `Query`. Sibling nodes can be grouped in a bracket, meaning that we do not need to add any fake anchor or whatever. We did however need to introduce a custom joiner that would not introduce any parentheses in the event of empty input collection or just a single `Node`. --- .../si/seart/analyzer/AbstractAnalyzer.java | 4 +- .../analyzer/printer/SExpressionPrinter.java | 44 +++- .../printer/SExpressionPrinterTest.java | 190 +++++++++++------- 3 files changed, 159 insertions(+), 79 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java index 108a3864..f2bde81d 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java @@ -143,7 +143,7 @@ protected File extractFileEntity() { .contentHash(contentHasher.hash(node)) .ast(syntaxTreePrinter.print(node)) .astHash(syntaxTreeHasher.hash(node)) - .sExpression("(" + sExpressionPrinter.print(node) + ")") + .sExpression(sExpressionPrinter.print(node)) .totalTokens(totalTokenCounter.count(node)) .codeTokens(codeTokenCounter.count(node)) .lines(lineCounter.count(node)) @@ -183,7 +183,7 @@ protected Function extractFunctionEntity(List> match) { .content(nodePrinter.print(nodes)) .astHash(syntaxTreeHasher.hash(nodes)) .contentHash(contentHasher.hash(nodes)) - .sExpression("(" + sExpressionPrinter.print(nodes) + ")") + .sExpression(sExpressionPrinter.print(nodes)) .totalTokens(totalTokenCounter.count(nodes)) .codeTokens(codeTokenCounter.count(nodes)) .lines(lineCounter.count(nodes)) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SExpressionPrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SExpressionPrinter.java index 93d070a1..a98437eb 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SExpressionPrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SExpressionPrinter.java @@ -2,8 +2,14 @@ import usi.si.seart.treesitter.Node; +import java.util.Collections; +import java.util.Set; +import java.util.StringJoiner; +import java.util.function.BiConsumer; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.function.Supplier; import java.util.stream.Collector; -import java.util.stream.Collectors; public class SExpressionPrinter extends AbstractPrinter { @@ -14,6 +20,40 @@ public String print(Node node) { @Override protected Collector resultCollector() { - return Collectors.joining(" "); + return new Collector() { + + int count = 0; + + @Override + public Supplier supplier() { + return () -> new StringJoiner(" "); + } + + @Override + public BiConsumer accumulator() { + return (joiner, sequence) -> { + count++; + joiner.add(sequence); + }; + } + + @Override + public BinaryOperator combiner() { + return StringJoiner::merge; + } + + @Override + public Function finisher() { + return (joiner) -> { + String joined = joiner.toString(); + return (count > 1) ? "(" + joined + ")" : joined; + }; + } + + @Override + public Set characteristics() { + return Collections.emptySet(); + } + }; } } diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SExpressionPrinterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SExpressionPrinterTest.java index a732f766..1aff5346 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SExpressionPrinterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SExpressionPrinterTest.java @@ -13,37 +13,52 @@ void printRootTest() { Node root = tree.getRootNode(); String actual = printer.print(root); String expected = - "(program " + - "(package_declaration " + - "(scoped_identifier " + - "scope: (scoped_identifier " + - "scope: (identifier) " + - "name: (identifier)) " + - "name: (identifier))) " + - "(class_declaration " + - "(modifiers) " + - "name: (identifier) " + - "body: (class_body " + - "(method_declaration " + - "(modifiers) " + - "type: (void_type) " + - "name: (identifier) " + - "parameters: (formal_parameters " + - "(formal_parameter " + - "type: (array_type " + - "element: (type_identifier) " + - "dimensions: (dimensions)) " + - "name: (identifier))) " + - "body: (block " + - "(line_comment) " + - "(expression_statement " + - "(method_invocation " + - "object: (field_access " + - "object: (identifier) " + - "field: (identifier)) " + - "name: (identifier) " + - "arguments: (argument_list " + - "(string_literal)))))))))"; + "(program " + + "(package_declaration " + + "(scoped_identifier " + + "scope: (scoped_identifier " + + "scope: (identifier) " + + "name: (identifier)" + + ") " + + "name: (identifier)" + + ")" + + ") " + + "(class_declaration " + + "(modifiers) " + + "name: (identifier) " + + "body: (class_body " + + "(method_declaration " + + "(modifiers) " + + "type: (void_type) " + + "name: (identifier) " + + "parameters: (formal_parameters " + + "(formal_parameter " + + "type: (array_type " + + "element: (type_identifier) " + + "dimensions: (dimensions)" + + ") " + + "name: (identifier)" + + ")" + + ") " + + "body: (block " + + "(line_comment) " + + "(expression_statement " + + "(method_invocation " + + "object: (field_access " + + "object: (identifier) " + + "field: (identifier)" + + ") " + + "name: (identifier) " + + "arguments: (argument_list " + + "(string_literal)" + + ")" + + ")" + + ")" + + ")" + + ")" + + ")" + + ")" + + ")"; Assertions.assertEquals(expected, actual); } @@ -54,26 +69,35 @@ void printChildTest() { Node method = root.getChild(1).getChildByFieldName("body").getChild(1); String actual = printer.print(method); String expected = - "(method_declaration " + - "(modifiers) " + - "type: (void_type) " + - "name: (identifier) " + - "parameters: (formal_parameters " + + "(method_declaration " + + "(modifiers) " + + "type: (void_type) " + + "name: (identifier) " + + "parameters: (formal_parameters " + "(formal_parameter " + - "type: (array_type " + - "element: (type_identifier) " + - "dimensions: (dimensions)) " + - "name: (identifier))) " + - "body: (block " + + "type: (array_type " + + "element: (type_identifier) " + + "dimensions: (dimensions)" + + ") " + + "name: (identifier)" + + ")" + + ") " + + "body: (block " + "(line_comment) " + - "(expression_statement " + - "(method_invocation " + - "object: (field_access " + - "object: (identifier) " + - "field: (identifier)) " + - "name: (identifier) " + - "arguments: (argument_list " + - "(string_literal))))))"; + "(expression_statement " + + "(method_invocation " + + "object: (field_access " + + "object: (identifier) " + + "field: (identifier)" + + ") " + + "name: (identifier) " + + "arguments: (argument_list " + + "(string_literal)" + + ")" + + ")" + + ")" + + ")" + + ")"; Assertions.assertEquals(expected, actual); } @@ -87,36 +111,52 @@ void printMultipleTest() { // The "program" root node is removed because // we are printing its children individually String expected = - "(package_declaration " + + "(" + + "(package_declaration " + "(scoped_identifier " + - "scope: (scoped_identifier " + - "scope: (identifier) " + - "name: (identifier)) " + - "name: (identifier))) " + - "(class_declaration " + + "scope: (scoped_identifier " + + "scope: (identifier) " + + "name: (identifier)" + + ") " + + "name: (identifier)" + + ")" + + ") " + + "(class_declaration " + "(modifiers) " + "name: (identifier) " + "body: (class_body " + - "(method_declaration " + - "(modifiers) " + - "type: (void_type) " + - "name: (identifier) " + - "parameters: (formal_parameters " + - "(formal_parameter " + - "type: (array_type " + - "element: (type_identifier) " + - "dimensions: (dimensions)) " + - "name: (identifier))) " + - "body: (block " + - "(line_comment) " + - "(expression_statement " + - "(method_invocation " + - "object: (field_access " + - "object: (identifier) " + - "field: (identifier)) " + - "name: (identifier) " + - "arguments: (argument_list " + - "(string_literal))))))))"; + "(method_declaration " + + "(modifiers) " + + "type: (void_type) " + + "name: (identifier) " + + "parameters: (formal_parameters " + + "(formal_parameter " + + "type: (array_type " + + "element: (type_identifier) " + + "dimensions: (dimensions)" + + ") " + + "name: (identifier)" + + ")" + + ") " + + "body: (block " + + "(line_comment) " + + "(expression_statement " + + "(method_invocation " + + "object: (field_access " + + "object: (identifier) " + + "field: (identifier)" + + ") " + + "name: (identifier) " + + "arguments: (argument_list " + + "(string_literal)" + + ")" + + ")" + + ")" + + ")" + + ")" + + ")" + + ")" + + ")"; Assertions.assertEquals(expected, actual); } } \ No newline at end of file From a955154f15ab2c54bcd6bab840470f2029b9376c Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 26 Jan 2023 16:12:37 +0100 Subject: [PATCH 0127/1089] Renamed `SExpressionPrinter` to `SymbolicExpressionPrinter` No more SEx jokes :( --- .../main/java/usi/si/seart/analyzer/AbstractAnalyzer.java | 8 ++++---- ...ressionPrinter.java => SymbolicExpressionPrinter.java} | 2 +- ...rinterTest.java => SymbolicExpressionPrinterTest.java} | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) rename dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/{SExpressionPrinter.java => SymbolicExpressionPrinter.java} (96%) rename dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/{SExpressionPrinterTest.java => SymbolicExpressionPrinterTest.java} (96%) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java index f2bde81d..26736851 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java @@ -18,7 +18,7 @@ import usi.si.seart.analyzer.predicate.path.TestFilePredicate; import usi.si.seart.analyzer.printer.NodePrinter; import usi.si.seart.analyzer.printer.Printer; -import usi.si.seart.analyzer.printer.SExpressionPrinter; +import usi.si.seart.analyzer.printer.SymbolicExpressionPrinter; import usi.si.seart.analyzer.printer.SyntaxTreePrinter; import usi.si.seart.analyzer.query.multi.MultiCaptureQueries; import usi.si.seart.analyzer.query.single.SingleCaptureQueries; @@ -65,7 +65,7 @@ public abstract class AbstractAnalyzer implements Analyzer { Printer nodePrinter; Printer syntaxTreePrinter = new SyntaxTreePrinter(); - Printer sExpressionPrinter = new SExpressionPrinter(); + Printer expressionPrinter = new SymbolicExpressionPrinter(); SingleCaptureQueries singleCaptureQueries = new SingleCaptureQueries(null) { @Override @@ -143,7 +143,7 @@ protected File extractFileEntity() { .contentHash(contentHasher.hash(node)) .ast(syntaxTreePrinter.print(node)) .astHash(syntaxTreeHasher.hash(node)) - .sExpression(sExpressionPrinter.print(node)) + .symbolicExpression(expressionPrinter.print(node)) .totalTokens(totalTokenCounter.count(node)) .codeTokens(codeTokenCounter.count(node)) .lines(lineCounter.count(node)) @@ -183,7 +183,7 @@ protected Function extractFunctionEntity(List> match) { .content(nodePrinter.print(nodes)) .astHash(syntaxTreeHasher.hash(nodes)) .contentHash(contentHasher.hash(nodes)) - .sExpression(sExpressionPrinter.print(nodes)) + .symbolicExpression(expressionPrinter.print(nodes)) .totalTokens(totalTokenCounter.count(nodes)) .codeTokens(codeTokenCounter.count(nodes)) .lines(lineCounter.count(nodes)) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SExpressionPrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinter.java similarity index 96% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SExpressionPrinter.java rename to dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinter.java index a98437eb..a3b41f3b 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SExpressionPrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinter.java @@ -11,7 +11,7 @@ import java.util.function.Supplier; import java.util.stream.Collector; -public class SExpressionPrinter extends AbstractPrinter { +public class SymbolicExpressionPrinter extends AbstractPrinter { @Override public String print(Node node) { diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SExpressionPrinterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinterTest.java similarity index 96% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SExpressionPrinterTest.java rename to dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinterTest.java index 1aff5346..da7c9a38 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SExpressionPrinterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinterTest.java @@ -5,11 +5,11 @@ import usi.si.seart.analyzer.test.BaseTest; import usi.si.seart.treesitter.Node; -class SExpressionPrinterTest extends BaseTest { +class SymbolicExpressionPrinterTest extends BaseTest { @Test void printRootTest() { - Printer printer = new SExpressionPrinter(); + Printer printer = new SymbolicExpressionPrinter(); Node root = tree.getRootNode(); String actual = printer.print(root); String expected = @@ -64,7 +64,7 @@ void printRootTest() { @Test void printChildTest() { - Printer printer = new SExpressionPrinter(); + Printer printer = new SymbolicExpressionPrinter(); Node root = tree.getRootNode(); Node method = root.getChild(1).getChildByFieldName("body").getChild(1); String actual = printer.print(method); @@ -103,7 +103,7 @@ void printChildTest() { @Test void printMultipleTest() { - Printer printer = new SExpressionPrinter(); + Printer printer = new SymbolicExpressionPrinter(); Node root = tree.getRootNode(); Node package_declaration = root.getChild(0); Node class_declaration = root.getChild(1); From b9ad3ccba9340a980c16b29e60a7748b6c0b02ba Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 26 Jan 2023 16:24:20 +0100 Subject: [PATCH 0128/1089] Added test cases for passing empty collections for `Count` --- .../si/seart/analyzer/count/CharacterCounterTest.java | 9 +++++++++ .../si/seart/analyzer/count/CodeTokenCounterTest.java | 9 +++++++++ .../usi/si/seart/analyzer/count/LineCounterTest.java | 9 +++++++++ .../usi/si/seart/analyzer/count/TokenCounterTest.java | 9 +++++++++ 4 files changed, 36 insertions(+) diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CharacterCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CharacterCounterTest.java index a8edff2c..87f8fafe 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CharacterCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CharacterCounterTest.java @@ -5,8 +5,17 @@ import usi.si.seart.analyzer.test.BaseTest; import usi.si.seart.treesitter.Node; +import java.util.HashSet; + class CharacterCounterTest extends BaseTest { + @Test + void countEmptyTest() { + Counter counter = new CharacterCounter(getNodeMapper()); + Assertions.assertEquals(0, counter.count()); + Assertions.assertEquals(0, counter.count(new HashSet<>())); + } + @Test void countRootTest(){ Counter counter = new CharacterCounter(getNodeMapper()); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CodeTokenCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CodeTokenCounterTest.java index 3ea919b8..75851f43 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CodeTokenCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CodeTokenCounterTest.java @@ -5,8 +5,17 @@ import usi.si.seart.analyzer.test.BaseTest; import usi.si.seart.treesitter.Node; +import java.util.HashSet; + class CodeTokenCounterTest extends BaseTest { + @Test + void countEmptyTest() { + Counter counter = new CodeTokenCounter(); + Assertions.assertEquals(0, counter.count()); + Assertions.assertEquals(0, counter.count(new HashSet<>())); + } + @Test void countRootTest() { Counter counter = new CodeTokenCounter(); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/LineCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/LineCounterTest.java index a61341e1..e8a41f8b 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/LineCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/LineCounterTest.java @@ -5,8 +5,17 @@ import usi.si.seart.analyzer.test.BaseTest; import usi.si.seart.treesitter.Node; +import java.util.HashSet; + class LineCounterTest extends BaseTest { + @Test + void countEmptyTest() { + Counter counter = new LineCounter(); + Assertions.assertEquals(0, counter.count()); + Assertions.assertEquals(0, counter.count(new HashSet<>())); + } + @Test void countRootTest() { Counter counter = new LineCounter(); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/TokenCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/TokenCounterTest.java index d4f4d14e..e7edf56b 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/TokenCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/TokenCounterTest.java @@ -5,8 +5,17 @@ import usi.si.seart.analyzer.test.BaseTest; import usi.si.seart.treesitter.Node; +import java.util.HashSet; + class TokenCounterTest extends BaseTest { + @Test + void countEmptyTest() { + Counter counter = new TokenCounter(getNodeMapper()); + Assertions.assertEquals(0, counter.count()); + Assertions.assertEquals(0, counter.count(new HashSet<>())); + } + @Test void countRootTest() { Counter counter = new TokenCounter(getNodeMapper()); From e320f44657e1c5f2be723b7f287ecc35f4ccaada Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 26 Jan 2023 16:35:05 +0100 Subject: [PATCH 0129/1089] Added test cases for passing empty collections for `Hasher` --- .../usi/si/seart/analyzer/hash/ContentHasherTest.java | 8 ++++++++ .../test/java/usi/si/seart/analyzer/hash/HasherTest.java | 3 +++ .../usi/si/seart/analyzer/hash/SyntaxTreeHasherTest.java | 8 ++++++++ 3 files changed, 19 insertions(+) diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java index 5e1b74d5..66c0617b 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java @@ -7,9 +7,17 @@ import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; +import java.util.HashSet; class ContentHasherTest extends HasherTest { + @Test + void emptyTest() { + Hasher hasher = new ContentHasher(getNodeMapper()); + Assertions.assertEquals(empty, hasher.hash()); + Assertions.assertEquals(empty, hasher.hash(new HashSet<>())); + } + @Test void hashTest() { Hasher hasher = new ContentHasher(getNodeMapper()); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/HasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/HasherTest.java index 7ba36307..8df84eb2 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/HasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/HasherTest.java @@ -9,6 +9,9 @@ public abstract class HasherTest extends BaseTest { + // https://crypto.stackexchange.com/a/26135 + protected String empty = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; + @Override protected List getTokens() { return List.of( diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/SyntaxTreeHasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/SyntaxTreeHasherTest.java index 05e35813..8e589eb2 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/SyntaxTreeHasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/SyntaxTreeHasherTest.java @@ -6,9 +6,17 @@ import usi.si.seart.treesitter.Tree; import java.io.UnsupportedEncodingException; +import java.util.HashSet; class SyntaxTreeHasherTest extends HasherTest { + @Test + void emptyTest() { + Hasher hasher = new SyntaxTreeHasher(); + Assertions.assertEquals(empty, hasher.hash()); + Assertions.assertEquals(empty, hasher.hash(new HashSet<>())); + } + @Test void hashTest() { Hasher hasher = new SyntaxTreeHasher(); From 1598e9f367c5dd5dd4402f60befab5974867595d Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 26 Jan 2023 16:39:01 +0100 Subject: [PATCH 0130/1089] Added test cases for passing empty collections for `NodePredicate` --- .../predicate/node/ContainsErrorPredicateTest.java | 8 ++++++++ .../predicate/node/ContainsNonAsciiPredicateTest.java | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicateTest.java index 94012677..a219bbe4 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicateTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicateTest.java @@ -10,9 +10,17 @@ import usi.si.seart.treesitter.Tree; import java.io.UnsupportedEncodingException; +import java.util.HashSet; class ContainsErrorPredicateTest extends PredicateTest { + @Test + void emptyInputTest() { + NodePredicate predicate = new ContainsErrorPredicate(); + Assertions.assertFalse(predicate.test()); + Assertions.assertFalse(predicate.test(new HashSet<>())); + } + @Test void containsNoErrorTest() { NodePredicate predicate = new ContainsErrorPredicate(); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicateTest.java index c87b5430..20585948 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicateTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicateTest.java @@ -8,9 +8,17 @@ import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; +import java.util.HashSet; class ContainsNonAsciiPredicateTest extends PredicateTest { + @Test + void emptyInputTest() { + NodePredicate predicate = new ContainsNonAsciiPredicate(getNodeMapper()); + Assertions.assertFalse(predicate.test()); + Assertions.assertFalse(predicate.test(new HashSet<>())); + } + @Test @SneakyThrows(UnsupportedEncodingException.class) void containsOnlyAsciiTest() { From 9b8215cd341b67bdb17fad15e84c05b4860a47b0 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 26 Jan 2023 16:43:07 +0100 Subject: [PATCH 0131/1089] Added test cases for passing empty collections for `Printer` --- .../usi/si/seart/analyzer/printer/NodePrinterTest.java | 9 +++++++++ .../analyzer/printer/SymbolicExpressionPrinterTest.java | 9 +++++++++ .../si/seart/analyzer/printer/SyntaxTreePrinterTest.java | 9 +++++++++ 3 files changed, 27 insertions(+) diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java index 8cbda976..d148f4a6 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java @@ -5,8 +5,17 @@ import usi.si.seart.analyzer.test.BaseTest; import usi.si.seart.treesitter.Node; +import java.util.HashSet; + class NodePrinterTest extends BaseTest { + @Test + void printNothingTest() { + Printer printer = new NodePrinter(getNodeMapper()); + Assertions.assertEquals("", printer.print()); + Assertions.assertEquals("", printer.print(new HashSet<>())); + } + @Test void printRootTest() { Printer printer = new NodePrinter(getNodeMapper()); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinterTest.java index da7c9a38..f70f0998 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinterTest.java @@ -5,8 +5,17 @@ import usi.si.seart.analyzer.test.BaseTest; import usi.si.seart.treesitter.Node; +import java.util.HashSet; + class SymbolicExpressionPrinterTest extends BaseTest { + @Test + void printNothingTest() { + Printer printer = new SymbolicExpressionPrinter(); + Assertions.assertEquals("", printer.print()); + Assertions.assertEquals("", printer.print(new HashSet<>())); + } + @Test void printRootTest() { Printer printer = new SymbolicExpressionPrinter(); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java index 17080b76..3a93fe23 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java @@ -5,8 +5,17 @@ import usi.si.seart.analyzer.test.BaseTest; import usi.si.seart.treesitter.Node; +import java.util.HashSet; + class SyntaxTreePrinterTest extends BaseTest { + @Test + void printNothingTest() { + Printer printer = new SyntaxTreePrinter(); + Assertions.assertEquals("", printer.print()); + Assertions.assertEquals("", printer.print(new HashSet<>())); + } + @Test void printRootTest() { Printer printer = new SyntaxTreePrinter(); From da86d3ebc5fb55263d849521d17708beec5340e6 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 27 Jan 2023 11:15:22 +0100 Subject: [PATCH 0132/1089] Added more customization options for `BaseTest`: specifying `Language` --- .../usi/si/seart/analyzer/test/BaseTest.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java index ed43fdaa..d3d7d039 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java @@ -1,9 +1,7 @@ package usi.si.seart.analyzer.test; import lombok.SneakyThrows; -import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import usi.si.seart.analyzer.NodeMapper; import usi.si.seart.treesitter.Language; @@ -17,34 +15,36 @@ public abstract class BaseTest { - protected static Parser parser; - static { LibraryLoader.load(); } - @BeforeAll - static void beforeAll() { - parser = new Parser(Language.JAVA); - } + protected Parser parser; + protected Tree tree; - @AfterAll - static void afterAll() { - parser.close(); + @BeforeEach + protected void setUp() { + setUpParser(); + setUpTree(); } - protected Tree tree; + void setUpParser() { + parser = new Parser(getLanguage()); + } - @BeforeEach @SneakyThrows(UnsupportedEncodingException.class) - void setUp() { + void setUpTree() { tree = parser.parseString(getInput()); } @AfterEach void tearDown() { + parser.close(); tree.close(); - tree = null; + } + + protected Language getLanguage() { + return Language.JAVA; } protected String getInput() { From 5bd254d860e9ea90535207c25e6b9403fd3cc88a Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 27 Jan 2023 11:17:48 +0100 Subject: [PATCH 0133/1089] Removed unnecessary `throws` from `provideArguments` implementations --- .../analyzer/predicate/path/JavaTestFilePredicateTest.java | 2 +- .../analyzer/predicate/path/PythonTestFilePredicateTest.java | 2 +- .../si/seart/analyzer/predicate/path/TestFilePredicateTest.java | 2 +- .../util/stream/DelimiterSuffixedStringCollectorTest.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/JavaTestFilePredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/JavaTestFilePredicateTest.java index 6ce068b9..9382be55 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/JavaTestFilePredicateTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/JavaTestFilePredicateTest.java @@ -16,7 +16,7 @@ class JavaTestFilePredicateTest { private static class JavaPathPredicateProvider implements ArgumentsProvider { @Override - public Stream provideArguments(ExtensionContext extensionContext) throws Exception { + public Stream provideArguments(ExtensionContext extensionContext) { return Stream.of( Arguments.of(Path.of("/src", "test", "README"), true), Arguments.of(Path.of("/src", "tests", "README"), true), diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/PythonTestFilePredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/PythonTestFilePredicateTest.java index 9459ddb5..4c87b0ff 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/PythonTestFilePredicateTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/PythonTestFilePredicateTest.java @@ -16,7 +16,7 @@ class PythonTestFilePredicateTest { private static class PythonPathPredicateProvider implements ArgumentsProvider { @Override - public Stream provideArguments(ExtensionContext extensionContext) throws Exception { + public Stream provideArguments(ExtensionContext extensionContext) { return Stream.of( Arguments.of(Path.of("/src", "app.py"), false), Arguments.of(Path.of("/src", "test", "app.py"), true), diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/TestFilePredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/TestFilePredicateTest.java index dabb4c88..c6074e7b 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/TestFilePredicateTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/TestFilePredicateTest.java @@ -16,7 +16,7 @@ class TestFilePredicateTest { private static class PathPredicateProvider implements ArgumentsProvider { @Override - public Stream provideArguments(ExtensionContext extensionContext) throws Exception { + public Stream provideArguments(ExtensionContext extensionContext) { return Stream.of( Arguments.of(Path.of("/src", "test", "README"), true), Arguments.of(Path.of("/src", "tests", "README"), true), diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/util/stream/DelimiterSuffixedStringCollectorTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/util/stream/DelimiterSuffixedStringCollectorTest.java index 37da8d90..8b2bd693 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/util/stream/DelimiterSuffixedStringCollectorTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/util/stream/DelimiterSuffixedStringCollectorTest.java @@ -15,7 +15,7 @@ class DelimiterSuffixedStringCollectorTest { private static class StringsArgumentsProvider implements ArgumentsProvider { @Override - public Stream provideArguments(ExtensionContext extensionContext) throws Exception { + public Stream provideArguments(ExtensionContext extensionContext) { return Stream.of( Arguments.of("", Stream.of(), " "), Arguments.of("A ", Stream.of("A"), " "), From 6804120f27e01585abbb2d904e7d11369a77cab5 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 27 Jan 2023 14:43:53 +0100 Subject: [PATCH 0134/1089] Added `PythonBoilerplateEnumerator` along with test cases A long-time coming. Boilerplate for Python is defined as overloads of magic functions coupled with functions decorated using `@property` and `@property.setter`. When searching through decorators, we iterate over sibling decorators until the first non-decorator node is found. Note that comment nodes are skipped because they can appear anywhere. --- .../usi/si/seart/analyzer/PythonAnalyzer.java | 2 +- .../PythonBoilerplateEnumerator.java | 101 ++++++++++++++ .../PythonBoilerplateEnumeratorTest.java | 129 ++++++++++++++++++ 3 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumerator.java create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java index fb62b98e..0cd24e90 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java @@ -15,6 +15,6 @@ public PythonAnalyzer(LocalClone localClone, Path path) { this.testFilePredicate = new PythonTestFilePredicate(); this.singleCaptureQueries = new PythonSingleCaptureQueries(); this.multiCaptureQueries = new PythonMultiCaptureQueries(); - // this.boilerplateEnumerator = new PythonBoilerplateEnumerator(this::getSourceBytes); + this.boilerplateEnumerator = new PythonBoilerplateEnumerator(this::getSourceBytes); } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumerator.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumerator.java new file mode 100644 index 00000000..a1ccc561 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumerator.java @@ -0,0 +1,101 @@ +package usi.si.seart.analyzer.enumerator; + +import usi.si.seart.analyzer.NodeMapper; +import usi.si.seart.model.code.Boilerplate; +import usi.si.seart.treesitter.Node; +import usi.si.seart.treesitter.Range; + +public class PythonBoilerplateEnumerator extends BoilerplateEnumerator { + + public PythonBoilerplateEnumerator(NodeMapper mapper) { + super(mapper); + } + + @Override + public Boilerplate asEnum(Node node) { + if (!node.getType().equals("function_definition")) return null; + traverser: { + for (Node prev = node.getPrevSibling(); prev != null; prev = prev.getPrevSibling()) { + switch (prev.getType()) { + case "decorator": + String decorator = mapper.getContentForRange(prev.getRange()); + if (decorator.equals("@property")) return Boilerplate.GETTER; + else if (decorator.endsWith(".setter")) return Boilerplate.SETTER; + case "comment": + break; + default: + break traverser; + } + } + } + Node identifier = node.getChildByFieldName("name"); + Range range = identifier.getRange(); + String name = mapper.getContentForRange(range); + switch (name) { + case "__new__": + return Boilerplate.CONSTRUCTOR; + case "__init__": + return Boilerplate.INITIALIZER; + case "__str__": + return Boilerplate.STRING_CONVERSION; + case "__repr__": + return Boilerplate.STRING_REPRESENTATION; + case "__hash__": + return Boilerplate.HASHER; + case "__get__": + case "__getattr__": + return Boilerplate.GETTER; + case "__set__": + case "__setattr__": + return Boilerplate.SETTER; + case "__del__": + case "__delattr__": + return Boilerplate.FINALIZER; + case "__eq__": + case "__lt__": + case "__le__": + case "__gt__": + case "__ge__": + return Boilerplate.COMPARISON; + case "__neg__": + case "__pos__": + case "__abs__": + case "__invert__": + case "__round__": + case "__floor__": + case "__ceil__": + case "__trunc__": + return Boilerplate.UNARY_ARITHMETIC; + case "__add__": + case "__sub__": + case "__mul__": + case "__div__": + case "__truediv__": + case "__floordiv__": + case "__mod__": + case "__pow__": + case "__lshift__": + case "__rshift__": + case "__and__": + case "__xor__": + case "__or__": + return Boilerplate.BINARY_ARITHMETIC; + case "__iadd__": + case "__isub__": + case "__imul__": + case "__imatmul__": + case "__itruediv__": + case "__ifloordiv__": + case "__imod__": + case "__ipow__": + case "__ilshift__": + case "__irshift__": + case "__iand__": + case "__ixor__": + case "__ior__": + return Boilerplate.AUGMENTED_ASSIGNMENT; + default: + return null; + } + } +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java new file mode 100644 index 00000000..0c507849 --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java @@ -0,0 +1,129 @@ +package usi.si.seart.analyzer.enumerator; + +import lombok.Cleanup; +import lombok.SneakyThrows; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; +import usi.si.seart.analyzer.test.BaseTest; +import usi.si.seart.model.code.Boilerplate; +import usi.si.seart.treesitter.Language; +import usi.si.seart.treesitter.Node; +import usi.si.seart.treesitter.Parser; +import usi.si.seart.treesitter.Tree; + +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; +import java.util.stream.Stream; + +class PythonBoilerplateEnumeratorTest extends BaseTest { + + private static class PythonCodeProvider implements ArgumentsProvider { + + @Override + public Stream provideArguments(ExtensionContext extensionContext) { + return Stream.of( + Arguments.of("def function():", null), + Arguments.of("def __new__():", Boilerplate.CONSTRUCTOR), + Arguments.of("def __init__():", Boilerplate.INITIALIZER), + Arguments.of("def __str__():", Boilerplate.STRING_CONVERSION), + Arguments.of("def __repr__():", Boilerplate.STRING_REPRESENTATION), + Arguments.of("def __hash__():", Boilerplate.HASHER), + Arguments.of("def __get__():", Boilerplate.GETTER), + Arguments.of("def __getattr__():", Boilerplate.GETTER), + Arguments.of("def __set__():", Boilerplate.SETTER), + Arguments.of("def __setattr__():", Boilerplate.SETTER), + Arguments.of("def __del__():", Boilerplate.FINALIZER), + Arguments.of("def __delattr__():", Boilerplate.FINALIZER), + Arguments.of("def __eq__():", Boilerplate.COMPARISON), + Arguments.of("def __lt__():", Boilerplate.COMPARISON), + Arguments.of("def __le__():", Boilerplate.COMPARISON), + Arguments.of("def __gt__():", Boilerplate.COMPARISON), + Arguments.of("def __ge__():", Boilerplate.COMPARISON), + Arguments.of("def __neg__():", Boilerplate.UNARY_ARITHMETIC), + Arguments.of("def __pos__():", Boilerplate.UNARY_ARITHMETIC), + Arguments.of("def __abs__():", Boilerplate.UNARY_ARITHMETIC), + Arguments.of("def __invert__():", Boilerplate.UNARY_ARITHMETIC), + Arguments.of("def __round__():", Boilerplate.UNARY_ARITHMETIC), + Arguments.of("def __floor__():", Boilerplate.UNARY_ARITHMETIC), + Arguments.of("def __ceil__():", Boilerplate.UNARY_ARITHMETIC), + Arguments.of("def __trunc__():", Boilerplate.UNARY_ARITHMETIC), + Arguments.of("def __add__():", Boilerplate.BINARY_ARITHMETIC), + Arguments.of("def __sub__():", Boilerplate.BINARY_ARITHMETIC), + Arguments.of("def __mul__():", Boilerplate.BINARY_ARITHMETIC), + Arguments.of("def __div__():", Boilerplate.BINARY_ARITHMETIC), + Arguments.of("def __truediv__():", Boilerplate.BINARY_ARITHMETIC), + Arguments.of("def __floordiv__():", Boilerplate.BINARY_ARITHMETIC), + Arguments.of("def __mod__():", Boilerplate.BINARY_ARITHMETIC), + Arguments.of("def __pow__():", Boilerplate.BINARY_ARITHMETIC), + Arguments.of("def __lshift__():", Boilerplate.BINARY_ARITHMETIC), + Arguments.of("def __rshift__():", Boilerplate.BINARY_ARITHMETIC), + Arguments.of("def __and__():", Boilerplate.BINARY_ARITHMETIC), + Arguments.of("def __xor__():", Boilerplate.BINARY_ARITHMETIC), + Arguments.of("def __or__():", Boilerplate.BINARY_ARITHMETIC), + Arguments.of("def __iadd__():", Boilerplate.AUGMENTED_ASSIGNMENT), + Arguments.of("def __isub__():", Boilerplate.AUGMENTED_ASSIGNMENT), + Arguments.of("def __imul__():", Boilerplate.AUGMENTED_ASSIGNMENT), + Arguments.of("def __imatmul__():", Boilerplate.AUGMENTED_ASSIGNMENT), + Arguments.of("def __itruediv__():", Boilerplate.AUGMENTED_ASSIGNMENT), + Arguments.of("def __ifloordiv__():", Boilerplate.AUGMENTED_ASSIGNMENT), + Arguments.of("def __imod__():", Boilerplate.AUGMENTED_ASSIGNMENT), + Arguments.of("def __ipow__():", Boilerplate.AUGMENTED_ASSIGNMENT), + Arguments.of("def __ilshift__():", Boilerplate.AUGMENTED_ASSIGNMENT), + Arguments.of("def __irshift__():", Boilerplate.AUGMENTED_ASSIGNMENT), + Arguments.of("def __iand__():", Boilerplate.AUGMENTED_ASSIGNMENT), + Arguments.of("def __ixor__():", Boilerplate.AUGMENTED_ASSIGNMENT), + Arguments.of("def __ior__():", Boilerplate.AUGMENTED_ASSIGNMENT) + ); + } + } + + + + @ParameterizedTest(name = "[{index}] {1}") + @ArgumentsSource(PythonCodeProvider.class) + @SneakyThrows(UnsupportedEncodingException.class) + void asEnumTest(String source, Boilerplate expected) { + @Cleanup Parser parser = new Parser(Language.PYTHON); + @Cleanup Tree tree = parser.parseString(source); + Node root = tree.getRootNode(); + Node function_definition = root.getChild(0); + BoilerplateEnumerator enumerator = new PythonBoilerplateEnumerator( + () -> source.getBytes(StandardCharsets.UTF_16LE) + ); + Boilerplate actual = enumerator.asEnum(function_definition); + Assertions.assertEquals(expected, actual); + } + + private static class PythonCodeProviderSpecial implements ArgumentsProvider { + + @Override + public Stream provideArguments(ExtensionContext context) { + return Stream.of( + Arguments.of("@something\ndef attr(self):\n pass", null), + Arguments.of("@property\ndef attr(self):\n pass", Boilerplate.GETTER), + Arguments.of("@property\n# line comment\ndef attr(self):\n pass", Boilerplate.GETTER), + Arguments.of("@attr.setter\ndef attr(self, attr):\n pass", Boilerplate.SETTER) + ); + } + } + + @ParameterizedTest(name = "[{index}] {1}") + @ArgumentsSource(PythonCodeProviderSpecial.class) + @SneakyThrows(UnsupportedEncodingException.class) + void asEnumTestSpecial(String source, Boilerplate expected) { + @Cleanup Parser parser = new Parser(Language.PYTHON); + @Cleanup Tree tree = parser.parseString(source); + Node root = tree.getRootNode(); + Node decorated_definition = root.getChild(0); + Node function_definition = decorated_definition.getChildByFieldName("definition"); + BoilerplateEnumerator enumerator = new PythonBoilerplateEnumerator( + () -> source.getBytes(StandardCharsets.UTF_16LE) + ); + Boilerplate actual = enumerator.asEnum(function_definition); + Assertions.assertEquals(expected, actual); + } +} \ No newline at end of file From 342e379d43e0a2d7c9af5e1ab1b4c8df2375c59e Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 27 Jan 2023 15:01:14 +0100 Subject: [PATCH 0135/1089] Cutting down the number of tests through expected case grouping --- .../PythonBoilerplateEnumeratorTest.java | 158 +++++++++++------- 1 file changed, 98 insertions(+), 60 deletions(-) diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java index 0c507849..ff246fcc 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java @@ -17,6 +17,7 @@ import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; +import java.util.List; import java.util.stream.Stream; class PythonBoilerplateEnumeratorTest extends BaseTest { @@ -26,57 +27,92 @@ private static class PythonCodeProvider implements ArgumentsProvider { @Override public Stream provideArguments(ExtensionContext extensionContext) { return Stream.of( - Arguments.of("def function():", null), - Arguments.of("def __new__():", Boilerplate.CONSTRUCTOR), - Arguments.of("def __init__():", Boilerplate.INITIALIZER), - Arguments.of("def __str__():", Boilerplate.STRING_CONVERSION), - Arguments.of("def __repr__():", Boilerplate.STRING_REPRESENTATION), - Arguments.of("def __hash__():", Boilerplate.HASHER), - Arguments.of("def __get__():", Boilerplate.GETTER), - Arguments.of("def __getattr__():", Boilerplate.GETTER), - Arguments.of("def __set__():", Boilerplate.SETTER), - Arguments.of("def __setattr__():", Boilerplate.SETTER), - Arguments.of("def __del__():", Boilerplate.FINALIZER), - Arguments.of("def __delattr__():", Boilerplate.FINALIZER), - Arguments.of("def __eq__():", Boilerplate.COMPARISON), - Arguments.of("def __lt__():", Boilerplate.COMPARISON), - Arguments.of("def __le__():", Boilerplate.COMPARISON), - Arguments.of("def __gt__():", Boilerplate.COMPARISON), - Arguments.of("def __ge__():", Boilerplate.COMPARISON), - Arguments.of("def __neg__():", Boilerplate.UNARY_ARITHMETIC), - Arguments.of("def __pos__():", Boilerplate.UNARY_ARITHMETIC), - Arguments.of("def __abs__():", Boilerplate.UNARY_ARITHMETIC), - Arguments.of("def __invert__():", Boilerplate.UNARY_ARITHMETIC), - Arguments.of("def __round__():", Boilerplate.UNARY_ARITHMETIC), - Arguments.of("def __floor__():", Boilerplate.UNARY_ARITHMETIC), - Arguments.of("def __ceil__():", Boilerplate.UNARY_ARITHMETIC), - Arguments.of("def __trunc__():", Boilerplate.UNARY_ARITHMETIC), - Arguments.of("def __add__():", Boilerplate.BINARY_ARITHMETIC), - Arguments.of("def __sub__():", Boilerplate.BINARY_ARITHMETIC), - Arguments.of("def __mul__():", Boilerplate.BINARY_ARITHMETIC), - Arguments.of("def __div__():", Boilerplate.BINARY_ARITHMETIC), - Arguments.of("def __truediv__():", Boilerplate.BINARY_ARITHMETIC), - Arguments.of("def __floordiv__():", Boilerplate.BINARY_ARITHMETIC), - Arguments.of("def __mod__():", Boilerplate.BINARY_ARITHMETIC), - Arguments.of("def __pow__():", Boilerplate.BINARY_ARITHMETIC), - Arguments.of("def __lshift__():", Boilerplate.BINARY_ARITHMETIC), - Arguments.of("def __rshift__():", Boilerplate.BINARY_ARITHMETIC), - Arguments.of("def __and__():", Boilerplate.BINARY_ARITHMETIC), - Arguments.of("def __xor__():", Boilerplate.BINARY_ARITHMETIC), - Arguments.of("def __or__():", Boilerplate.BINARY_ARITHMETIC), - Arguments.of("def __iadd__():", Boilerplate.AUGMENTED_ASSIGNMENT), - Arguments.of("def __isub__():", Boilerplate.AUGMENTED_ASSIGNMENT), - Arguments.of("def __imul__():", Boilerplate.AUGMENTED_ASSIGNMENT), - Arguments.of("def __imatmul__():", Boilerplate.AUGMENTED_ASSIGNMENT), - Arguments.of("def __itruediv__():", Boilerplate.AUGMENTED_ASSIGNMENT), - Arguments.of("def __ifloordiv__():", Boilerplate.AUGMENTED_ASSIGNMENT), - Arguments.of("def __imod__():", Boilerplate.AUGMENTED_ASSIGNMENT), - Arguments.of("def __ipow__():", Boilerplate.AUGMENTED_ASSIGNMENT), - Arguments.of("def __ilshift__():", Boilerplate.AUGMENTED_ASSIGNMENT), - Arguments.of("def __irshift__():", Boilerplate.AUGMENTED_ASSIGNMENT), - Arguments.of("def __iand__():", Boilerplate.AUGMENTED_ASSIGNMENT), - Arguments.of("def __ixor__():", Boilerplate.AUGMENTED_ASSIGNMENT), - Arguments.of("def __ior__():", Boilerplate.AUGMENTED_ASSIGNMENT) + Arguments.of(List.of("def function():"), null), + Arguments.of(List.of("def __new__():"), Boilerplate.CONSTRUCTOR), + Arguments.of(List.of("def __init__():"), Boilerplate.INITIALIZER), + Arguments.of(List.of("def __str__():"), Boilerplate.STRING_CONVERSION), + Arguments.of(List.of("def __repr__():"), Boilerplate.STRING_REPRESENTATION), + Arguments.of(List.of("def __hash__():"), Boilerplate.HASHER), + Arguments.of( + List.of( + "def __get__():", + "def __getattr__():" + ), + Boilerplate.GETTER + ), + Arguments.of( + List.of( + "def __set__():", + "def __setattr__():" + ), + Boilerplate.SETTER + ), + Arguments.of( + List.of( + "def __del__():", + "def __delattr__():" + ), + Boilerplate.FINALIZER + ), + Arguments.of( + List.of( + "def __eq__():", + "def __lt__():", + "def __le__():", + "def __gt__():", + "def __ge__():" + ), + Boilerplate.COMPARISON + ), + Arguments.of( + List.of( + "def __neg__():", + "def __pos__():", + "def __abs__():", + "def __invert__():", + "def __round__():", + "def __floor__():", + "def __ceil__():", + "def __trunc__():" + ), + Boilerplate.UNARY_ARITHMETIC + ), + Arguments.of( + List.of( + "def __add__():", + "def __sub__():", + "def __mul__():", + "def __div__():", + "def __truediv__():", + "def __floordiv__():", + "def __mod__():", + "def __pow__():", + "def __lshift__():", + "def __rshift__():", + "def __and__():", + "def __xor__():", + "def __or__():" + ), + Boilerplate.BINARY_ARITHMETIC + ), + Arguments.of( + List.of( + "def __iadd__():", + "def __isub__():", + "def __imul__():", + "def __imatmul__():", + "def __itruediv__():", + "def __ifloordiv__():", + "def __imod__():", + "def __ipow__():", + "def __ilshift__():", + "def __irshift__():", + "def __iand__():", + "def __ixor__():", + "def __ior__():" + ), + Boilerplate.AUGMENTED_ASSIGNMENT + ) ); } } @@ -86,16 +122,18 @@ public Stream provideArguments(ExtensionContext extensionCo @ParameterizedTest(name = "[{index}] {1}") @ArgumentsSource(PythonCodeProvider.class) @SneakyThrows(UnsupportedEncodingException.class) - void asEnumTest(String source, Boilerplate expected) { + void asEnumTest(List sources, Boilerplate expected) { @Cleanup Parser parser = new Parser(Language.PYTHON); - @Cleanup Tree tree = parser.parseString(source); - Node root = tree.getRootNode(); - Node function_definition = root.getChild(0); - BoilerplateEnumerator enumerator = new PythonBoilerplateEnumerator( - () -> source.getBytes(StandardCharsets.UTF_16LE) - ); - Boilerplate actual = enumerator.asEnum(function_definition); - Assertions.assertEquals(expected, actual); + for (String source: sources) { + @Cleanup Tree tree = parser.parseString(source); + Node root = tree.getRootNode(); + Node function_definition = root.getChild(0); + BoilerplateEnumerator enumerator = new PythonBoilerplateEnumerator( + () -> source.getBytes(StandardCharsets.UTF_16LE) + ); + Boilerplate actual = enumerator.asEnum(function_definition); + Assertions.assertEquals(expected, actual); + } } private static class PythonCodeProviderSpecial implements ArgumentsProvider { From e39c9401aa94e8d7f0a6a2143b3be122aeca7cb7 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 27 Jan 2023 15:22:10 +0100 Subject: [PATCH 0136/1089] `JavaBoilerplateEnumeratorTest` now receiving the same treatment --- .../JavaBoilerplateEnumeratorTest.java | 117 ++++++++---------- 1 file changed, 52 insertions(+), 65 deletions(-) diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java index a87518b7..fef118ef 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java @@ -1,79 +1,66 @@ package usi.si.seart.analyzer.enumerator; +import lombok.Cleanup; +import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; import usi.si.seart.analyzer.test.BaseTest; import usi.si.seart.model.code.Boilerplate; +import usi.si.seart.treesitter.Language; import usi.si.seart.treesitter.Node; +import usi.si.seart.treesitter.Parser; +import usi.si.seart.treesitter.Tree; + +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; +import java.util.stream.Stream; class JavaBoilerplateEnumeratorTest extends BaseTest { - @Override - protected String getInput() { - return - "package ch.usi.si;\n" + - "\n" + - "public class Main {\n" + - " public Main() {}\n" + - " public Main(int i) {}\n" + - " public void getI() {}\n" + - " public void getI(int i) {}\n" + - " public void setI() {}\n" + - " public void setI(int i) {}\n" + - " public void compareTo() {}\n" + - " public void equals() {}\n" + - " public void hashCode() {}\n" + - " public void toString() {}\n" + - " public void writeObject() {}\n" + - " public void readObject() {}\n" + - " public void readObjectNoData() {}\n" + - " public void clone() {}\n" + - " public void finalize() {}\n" + - " public void run() {}\n" + - " public static void main(String[] args) {}\n" + - "}"; + private static class JavaCodeProvider implements ArgumentsProvider { + + @Override + public Stream provideArguments(ExtensionContext context) { + return Stream.of( + Arguments.of("public class _ { public void run() {} }", null), + Arguments.of("public class _ { public static void main(String[] args) {} }", null), + Arguments.of("public class _ { public Main() {} }", Boilerplate.CONSTRUCTOR), + Arguments.of("public class _ { public Main(int i) {} }", Boilerplate.CONSTRUCTOR), + Arguments.of("public class _ { public void getI() {} }", Boilerplate.GETTER), + Arguments.of("public class _ { public void getI(int i) {} }", Boilerplate.GETTER), + Arguments.of("public class _ { public void setI() {} }", Boilerplate.SETTER), + Arguments.of("public class _ { public void setI(int i) {} }", Boilerplate.SETTER), + Arguments.of("public class _ { public void compareTo() {} }", Boilerplate.COMPARISON), + Arguments.of("public class _ { public void equals() {} }", Boilerplate.COMPARISON), + Arguments.of("public class _ { public void hashCode() {} }", Boilerplate.HASHER), + Arguments.of("public class _ { public void toString() {} }", Boilerplate.STRING_CONVERSION), + Arguments.of("public class _ { public void writeObject() {} }", Boilerplate.SERIALIZER), + Arguments.of("public class _ { public void readObject() {} }", Boilerplate.DESERIALIZER), + Arguments.of("public class _ { public void readObjectNoData() {} }", Boilerplate.DESERIALIZER), + Arguments.of("public class _ { public void clone() {} }", Boilerplate.CLONER), + Arguments.of("public class _ { public void finalize() {} }", Boilerplate.FINALIZER) + ); + } } - @Test - void asEnumTest() { - BoilerplateEnumerator enumerator = new JavaBoilerplateEnumerator(getNodeMapper()); + @ParameterizedTest(name = "[{index}] {1}") + @ArgumentsSource(JavaCodeProvider.class) + @SneakyThrows(UnsupportedEncodingException.class) + void asEnumTest(String source, Boilerplate expected) { + BoilerplateEnumerator enumerator = new JavaBoilerplateEnumerator( + () -> source.getBytes(StandardCharsets.UTF_16LE) + ); + @Cleanup Parser parser = new Parser(Language.JAVA); + @Cleanup Tree tree = parser.parseString(source); Node root = tree.getRootNode(); - Node clazz = root.getChild(1); - Node body = clazz.getChildByFieldName("body"); - Node constructor_0 = body.getChild(1); - Node constructor_1 = body.getChild(2); - Node method_00 = body.getChild(3); - Node method_01 = body.getChild(4); - Node method_02 = body.getChild(5); - Node method_03 = body.getChild(6); - Node method_04 = body.getChild(7); - Node method_05 = body.getChild(8); - Node method_06 = body.getChild(9); - Node method_07 = body.getChild(10); - Node method_08 = body.getChild(11); - Node method_09 = body.getChild(12); - Node method_10 = body.getChild(13); - Node method_11 = body.getChild(14); - Node method_12 = body.getChild(15); - Node method_13 = body.getChild(16); - Node method_14 = body.getChild(17); - - Assertions.assertEquals(Boilerplate.CONSTRUCTOR, enumerator.asEnum(constructor_0)); - Assertions.assertEquals(Boilerplate.CONSTRUCTOR, enumerator.asEnum(constructor_1)); - Assertions.assertEquals(Boilerplate.GETTER, enumerator.asEnum(method_00)); - Assertions.assertEquals(Boilerplate.GETTER, enumerator.asEnum(method_01)); - Assertions.assertEquals(Boilerplate.SETTER, enumerator.asEnum(method_02)); - Assertions.assertEquals(Boilerplate.SETTER, enumerator.asEnum(method_03)); - Assertions.assertEquals(Boilerplate.COMPARISON, enumerator.asEnum(method_04)); - Assertions.assertEquals(Boilerplate.COMPARISON, enumerator.asEnum(method_05)); - Assertions.assertEquals(Boilerplate.HASHER, enumerator.asEnum(method_06)); - Assertions.assertEquals(Boilerplate.STRING_CONVERSION, enumerator.asEnum(method_07)); - Assertions.assertEquals(Boilerplate.SERIALIZER, enumerator.asEnum(method_08)); - Assertions.assertEquals(Boilerplate.DESERIALIZER, enumerator.asEnum(method_09)); - Assertions.assertEquals(Boilerplate.DESERIALIZER, enumerator.asEnum(method_10)); - Assertions.assertEquals(Boilerplate.CLONER, enumerator.asEnum(method_11)); - Assertions.assertEquals(Boilerplate.FINALIZER, enumerator.asEnum(method_12)); - Assertions.assertNull(enumerator.asEnum(method_13)); - Assertions.assertNull(enumerator.asEnum(method_14)); + Node class_declaration = root.getChild(0); + Node class_body = class_declaration.getChildByFieldName("body"); + Node callable_declaration = class_body.getChild(1); + Boilerplate actual = enumerator.asEnum(callable_declaration); + Assertions.assertEquals(expected, actual); } } \ No newline at end of file From ac172546ed899282365ee334c34ecc2ac506d08a Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 27 Jan 2023 15:23:04 +0100 Subject: [PATCH 0137/1089] The enumerator tests no longer extend `BaseTest` --- .../analyzer/enumerator/JavaBoilerplateEnumeratorTest.java | 3 +-- .../analyzer/enumerator/PythonBoilerplateEnumeratorTest.java | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java index fef118ef..8ce00dc8 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java @@ -8,7 +8,6 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.ArgumentsProvider; import org.junit.jupiter.params.provider.ArgumentsSource; -import usi.si.seart.analyzer.test.BaseTest; import usi.si.seart.model.code.Boilerplate; import usi.si.seart.treesitter.Language; import usi.si.seart.treesitter.Node; @@ -19,7 +18,7 @@ import java.nio.charset.StandardCharsets; import java.util.stream.Stream; -class JavaBoilerplateEnumeratorTest extends BaseTest { +class JavaBoilerplateEnumeratorTest { private static class JavaCodeProvider implements ArgumentsProvider { diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java index ff246fcc..e73e6c8e 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java @@ -8,7 +8,6 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.ArgumentsProvider; import org.junit.jupiter.params.provider.ArgumentsSource; -import usi.si.seart.analyzer.test.BaseTest; import usi.si.seart.model.code.Boilerplate; import usi.si.seart.treesitter.Language; import usi.si.seart.treesitter.Node; @@ -20,7 +19,7 @@ import java.util.List; import java.util.stream.Stream; -class PythonBoilerplateEnumeratorTest extends BaseTest { +class PythonBoilerplateEnumeratorTest { private static class PythonCodeProvider implements ArgumentsProvider { From bee56bfedbfa5c4518e253e7f629a1ddb4ad1f20 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 30 Jan 2023 10:28:54 +0100 Subject: [PATCH 0138/1089] Separated `TokenCounter` into a more specific `JavaTokenCounter` We will introduce a `PythonTokenCounter` later, so doing this makes sense. The test corresponding to this will also change. The current `TokenCounter` abstract class is so general that it should only be used in case of fallback being required. --- .../si/seart/analyzer/AbstractAnalyzer.java | 4 +- .../usi/si/seart/analyzer/JavaAnalyzer.java | 2 + .../analyzer/count/JavaTokenCounter.java | 40 +++++++++++++++++++ .../si/seart/analyzer/count/TokenCounter.java | 28 ++++--------- ...terTest.java => JavaTokenCounterTest.java} | 8 ++-- 5 files changed, 56 insertions(+), 26 deletions(-) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/JavaTokenCounter.java rename dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/{TokenCounterTest.java => JavaTokenCounterTest.java} (81%) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java index 26736851..0f095f96 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java @@ -101,7 +101,7 @@ public List>> execute(Node node, String pattern) { Enumerator boilerplateEnumerator = node -> null; - @SneakyThrows({IOException.class}) + @SneakyThrows(IOException.class) protected AbstractAnalyzer(LocalClone localClone, Path path, Language language) { this.language = language; this.parser = new Parser(language); @@ -110,7 +110,7 @@ protected AbstractAnalyzer(LocalClone localClone, Path path, Language language) this.source = Files.readString(path); this.tree = parser.parseString(source); NodeMapper mapper = this::getSourceBytes; - this.totalTokenCounter = new TokenCounter(mapper); + this.totalTokenCounter = new TokenCounter(mapper){}; this.characterCounter = new CharacterCounter(mapper); this.contentHasher = new ContentHasher(mapper); this.containsNonAscii = new ContainsNonAsciiPredicate(mapper); diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java index b61bfa6c..911b15f8 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java @@ -1,5 +1,6 @@ package usi.si.seart.analyzer; +import usi.si.seart.analyzer.count.JavaTokenCounter; import usi.si.seart.analyzer.enumerator.JavaBoilerplateEnumerator; import usi.si.seart.analyzer.predicate.path.JavaTestFilePredicate; import usi.si.seart.analyzer.query.multi.JavaMultiCaptureQueries; @@ -12,6 +13,7 @@ public class JavaAnalyzer extends AbstractAnalyzer { public JavaAnalyzer(LocalClone localClone, Path path) { super(localClone, path, Language.JAVA); + this.totalTokenCounter = new JavaTokenCounter(this::getSourceBytes); this.testFilePredicate = new JavaTestFilePredicate(); this.singleCaptureQueries = new JavaSingleCaptureQueries(); this.multiCaptureQueries = new JavaMultiCaptureQueries(); diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/JavaTokenCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/JavaTokenCounter.java new file mode 100644 index 00000000..bb8d821e --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/JavaTokenCounter.java @@ -0,0 +1,40 @@ +package usi.si.seart.analyzer.count; + +import usi.si.seart.analyzer.NodeMapper; +import usi.si.seart.treesitter.Node; +import usi.si.seart.treesitter.Range; + +public class JavaTokenCounter extends TokenCounter { + + public JavaTokenCounter(NodeMapper mapper) { + super(mapper); + } + + @Override + protected void nodeCallback(Node node) { + boolean leafNode = node.getChildCount() == 0; + if (leafNode) { + String[] tokens; + Range range = node.getRange(); + String content = mapper.getContentForRange(range); + String type = node.getType(); + switch (type) { + case "block_comment": + int idxLo = (content.startsWith("/**")) ? 3 : 2; + int idxHi = content.length() - 2; + content = content.substring(idxLo, idxHi); + tokens = content.split("\\s+"); + count.addAndGet(tokens.length + 2L); + break; + case "line_comment": + content = content.substring(2); + tokens = content.split("\\s+"); + count.addAndGet(tokens.length + 1L); + break; + default: + count.addAndGet(1L); + break; + } + } + } +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TokenCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TokenCounter.java index a1cc56bc..c733ecd9 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TokenCounter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TokenCounter.java @@ -4,7 +4,7 @@ import usi.si.seart.treesitter.Node; import usi.si.seart.treesitter.Range; -public class TokenCounter extends ContentTraverseCounter { +public abstract class TokenCounter extends ContentTraverseCounter { public TokenCounter(NodeMapper mapper) { super(mapper); @@ -14,26 +14,14 @@ public TokenCounter(NodeMapper mapper) { protected void nodeCallback(Node node) { boolean leafNode = node.getChildCount() == 0; if (leafNode) { - String[] tokens; - Range range = node.getRange(); - String content = mapper.getContentForRange(range); String type = node.getType(); - switch (type) { - case "block_comment": - int idxLo = (content.startsWith("/**")) ? 3 : 2; - int idxHi = content.length() - 2; - content = content.substring(idxLo, idxHi); - tokens = content.split("\\s+"); - count.addAndGet(tokens.length + 2L); - break; - case "line_comment": - content = content.substring(2); - tokens = content.split("\\s+"); - count.addAndGet(tokens.length + 1L); - break; - default: - count.addAndGet(1L); - break; + if (type.equals("comment")) { + Range range = node.getRange(); + String content = mapper.getContentForRange(range); + String[] tokens = content.split("\\s+"); + count.addAndGet(tokens.length); + } else { + count.addAndGet(1L); } } } diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/TokenCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaTokenCounterTest.java similarity index 81% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/TokenCounterTest.java rename to dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaTokenCounterTest.java index e7edf56b..507ad760 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/TokenCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaTokenCounterTest.java @@ -7,18 +7,18 @@ import java.util.HashSet; -class TokenCounterTest extends BaseTest { +class JavaTokenCounterTest extends BaseTest { @Test void countEmptyTest() { - Counter counter = new TokenCounter(getNodeMapper()); + Counter counter = new JavaTokenCounter(getNodeMapper()); Assertions.assertEquals(0, counter.count()); Assertions.assertEquals(0, counter.count(new HashSet<>())); } @Test void countRootTest() { - Counter counter = new TokenCounter(getNodeMapper()); + Counter counter = new JavaTokenCounter(getNodeMapper()); Long actual = counter.count(tree.getRootNode()); // Add 1 for the extra comment word Assertions.assertEquals( @@ -29,7 +29,7 @@ void countRootTest() { @Test void countChildrenTest() { - Counter counter = new TokenCounter(getNodeMapper()); + Counter counter = new JavaTokenCounter(getNodeMapper()); Node root = tree.getRootNode(); Node package_declaration = root.getChild(0); Node class_declaration = root.getChild(1); From fe5269333bf8c6fdadfc55c5b2137a7116da09f5 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 30 Jan 2023 10:40:22 +0100 Subject: [PATCH 0139/1089] Separated `JavaBaseTest` from `BaseTest` We will start introducing more python-specific tests now, and as such we need to start making a distinction between the two test types. --- .../analyzer/count/CharacterCounterTest.java | 4 +- .../analyzer/count/CodeTokenCounterTest.java | 4 +- .../analyzer/count/JavaTokenCounterTest.java | 4 +- .../seart/analyzer/count/LineCounterTest.java | 4 +- .../si/seart/analyzer/hash/HasherTest.java | 4 +- .../predicate/node/PredicateTest.java | 4 +- .../analyzer/printer/NodePrinterTest.java | 4 +- .../printer/OffsetSyntaxTreePrinterTest.java | 4 +- .../SymbolicExpressionPrinterTest.java | 4 +- .../printer/SyntaxTreePrinterTest.java | 4 +- .../usi/si/seart/analyzer/test/BaseTest.java | 94 +--------------- .../si/seart/analyzer/test/JavaBaseTest.java | 106 ++++++++++++++++++ .../PreviousCommentTraverserTest.java | 4 +- 13 files changed, 132 insertions(+), 112 deletions(-) create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/JavaBaseTest.java diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CharacterCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CharacterCounterTest.java index 87f8fafe..2257f238 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CharacterCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CharacterCounterTest.java @@ -2,12 +2,12 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import usi.si.seart.analyzer.test.BaseTest; +import usi.si.seart.analyzer.test.JavaBaseTest; import usi.si.seart.treesitter.Node; import java.util.HashSet; -class CharacterCounterTest extends BaseTest { +class CharacterCounterTest extends JavaBaseTest { @Test void countEmptyTest() { diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CodeTokenCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CodeTokenCounterTest.java index 75851f43..e5dbc625 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CodeTokenCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CodeTokenCounterTest.java @@ -2,12 +2,12 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import usi.si.seart.analyzer.test.BaseTest; +import usi.si.seart.analyzer.test.JavaBaseTest; import usi.si.seart.treesitter.Node; import java.util.HashSet; -class CodeTokenCounterTest extends BaseTest { +class CodeTokenCounterTest extends JavaBaseTest { @Test void countEmptyTest() { diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaTokenCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaTokenCounterTest.java index 507ad760..36d6a444 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaTokenCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaTokenCounterTest.java @@ -2,12 +2,12 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import usi.si.seart.analyzer.test.BaseTest; +import usi.si.seart.analyzer.test.JavaBaseTest; import usi.si.seart.treesitter.Node; import java.util.HashSet; -class JavaTokenCounterTest extends BaseTest { +class JavaTokenCounterTest extends JavaBaseTest { @Test void countEmptyTest() { diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/LineCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/LineCounterTest.java index e8a41f8b..66f64b91 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/LineCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/LineCounterTest.java @@ -2,12 +2,12 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import usi.si.seart.analyzer.test.BaseTest; +import usi.si.seart.analyzer.test.JavaBaseTest; import usi.si.seart.treesitter.Node; import java.util.HashSet; -class LineCounterTest extends BaseTest { +class LineCounterTest extends JavaBaseTest { @Test void countEmptyTest() { diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/HasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/HasherTest.java index 8df84eb2..54fa1746 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/HasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/HasherTest.java @@ -1,13 +1,13 @@ package usi.si.seart.analyzer.hash; import lombok.SneakyThrows; -import usi.si.seart.analyzer.test.BaseTest; +import usi.si.seart.analyzer.test.JavaBaseTest; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.List; -public abstract class HasherTest extends BaseTest { +public abstract class HasherTest extends JavaBaseTest { // https://crypto.stackexchange.com/a/26135 protected String empty = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/PredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/PredicateTest.java index ac0d42a7..a65578f8 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/PredicateTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/PredicateTest.java @@ -1,8 +1,8 @@ package usi.si.seart.analyzer.predicate.node; -import usi.si.seart.analyzer.test.BaseTest; +import usi.si.seart.analyzer.test.JavaBaseTest; -public abstract class PredicateTest extends BaseTest { +public abstract class PredicateTest extends JavaBaseTest { @Override protected String getInput() { diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java index d148f4a6..efa08438 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java @@ -2,12 +2,12 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import usi.si.seart.analyzer.test.BaseTest; +import usi.si.seart.analyzer.test.JavaBaseTest; import usi.si.seart.treesitter.Node; import java.util.HashSet; -class NodePrinterTest extends BaseTest { +class NodePrinterTest extends JavaBaseTest { @Test void printNothingTest() { diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinterTest.java index a5b0cc5c..81e5cc42 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinterTest.java @@ -2,11 +2,11 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import usi.si.seart.analyzer.test.BaseTest; +import usi.si.seart.analyzer.test.JavaBaseTest; import usi.si.seart.treesitter.Node; import usi.si.seart.treesitter.Point; -class OffsetSyntaxTreePrinterTest extends BaseTest { +class OffsetSyntaxTreePrinterTest extends JavaBaseTest { @Test void idempotencyTest() { diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinterTest.java index f70f0998..f40252a7 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinterTest.java @@ -2,12 +2,12 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import usi.si.seart.analyzer.test.BaseTest; +import usi.si.seart.analyzer.test.JavaBaseTest; import usi.si.seart.treesitter.Node; import java.util.HashSet; -class SymbolicExpressionPrinterTest extends BaseTest { +class SymbolicExpressionPrinterTest extends JavaBaseTest { @Test void printNothingTest() { diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java index 3a93fe23..1502528a 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java @@ -2,12 +2,12 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import usi.si.seart.analyzer.test.BaseTest; +import usi.si.seart.analyzer.test.JavaBaseTest; import usi.si.seart.treesitter.Node; import java.util.HashSet; -class SyntaxTreePrinterTest extends BaseTest { +class SyntaxTreePrinterTest extends JavaBaseTest { @Test void printNothingTest() { diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java index d3d7d039..553c1c3a 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java @@ -43,21 +43,9 @@ void tearDown() { tree.close(); } - protected Language getLanguage() { - return Language.JAVA; - } + protected abstract Language getLanguage(); - protected String getInput() { - return - "package ch.usi.si;\n" + - "\n" + - "public class Main {\n" + - " public static void main(String[] args) {\n" + - " //line comment\n" + - " System.out.println(\"Hello, World!\");\n" + - " }\n" + - "}"; - } + protected abstract String getInput(); protected byte[] getBytes() { return getInput().getBytes(StandardCharsets.UTF_16LE); @@ -67,87 +55,13 @@ protected NodeMapper getNodeMapper() { return this::getBytes; } - protected List getTokens() { - return List.of( - "package", - "ch", - ".", - "usi", - ".", - "si", - ";", - "public", - "class", - "Main", - "{", - "//line comment", - "public", - "static", - "void", - "main", - "(", - "String", - "[", - "]", - "args", - ")", - "{", - "System", - ".", - "out", - ".", - "println", - "(", - "\"Hello, World!\"", - ")", - ";", - "}", - "}" - ); - } + protected abstract List getTokens(); protected String getJoinedTokens() { return String.join("", getTokens()); } - protected List getNodes() { - return List.of( - "package", - "identifier", - ".", - "identifier", - ".", - "identifier", - ";", - "public", - "class", - "identifier", - "{", - "line_comment", - "public", - "static", - "void_type", - "identifier", - "(", - "type_identifier", - "[", - "]", - "identifier", - ")", - "{", - "identifier", - ".", - "identifier", - ".", - "identifier", - "(", - "string_literal", - ")", - ";", - "}", - "}" - ); - } + protected abstract List getNodes(); protected String getJoinedNodes() { return String.join("", getNodes()); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/JavaBaseTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/JavaBaseTest.java new file mode 100644 index 00000000..32c95deb --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/JavaBaseTest.java @@ -0,0 +1,106 @@ +package usi.si.seart.analyzer.test; + +import usi.si.seart.treesitter.Language; + +import java.util.List; + +public abstract class JavaBaseTest extends BaseTest { + + @Override + protected Language getLanguage() { + return Language.JAVA; + } + + @Override + protected String getInput() { + return + "package ch.usi.si;\n" + + "\n" + + "public class Main {\n" + + " public static void main(String[] args) {\n" + + " //line comment\n" + + " System.out.println(\"Hello, World!\");\n" + + " }\n" + + "}"; + } + + @Override + protected List getTokens() { + return List.of( + "package", + "ch", + ".", + "usi", + ".", + "si", + ";", + "public", + "class", + "Main", + "{", + "//line comment", + "public", + "static", + "void", + "main", + "(", + "String", + "[", + "]", + "args", + ")", + "{", + "System", + ".", + "out", + ".", + "println", + "(", + "\"Hello, World!\"", + ")", + ";", + "}", + "}" + ); + } + + @Override + protected List getNodes() { + return List.of( + "package", + "identifier", + ".", + "identifier", + ".", + "identifier", + ";", + "public", + "class", + "identifier", + "{", + "line_comment", + "public", + "static", + "void_type", + "identifier", + "(", + "type_identifier", + "[", + "]", + "identifier", + ")", + "{", + "identifier", + ".", + "identifier", + ".", + "identifier", + "(", + "string_literal", + ")", + ";", + "}", + "}" + ); + } +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/traverser/PreviousCommentTraverserTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/traverser/PreviousCommentTraverserTest.java index aede66d5..bfbb71b7 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/traverser/PreviousCommentTraverserTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/traverser/PreviousCommentTraverserTest.java @@ -3,12 +3,12 @@ import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import usi.si.seart.analyzer.test.BaseTest; +import usi.si.seart.analyzer.test.JavaBaseTest; import usi.si.seart.treesitter.Node; import java.util.Collection; -class PreviousCommentTraverserTest extends BaseTest { +class PreviousCommentTraverserTest extends JavaBaseTest { @Override protected String getInput() { From 996cf95966ad000f279104be661abbdfe8353eb9 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 30 Jan 2023 10:47:54 +0100 Subject: [PATCH 0140/1089] Renamed language-specific tests --- ...{CharacterCounterTest.java => JavaCharacterCounterTest.java} | 2 +- ...{CodeTokenCounterTest.java => JavaCodeTokenCounterTest.java} | 2 +- .../count/{LineCounterTest.java => JavaLineCounterTest.java} | 2 +- .../hash/{ContentHasherTest.java => JavaContentHasherTest.java} | 2 +- .../analyzer/hash/{HasherTest.java => JavaHasherTest.java} | 2 +- ...{SyntaxTreeHasherTest.java => JavaSyntaxTreeHasherTest.java} | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) rename dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/{CharacterCounterTest.java => JavaCharacterCounterTest.java} (95%) rename dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/{CodeTokenCounterTest.java => JavaCodeTokenCounterTest.java} (95%) rename dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/{LineCounterTest.java => JavaLineCounterTest.java} (96%) rename dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/{ContentHasherTest.java => JavaContentHasherTest.java} (97%) rename dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/{HasherTest.java => JavaHasherTest.java} (97%) rename dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/{SyntaxTreeHasherTest.java => JavaSyntaxTreeHasherTest.java} (97%) diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CharacterCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCharacterCounterTest.java similarity index 95% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CharacterCounterTest.java rename to dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCharacterCounterTest.java index 2257f238..3843af1d 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CharacterCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCharacterCounterTest.java @@ -7,7 +7,7 @@ import java.util.HashSet; -class CharacterCounterTest extends JavaBaseTest { +class JavaCharacterCounterTest extends JavaBaseTest { @Test void countEmptyTest() { diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CodeTokenCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCodeTokenCounterTest.java similarity index 95% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CodeTokenCounterTest.java rename to dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCodeTokenCounterTest.java index e5dbc625..bc135940 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/CodeTokenCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCodeTokenCounterTest.java @@ -7,7 +7,7 @@ import java.util.HashSet; -class CodeTokenCounterTest extends JavaBaseTest { +class JavaCodeTokenCounterTest extends JavaBaseTest { @Test void countEmptyTest() { diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/LineCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaLineCounterTest.java similarity index 96% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/LineCounterTest.java rename to dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaLineCounterTest.java index 66f64b91..459e30c1 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/LineCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaLineCounterTest.java @@ -7,7 +7,7 @@ import java.util.HashSet; -class LineCounterTest extends JavaBaseTest { +class JavaLineCounterTest extends JavaBaseTest { @Test void countEmptyTest() { diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaContentHasherTest.java similarity index 97% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java rename to dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaContentHasherTest.java index 66c0617b..97c4e21c 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/ContentHasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaContentHasherTest.java @@ -9,7 +9,7 @@ import java.nio.charset.StandardCharsets; import java.util.HashSet; -class ContentHasherTest extends HasherTest { +class JavaContentHasherTest extends JavaHasherTest { @Test void emptyTest() { diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/HasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaHasherTest.java similarity index 97% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/HasherTest.java rename to dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaHasherTest.java index 54fa1746..0614d365 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/HasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaHasherTest.java @@ -7,7 +7,7 @@ import java.security.NoSuchAlgorithmException; import java.util.List; -public abstract class HasherTest extends JavaBaseTest { +public abstract class JavaHasherTest extends JavaBaseTest { // https://crypto.stackexchange.com/a/26135 protected String empty = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/SyntaxTreeHasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java similarity index 97% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/SyntaxTreeHasherTest.java rename to dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java index 8e589eb2..5e10306f 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/SyntaxTreeHasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java @@ -8,7 +8,7 @@ import java.io.UnsupportedEncodingException; import java.util.HashSet; -class SyntaxTreeHasherTest extends HasherTest { +class JavaSyntaxTreeHasherTest extends JavaHasherTest { @Test void emptyTest() { From 57c9239b3c9ba3f6803c83b33a122fe9fe84e3af Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 16 May 2023 09:59:28 +0200 Subject: [PATCH 0141/1089] Bumping versions of dependencies and isolating to properties --- pom.xml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 6f0d6e56..22572925 100644 --- a/pom.xml +++ b/pom.xml @@ -35,8 +35,10 @@ 1.0.0 UTF-8 - 5.8.2 - 3.24.4 + 5.9.3 + 3.25.3 + 1.18.26 + 42.6.0 @@ -65,12 +67,12 @@ org.projectlombok lombok - 1.18.24 + ${lombok.version} org.postgresql postgresql - 42.5.0 + ${postgresql.version} From 3b2cfad21c3dcde020b76a47426e8d57e1fc64c0 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 16 May 2023 10:16:43 +0200 Subject: [PATCH 0142/1089] Moving `jackson` dependency management to parent POM --- dl4se-model/pom.xml | 13 ------------- pom.xml | 8 ++++++++ 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/dl4se-model/pom.xml b/dl4se-model/pom.xml index dfb6be98..e11340a7 100644 --- a/dl4se-model/pom.xml +++ b/dl4se-model/pom.xml @@ -14,21 +14,8 @@ UTF-8 - 2.13.4 - - - - com.fasterxml.jackson - jackson-bom - ${jackson.version} - pom - import - - - - com.fasterxml.jackson.core diff --git a/pom.xml b/pom.xml index 22572925..c9566c8a 100644 --- a/pom.xml +++ b/pom.xml @@ -39,6 +39,7 @@ 3.25.3 1.18.26 42.6.0 + 2.15.0
@@ -50,6 +51,13 @@ pom import + + com.fasterxml.jackson + jackson-bom + ${jackson.version} + pom + import + From 542d6cdf6d8701f1ee2c70eb1b3c642d7a47304e Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 16 May 2023 11:54:59 +0200 Subject: [PATCH 0143/1089] Added `PythonBaseTest`, for now unused --- .../seart/analyzer/test/PythonBaseTest.java | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/PythonBaseTest.java diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/PythonBaseTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/PythonBaseTest.java new file mode 100644 index 00000000..731c52ab --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/PythonBaseTest.java @@ -0,0 +1,55 @@ +package usi.si.seart.analyzer.test; + +import usi.si.seart.treesitter.Language; + +import java.util.List; + +public abstract class PythonBaseTest extends BaseTest { + + @Override + protected Language getLanguage() { + return Language.PYTHON; + } + + @Override + protected String getInput() { + return + "def main(arg):\n" + + " #line comment\n" + + " print(f\"Hello, {arg}!\")"; + } + + @Override + protected List getTokens() { + return List.of( + "def", + "main", + "(", + "arg", + ")", + ":", + "#line comment", + "print", + "(", + "f\"Hello, {arg}!\"", + ")" + ); + } + + @Override + protected List getNodes() { + return List.of( + "def", + "identifier", + "(", + "identifier", + ")", + ":", + "comment", + "identifier", + "(", + "string", + ")" + ); + } +} From 43a929cbd57429b39008c8aa919ad537ebf239fc Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 16 May 2023 11:55:32 +0200 Subject: [PATCH 0144/1089] Added various TODOs in the code to outline direction of development --- .../main/java/usi/si/seart/analyzer/AbstractAnalyzer.java | 6 ++++++ .../src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java | 3 +++ .../java/usi/si/seart/analyzer/count/TraverseCounter.java | 4 ++++ 3 files changed, 13 insertions(+) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java index 0f095f96..c4e28b47 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java @@ -168,6 +168,12 @@ protected List extractFunctionEntities(File file) { return functions; } + // TODO: 25.01.23 Parse content again for the AST + // - use the same parser instance to construct a new tree from the content + // - in case we are dealing with Java, wrap the content with `class _ {\n...}` (define protected `wrap`) + // - define extraction of the targets from the wrapper + // (just getChildren or more specific getChild(0).getChildByFieldName("body")) + // - stream over them and do the same as before protected Function extractFunctionEntity(List> match) { List nodes = match.stream() .map(Tuple::getValue) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java index 0cd24e90..a04646f4 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java @@ -12,6 +12,9 @@ public class PythonAnalyzer extends AbstractAnalyzer { public PythonAnalyzer(LocalClone localClone, Path path) { super(localClone, path, Language.PYTHON); + // TODO: 16.05.23 Add dedicated counters for all/code-only tokens + // this.codeTokenCounter = new PythonCodeTokenCounter(); + // this.totalTokenCounter = new PythonTokenCounter(this::getSourceBytes); this.testFilePredicate = new PythonTestFilePredicate(); this.singleCaptureQueries = new PythonSingleCaptureQueries(); this.multiCaptureQueries = new PythonMultiCaptureQueries(); diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TraverseCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TraverseCounter.java index e84b0b98..1eea2b44 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TraverseCounter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TraverseCounter.java @@ -15,6 +15,10 @@ public abstract class TraverseCounter implements Counter { AtomicLong count = new AtomicLong(); + // TODO: 16.05.23 + // This implementation will not work for languages like Python. + // tree-sitter treats Python strings as non-leaf nodes that can contain interpolations. + // Rather than editing the grammar, which would hurt users of our API, we should alter this logic. @Override public Long count(Node node) { @Cleanup TreeCursor cursor = node.walk(); From f002e4a983323cd05bdc63c9a203bde9c4808121 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 16 May 2023 12:56:47 +0200 Subject: [PATCH 0145/1089] Replaced local `dl4se-tree-sitter` with our Maven dependency Also, removed all submodules associated with it --- .gitmodules | 18 - dl4se-analyzer/pom.xml | 6 +- .../si/seart/analyzer/AbstractAnalyzer.java | 10 +- .../usi/si/seart/analyzer/JavaAnalyzer.java | 2 +- .../usi/si/seart/analyzer/NodeMapper.java | 2 +- .../usi/si/seart/analyzer/PythonAnalyzer.java | 2 +- .../analyzer/count/CharacterCounter.java | 4 +- .../analyzer/count/CodeTokenCounter.java | 2 +- .../usi/si/seart/analyzer/count/Counter.java | 2 +- .../analyzer/count/JavaTokenCounter.java | 4 +- .../si/seart/analyzer/count/LineCounter.java | 6 +- .../si/seart/analyzer/count/TokenCounter.java | 4 +- .../seart/analyzer/count/TraverseCounter.java | 4 +- .../seart/analyzer/enumerator/Enumerator.java | 2 +- .../enumerator/JavaBoilerplateEnumerator.java | 4 +- .../PythonBoilerplateEnumerator.java | 4 +- .../si/seart/analyzer/hash/ContentHasher.java | 6 +- .../usi/si/seart/analyzer/hash/Hasher.java | 2 +- .../si/seart/analyzer/hash/SHA256Hasher.java | 2 +- .../seart/analyzer/hash/SyntaxTreeHasher.java | 4 +- .../node/ContainsErrorPredicate.java | 2 +- .../node/ContainsNonAsciiPredicate.java | 4 +- .../predicate/node/NodePredicate.java | 2 +- .../analyzer/printer/AbstractPrinter.java | 2 +- .../seart/analyzer/printer/NodePrinter.java | 4 +- .../printer/OffsetSyntaxTreePrinter.java | 6 +- .../si/seart/analyzer/printer/Printer.java | 2 +- .../printer/SymbolicExpressionPrinter.java | 2 +- .../analyzer/printer/SyntaxTreePrinter.java | 4 +- .../usi/si/seart/analyzer/query/Queries.java | 4 +- .../query/multi/JavaMultiCaptureQueries.java | 4 +- .../query/multi/MultiCaptureQueries.java | 12 +- .../multi/PythonMultiCaptureQueries.java | 4 +- .../single/JavaSingleCaptureQueries.java | 4 +- .../single/PythonSingleCaptureQueries.java | 4 +- .../query/single/SingleCaptureQueries.java | 12 +- .../traverser/PreviousCommentTraverser.java | 2 +- .../seart/analyzer/traverser/Traverser.java | 2 +- .../count/JavaCharacterCounterTest.java | 2 +- .../count/JavaCodeTokenCounterTest.java | 2 +- .../analyzer/count/JavaLineCounterTest.java | 2 +- .../analyzer/count/JavaTokenCounterTest.java | 2 +- .../JavaBoilerplateEnumeratorTest.java | 8 +- .../PythonBoilerplateEnumeratorTest.java | 8 +- .../analyzer/hash/JavaContentHasherTest.java | 2 +- .../hash/JavaSyntaxTreeHasherTest.java | 2 +- .../node/ContainsErrorPredicateTest.java | 8 +- .../node/ContainsNonAsciiPredicateTest.java | 4 +- .../analyzer/printer/NodePrinterTest.java | 2 +- .../printer/OffsetSyntaxTreePrinterTest.java | 4 +- .../SymbolicExpressionPrinterTest.java | 2 +- .../printer/SyntaxTreePrinterTest.java | 2 +- .../usi/si/seart/analyzer/test/BaseTest.java | 8 +- .../si/seart/analyzer/test/JavaBaseTest.java | 2 +- .../seart/analyzer/test/PythonBaseTest.java | 2 +- .../PreviousCommentTraverserTest.java | 2 +- dl4se-tree-sitter/build.py | 136 ----- .../lib/usi_si_seart_treesitter_Languages.cc | 235 ------- .../lib/usi_si_seart_treesitter_Languages.h | 277 --------- .../lib/usi_si_seart_treesitter_TreeSitter.cc | 576 ------------------ .../lib/usi_si_seart_treesitter_TreeSitter.h | 413 ------------- dl4se-tree-sitter/pom.xml | 106 ---- .../usi/si/seart/treesitter/External.java | 29 - .../usi/si/seart/treesitter/InputEdit.java | 19 - .../usi/si/seart/treesitter/Language.java | 114 ---- .../usi/si/seart/treesitter/Languages.java | 50 -- .../si/seart/treesitter/LibraryLoader.java | 72 --- .../java/usi/si/seart/treesitter/Node.java | 300 --------- .../java/usi/si/seart/treesitter/Parser.java | 134 ---- .../java/usi/si/seart/treesitter/Point.java | 28 - .../java/usi/si/seart/treesitter/Query.java | 110 ---- .../usi/si/seart/treesitter/QueryCapture.java | 20 - .../usi/si/seart/treesitter/QueryCursor.java | 96 --- .../usi/si/seart/treesitter/QueryMatch.java | 27 - .../java/usi/si/seart/treesitter/Range.java | 26 - .../seart/treesitter/SyntaxTreePrinter.java | 83 --- .../java/usi/si/seart/treesitter/Tree.java | 60 -- .../usi/si/seart/treesitter/TreeCursor.java | 98 --- .../si/seart/treesitter/TreeCursorNode.java | 28 - .../usi/si/seart/treesitter/TreeSitter.java | 108 ---- .../treesitter/error/ABIVersionError.java | 13 - .../exception/TreeSitterException.java | 10 - .../query/QueryCaptureException.java | 7 - .../exception/query/QueryException.java | 11 - .../exception/query/QueryFieldException.java | 7 - .../query/QueryNodeTypeException.java | 7 - .../query/QueryStructureException.java | 7 - .../exception/query/QuerySyntaxException.java | 7 - dl4se-tree-sitter/src/main/resources/.gitkeep | 0 .../usi/si/seart/treesitter/NodeTest.java | 204 ------- .../usi/si/seart/treesitter/ParserTest.java | 60 -- .../usi/si/seart/treesitter/PointTest.java | 18 - .../si/seart/treesitter/QueryCursorTest.java | 95 --- .../usi/si/seart/treesitter/QueryTest.java | 62 -- .../usi/si/seart/treesitter/TestBase.java | 8 - .../si/seart/treesitter/TreeCursorTest.java | 40 -- .../usi/si/seart/treesitter/TreeTest.java | 42 -- dl4se-tree-sitter/tree-sitter | 1 - dl4se-tree-sitter/tree-sitter-c | 1 - dl4se-tree-sitter/tree-sitter-cpp | 1 - dl4se-tree-sitter/tree-sitter-java | 1 - dl4se-tree-sitter/tree-sitter-javascript | 1 - dl4se-tree-sitter/tree-sitter-python | 1 - pom.xml | 1 - 104 files changed, 106 insertions(+), 3874 deletions(-) delete mode 100755 dl4se-tree-sitter/build.py delete mode 100644 dl4se-tree-sitter/lib/usi_si_seart_treesitter_Languages.cc delete mode 100644 dl4se-tree-sitter/lib/usi_si_seart_treesitter_Languages.h delete mode 100644 dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc delete mode 100644 dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.h delete mode 100644 dl4se-tree-sitter/pom.xml delete mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/External.java delete mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/InputEdit.java delete mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Language.java delete mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Languages.java delete mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/LibraryLoader.java delete mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java delete mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java delete mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Point.java delete mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java delete mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCapture.java delete mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCursor.java delete mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryMatch.java delete mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Range.java delete mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/SyntaxTreePrinter.java delete mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java delete mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursor.java delete mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursorNode.java delete mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitter.java delete mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/error/ABIVersionError.java delete mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/TreeSitterException.java delete mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryCaptureException.java delete mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryException.java delete mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryFieldException.java delete mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryNodeTypeException.java delete mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryStructureException.java delete mode 100644 dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QuerySyntaxException.java delete mode 100644 dl4se-tree-sitter/src/main/resources/.gitkeep delete mode 100644 dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java delete mode 100644 dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/ParserTest.java delete mode 100644 dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/PointTest.java delete mode 100644 dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryCursorTest.java delete mode 100644 dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java delete mode 100644 dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TestBase.java delete mode 100644 dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeCursorTest.java delete mode 100644 dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeTest.java delete mode 160000 dl4se-tree-sitter/tree-sitter delete mode 160000 dl4se-tree-sitter/tree-sitter-c delete mode 160000 dl4se-tree-sitter/tree-sitter-cpp delete mode 160000 dl4se-tree-sitter/tree-sitter-java delete mode 160000 dl4se-tree-sitter/tree-sitter-javascript delete mode 160000 dl4se-tree-sitter/tree-sitter-python diff --git a/.gitmodules b/.gitmodules index 5bebf0a5..e69de29b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,18 +0,0 @@ -[submodule "tree-sitter"] - path = dl4se-tree-sitter/tree-sitter - url = https://github.com/tree-sitter/tree-sitter.git -[submodule "tree-sitter-c"] - path = dl4se-tree-sitter/tree-sitter-c - url = https://github.com/tree-sitter/tree-sitter-c.git -[submodule "tree-sitter-cpp"] - path = dl4se-tree-sitter/tree-sitter-cpp - url = https://github.com/tree-sitter/tree-sitter-cpp.git -[submodule "tree-sitter-java"] - path = dl4se-tree-sitter/tree-sitter-java - url = https://github.com/tree-sitter/tree-sitter-java.git -[submodule "tree-sitter-javascript"] - path = dl4se-tree-sitter/tree-sitter-javascript - url = https://github.com/tree-sitter/tree-sitter-javascript.git -[submodule "tree-sitter-python"] - path = dl4se-tree-sitter/tree-sitter-python - url = https://github.com/tree-sitter/tree-sitter-python.git diff --git a/dl4se-analyzer/pom.xml b/dl4se-analyzer/pom.xml index 2e40683d..4c6419a2 100644 --- a/dl4se-analyzer/pom.xml +++ b/dl4se-analyzer/pom.xml @@ -25,9 +25,9 @@ ${project.version} - usi.si.seart - dl4se-tree-sitter - ${project.version} + ch.usi.si.seart + java-tree-sitter + 1.0.0 diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java index c4e28b47..62e5741f 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java @@ -1,5 +1,10 @@ package usi.si.seart.analyzer; +import ch.usi.si.seart.treesitter.Language; +import ch.usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Parser; +import ch.usi.si.seart.treesitter.Query; +import ch.usi.si.seart.treesitter.Tree; import lombok.AccessLevel; import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; @@ -26,11 +31,6 @@ import usi.si.seart.model.code.Boilerplate; import usi.si.seart.model.code.File; import usi.si.seart.model.code.Function; -import usi.si.seart.treesitter.Language; -import usi.si.seart.treesitter.Node; -import usi.si.seart.treesitter.Parser; -import usi.si.seart.treesitter.Query; -import usi.si.seart.treesitter.Tree; import java.io.IOException; import java.nio.file.Files; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java index 911b15f8..0f9b8e85 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java @@ -1,11 +1,11 @@ package usi.si.seart.analyzer; +import ch.usi.si.seart.treesitter.Language; import usi.si.seart.analyzer.count.JavaTokenCounter; import usi.si.seart.analyzer.enumerator.JavaBoilerplateEnumerator; import usi.si.seart.analyzer.predicate.path.JavaTestFilePredicate; import usi.si.seart.analyzer.query.multi.JavaMultiCaptureQueries; import usi.si.seart.analyzer.query.single.JavaSingleCaptureQueries; -import usi.si.seart.treesitter.Language; import java.nio.file.Path; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/NodeMapper.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/NodeMapper.java index 7fd8f545..7673d047 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/NodeMapper.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/NodeMapper.java @@ -1,6 +1,6 @@ package usi.si.seart.analyzer; -import usi.si.seart.treesitter.Range; +import ch.usi.si.seart.treesitter.Range; import java.util.Arrays; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java index a04646f4..709af803 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java @@ -1,10 +1,10 @@ package usi.si.seart.analyzer; +import ch.usi.si.seart.treesitter.Language; import usi.si.seart.analyzer.enumerator.PythonBoilerplateEnumerator; import usi.si.seart.analyzer.predicate.path.PythonTestFilePredicate; import usi.si.seart.analyzer.query.multi.PythonMultiCaptureQueries; import usi.si.seart.analyzer.query.single.PythonSingleCaptureQueries; -import usi.si.seart.treesitter.Language; import java.nio.file.Path; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CharacterCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CharacterCounter.java index 5ee51c91..b829d798 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CharacterCounter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CharacterCounter.java @@ -1,8 +1,8 @@ package usi.si.seart.analyzer.count; +import ch.usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Range; import usi.si.seart.analyzer.NodeMapper; -import usi.si.seart.treesitter.Node; -import usi.si.seart.treesitter.Range; public class CharacterCounter extends ContentTraverseCounter { diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CodeTokenCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CodeTokenCounter.java index 336d1f66..a71af870 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CodeTokenCounter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CodeTokenCounter.java @@ -1,6 +1,6 @@ package usi.si.seart.analyzer.count; -import usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Node; public class CodeTokenCounter extends TraverseCounter { diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/Counter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/Counter.java index e89ffd13..9ea66255 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/Counter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/Counter.java @@ -1,6 +1,6 @@ package usi.si.seart.analyzer.count; -import usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Node; import java.util.Collection; import java.util.stream.Stream; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/JavaTokenCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/JavaTokenCounter.java index bb8d821e..f8f32eb7 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/JavaTokenCounter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/JavaTokenCounter.java @@ -1,8 +1,8 @@ package usi.si.seart.analyzer.count; +import ch.usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Range; import usi.si.seart.analyzer.NodeMapper; -import usi.si.seart.treesitter.Node; -import usi.si.seart.treesitter.Range; public class JavaTokenCounter extends TokenCounter { diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/LineCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/LineCounter.java index 0836046a..c69b4679 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/LineCounter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/LineCounter.java @@ -1,8 +1,8 @@ package usi.si.seart.analyzer.count; -import usi.si.seart.treesitter.Node; -import usi.si.seart.treesitter.Point; -import usi.si.seart.treesitter.Range; +import ch.usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Point; +import ch.usi.si.seart.treesitter.Range; public class LineCounter implements Counter { diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TokenCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TokenCounter.java index c733ecd9..80e43852 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TokenCounter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TokenCounter.java @@ -1,8 +1,8 @@ package usi.si.seart.analyzer.count; +import ch.usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Range; import usi.si.seart.analyzer.NodeMapper; -import usi.si.seart.treesitter.Node; -import usi.si.seart.treesitter.Range; public abstract class TokenCounter extends ContentTraverseCounter { diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TraverseCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TraverseCounter.java index 1eea2b44..6f4f6351 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TraverseCounter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TraverseCounter.java @@ -1,11 +1,11 @@ package usi.si.seart.analyzer.count; +import ch.usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.TreeCursor; import lombok.AccessLevel; import lombok.Cleanup; import lombok.NoArgsConstructor; import lombok.experimental.FieldDefaults; -import usi.si.seart.treesitter.Node; -import usi.si.seart.treesitter.TreeCursor; import java.util.concurrent.atomic.AtomicLong; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/Enumerator.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/Enumerator.java index 27439ec9..3c3ca81c 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/Enumerator.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/Enumerator.java @@ -1,6 +1,6 @@ package usi.si.seart.analyzer.enumerator; -import usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Node; public interface Enumerator> { E asEnum(Node node); diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumerator.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumerator.java index ac064e6c..4bf06228 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumerator.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumerator.java @@ -1,9 +1,9 @@ package usi.si.seart.analyzer.enumerator; +import ch.usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Range; import usi.si.seart.analyzer.NodeMapper; import usi.si.seart.model.code.Boilerplate; -import usi.si.seart.treesitter.Node; -import usi.si.seart.treesitter.Range; public class JavaBoilerplateEnumerator extends BoilerplateEnumerator { diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumerator.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumerator.java index a1ccc561..1a380753 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumerator.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumerator.java @@ -1,9 +1,9 @@ package usi.si.seart.analyzer.enumerator; +import ch.usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Range; import usi.si.seart.analyzer.NodeMapper; import usi.si.seart.model.code.Boilerplate; -import usi.si.seart.treesitter.Node; -import usi.si.seart.treesitter.Range; public class PythonBoilerplateEnumerator extends BoilerplateEnumerator { diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java index ab12abe4..dba84f67 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java @@ -1,11 +1,11 @@ package usi.si.seart.analyzer.hash; +import ch.usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Range; +import ch.usi.si.seart.treesitter.TreeCursor; import lombok.Cleanup; import lombok.Getter; import usi.si.seart.analyzer.NodeMapper; -import usi.si.seart.treesitter.Node; -import usi.si.seart.treesitter.Range; -import usi.si.seart.treesitter.TreeCursor; @Getter public class ContentHasher extends SHA256Hasher { diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/Hasher.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/Hasher.java index e4af7f98..7d5fd20a 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/Hasher.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/Hasher.java @@ -1,6 +1,6 @@ package usi.si.seart.analyzer.hash; -import usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Node; import java.util.Collection; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SHA256Hasher.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SHA256Hasher.java index a8e2cf3a..eae40249 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SHA256Hasher.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SHA256Hasher.java @@ -1,7 +1,7 @@ package usi.si.seart.analyzer.hash; +import ch.usi.si.seart.treesitter.Node; import lombok.SneakyThrows; -import usi.si.seart.treesitter.Node; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SyntaxTreeHasher.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SyntaxTreeHasher.java index af71f138..aac9779e 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SyntaxTreeHasher.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SyntaxTreeHasher.java @@ -1,8 +1,8 @@ package usi.si.seart.analyzer.hash; +import ch.usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.TreeCursor; import lombok.Cleanup; -import usi.si.seart.treesitter.Node; -import usi.si.seart.treesitter.TreeCursor; public class SyntaxTreeHasher extends SHA256Hasher { diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicate.java index a974bdcb..b97c9ee7 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicate.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicate.java @@ -1,6 +1,6 @@ package usi.si.seart.analyzer.predicate.node; -import usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Node; public class ContainsErrorPredicate extends NodePredicate { diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicate.java index 2fe455a2..119525e0 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicate.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicate.java @@ -1,8 +1,8 @@ package usi.si.seart.analyzer.predicate.node; +import ch.usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Range; import usi.si.seart.analyzer.NodeMapper; -import usi.si.seart.treesitter.Node; -import usi.si.seart.treesitter.Range; public class ContainsNonAsciiPredicate extends NodeContentPredicate { diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/NodePredicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/NodePredicate.java index d413d4fb..c9986fac 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/NodePredicate.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/NodePredicate.java @@ -1,6 +1,6 @@ package usi.si.seart.analyzer.predicate.node; -import usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Node; import java.util.Collection; import java.util.function.Predicate; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/AbstractPrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/AbstractPrinter.java index 883d20e9..b7bd16af 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/AbstractPrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/AbstractPrinter.java @@ -1,6 +1,6 @@ package usi.si.seart.analyzer.printer; -import usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Node; import java.util.Collection; import java.util.stream.Collector; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java index e22eebd7..980a44ad 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java @@ -1,8 +1,8 @@ package usi.si.seart.analyzer.printer; +import ch.usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Range; import usi.si.seart.analyzer.NodeMapper; -import usi.si.seart.treesitter.Node; -import usi.si.seart.treesitter.Range; import java.util.List; import java.util.stream.Collector; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java index 302c660e..b12371e1 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java @@ -1,8 +1,8 @@ package usi.si.seart.analyzer.printer; +import ch.usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Point; import lombok.AllArgsConstructor; -import usi.si.seart.treesitter.Node; -import usi.si.seart.treesitter.Point; @AllArgsConstructor public class OffsetSyntaxTreePrinter extends AbstractPrinter { @@ -11,6 +11,6 @@ public class OffsetSyntaxTreePrinter extends AbstractPrinter { @Override public String print(Node node) { - return new usi.si.seart.treesitter.SyntaxTreePrinter(node, offset).printSubtree(); + return new ch.usi.si.seart.treesitter.SyntaxTreePrinter(node, offset).printSubtree(); } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/Printer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/Printer.java index d4e6a967..35635d12 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/Printer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/Printer.java @@ -1,6 +1,6 @@ package usi.si.seart.analyzer.printer; -import usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Node; import java.util.Collection; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinter.java index a3b41f3b..5e07d4c9 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinter.java @@ -1,6 +1,6 @@ package usi.si.seart.analyzer.printer; -import usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Node; import java.util.Collections; import java.util.Set; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java index cbe21431..4ab8cf7f 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java @@ -1,11 +1,11 @@ package usi.si.seart.analyzer.printer; -import usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Node; public class SyntaxTreePrinter extends AbstractPrinter { @Override public String print(Node node) { - return new usi.si.seart.treesitter.SyntaxTreePrinter(node).printSubtree(); + return new ch.usi.si.seart.treesitter.SyntaxTreePrinter(node).printSubtree(); } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/Queries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/Queries.java index 8c6bfb4e..4fb9b5bb 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/Queries.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/Queries.java @@ -1,7 +1,7 @@ package usi.si.seart.analyzer.query; -import usi.si.seart.treesitter.Node; -import usi.si.seart.treesitter.Query; +import ch.usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Query; import java.util.List; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/JavaMultiCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/JavaMultiCaptureQueries.java index d53f5315..0e89bdf6 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/JavaMultiCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/JavaMultiCaptureQueries.java @@ -1,8 +1,8 @@ package usi.si.seart.analyzer.query.multi; +import ch.usi.si.seart.treesitter.Language; +import ch.usi.si.seart.treesitter.Node; import usi.si.seart.analyzer.util.Tuple; -import usi.si.seart.treesitter.Language; -import usi.si.seart.treesitter.Node; import java.util.List; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java index 6206c666..0484cb31 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java @@ -1,16 +1,16 @@ package usi.si.seart.analyzer.query.multi; +import ch.usi.si.seart.treesitter.Language; +import ch.usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Query; +import ch.usi.si.seart.treesitter.QueryCapture; +import ch.usi.si.seart.treesitter.QueryCursor; +import ch.usi.si.seart.treesitter.QueryMatch; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Cleanup; import usi.si.seart.analyzer.query.Queries; import usi.si.seart.analyzer.util.Tuple; -import usi.si.seart.treesitter.Language; -import usi.si.seart.treesitter.Node; -import usi.si.seart.treesitter.Query; -import usi.si.seart.treesitter.QueryCapture; -import usi.si.seart.treesitter.QueryCursor; -import usi.si.seart.treesitter.QueryMatch; import java.util.ArrayList; import java.util.List; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/PythonMultiCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/PythonMultiCaptureQueries.java index d48c1044..8d54f6aa 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/PythonMultiCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/PythonMultiCaptureQueries.java @@ -1,8 +1,8 @@ package usi.si.seart.analyzer.query.multi; +import ch.usi.si.seart.treesitter.Language; +import ch.usi.si.seart.treesitter.Node; import usi.si.seart.analyzer.util.Tuple; -import usi.si.seart.treesitter.Language; -import usi.si.seart.treesitter.Node; import java.util.List; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/JavaSingleCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/JavaSingleCaptureQueries.java index 7efffa00..0a3ff080 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/JavaSingleCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/JavaSingleCaptureQueries.java @@ -1,7 +1,7 @@ package usi.si.seart.analyzer.query.single; -import usi.si.seart.treesitter.Language; -import usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Language; +import ch.usi.si.seart.treesitter.Node; import java.util.List; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/PythonSingleCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/PythonSingleCaptureQueries.java index 69a9a98f..adbd61c8 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/PythonSingleCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/PythonSingleCaptureQueries.java @@ -1,7 +1,7 @@ package usi.si.seart.analyzer.query.single; -import usi.si.seart.treesitter.Language; -import usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Language; +import ch.usi.si.seart.treesitter.Node; import java.util.List; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/SingleCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/SingleCaptureQueries.java index ed98569a..893e21a1 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/SingleCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/SingleCaptureQueries.java @@ -1,15 +1,15 @@ package usi.si.seart.analyzer.query.single; +import ch.usi.si.seart.treesitter.Language; +import ch.usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Query; +import ch.usi.si.seart.treesitter.QueryCapture; +import ch.usi.si.seart.treesitter.QueryCursor; +import ch.usi.si.seart.treesitter.QueryMatch; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Cleanup; import usi.si.seart.analyzer.query.Queries; -import usi.si.seart.treesitter.Language; -import usi.si.seart.treesitter.Node; -import usi.si.seart.treesitter.Query; -import usi.si.seart.treesitter.QueryCapture; -import usi.si.seart.treesitter.QueryCursor; -import usi.si.seart.treesitter.QueryMatch; import java.util.Arrays; import java.util.List; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/traverser/PreviousCommentTraverser.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/traverser/PreviousCommentTraverser.java index f7e00211..ab5e75af 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/traverser/PreviousCommentTraverser.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/traverser/PreviousCommentTraverser.java @@ -1,6 +1,6 @@ package usi.si.seart.analyzer.traverser; -import usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Node; import java.util.ArrayList; import java.util.List; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/traverser/Traverser.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/traverser/Traverser.java index 919148c4..77db5640 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/traverser/Traverser.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/traverser/Traverser.java @@ -1,6 +1,6 @@ package usi.si.seart.analyzer.traverser; -import usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Node; import java.util.Collection; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCharacterCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCharacterCounterTest.java index 3843af1d..0e4d0c2c 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCharacterCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCharacterCounterTest.java @@ -1,9 +1,9 @@ package usi.si.seart.analyzer.count; +import ch.usi.si.seart.treesitter.Node; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import usi.si.seart.analyzer.test.JavaBaseTest; -import usi.si.seart.treesitter.Node; import java.util.HashSet; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCodeTokenCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCodeTokenCounterTest.java index bc135940..9ec44585 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCodeTokenCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCodeTokenCounterTest.java @@ -1,9 +1,9 @@ package usi.si.seart.analyzer.count; +import ch.usi.si.seart.treesitter.Node; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import usi.si.seart.analyzer.test.JavaBaseTest; -import usi.si.seart.treesitter.Node; import java.util.HashSet; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaLineCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaLineCounterTest.java index 459e30c1..1a6e588e 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaLineCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaLineCounterTest.java @@ -1,9 +1,9 @@ package usi.si.seart.analyzer.count; +import ch.usi.si.seart.treesitter.Node; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import usi.si.seart.analyzer.test.JavaBaseTest; -import usi.si.seart.treesitter.Node; import java.util.HashSet; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaTokenCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaTokenCounterTest.java index 36d6a444..7d233b4d 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaTokenCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaTokenCounterTest.java @@ -1,9 +1,9 @@ package usi.si.seart.analyzer.count; +import ch.usi.si.seart.treesitter.Node; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import usi.si.seart.analyzer.test.JavaBaseTest; -import usi.si.seart.treesitter.Node; import java.util.HashSet; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java index 8ce00dc8..ba2b1e5f 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java @@ -1,5 +1,9 @@ package usi.si.seart.analyzer.enumerator; +import ch.usi.si.seart.treesitter.Language; +import ch.usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Parser; +import ch.usi.si.seart.treesitter.Tree; import lombok.Cleanup; import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; @@ -9,10 +13,6 @@ import org.junit.jupiter.params.provider.ArgumentsProvider; import org.junit.jupiter.params.provider.ArgumentsSource; import usi.si.seart.model.code.Boilerplate; -import usi.si.seart.treesitter.Language; -import usi.si.seart.treesitter.Node; -import usi.si.seart.treesitter.Parser; -import usi.si.seart.treesitter.Tree; import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java index e73e6c8e..ab58d622 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java @@ -1,5 +1,9 @@ package usi.si.seart.analyzer.enumerator; +import ch.usi.si.seart.treesitter.Language; +import ch.usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Parser; +import ch.usi.si.seart.treesitter.Tree; import lombok.Cleanup; import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; @@ -9,10 +13,6 @@ import org.junit.jupiter.params.provider.ArgumentsProvider; import org.junit.jupiter.params.provider.ArgumentsSource; import usi.si.seart.model.code.Boilerplate; -import usi.si.seart.treesitter.Language; -import usi.si.seart.treesitter.Node; -import usi.si.seart.treesitter.Parser; -import usi.si.seart.treesitter.Tree; import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaContentHasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaContentHasherTest.java index 97c4e21c..f58000d0 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaContentHasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaContentHasherTest.java @@ -1,9 +1,9 @@ package usi.si.seart.analyzer.hash; +import ch.usi.si.seart.treesitter.Tree; import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import usi.si.seart.treesitter.Tree; import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java index 5e10306f..4b6a03a7 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java @@ -1,9 +1,9 @@ package usi.si.seart.analyzer.hash; +import ch.usi.si.seart.treesitter.Tree; import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import usi.si.seart.treesitter.Tree; import java.io.UnsupportedEncodingException; import java.util.HashSet; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicateTest.java index a219bbe4..9e0fe3b9 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicateTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicateTest.java @@ -1,13 +1,13 @@ package usi.si.seart.analyzer.predicate.node; +import ch.usi.si.seart.treesitter.Language; +import ch.usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Parser; +import ch.usi.si.seart.treesitter.Tree; import lombok.Cleanup; import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import usi.si.seart.treesitter.Language; -import usi.si.seart.treesitter.Node; -import usi.si.seart.treesitter.Parser; -import usi.si.seart.treesitter.Tree; import java.io.UnsupportedEncodingException; import java.util.HashSet; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicateTest.java index 20585948..4384a805 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicateTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicateTest.java @@ -1,10 +1,10 @@ package usi.si.seart.analyzer.predicate.node; +import ch.usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Tree; import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import usi.si.seart.treesitter.Node; -import usi.si.seart.treesitter.Tree; import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java index efa08438..b9b77be3 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java @@ -1,9 +1,9 @@ package usi.si.seart.analyzer.printer; +import ch.usi.si.seart.treesitter.Node; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import usi.si.seart.analyzer.test.JavaBaseTest; -import usi.si.seart.treesitter.Node; import java.util.HashSet; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinterTest.java index 81e5cc42..63f9aa50 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinterTest.java @@ -1,10 +1,10 @@ package usi.si.seart.analyzer.printer; +import ch.usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Point; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import usi.si.seart.analyzer.test.JavaBaseTest; -import usi.si.seart.treesitter.Node; -import usi.si.seart.treesitter.Point; class OffsetSyntaxTreePrinterTest extends JavaBaseTest { diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinterTest.java index f40252a7..9b545668 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinterTest.java @@ -1,9 +1,9 @@ package usi.si.seart.analyzer.printer; +import ch.usi.si.seart.treesitter.Node; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import usi.si.seart.analyzer.test.JavaBaseTest; -import usi.si.seart.treesitter.Node; import java.util.HashSet; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java index 1502528a..73cc9896 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java @@ -1,9 +1,9 @@ package usi.si.seart.analyzer.printer; +import ch.usi.si.seart.treesitter.Node; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import usi.si.seart.analyzer.test.JavaBaseTest; -import usi.si.seart.treesitter.Node; import java.util.HashSet; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java index 553c1c3a..edeb8da0 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java @@ -1,13 +1,13 @@ package usi.si.seart.analyzer.test; +import ch.usi.si.seart.treesitter.Language; +import ch.usi.si.seart.treesitter.LibraryLoader; +import ch.usi.si.seart.treesitter.Parser; +import ch.usi.si.seart.treesitter.Tree; import lombok.SneakyThrows; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import usi.si.seart.analyzer.NodeMapper; -import usi.si.seart.treesitter.Language; -import usi.si.seart.treesitter.LibraryLoader; -import usi.si.seart.treesitter.Parser; -import usi.si.seart.treesitter.Tree; import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/JavaBaseTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/JavaBaseTest.java index 32c95deb..2f02afa9 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/JavaBaseTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/JavaBaseTest.java @@ -1,6 +1,6 @@ package usi.si.seart.analyzer.test; -import usi.si.seart.treesitter.Language; +import ch.usi.si.seart.treesitter.Language; import java.util.List; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/PythonBaseTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/PythonBaseTest.java index 731c52ab..97c0ee08 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/PythonBaseTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/PythonBaseTest.java @@ -1,6 +1,6 @@ package usi.si.seart.analyzer.test; -import usi.si.seart.treesitter.Language; +import ch.usi.si.seart.treesitter.Language; import java.util.List; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/traverser/PreviousCommentTraverserTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/traverser/PreviousCommentTraverserTest.java index bfbb71b7..ddce7e42 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/traverser/PreviousCommentTraverserTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/traverser/PreviousCommentTraverserTest.java @@ -1,10 +1,10 @@ package usi.si.seart.analyzer.traverser; +import ch.usi.si.seart.treesitter.Node; import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import usi.si.seart.analyzer.test.JavaBaseTest; -import usi.si.seart.treesitter.Node; import java.util.Collection; diff --git a/dl4se-tree-sitter/build.py b/dl4se-tree-sitter/build.py deleted file mode 100755 index 68f70b63..00000000 --- a/dl4se-tree-sitter/build.py +++ /dev/null @@ -1,136 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import ctypes.util -import distutils.ccompiler -import os -import platform -import tempfile - - -# adapted from https://github.com/tree-sitter/py-tree-sitter -def build(repositories, output_path="libjava-tree-sitter", arch=None, verbose=False): - if arch and platform.system() != "Darwin": - arch = "64" if "64" in arch else "32" - - output_path = f"{output_path}.{'dylib' if platform.system() == 'Darwin' else 'so'}" - here = os.path.dirname(os.path.realpath(__file__)) - env = "" - if arch: - env += ( - f"CFLAGS='-arch {arch} -mmacosx-version-min=11.0' LDFLAGS='-arch {arch}'" - if platform.system() == "Darwin" - else f"CFLAGS='-m{arch}' LDFLAGS='-m{arch}'" - ) - - os.system( - f"make -C {os.path.join(here, 'tree-sitter')} clean {'> /dev/null' if not verbose else ''}" - ) - os.system( - f"{env} make -C {os.path.join(here, 'tree-sitter')} {'> /dev/null' if not verbose else ''}" - ) - - cpp = False - source_paths = [ - os.path.join(here, "lib", "usi_si_seart_treesitter_Languages.cc"), - os.path.join(here, "lib", "usi_si_seart_treesitter_TreeSitter.cc"), - ] - - compiler = distutils.ccompiler.new_compiler() - for repository in repositories: - src_path = os.path.join(repository, "src") - source_paths.append(os.path.join(src_path, "parser.c")) - scanner_c = os.path.join(src_path, "scanner.c") - scanner_cc = os.path.join(src_path, "scanner.cc") - if os.path.exists(scanner_cc): - cpp = True - source_paths.append(scanner_cc) - elif os.path.exists(scanner_c): - source_paths.append(scanner_c) - - compiler.define_macro( - f"TS_LANGUAGE_{os.path.split(repository.rstrip('/'))[1].split('tree-sitter-')[-1].replace('-', '_').upper()}", - "1", - ) - - source_mtimes = [os.path.getmtime(__file__)] + [os.path.getmtime(path) for path in source_paths] - if cpp: - if ctypes.util.find_library("stdc++"): - compiler.add_library("stdc++") - elif ctypes.util.find_library("c++"): - compiler.add_library("c++") - - output_mtime = os.path.getmtime(output_path) if os.path.exists(output_path) else 0 - if max(source_mtimes) <= output_mtime: - return False - - with tempfile.TemporaryDirectory(suffix="tree_sitter_language") as out_dir: - object_paths = [] - for source_path in source_paths: - flags = ["-O3"] - - if platform.system() == "Linux": - flags.append("-fPIC") - - if source_path.endswith(".c"): - flags.append("-std=c99") - - if arch: - flags += ["-arch", arch] if platform.system() == "Darwin" else [f"-m{arch}"] - - include_dirs = [ - os.path.dirname(source_path), - os.path.join(here, "tree-sitter", "lib", "include"), - os.path.join(os.environ["JAVA_HOME"], "include"), - ] - - if platform.system() == "Linux": - include_dirs.append(os.path.join(os.environ["JAVA_HOME"], "include", "linux")) - elif platform.system() == "Darwin": - include_dirs.append(os.path.join(os.environ["JAVA_HOME"], "include", "darwin")) - - object_paths.append( - compiler.compile( - [source_path], - output_dir=out_dir, - include_dirs=include_dirs, - extra_preargs=flags, - )[0] - ) - - extra_preargs = [] - if platform.system() == "Darwin": - extra_preargs.append("-dynamiclib") - - if arch: - extra_preargs += ["-arch", arch] if platform.system() == "Darwin" else [f"-m{arch}"] - - compiler.link_shared_object( - object_paths, - output_path, - extra_preargs=extra_preargs, - extra_postargs=[os.path.join(here, "tree-sitter", "libtree-sitter.a")], - library_dirs=[os.path.join(here, "tree-sitter")], - ) - - return True - - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Build a tree-sitter library") - parser.add_argument( - "-a", - "--arch", - help="Architecture to build for (x86, x86_64, arm64)", - ) - parser.add_argument("-o", "--output", default="libjava-tree-sitter", help="Output file name") - parser.add_argument("-v", "--verbose", action="store_true", help="Print verbose output") - parser.add_argument( - "repositories", - nargs="+", - help="tree-sitter repositories to include in build", - ) - - args = parser.parse_args() - distutils.log.set_verbosity(int(args.verbose)) - build(args.repositories, args.output, args.arch, args.verbose) diff --git a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_Languages.cc b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_Languages.cc deleted file mode 100644 index 253db39a..00000000 --- a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_Languages.cc +++ /dev/null @@ -1,235 +0,0 @@ -#include "usi_si_seart_treesitter_Languages.h" -#include -#include -#include - -#ifdef TS_LANGUAGE_AGDA -extern "C" TSLanguage* tree_sitter_agda(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_agda(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_agda(); -} -#endif - -#ifdef TS_LANGUAGE_BASH -extern "C" TSLanguage* tree_sitter_bash(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_bash(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_bash(); -} -#endif - -#ifdef TS_LANGUAGE_C -extern "C" TSLanguage* tree_sitter_c(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_c(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_c(); -} -#endif - -#ifdef TS_LANGUAGE_C_SHARP -extern "C" TSLanguage* tree_sitter_c_sharp(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_cSharp(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_c_sharp(); -} -#endif - -#ifdef TS_LANGUAGE_CPP -extern "C" TSLanguage* tree_sitter_cpp(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_cpp(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_cpp(); -} -#endif - -#ifdef TS_LANGUAGE_CSS -extern "C" TSLanguage* tree_sitter_css(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_css(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_css(); -} -#endif - -#ifdef TS_LANGUAGE_DART -extern "C" TSLanguage* tree_sitter_dart(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_dart(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_dart(); -} -#endif - -#ifdef TS_LANGUAGE_ELM -extern "C" TSLanguage* tree_sitter_elm(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_elm(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_elm(); -} -#endif - -#ifdef TS_LANGUAGE_EMBEDDED_TEMPLATE -extern "C" TSLanguage* tree_sitter_embedded_template(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_embeddedTemplate(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_embedded_template(); -} -#endif - -#ifdef TS_LANGUAGE_ENO -extern "C" TSLanguage* tree_sitter_eno(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_eno(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_eno(); -} -#endif - -#ifdef TS_LANGUAGE_GO -extern "C" TSLanguage* tree_sitter_go(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_go(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_go(); -} -#endif - -#ifdef TS_LANGUAGE_HASKELL -extern "C" TSLanguage* tree_sitter_haskell(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_haskell(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_haskell(); -} -#endif - -#ifdef TS_LANGUAGE_HTML -extern "C" TSLanguage* tree_sitter_html(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_html(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_html(); -} -#endif - -#ifdef TS_LANGUAGE_JAVA -extern "C" TSLanguage* tree_sitter_java(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_java(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_java(); -} -#endif - -#ifdef TS_LANGUAGE_JAVASCRIPT -extern "C" TSLanguage* tree_sitter_javascript(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_javascript(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_javascript(); -} -#endif - -#ifdef TS_LANGUAGE_JULIA -extern "C" TSLanguage* tree_sitter_julia(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_julia(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_julia(); -} -#endif - -#ifdef TS_LANGUAGE_KOTLIN -extern "C" TSLanguage* tree_sitter_kotlin(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_kotlin(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_kotlin(); -} -#endif - -#ifdef TS_LANGUAGE_LUA -extern "C" TSLanguage* tree_sitter_lua(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_lua(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_lua(); -} -#endif - -#ifdef TS_LANGUAGE_MARKDOWN -extern "C" TSLanguage* tree_sitter_markdown(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_markdown(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_markdown(); -} -#endif - -#ifdef TS_LANGUAGE_OCAML -extern "C" TSLanguage* tree_sitter_ocaml(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_ocaml(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_ocaml(); -} -#endif - -#ifdef TS_LANGUAGE_PHP -extern "C" TSLanguage* tree_sitter_php(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_php(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_php(); -} -#endif - -#ifdef TS_LANGUAGE_PYTHON -extern "C" TSLanguage* tree_sitter_python(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_python(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_python(); -} -#endif - -#ifdef TS_LANGUAGE_RUBY -extern "C" TSLanguage* tree_sitter_ruby(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_ruby(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_ruby(); -} -#endif - -#ifdef TS_LANGUAGE_RUST -extern "C" TSLanguage* tree_sitter_rust(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_rust(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_rust(); -} -#endif - -#ifdef TS_LANGUAGE_SCALA -extern "C" TSLanguage* tree_sitter_scala(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_scala(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_scala(); -} -#endif - -#ifdef TS_LANGUAGE_SCSS -extern "C" TSLanguage* tree_sitter_scss(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_scss(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_scss(); -} -#endif - -#ifdef TS_LANGUAGE_SWIFT -extern "C" TSLanguage* tree_sitter_swift(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_swift(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_swift(); -} -#endif - -#ifdef TS_LANGUAGE_TOML -extern "C" TSLanguage* tree_sitter_toml(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_toml(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_toml(); -} -#endif - -#ifdef TS_LANGUAGE_TSX -extern "C" TSLanguage* tree_sitter_tsx(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_tsx(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_tsx(); -} -#endif - -#ifdef TS_LANGUAGE_TYPESCRIPT -extern "C" TSLanguage* tree_sitter_typescript(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_typescript(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_typescript(); -} -#endif - -#ifdef TS_LANGUAGE_VUE -extern "C" TSLanguage* tree_sitter_vue(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_vue(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_vue(); -} -#endif - -#ifdef TS_LANGUAGE_YAML -extern "C" TSLanguage* tree_sitter_yaml(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_yaml(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_yaml(); -} -#endif - -#ifdef TS_LANGUAGE_WASM -extern "C" TSLanguage* tree_sitter_wasm(); -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_wasm(JNIEnv* env, jclass self) { - return (jlong)tree_sitter_wasm(); -} -#endif diff --git a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_Languages.h b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_Languages.h deleted file mode 100644 index e7cec52d..00000000 --- a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_Languages.h +++ /dev/null @@ -1,277 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class usi_si_seart_treesitter_Languages */ - -#ifndef _Included_usi_si_seart_treesitter_Languages -#define _Included_usi_si_seart_treesitter_Languages -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: usi_si_seart_treesitter_Languages - * Method: agda - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_agda - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: bash - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_bash - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: c - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_c - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: cSharp - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_cSharp - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: cpp - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_cpp - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: css - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_css - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: dart - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_dart - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: elm - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_elm - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: embeddedTemplate - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_embeddedTemplate - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: eno - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_eno - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: go - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_go - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: haskell - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_haskell - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: html - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_html - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: java - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_java - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: javascript - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_javascript - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: julia - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_julia - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: kotlin - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_kotlin - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: lua - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_lua - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: markdown - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_markdown - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: ocaml - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_ocaml - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: php - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_php - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: python - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_python - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: ruby - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_ruby - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: rust - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_rust - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: scala - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_scala - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: scss - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_scss - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: swift - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_swift - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: toml - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_toml - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: tsx - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_tsx - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: typescript - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_typescript - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: vue - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_vue - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: yaml - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_yaml - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_Languages - * Method: wasm - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_Languages_wasm - (JNIEnv *, jclass); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc deleted file mode 100644 index be7a5640..00000000 --- a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.cc +++ /dev/null @@ -1,576 +0,0 @@ -#include "usi_si_seart_treesitter_TreeSitter.h" - -#include -#include -#include -#include - -struct TreeCursorNode { - const char* type; - const char* name; - uint32_t startByte; - uint32_t endByte; - TSPoint startPoint; - TSPoint endPoint; - bool isNamed; -}; - -static jint JNI_VERSION = JNI_VERSION_10; - -static jclass _inputEditClass; -static jfieldID _inputEditStartByteField; -static jfieldID _inputEditOldEndByteField; -static jfieldID _inputEditNewEndByteField; -static jfieldID _inputEditStartPointField; -static jfieldID _inputEditOldEndPointField; -static jfieldID _inputEditNewEndPointField; - -static jclass _nodeClass; -static jfieldID _nodeContext0Field; -static jfieldID _nodeContext1Field; -static jfieldID _nodeContext2Field; -static jfieldID _nodeContext3Field; -static jfieldID _nodeIdField; -static jfieldID _nodeTreeField; - -static jclass _pointClass; -static jfieldID _pointRowField; -static jfieldID _pointColumnField; - -static jclass _queryCursorClass; - -static jclass _queryMatchClass; -static jfieldID _queryMatchIdField; -static jfieldID _queryMatchPatternIndexField; -static jfieldID _queryMatchCapturesField; - -static jclass _queryCaptureClass; -static jfieldID _queryCaptureNode; -static jfieldID _queryCaptureIndex; - -static jclass _treeCursorNodeClass; -static jfieldID _treeCursorNodeTypeField; -static jfieldID _treeCursorNodeNameField; -static jfieldID _treeCursorNodeStartByteField; -static jfieldID _treeCursorNodeEndByteField; -static jfieldID _treeCursorNodeStartPointField; -static jfieldID _treeCursorNodeEndPointField; -static jfieldID _treeCursorNodeIsNamed; - -static jclass _treeSitterException; - -static jclass _queryCaptureExceptionClass; -static jclass _queryFieldExceptionClass; -static jclass _queryNodeTypeExceptionClass; -static jclass _queryStructureExceptionClass; -static jclass _querySyntaxExceptionClass; - -#define _loadClass(VARIABLE, NAME) \ - { \ - jclass tmp; \ - tmp = env->FindClass(NAME); \ - VARIABLE = (jclass)env->NewGlobalRef(tmp); \ - env->DeleteLocalRef(tmp); \ - } - -#define _loadField(VARIABLE, CLASS, NAME, TYPE) \ - { VARIABLE = env->GetFieldID(CLASS, NAME, TYPE); } - -jint JNI_OnLoad(JavaVM* vm, void* reserved) { - JNIEnv* env; - if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION) != JNI_OK) { - return JNI_ERR; - } - - _loadClass(_nodeClass, "usi/si/seart/treesitter/Node"); - _loadField(_nodeContext0Field, _nodeClass, "context0", "I"); - _loadField(_nodeContext1Field, _nodeClass, "context1", "I"); - _loadField(_nodeContext2Field, _nodeClass, "context2", "I"); - _loadField(_nodeContext3Field, _nodeClass, "context3", "I"); - _loadField(_nodeIdField, _nodeClass, "id", "J"); - _loadField(_nodeTreeField, _nodeClass, "tree", "J"); - - _loadClass(_pointClass, "usi/si/seart/treesitter/Point"); - _loadField(_pointRowField, _pointClass, "row", "I"); - _loadField(_pointColumnField, _pointClass, "column", "I"); - - _loadClass(_queryCursorClass, "usi/si/seart/treesitter/QueryCursor"); - - _loadClass(_queryCaptureClass, "usi/si/seart/treesitter/QueryCapture"); - _loadField(_queryCaptureNode, _queryCaptureClass, "node", "Lusi/si/seart/treesitter/Node;"); - _loadField(_queryCaptureIndex, _queryCaptureClass, "index", "I"); - - _loadClass(_queryMatchClass, "usi/si/seart/treesitter/QueryMatch"); - _loadField(_queryMatchIdField, _queryMatchClass, "id", "I"); - _loadField(_queryMatchPatternIndexField, _queryMatchClass, "pattern_index", "I"); - _loadField(_queryMatchCapturesField, _queryMatchClass, "captures", "[Lusi/si/seart/treesitter/QueryCapture;"); - - _loadClass(_treeCursorNodeClass, "usi/si/seart/treesitter/TreeCursorNode"); - _loadField(_treeCursorNodeTypeField, _treeCursorNodeClass, "type", "Ljava/lang/String;"); - _loadField(_treeCursorNodeNameField, _treeCursorNodeClass, "name", "Ljava/lang/String;"); - _loadField(_treeCursorNodeStartByteField, _treeCursorNodeClass, "startByte", "I"); - _loadField(_treeCursorNodeEndByteField, _treeCursorNodeClass, "endByte", "I"); - _loadField(_treeCursorNodeStartPointField, _treeCursorNodeClass, "startPoint", "Lusi/si/seart/treesitter/Point;"); - _loadField(_treeCursorNodeEndPointField, _treeCursorNodeClass, "endPoint", "Lusi/si/seart/treesitter/Point;"); - _loadField(_treeCursorNodeIsNamed, _treeCursorNodeClass, "isNamed", "Z"); - - _loadClass(_inputEditClass, "usi/si/seart/treesitter/InputEdit"); - _loadField(_inputEditStartByteField, _inputEditClass, "startByte", "I"); - _loadField(_inputEditOldEndByteField, _inputEditClass, "oldEndByte", "I"); - _loadField(_inputEditNewEndByteField, _inputEditClass, "newEndByte", "I"); - _loadField(_inputEditStartPointField, _inputEditClass, "startPoint", "Lusi/si/seart/treesitter/Point;"); - _loadField(_inputEditOldEndPointField, _inputEditClass, "oldEndPoint", "Lusi/si/seart/treesitter/Point;"); - _loadField(_inputEditNewEndPointField, _inputEditClass, "newEndPoint", "Lusi/si/seart/treesitter/Point;"); - - _loadClass(_treeSitterException, "usi/si/seart/treesitter/exception/TreeSitterException"); - - _loadClass(_queryCaptureExceptionClass, "usi/si/seart/treesitter/exception/query/QueryCaptureException"); - _loadClass(_queryFieldExceptionClass, "usi/si/seart/treesitter/exception/query/QueryFieldException"); - _loadClass(_queryNodeTypeExceptionClass, "usi/si/seart/treesitter/exception/query/QueryNodeTypeException"); - _loadClass(_queryStructureExceptionClass, "usi/si/seart/treesitter/exception/query/QueryStructureException"); - _loadClass(_querySyntaxExceptionClass, "usi/si/seart/treesitter/exception/query/QuerySyntaxException"); - - return JNI_VERSION; -} - -void JNI_OnUnload(JavaVM* vm, void* reserved) { - JNIEnv* env; - vm->GetEnv(reinterpret_cast(&env), JNI_VERSION); - env->DeleteGlobalRef(_nodeClass); - env->DeleteGlobalRef(_treeCursorNodeClass); -} - -jobject _marshalNode(JNIEnv* env, TSNode node) { - if (node.id == 0) return NULL; - jobject javaObject = env->AllocObject(_nodeClass); - env->SetIntField(javaObject, _nodeContext0Field, node.context[0]); - env->SetIntField(javaObject, _nodeContext1Field, node.context[1]); - env->SetIntField(javaObject, _nodeContext2Field, node.context[2]); - env->SetIntField(javaObject, _nodeContext3Field, node.context[3]); - env->SetLongField(javaObject, _nodeIdField, (jlong)node.id); - env->SetLongField(javaObject, _nodeTreeField, (jlong)node.tree); - return javaObject; -} - -TSNode _unmarshalNode(JNIEnv* env, jobject javaObject) { - return (TSNode){ - { - (uint32_t)env->GetIntField(javaObject, _nodeContext0Field), - (uint32_t)env->GetIntField(javaObject, _nodeContext1Field), - (uint32_t)env->GetIntField(javaObject, _nodeContext2Field), - (uint32_t)env->GetIntField(javaObject, _nodeContext3Field), - }, - (const void*)env->GetLongField(javaObject, _nodeIdField), - (const TSTree*)env->GetLongField(javaObject, _nodeTreeField)}; -} - -jobject _marshalPoint(JNIEnv* env, TSPoint point) { - jobject javaObject = env->AllocObject(_pointClass); - env->SetIntField(javaObject, _pointRowField, point.row); - env->SetIntField(javaObject, _pointColumnField, point.column / 2); - // Not sure why I need to divide by two, probably because of utf-16 - return javaObject; -} - -TSPoint _unmarshalPoint(JNIEnv* env, jobject javaObject) { - return (TSPoint) { - (uint32_t)env->GetIntField(javaObject, _pointRowField), - (uint32_t)env->GetIntField(javaObject, _pointColumnField), - }; -} - -jobject _marshalQueryCapture(JNIEnv* env, TSQueryCapture capture) { - jobject javaObject = env->AllocObject(_queryCaptureClass); - env->SetIntField(javaObject, _queryCaptureIndex, capture.index); - env->SetObjectField(javaObject, _queryCaptureNode, _marshalNode(env, capture.node)); - - return javaObject; -} - -jobject _marshalQueryMatch(JNIEnv* env, TSQueryMatch match) { - jobject javaObject = env->AllocObject(_queryMatchClass); - env->SetIntField(javaObject, _queryMatchIdField, match.id); - env->SetIntField(javaObject, _queryMatchPatternIndexField, match.pattern_index); - - jobjectArray captures = (*env).NewObjectArray(match.capture_count, _queryCaptureClass, NULL); - for (int i = 0; i < match.capture_count; i++) { - env->SetObjectArrayElement(captures, i, _marshalQueryCapture(env, match.captures[i])); - } - env->SetObjectField(javaObject, _queryMatchCapturesField, captures); - - return javaObject; -} - -jobject _marshalTreeCursorNode(JNIEnv* env, TreeCursorNode node) { - jobject javaObject = env->AllocObject(_treeCursorNodeClass); - env->SetObjectField(javaObject, _treeCursorNodeTypeField, env->NewStringUTF(node.type)); - env->SetObjectField(javaObject, _treeCursorNodeNameField, env->NewStringUTF(node.name)); - env->SetIntField(javaObject, _treeCursorNodeStartByteField, node.startByte); - env->SetIntField(javaObject, _treeCursorNodeEndByteField, node.endByte); - env->SetObjectField(javaObject, _treeCursorNodeStartPointField, _marshalPoint(env, node.startPoint)); - env->SetObjectField(javaObject, _treeCursorNodeEndPointField, _marshalPoint(env, node.endPoint)); - env->SetBooleanField(javaObject, _treeCursorNodeIsNamed, node.isNamed); - return javaObject; -} - -TSInputEdit _unmarshalInputEdit(JNIEnv* env, jobject inputEdit) { - return (TSInputEdit) { - (uint32_t)env->GetIntField(inputEdit, _inputEditStartByteField), - (uint32_t)env->GetIntField(inputEdit, _inputEditOldEndByteField), - (uint32_t)env->GetIntField(inputEdit, _inputEditNewEndByteField), - _unmarshalPoint(env, env->GetObjectField(inputEdit, _inputEditStartPointField)), - _unmarshalPoint(env, env->GetObjectField(inputEdit, _inputEditOldEndPointField)), - _unmarshalPoint(env, env->GetObjectField(inputEdit, _inputEditNewEndPointField)), - }; -} - -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeChild( - JNIEnv* env, jclass self, jobject node, jint child) { - return _marshalNode(env, ts_node_child(_unmarshalNode(env, node), (uint32_t)child)); -} - -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeChildByFieldName( - JNIEnv* env, jclass self, jobject node, jstring name) { - const char* c_name; - uint32_t name_length = env->GetStringLength(name); - c_name = env->GetStringUTFChars(name, NULL); - TSNode child = ts_node_child_by_field_name(_unmarshalNode(env, node), c_name, name_length); - if (ts_node_is_null(child)) return NULL; - return _marshalNode(env, child); -} - -JNIEXPORT jint JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeChildCount( - JNIEnv* env, jclass self, jobject node) { - return (jint)ts_node_child_count(_unmarshalNode(env, node)); -} - -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeDescendantForByteRange( - JNIEnv* env, jclass self, jobject node, jint start, jint end) { - TSNode descendant = ts_node_descendant_for_byte_range( - _unmarshalNode(env, node), (uint32_t)start * 2, (uint32_t)end * 2 - // Not sure why I need to multiply by two, again probably because of utf-16 - ); - return _marshalNode(env, descendant); -} - -JNIEXPORT jstring JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeString( - JNIEnv* env, jclass self, jobject node) { - char* nodeString = ts_node_string(_unmarshalNode(env, node)); - jstring result = env->NewStringUTF(nodeString); - free(nodeString); - return result; -} - -JNIEXPORT jint JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeEndByte( - JNIEnv* env, jclass self, jobject node) { - return (jint)ts_node_end_byte(_unmarshalNode(env, node)) / 2; -} - -JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeEq( - JNIEnv* env, jclass self, jobject node, jobject other) { - TSNode node_1 = _unmarshalNode(env, node); - TSNode node_2 = _unmarshalNode(env, other); - return ts_node_eq(node_1, node_2); -} - -JNIEXPORT jstring JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeFieldNameForChild( - JNIEnv* env, jclass self, jobject node, jint child) { - const char* nameForChild = ts_node_field_name_for_child(_unmarshalNode(env, node), (uint32_t)child); - jstring result = env->NewStringUTF(nameForChild); - return result; -} - -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeFirstChildForByte( - JNIEnv* env, jclass self, jobject node, jint offset) { - TSNode child = ts_node_first_child_for_byte(_unmarshalNode(env, node), (uint32_t)offset * 2); - return _marshalNode(env, child); -} - -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeFirstNamedChildForByte( - JNIEnv* env, jclass self, jobject node, jint offset) { - TSNode child = ts_node_first_named_child_for_byte(_unmarshalNode(env, node), (uint32_t)offset * 2); - return _marshalNode(env, child); -} - -JNIEXPORT jint JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeStartByte( - JNIEnv* env, jclass self, jobject node) { - return (jint)ts_node_start_byte(_unmarshalNode(env, node)) / 2; -} - -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeStartPoint( - JNIEnv* env, jclass self, jobject node) { - return _marshalPoint(env, ts_node_start_point(_unmarshalNode(env, node))); -} - -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeEndPoint( - JNIEnv* env, jclass self, jobject node) { - return _marshalPoint(env, ts_node_end_point(_unmarshalNode(env, node))); -} - -JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeHasError( - JNIEnv* env, jclass self, jobject node) { - return ts_node_has_error(_unmarshalNode(env, node)) ? JNI_TRUE : JNI_FALSE; -} - -JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeIsExtra( - JNIEnv* env, jclass self, jobject node) { - return ts_node_is_extra(_unmarshalNode(env, node)) ? JNI_TRUE : JNI_FALSE; -} - -JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeIsMissing( - JNIEnv* env, jclass self, jobject node) { - return ts_node_is_missing(_unmarshalNode(env, node)) ? JNI_TRUE : JNI_FALSE; -} - -JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeIsNamed( - JNIEnv* env, jclass self, jobject node) { - return ts_node_is_named(_unmarshalNode(env, node)) ? JNI_TRUE : JNI_FALSE; -} - -JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeIsNull( - JNIEnv* env, jclass self, jobject node) { - return ts_node_is_null(_unmarshalNode(env, node)) ? JNI_TRUE : JNI_FALSE; -} - -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeParent( - JNIEnv* env, jclass self, jobject node) { - TSNode parent = ts_node_parent(_unmarshalNode(env, node)); - if (ts_node_is_null(parent)) return NULL; - return _marshalNode(env, parent); -} - -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeNextNamedSibling( - JNIEnv* env, jclass self, jobject node) { - TSNode sibling = ts_node_next_named_sibling(_unmarshalNode(env, node)); - if (ts_node_is_null(sibling)) return NULL; - return _marshalNode(env, sibling); -} - -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeNextSibling( - JNIEnv* env, jclass self, jobject node) { - TSNode sibling = ts_node_next_sibling(_unmarshalNode(env, node)); - if (ts_node_is_null(sibling)) return NULL; - return _marshalNode(env, sibling); -} - -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodePrevNamedSibling( - JNIEnv* env, jclass self, jobject node) { - TSNode sibling = ts_node_prev_named_sibling(_unmarshalNode(env, node)); - if (ts_node_is_null(sibling)) return NULL; - return _marshalNode(env, sibling); -} - -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodePrevSibling( - JNIEnv* env, jclass self, jobject node) { - TSNode sibling = ts_node_prev_sibling(_unmarshalNode(env, node)); - if (ts_node_is_null(sibling)) return NULL; - return _marshalNode(env, sibling); -} - -JNIEXPORT jstring JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeType( - JNIEnv* env, jclass self, jobject node) { - const char* type = ts_node_type(_unmarshalNode(env, node)); - jstring result = env->NewStringUTF(type); - return result; -} - -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_parserNew( - JNIEnv* env, jclass self) { - return (jlong)ts_parser_new(); -} - -JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_parserDelete( - JNIEnv* env, jclass self, jlong parser) { - ts_parser_delete((TSParser*)parser); -} - -JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_parserSetLanguage( - JNIEnv* env, jclass self, jlong parser, jlong language) { - return ts_parser_set_language((TSParser*)parser, (TSLanguage*)language) ? JNI_TRUE : JNI_FALSE; -} - -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_parserParseBytes( - JNIEnv* env, jclass self, jlong parser, jbyteArray source_bytes, jint length) { - jbyte* source = env->GetByteArrayElements(source_bytes, NULL); - jlong result = (jlong)ts_parser_parse_string_encoding( - (TSParser*)parser, NULL, reinterpret_cast(source), length, TSInputEncodingUTF16 - ); - env->ReleaseByteArrayElements(source_bytes, source, JNI_ABORT); - return result; -} - -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_parserIncrementalParseBytes( - JNIEnv* env, jclass self, jlong parser, jlong old_tree, jbyteArray source_bytes, jint length) { - jbyte* source = env->GetByteArrayElements(source_bytes, NULL); - jlong result = (jlong)ts_parser_parse_string_encoding( - (TSParser*)parser, (TSTree*)old_tree, reinterpret_cast(source), length, TSInputEncodingUTF16 - ); - env->ReleaseByteArrayElements(source_bytes, source, JNI_ABORT); - return result; -} - -JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryDelete( - JNIEnv* env, jclass self, jlong query) { - ts_query_delete((TSQuery*)query); -} - -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryNew( - JNIEnv* env, jclass self, jlong language, jstring source) { - const char* c_source; - uint32_t source_length = env->GetStringLength(source); - c_source = env->GetStringUTFChars(source, NULL); - uint32_t* error_offset = new uint32_t; - TSQueryError* error_type = new TSQueryError; - TSQuery* query = ts_query_new((TSLanguage*)language, c_source, source_length, error_offset, error_type); - jclass exceptionClass; - const char* c_pattern; - switch (*error_type) { - case TSQueryErrorNone: - return (jlong)query; - case TSQueryErrorSyntax: - exceptionClass = _querySyntaxExceptionClass; - c_pattern = "Bad syntax at offset %d"; - break; - case TSQueryErrorNodeType: - exceptionClass = _queryNodeTypeExceptionClass; - c_pattern = "Bad node name at offset %d"; - break; - case TSQueryErrorField: - exceptionClass = _queryFieldExceptionClass; - c_pattern = "Bad field name at offset %d"; - break; - case TSQueryErrorCapture: - exceptionClass = _queryCaptureExceptionClass; - c_pattern = "Bad capture at offset %d"; - break; - case TSQueryErrorStructure: - exceptionClass = _queryStructureExceptionClass; - c_pattern = "Bad pattern structure at offset %d"; - break; - default: - return env->ThrowNew(_treeSitterException, NULL); - } - int digits = static_cast(floor(log10(*error_offset))) + 1; - char c_message[strlen(c_pattern) + 1 + digits]; - snprintf(c_message, sizeof(c_message), c_pattern, *error_offset); - return env->ThrowNew(exceptionClass, c_message); -} - -JNIEXPORT jstring JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryCaptureName( - JNIEnv* env, jclass self, jlong query, jint index) { - uint32_t* length = new uint32_t; - const char* nameForIndex = ts_query_capture_name_for_id((TSQuery*)query, index, length); - jstring result = env->NewStringUTF(nameForIndex); - return result; -} - -JNIEXPORT jint JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryPatternCount( - JNIEnv* env, jclass self, jlong query) { - return (jint)ts_query_pattern_count((TSQuery*)query); -} - -JNIEXPORT jint JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryCaptureCount( - JNIEnv* env, jclass self, jlong query) { - return (jint)ts_query_capture_count((TSQuery*)query); -} - -JNIEXPORT jint JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryStringCount( - JNIEnv* env, jclass self, jlong query) { - return (jint)ts_query_string_count((TSQuery*)query); -} - -JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryCursorDelete( - JNIEnv* env, jclass self, jlong query_cursor) { - ts_query_cursor_delete((TSQueryCursor*)query_cursor); -} - -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryCursorNew( - JNIEnv* env, jclass self) { - TSQueryCursor* cursor = ts_query_cursor_new(); - return (jlong)cursor; -} - -JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryCursorExec( - JNIEnv* env, jclass self, jlong query_cursor, jlong query, jobject node) { - ts_query_cursor_exec((TSQueryCursor*) query_cursor, (TSQuery*) query, _unmarshalNode(env,node)); -} - -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryCursorNextMatch( - JNIEnv * env, jclass self, jlong query_cursor) { - TSQueryMatch query_match; - bool found = ts_query_cursor_next_match((TSQueryCursor*)query_cursor, &query_match); - if (!found) return NULL; - return _marshalQueryMatch(env, query_match); -} - -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorNew( - JNIEnv* env, jclass self, jobject node) { - TSTreeCursor* cursor = new TSTreeCursor(ts_tree_cursor_new(_unmarshalNode(env, node))); - return (jlong)cursor; -} - -JNIEXPORT jstring JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorCurrentFieldName( - JNIEnv* env, jclass self, jlong cursor) { - const char* name = ts_tree_cursor_current_field_name((TSTreeCursor*)cursor); - jstring result = env->NewStringUTF(name); - return result; -} - -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorCurrentNode( - JNIEnv* env, jclass self, jlong cursor) { - return _marshalNode(env, ts_tree_cursor_current_node((TSTreeCursor*)cursor)); -} - -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorCurrentTreeCursorNode( - JNIEnv* env, jclass self, jlong cursor) { - TSNode node = ts_tree_cursor_current_node((TSTreeCursor*)cursor); - return _marshalTreeCursorNode( - env, - (TreeCursorNode){ - ts_node_type(node), - ts_tree_cursor_current_field_name((TSTreeCursor*)cursor), - ts_node_start_byte(node) / 2, - ts_node_end_byte(node) / 2, - ts_node_start_point(node), - ts_node_end_point(node), - ts_node_is_named(node) - } - ); -} - -JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorDelete( - JNIEnv* env, jclass self, jlong cursor) { - delete (TSTreeCursor*)cursor; -} - -JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorGotoFirstChild( - JNIEnv* env, jclass self, jlong cursor) { - return ts_tree_cursor_goto_first_child((TSTreeCursor*)cursor) ? JNI_TRUE : JNI_FALSE; -} - -JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorGotoNextSibling( - JNIEnv* env, jclass self, jlong cursor) { - return ts_tree_cursor_goto_next_sibling((TSTreeCursor*)cursor) ? JNI_TRUE : JNI_FALSE; -} - -JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorGotoParent( - JNIEnv* env, jclass self, jlong cursor) { - return ts_tree_cursor_goto_parent((TSTreeCursor*)cursor) ? JNI_TRUE : JNI_FALSE; -} - -JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeDelete( - JNIEnv* env, jclass self, jlong tree) { - ts_tree_delete((TSTree*)tree); -} - - -JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeEdit( - JNIEnv* env, jclass self, jlong tree, jobject inputEdit) { - TSInputEdit edit = _unmarshalInputEdit(env, inputEdit); - ts_tree_edit((TSTree*) tree, &edit); -} - -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeRootNode( - JNIEnv* env, jclass self, jlong tree) { - return _marshalNode(env, ts_tree_root_node((TSTree*)tree)); -} diff --git a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.h b/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.h deleted file mode 100644 index cff7c456..00000000 --- a/dl4se-tree-sitter/lib/usi_si_seart_treesitter_TreeSitter.h +++ /dev/null @@ -1,413 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class usi_si_seart_treesitter_TreeSitter */ - -#ifndef _Included_usi_si_seart_treesitter_TreeSitter -#define _Included_usi_si_seart_treesitter_TreeSitter -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: nodeChild - * Signature: (Lusi/si/seart/treesitter/Node;I)Lusi/si/seart/treesitter/Node; - */ -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeChild - (JNIEnv *, jclass, jobject, jint); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: nodeChildByFieldName - * Signature: (Lusi/si/seart/treesitter/Node;Ljava/lang/String;)Lusi/si/seart/treesitter/Node; - */ -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeChildByFieldName - (JNIEnv *, jclass, jobject, jstring); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: nodeChildCount - * Signature: (Lusi/si/seart/treesitter/Node;)I - */ -JNIEXPORT jint JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeChildCount - (JNIEnv *, jclass, jobject); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: nodeDescendantForByteRange - * Signature: (Lusi/si/seart/treesitter/Node;II)Lusi/si/seart/treesitter/Node; - */ -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeDescendantForByteRange - (JNIEnv *, jclass, jobject, jint, jint); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: nodeEndByte - * Signature: (Lusi/si/seart/treesitter/Node;)I - */ -JNIEXPORT jint JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeEndByte - (JNIEnv *, jclass, jobject); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: nodeEndPoint - * Signature: (Lusi/si/seart/treesitter/Node;)Lusi/si/seart/treesitter/Point; - */ -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeEndPoint - (JNIEnv *, jclass, jobject); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: nodeEq - * Signature: (Lusi/si/seart/treesitter/Node;Lusi/si/seart/treesitter/Node;)Z - */ -JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeEq - (JNIEnv *, jclass, jobject, jobject); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: nodeFieldNameForChild - * Signature: (Lusi/si/seart/treesitter/Node;I)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeFieldNameForChild - (JNIEnv *, jclass, jobject, jint); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: nodeFirstChildForByte - * Signature: (Lusi/si/seart/treesitter/Node;I)Lusi/si/seart/treesitter/Node; - */ -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeFirstChildForByte - (JNIEnv *, jclass, jobject, jint); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: nodeFirstNamedChildForByte - * Signature: (Lusi/si/seart/treesitter/Node;I)Lusi/si/seart/treesitter/Node; - */ -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeFirstNamedChildForByte - (JNIEnv *, jclass, jobject, jint); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: nodeHasError - * Signature: (Lusi/si/seart/treesitter/Node;)Z - */ -JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeHasError - (JNIEnv *, jclass, jobject); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: nodeIsExtra - * Signature: (Lusi/si/seart/treesitter/Node;)Z - */ -JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeIsExtra - (JNIEnv *, jclass, jobject); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: nodeIsMissing - * Signature: (Lusi/si/seart/treesitter/Node;)Z - */ -JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeIsMissing - (JNIEnv *, jclass, jobject); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: nodeIsNamed - * Signature: (Lusi/si/seart/treesitter/Node;)Z - */ -JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeIsNamed - (JNIEnv *, jclass, jobject); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: nodeIsNull - * Signature: (Lusi/si/seart/treesitter/Node;)Z - */ -JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeIsNull - (JNIEnv *, jclass, jobject); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: nodeParent - * Signature: (Lusi/si/seart/treesitter/Node;)Lusi/si/seart/treesitter/Node; - */ -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeParent - (JNIEnv *, jclass, jobject); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: nodePrevNamedSibling - * Signature: (Lusi/si/seart/treesitter/Node;)Lusi/si/seart/treesitter/Node; - */ -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodePrevNamedSibling - (JNIEnv *, jclass, jobject); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: nodePrevSibling - * Signature: (Lusi/si/seart/treesitter/Node;)Lusi/si/seart/treesitter/Node; - */ -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodePrevSibling - (JNIEnv *, jclass, jobject); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: nodeNextNamedSibling - * Signature: (Lusi/si/seart/treesitter/Node;)Lusi/si/seart/treesitter/Node; - */ -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeNextNamedSibling - (JNIEnv *, jclass, jobject); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: nodeNextSibling - * Signature: (Lusi/si/seart/treesitter/Node;)Lusi/si/seart/treesitter/Node; - */ -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeNextSibling - (JNIEnv *, jclass, jobject); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: nodeStartByte - * Signature: (Lusi/si/seart/treesitter/Node;)I - */ -JNIEXPORT jint JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeStartByte - (JNIEnv *, jclass, jobject); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: nodeStartPoint - * Signature: (Lusi/si/seart/treesitter/Node;)Lusi/si/seart/treesitter/Point; - */ -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeStartPoint - (JNIEnv *, jclass, jobject); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: nodeString - * Signature: (Lusi/si/seart/treesitter/Node;)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeString - (JNIEnv *, jclass, jobject); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: nodeType - * Signature: (Lusi/si/seart/treesitter/Node;)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_usi_si_seart_treesitter_TreeSitter_nodeType - (JNIEnv *, jclass, jobject); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: parserNew - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_parserNew - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: parserDelete - * Signature: (J)V - */ -JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_parserDelete - (JNIEnv *, jclass, jlong); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: parserSetLanguage - * Signature: (JJ)Z - */ -JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_parserSetLanguage - (JNIEnv *, jclass, jlong, jlong); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: parserParseBytes - * Signature: (J[BI)J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_parserParseBytes - (JNIEnv *, jclass, jlong, jbyteArray, jint); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: parserIncrementalParseBytes - * Signature: (JJ[BI)J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_parserIncrementalParseBytes - (JNIEnv *, jclass, jlong, jlong, jbyteArray, jint); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: queryDelete - * Signature: (J)V - */ -JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryDelete - (JNIEnv *, jclass, jlong); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: queryNew - * Signature: (JLjava/lang/String;)J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryNew - (JNIEnv *, jclass, jlong, jstring); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: queryCaptureName - * Signature: (JI)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryCaptureName - (JNIEnv *, jclass, jlong, jint); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: queryStringCount - * Signature: (J)I - */ -JNIEXPORT jint JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryStringCount - (JNIEnv *, jclass, jlong); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: queryCaptureCount - * Signature: (J)I - */ -JNIEXPORT jint JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryCaptureCount - (JNIEnv *, jclass, jlong); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: queryPatternCount - * Signature: (J)I - */ -JNIEXPORT jint JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryPatternCount - (JNIEnv *, jclass, jlong); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: queryCursorDelete - * Signature: (J)V - */ -JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryCursorDelete - (JNIEnv *, jclass, jlong); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: queryCursorNew - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryCursorNew - (JNIEnv *, jclass); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: queryCursorExec - * Signature: (JJLusi/si/seart/treesitter/Node;)V - */ -JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryCursorExec - (JNIEnv *, jclass, jlong, jlong, jobject); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: queryCursorNextMatch - * Signature: (J)Lusi/si/seart/treesitter/QueryMatch; - */ -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_queryCursorNextMatch - (JNIEnv *, jclass, jlong); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: treeCursorNew - * Signature: (Lusi/si/seart/treesitter/Node;)J - */ -JNIEXPORT jlong JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorNew - (JNIEnv *, jclass, jobject); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: treeCursorCurrentTreeCursorNode - * Signature: (J)Lusi/si/seart/treesitter/TreeCursorNode; - */ -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorCurrentTreeCursorNode - (JNIEnv *, jclass, jlong); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: treeCursorCurrentFieldName - * Signature: (J)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorCurrentFieldName - (JNIEnv *, jclass, jlong); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: treeCursorCurrentNode - * Signature: (J)Lusi/si/seart/treesitter/Node; - */ -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorCurrentNode - (JNIEnv *, jclass, jlong); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: treeCursorDelete - * Signature: (J)V - */ -JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorDelete - (JNIEnv *, jclass, jlong); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: treeCursorGotoFirstChild - * Signature: (J)Z - */ -JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorGotoFirstChild - (JNIEnv *, jclass, jlong); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: treeCursorGotoNextSibling - * Signature: (J)Z - */ -JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorGotoNextSibling - (JNIEnv *, jclass, jlong); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: treeCursorGotoParent - * Signature: (J)Z - */ -JNIEXPORT jboolean JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeCursorGotoParent - (JNIEnv *, jclass, jlong); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: treeDelete - * Signature: (J)V - */ -JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeDelete - (JNIEnv *, jclass, jlong); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: treeEdit - * Signature: (JLusi/si/seart/treesitter/InputEdit;)V - */ -JNIEXPORT void JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeEdit - (JNIEnv *, jclass, jlong, jobject); - -/* - * Class: usi_si_seart_treesitter_TreeSitter - * Method: treeRootNode - * Signature: (J)Lusi/si/seart/treesitter/Node; - */ -JNIEXPORT jobject JNICALL Java_usi_si_seart_treesitter_TreeSitter_treeRootNode - (JNIEnv *, jclass, jlong); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/dl4se-tree-sitter/pom.xml b/dl4se-tree-sitter/pom.xml deleted file mode 100644 index b27e75a9..00000000 --- a/dl4se-tree-sitter/pom.xml +++ /dev/null @@ -1,106 +0,0 @@ - - - 4.0.0 - - dl4se - usi.si.seart - ${revision} - ../pom.xml - - - dl4se-tree-sitter - - dl4se-tree-sitter - - - UTF-8 - - - - - - src/main/resources - - **/.gitkeep - - - - - - maven-shade-plugin - - - package - - shade - - - - - - org.codehaus.mojo - exec-maven-plugin - 1.2.1 - - - clean-generated-files - pre-clean - - exec - - - sh - ${project.basedir} - - -c - printf "Removed files:\n$(rm -vf src/main/resources/libjava-tree-sitter.*)\n" - - - - - generate-jni-headers - generate-sources - - exec - - - javah - ${project.basedir} - - -verbose - -jni - -classpath - ${project.build.sourceDirectory} - -d - ${project.basedir}/lib - usi.si.seart.treesitter.Languages - usi.si.seart.treesitter.TreeSitter - - - - - generate-dynamic-library - generate-sources - - exec - - - python - ${project.basedir} - - build.py - -o - src/main/resources/libjava-tree-sitter - tree-sitter-c - tree-sitter-cpp - tree-sitter-java - tree-sitter-javascript - tree-sitter-python - - - - - - - - diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/External.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/External.java deleted file mode 100644 index 0d723015..00000000 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/External.java +++ /dev/null @@ -1,29 +0,0 @@ -package usi.si.seart.treesitter; - -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Getter; - -@Getter(value = AccessLevel.PACKAGE) -@AllArgsConstructor(access = AccessLevel.PROTECTED) -abstract class External implements AutoCloseable { - - protected final long pointer; - - public final boolean isNull() { - return pointer == 0; - } - - @Override - public boolean equals(Object obj) { - if (obj == this) return true; - if (obj == null || getClass() != obj.getClass()) return false; - External other = (External) obj; - return pointer == other.pointer; - } - - @Override - public int hashCode() { - return Long.hashCode(pointer); - } -} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/InputEdit.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/InputEdit.java deleted file mode 100644 index fcc88784..00000000 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/InputEdit.java +++ /dev/null @@ -1,19 +0,0 @@ -package usi.si.seart.treesitter; - -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.experimental.FieldDefaults; - -@Getter -@AllArgsConstructor -@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) -public class InputEdit { - - int startByte; - int oldEndByte; - int newEndByte; - Point startPoint; - Point oldEndPoint; - Point newEndPoint; -} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Language.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Language.java deleted file mode 100644 index 1b170344..00000000 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Language.java +++ /dev/null @@ -1,114 +0,0 @@ -package usi.si.seart.treesitter; - -import lombok.Getter; - -import java.util.function.LongSupplier; - -public enum Language { - - _INVALID_(), - AGDA(Languages::agda), - BASH(Languages::bash), - C(Languages::c), - CSHARP(Languages::cSharp), - CPP(Languages::cpp), - CSS(Languages::css), - DART(Languages::dart), - ELM(Languages::elm), - EMBEDDED_TEMPLATE(Languages::embeddedTemplate), - ENO(Languages::eno), - GO(Languages::go), - HASKELL(Languages::haskell), - HTML(Languages::html), - JAVA(Languages::java), - JAVASCRIPT(Languages::javascript), - JULIA(Languages::julia), - KOTLIN(Languages::kotlin), - LUA(Languages::lua), - MARKDOWN(Languages::markdown), - OCAML(Languages::ocaml), - PHP(Languages::php), - PYTHON(Languages::python), - RUBY(Languages::ruby), - RUST(Languages::rust), - SCALA(Languages::scala), - SCSS(Languages::scss), - SWIFT(Languages::swift), - TOML(Languages::toml), - TSX(Languages::tsx), - TYPESCRIPT(Languages::typescript), - VUE(Languages::vue), - YAML(Languages::yaml), - WASM(Languages::wasm); - - @Getter - private final long id; - - static final long INVALID = 0L; - - Language() { - this.id = INVALID; - } - - Language(LongSupplier supplier) { - long id = INVALID; - try { - id = supplier.getAsLong(); - } catch (UnsatisfiedLinkError ignored) { - // Triggered whenever a language is not included in the native library. - } finally { - this.id = id; - } - } - - - @Override - public String toString() { - switch (this) { - // Unmodified - case C: - case CSS: - case HTML: - case PHP: - case SCSS: - case TOML: - case TSX: - case YAML: - return name(); - - // Capital Case - case AGDA: - case BASH: - case DART: - case ELM: - case ENO: - case GO: - case HASKELL: - case JAVA: - case JULIA: - case KOTLIN: - case LUA: - case MARKDOWN: - case PYTHON: - case RUBY: - case RUST: - case SCALA: - case SWIFT: - case VUE: - return name().charAt(0) + name().substring(1).toLowerCase(); - - // Special Cases - case CSHARP: return "C#"; - case CPP: return "C++"; - case EMBEDDED_TEMPLATE: return "Embedded Template"; - case JAVASCRIPT: return "JavaScript"; - case OCAML: return "OCaml"; - case TYPESCRIPT: return "TypeScript"; - case WASM: return "WebAssembly"; - - // Default / Undefined - default: - return "???"; - } - } -} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Languages.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Languages.java deleted file mode 100644 index 20668281..00000000 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Languages.java +++ /dev/null @@ -1,50 +0,0 @@ -package usi.si.seart.treesitter; - -import lombok.experimental.UtilityClass; - -import java.util.Objects; - -@UtilityClass -class Languages { - static native long agda(); - static native long bash(); - static native long c(); - static native long cSharp(); - static native long cpp(); - static native long css(); - static native long dart(); - static native long elm(); - static native long embeddedTemplate(); - static native long eno(); - static native long go(); - static native long haskell(); - static native long html(); - static native long java(); - static native long javascript(); - static native long julia(); - static native long kotlin(); - static native long lua(); - static native long markdown(); - static native long ocaml(); - static native long php(); - static native long python(); - static native long ruby(); - static native long rust(); - static native long scala(); - static native long scss(); - static native long swift(); - static native long toml(); - static native long tsx(); - static native long typescript(); - static native long vue(); - static native long yaml(); - static native long wasm(); - - static void validate(Language language) { - Objects.requireNonNull(language, "Language must not be null!"); - long id = language.getId(); - if (id == Language.INVALID) throw new UnsatisfiedLinkError( - "Language binding has not been defined for: " + language - ); - } -} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/LibraryLoader.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/LibraryLoader.java deleted file mode 100644 index 2f2302b3..00000000 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/LibraryLoader.java +++ /dev/null @@ -1,72 +0,0 @@ -package usi.si.seart.treesitter; - -import lombok.AccessLevel; -import lombok.Cleanup; -import lombok.experimental.FieldDefaults; -import lombok.experimental.UtilityClass; -import usi.si.seart.treesitter.exception.TreeSitterException; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.URL; - -@UtilityClass -public class LibraryLoader { - - @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) - private static final class SystemResource { - - URL url; - String name; - - private SystemResource(String name) { - this.url = ClassLoader.getSystemResource(name); - this.name = name; - } - } - - public void load() { - String name = "libjava-tree-sitter"; - String extension = getExtension(); - String filename = name + "." + extension; - SystemResource systemResource = new SystemResource(filename); - String libPath = getLibPath(systemResource); - System.load(libPath); - } - - private String getLibPath(SystemResource systemResource) { - String protocol = systemResource.url.getProtocol(); - switch (protocol) { - case "file": - return systemResource.url.getPath(); - case "jar": - try { - @Cleanup InputStream input = systemResource.url.openStream(); - String tmpdir = System.getProperty("java.io.tmpdir"); - File temporary = new File(tmpdir, systemResource.name); - temporary.deleteOnExit(); - @Cleanup OutputStream output = new FileOutputStream(temporary, false); - input.transferTo(output); - return temporary.getPath(); - } catch (IOException cause) { - throw new TreeSitterException(cause); - } - default: - Exception cause = new UnsupportedOperationException("Unsupported protocol: " + protocol); - throw new TreeSitterException(cause); - } - } - - private String getExtension() { - String platform = System.getProperty("os.name").toLowerCase(); - if (platform.contains("nix") || platform.contains("nux") || platform.contains("aix")) - return "so"; - else if (platform.contains("mac") || platform.contains("darwin")) - return "dylib"; - else - throw new TreeSitterException("The tree-sitter library was not compiled for this platform: " + platform); - } -} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java deleted file mode 100644 index eb90bc7b..00000000 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Node.java +++ /dev/null @@ -1,300 +0,0 @@ -package usi.si.seart.treesitter; - -import lombok.AccessLevel; -import lombok.NoArgsConstructor; - -import java.util.Iterator; -import java.util.NoSuchElementException; -import java.util.Objects; -import java.util.Stack; - -/** - * A Node represents a single node in the syntax tree. - * It tracks its start and end positions in the source code, - * as well as its relation to other nodes like its parent, - * siblings and children. - */ -@NoArgsConstructor(access = AccessLevel.PACKAGE) -public class Node implements Iterable { - - private int context0; - private int context1; - private int context2; - private int context3; - private long id; - private long tree; - - /** - * Get the node's child at the given index, - * where zero represents the first child. - * - * @param child The zero-indexed child position - * @return The Node's child at the given index - * @throws IndexOutOfBoundsException - * if the index is a negative number - */ - public Node getChild(int child) { - if (child < 0) - throw new IndexOutOfBoundsException("Child index must not be negative!"); - return TreeSitter.nodeChild(this, child); - } - - /** - * @param name The child field name. - * @return The node's child with the given field name. - * @throws NullPointerException - * if the field name is null - */ - public Node getChildByFieldName(String name) { - Objects.requireNonNull(name, "Field name must not be null!"); - return TreeSitter.nodeChildByFieldName(this, name); - } - - /** - * @return The node's number of children. - */ - public int getChildCount() { - return TreeSitter.nodeChildCount(this); - } - - /** - * @param startByte The starting byte of the range - * @param endByte The ending byte of the range - * @return The smallest node within this node that spans the given range of bytes - * @throws IllegalArgumentException if {@code startByte} > {@code endByte} - */ - public Node getDescendantForByteRange(int startByte, int endByte) { - if (startByte > endByte) - throw new IllegalArgumentException("The starting byte of the range must not be greater than the ending byte!"); - return TreeSitter.nodeDescendantForByteRange(this, startByte, endByte); - } - - /** - * @return The node's end byte. - */ - public int getEndByte() { - return TreeSitter.nodeEndByte(this); - } - - /** - * @return The node's end position in terms of rows and columns. - */ - public Point getEndPoint() { - return TreeSitter.nodeEndPoint(this); - } - - /** - * @return - * The field name for node's child at the given index, - * with zero representing the first child. - * Returns NULL, if no field is found. - * @throws IndexOutOfBoundsException - * if the index is a negative number - */ - public String getFieldNameForChild(int child) { - if (child < 0) - throw new IndexOutOfBoundsException("Child index must not be negative!"); - return TreeSitter.nodeFieldNameForChild(this, child); - } - - /** - * @param offset The offset in bytes. - * @return The node's first child that extends beyond the given byte offset. - * @throws IndexOutOfBoundsException if the offset is a negative number - */ - public Node getFirstChildForByte(int offset) { - if (offset < 0) - throw new IndexOutOfBoundsException("Byte offset must not be negative!"); - return TreeSitter.nodeFirstChildForByte(this, offset); - } - - /** - * @param offset The offset in bytes. - * @return The node's first named child that extends beyond the given byte offset. - * @throws IndexOutOfBoundsException if the offset is a negative number - */ - public Node getFirstNamedChildForByte(int offset) { - if (offset < 0) - throw new IndexOutOfBoundsException("Byte offset must not be negative!"); - return TreeSitter.nodeFirstNamedChildForByte(this, offset); - } - - /** - * @return An S-expression representing the node as a string. - */ - public String getNodeString() { - return TreeSitter.nodeString(this); - } - - /** - * @return The node's next named sibling. - */ - public Node getNextNamedSibling() { - return TreeSitter.nodeNextNamedSibling(this); - } - - /** - * @return The node's next sibling. - */ - public Node getNextSibling() { - return TreeSitter.nodeNextSibling(this); - } - - /** - * @return The node's previous named sibling. - */ - public Node getPrevNamedSibling() { - return TreeSitter.nodePrevNamedSibling(this); - } - - /** - * @return The node's previous sibling. - */ - public Node getPrevSibling() { - return TreeSitter.nodePrevSibling(this); - } - - /** - * @return The node's immediate parent. - */ - public Node getParent() { - return TreeSitter.nodeParent(this); - } - - /** - * @return The node's range, indicating its byte and file position span. - */ - public Range getRange() { - return new Range(this); - } - - /** - * @return The node's start byte. - */ - public int getStartByte() { - return TreeSitter.nodeStartByte(this); - } - - /** - * @return The node's start position in terms of rows and columns. - */ - public Point getStartPoint() { - return TreeSitter.nodeStartPoint(this); - } - - /** - * @return The node's type as a string - */ - public String getType() { - return TreeSitter.nodeType(this); - } - - /** - * @return true if the node is a syntax error or contains any syntax errors, false otherwise. - */ - public boolean hasError() { - return TreeSitter.nodeHasError(this); - } - - /** - * Check if the node is extra. - * Extra nodes represent things like comments, - * which are not required the grammar, - * but can appear anywhere. - * - * @return true if the node is an extra, false otherwise. - */ - public boolean isExtra() { - return TreeSitter.nodeIsExtra(this); - } - - /** - * Check if the node is missing. - * Missing nodes are inserted by the parser - * in order to recover from certain kinds - * of syntax errors. - * - * @return true if the node is missing, false otherwise. - */ - public boolean isMissing() { - return TreeSitter.nodeIsMissing(this); - } - - /** - * Check if the node is named. - * Named nodes correspond to named rules in the grammar, - * whereas anonymous nodes correspond to string - * literals in the grammar. - * - * @return true if the node is named, false otherwise. - */ - public boolean isNamed() { - return TreeSitter.nodeIsNamed(this); - } - - /** - * Check if the node is null node. - * - * @return true if {@code id == 0}, false otherwise - */ - public boolean isNull() { - return TreeSitter.nodeIsNull(this); - } - - /** - * A tree cursor allows you to walk a syntax tree more - * efficiently than is possible using the instance functions. - * It is a mutable object that is always on a certain syntax node, - * and can be moved imperatively to different nodes. - * - * @return A new tree cursor starting from the given node. - */ - public TreeCursor walk() { - return new TreeCursor(TreeSitter.treeCursorNew(this)); - } - - @Override - public boolean equals(Object obj) { - if (obj == this) return true; - if (obj == null || getClass() != obj.getClass()) return false; - Node other = (Node) obj; - return TreeSitter.nodeEq(this, other); - } - - @Override - public int hashCode() { - return Long.hashCode(id); - } - - @Override - public String toString() { - return "Node(id: "+id+", tree: "+tree+")"; - } - - /** - * @return An iterator over the node subtree, starting from the current node. - */ - @Override - public Iterator iterator() { - return new Iterator<>() { - - private final Stack stack = new Stack<>() {{ push(Node.this); }}; - - @Override - public boolean hasNext() { - return !stack.isEmpty(); - } - - @Override - public Node next() { - if (!hasNext()) throw new NoSuchElementException(); - Node node = stack.pop(); - int children = node.getChildCount(); - for (int child = children - 1; child >= 0; child--) { - stack.push(node.getChild(child)); - } - return node; - } - }; - } -} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java deleted file mode 100644 index c6a90375..00000000 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Parser.java +++ /dev/null @@ -1,134 +0,0 @@ -package usi.si.seart.treesitter; - -import lombok.AccessLevel; -import lombok.Getter; -import lombok.experimental.FieldDefaults; -import usi.si.seart.treesitter.error.ABIVersionError; - -import java.io.File; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; - -/** - * Parsers are stateful objects that can be assigned a language - * and used to produce a {@link Tree Tree} based on some source code. - * Instances of this class can not be created - * without an initially set language. - */ -@Getter -@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) -public class Parser extends External { - - Language language; - - /** - * @param language The language used for parsing. - * @throws NullPointerException - * if the specified language is null - * @throws UnsatisfiedLinkError - * if the specified language has not - * been linked to the system library - */ - public Parser(Language language) { - super(createIfValid(language)); - this.language = language; - } - - /* - * Constructor precondition for creating a parser. - * In essence, we should never allocate memory to - * these structures if the language: - * - Has not been specified (i.e. is null) - * - Has not been linked to the system library - */ - private static long createIfValid(Language language) { - Languages.validate(language); - long pointer = TreeSitter.parserNew(); - setLanguage(pointer, language); - return pointer; - } - - /** - * Set the language that the parser should use for parsing. - * - * @param language The language used for parsing. - * @throws NullPointerException - * if the specified language is null - * @throws UnsatisfiedLinkError - * if the specified language has not - * been linked to the system library - */ - public void setLanguage(Language language) { - Languages.validate(language); - setLanguage(pointer, language); - } - - private static void setLanguage(long pointer, Language language) { - boolean success = TreeSitter.parserSetLanguage(pointer, language.getId()); - if (!success) throw new ABIVersionError("Language could not be assigned to parser!"); - } - - /** - * Use the parser to parse some source code and create a syntax tree. - * - * @param source The source code string to be parsed. - * @return A syntax tree matching the provided source. - */ - public Tree parseString(String source) throws UnsupportedEncodingException { - byte[] bytes = source.getBytes(StandardCharsets.UTF_16LE); - long treePointer = TreeSitter.parserParseBytes(pointer, bytes, bytes.length); - return new Tree(treePointer, language); - } - - /** - * Use the parser to incrementally parse a changed source code string, - * reusing unchanged parts of the tree to speed up the process. - * - * @param oldTree The syntax tree before changes were made. - * @param source The source code string to be parsed. - * @return A syntax tree matching the provided source. - */ - public Tree parseString(Tree oldTree, String source) throws UnsupportedEncodingException { - byte[] bytes = source.getBytes(StandardCharsets.UTF_16LE); - long treePointer = TreeSitter.parserIncrementalParseBytes(pointer, oldTree.getPointer(), bytes, bytes.length); - return new Tree(treePointer, language); - } - - /** - * Use the parser to parse some source code found in a file at the specified path. - * - * @param path The path of the file to be parsed. - * @return A tree-sitter Tree matching the provided source. - */ - public Tree parseFile(Path path) throws IOException { - String source = Files.readString(path); - return parseString(source); - } - - /** - * Use the parser to parse some source code found in a file represented by the reference. - * - * @param file The reference to the file which will be parsed. - * @return A tree-sitter Tree matching the provided source. - */ - public Tree parseFile(File file) throws IOException { - Path path = file.toPath(); - return parseFile(path); - } - - /** - * Delete the parser, freeing all the memory that it used. - */ - @Override - public void close() { - TreeSitter.parserDelete(pointer); - } - - @Override - public String toString() { - return "Parser(id: "+pointer+", language: "+language+")"; - } -} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Point.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Point.java deleted file mode 100644 index 6149be19..00000000 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Point.java +++ /dev/null @@ -1,28 +0,0 @@ -package usi.si.seart.treesitter; - -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.Setter; -import lombok.experimental.FieldDefaults; - -@Getter -@Setter(value = AccessLevel.PACKAGE) -@AllArgsConstructor -@FieldDefaults(level = AccessLevel.PRIVATE) -@EqualsAndHashCode -public class Point { - - int row; - int column; - - @Override - public String toString() { - return row + ":" + column; - } - - public boolean isOrigin() { - return row == 0 && column == 0; - } -} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java deleted file mode 100644 index f0af00ac..00000000 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Query.java +++ /dev/null @@ -1,110 +0,0 @@ -package usi.si.seart.treesitter; - -import lombok.AccessLevel; -import lombok.Getter; -import lombok.experimental.FieldDefaults; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; - -/** - * A query consists of one or more patterns, where each pattern is an S-expression that matches a certain set of nodes - * in a syntax tree. The query is associated with a particular language, and can only be run on syntax nodes parsed with - * that language. The expression to match a given node consists of a pair of parentheses containing two things: the - * node's type, and optionally, a series of other S-expressions that match the node's children. For example, this - * pattern would match any {@code binary_expression} node whose children are both {@code number_literal} nodes: - * - *
- *     (binary_expression (number_literal) (number_literal))
- * 
- * - * Children can also be omitted. For example, this would match any {@code binary_expression} where at least one of - * child is a {@code string_literal} node: - * - *
- *     (binary_expression (string_literal))
- * 
- * - * @apiNote The underlying query value is immutable and can be safely shared between threads. - */ -@Getter -@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) -public class Query extends External { - - Language language; - String pattern; - List captures; - - public Query(Language language, String pattern) { - super(createIfValid(language, pattern)); - this.language = language; - this.pattern = pattern; - int capturesCount = TreeSitter.queryCaptureCount(pointer); - List captures = new ArrayList<>(capturesCount); - for (int idx = 0; idx < capturesCount; idx++) { - String capture = TreeSitter.queryCaptureName(pointer, idx); - captures.add(capture); - } - this.captures = Collections.unmodifiableList(captures); - } - - private static long createIfValid(Language language, String pattern) { - Languages.validate(language); - Objects.requireNonNull(pattern, "Pattern must not be null!"); - return TreeSitter.queryNew(language.getId(), pattern); - } - - /** - * @return The number of string literals in this query. - */ - public int countStrings() { - return TreeSitter.queryStringCount(pointer); - } - - /** - * @return The number of captures in this query. - */ - public int countCaptures() { - return TreeSitter.queryCaptureCount(pointer); - } - - /** - * @return The number of patterns in this query. - */ - public int countPatterns() { - return TreeSitter.queryPatternCount(pointer); - } - - /** - * @param capture The query capture. - * @return The name of the provided query captures. - */ - public String getCaptureName(QueryCapture capture) { - return captures.get(capture.getIndex()); - } - - /** - * @return true if the query has captures, false otherwise. - */ - public boolean hasCaptures() { - return !captures.isEmpty(); - } - - /** - * Delete a query, freeing all the memory that it used. - */ - @Override - public void close() { - TreeSitter.queryDelete(pointer); - } - - @Override - public String toString() { - return String.format( - "Query(language: %s, pattern: '%s', captures: [%s])", - language, pattern, String.join(", ", captures) - ); - } -} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCapture.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCapture.java deleted file mode 100644 index e0096f35..00000000 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCapture.java +++ /dev/null @@ -1,20 +0,0 @@ -package usi.si.seart.treesitter; - -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.experimental.FieldDefaults; - -@Getter -@AllArgsConstructor(access = AccessLevel.PACKAGE) -@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) -public class QueryCapture { - - Node node; - int index; - - @Override - public String toString() { - return "QueryCapture(index: "+index+", node: "+node+")"; - } -} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCursor.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCursor.java deleted file mode 100644 index 6a828ead..00000000 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryCursor.java +++ /dev/null @@ -1,96 +0,0 @@ -package usi.si.seart.treesitter; - -import lombok.AccessLevel; -import lombok.experimental.FieldDefaults; -import lombok.experimental.NonFinal; - -import java.util.Iterator; -import java.util.NoSuchElementException; -import java.util.Objects; - -/** - * Cursor used for executing queries, carrying the state needed to process them. - * - * @apiNote The query cursor should not be shared between threads, but can be reused for many query executions. - */ -@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) -public class QueryCursor extends External implements Iterable { - - Node node; - Query query; - - @NonFinal - boolean executed = false; - - public QueryCursor(Node node, Query query) { - super(createIfValid(node, query)); - this.node = node; - this.query = query; - } - - private static long createIfValid(Node node, Query query) { - Objects.requireNonNull(node, "Node must not be null!"); - Objects.requireNonNull(query, "Query must not be null!"); - return TreeSitter.queryCursorNew(); - } - - /** - * Start running a given query on a given node. - * Successive calls to this method are ignored. - */ - public void execute() { - if (executed) return; - TreeSitter.queryCursorExec(pointer, query.pointer, node); - this.executed = true; - } - - /** - * Advance to the next match of the currently running query. - * - * @return A match if there is one, null otherwise. - * @throws IllegalStateException - * if {@code queryExec()} was not called beforehand - */ - public QueryMatch nextMatch() { - if (!executed) throw new IllegalStateException("Query was not executed on node!"); - return TreeSitter.queryCursorNextMatch(pointer); - } - - /** - * Delete a query cursor, freeing all the memory that it used. - */ - @Override - public void close() { - TreeSitter.queryCursorDelete(pointer); - } - - /** - * @return An iterator over the query cursor matches, starting from the first match. - */ - @Override - public Iterator iterator() { - execute(); - return new Iterator<>() { - - private QueryMatch current = nextMatch(); - - @Override - public boolean hasNext() { - return current != null; - } - - @Override - public QueryMatch next() { - if (!hasNext()) throw new NoSuchElementException(); - QueryMatch match = current; - current = nextMatch(); - return match; - } - }; - } - - @Override - public String toString() { - return "QueryCursor(node: "+node+", query: "+query+")"; - } -} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryMatch.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryMatch.java deleted file mode 100644 index c571ef99..00000000 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/QueryMatch.java +++ /dev/null @@ -1,27 +0,0 @@ -package usi.si.seart.treesitter; - -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.experimental.FieldDefaults; - -import java.util.stream.Collectors; -import java.util.stream.Stream; - -@Getter -@AllArgsConstructor(access = AccessLevel.PACKAGE) -@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) -public class QueryMatch { - - int id; - int pattern_index; - QueryCapture[] captures; - - @Override - public String toString() { - String joined = Stream.of(captures) - .map(QueryCapture::toString) - .collect(Collectors.joining(", ")); - return String.format("QueryMatch(id: %d, pattern: %d, captures: [%s])", id, pattern_index, joined); - } -} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Range.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Range.java deleted file mode 100644 index f92a6f02..00000000 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Range.java +++ /dev/null @@ -1,26 +0,0 @@ -package usi.si.seart.treesitter; - -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.experimental.FieldDefaults; - -@Getter -@AllArgsConstructor(access = AccessLevel.PACKAGE) -@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) -public class Range { - - int startByte; - int endByte; - Point startPoint; - Point endPoint; - - public Range(Node node) { - this(node.getStartByte(), node.getEndByte(), node.getStartPoint(), node.getEndPoint()); - } - - @Override - public String toString() { - return "["+startPoint+"] - ["+endPoint+"]"; - } -} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/SyntaxTreePrinter.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/SyntaxTreePrinter.java deleted file mode 100644 index 4b57195c..00000000 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/SyntaxTreePrinter.java +++ /dev/null @@ -1,83 +0,0 @@ -package usi.si.seart.treesitter; - -import lombok.AccessLevel; -import lombok.Cleanup; -import lombok.RequiredArgsConstructor; -import lombok.experimental.FieldDefaults; - -/** - * Utility used for pretty-printing entire syntax trees, as well as their subtrees. - */ -@RequiredArgsConstructor -@FieldDefaults(level = AccessLevel.PRIVATE) -public class SyntaxTreePrinter { - - int depth = 0; - final Node node; - Point offset = new Point(0, 0); - - public SyntaxTreePrinter(Node node, Point offset) { - this.node = node; - this.offset = offset; - } - - /** - * @return A string representation of the subtree. Consists only of named nodes. - * @see Syntax Tree Playground - */ - public String printSubtree() { - StringBuilder stringBuilder = new StringBuilder(); - @Cleanup TreeCursor cursor = new TreePrinterCursor(node); - for (;;) { - TreeCursorNode cursorNode = cursor.getCurrentTreeCursorNode(); - if (cursorNode.isNamed()) { - recalculatePosition(cursorNode); - String indentation = " ".repeat(depth); - stringBuilder - .append(indentation) - .append(cursorNode) - .append("\n"); - } - if (cursor.gotoFirstChild() || cursor.gotoNextSibling()) continue; - do { - if (!cursor.gotoParent()) return stringBuilder.toString(); - } while (!cursor.gotoNextSibling()); - } - } - - private void recalculatePosition(TreeCursorNode cursorNode) { - if (!offset.isOrigin()) { - Point cursorStartPoint = cursorNode.getStartPoint(); - Point cursorEndPoint = cursorNode.getEndPoint(); - - int rowOffset = offset.getRow(); - cursorStartPoint.setRow(cursorStartPoint.getRow() + rowOffset); - cursorEndPoint.setRow(cursorEndPoint.getRow() + rowOffset); - - int columnOffset = offset.getColumn(); - cursorStartPoint.setColumn(cursorStartPoint.getColumn() + columnOffset); - cursorEndPoint.setColumn(cursorEndPoint.getColumn() + columnOffset); - } - } - - private final class TreePrinterCursor extends TreeCursor { - - private TreePrinterCursor(Node node) { - super(TreeSitter.treeCursorNew(node)); - } - - @Override - public boolean gotoFirstChild() { - boolean success = super.gotoFirstChild(); - if (success) depth++; - return success; - } - - @Override - public boolean gotoParent() { - boolean success = super.gotoParent(); - if (success) depth--; - return success; - } - } -} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java deleted file mode 100644 index 9a2d1459..00000000 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/Tree.java +++ /dev/null @@ -1,60 +0,0 @@ -package usi.si.seart.treesitter; - -import lombok.AccessLevel; -import lombok.Getter; -import lombok.experimental.FieldDefaults; - -import java.util.Iterator; - -/** - * A Tree represents the syntax tree of an entire source code file. It contains {@link Node Node} - * instances that indicate the structure of the source code. - */ -@Getter -@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) -public class Tree extends External implements Iterable { - - Language language; - - Tree(long pointer, Language language) { - super(pointer); - this.language = language; - } - - /** - * Delete the syntax tree, freeing all the memory that it used. - */ - @Override - public void close() { - TreeSitter.treeDelete(pointer); - } - - /** - * Edit the syntax tree to keep it in sync with source code that has been edited. - * - * @param edit Changes made to the source code in terms of both byte offsets and row/column coordinates. - */ - public void edit(InputEdit edit) { - TreeSitter.treeEdit(pointer, edit); - } - - /** - * @return The root node of the syntax tree. - */ - public Node getRootNode() { - return TreeSitter.treeRootNode(pointer); - } - - /** - * @return An iterator over the entire syntax tree, starting from the root node. - */ - @Override - public Iterator iterator() { - return getRootNode().iterator(); - } - - @Override - public String toString() { - return "Tree(id: "+pointer+", language: "+language+")"; - } -} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursor.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursor.java deleted file mode 100644 index 232aa19b..00000000 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursor.java +++ /dev/null @@ -1,98 +0,0 @@ -package usi.si.seart.treesitter; - -import java.util.function.Consumer; - -/** - * A tree cursor is a stateful object that allows you to walk a syntax tree with maximum efficiency. - */ -public class TreeCursor extends External { - - private int context0; - private int context1; - private long id; - private long tree; - - TreeCursor(long pointer) { - super(pointer); - } - - /** - * Delete the tree cursor, freeing all the memory that it used. - */ - @Override - public void close() { - TreeSitter.treeCursorDelete(pointer); - } - - /** - * @return The tree cursor's current node. - */ - public Node getCurrentNode() { - return TreeSitter.treeCursorCurrentNode(pointer); - } - - /** - * @return The field name of the tree cursor's current node. - * Will return null if the current node doesn't have a field. - */ - public String getCurrentFieldName() { - return TreeSitter.treeCursorCurrentFieldName(pointer); - } - - /** - * @return The tree cursor's current node. - */ - public TreeCursorNode getCurrentTreeCursorNode() { - return TreeSitter.treeCursorCurrentTreeCursorNode(pointer); - } - - /** - * Move the cursor to the first child of its current node. - * - * @return true if the cursor successfully moved, and false if there were no children. - */ - public boolean gotoFirstChild() { - return TreeSitter.treeCursorGotoFirstChild(pointer); - } - - /** - * Move the cursor to the next sibling of its current node. - * - * @return true if the cursor successfully moved, and false if there was no next sibling node. - */ - public boolean gotoNextSibling() { - return TreeSitter.treeCursorGotoNextSibling(pointer); - } - - /** - * Move the cursor to the parent of its current node. - * - * @return true if the cursor successfully moved, and false if there was no parent node - * (the cursor was already on the root node). - */ - public boolean gotoParent() { - return TreeSitter.treeCursorGotoParent(pointer); - } - - /** - * Iteratively traverse over the parse tree, applying a callback to the nodes before they are visited. - * - * @param callback The callback consumer which will execute upon visiting a node. - */ - public void preorderTraversal(Consumer callback) { - for (;;) { - callback.accept(this.getCurrentNode()); - if (this.gotoFirstChild() || this.gotoNextSibling()) - continue; - do { - if (!this.gotoParent()) - return; - } while (!this.gotoNextSibling()); - } - } - - @Override - public String toString() { - return "TreeCursor(id: "+id+", tree: "+tree+")"; - } -} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursorNode.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursorNode.java deleted file mode 100644 index 16ef6069..00000000 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeCursorNode.java +++ /dev/null @@ -1,28 +0,0 @@ -package usi.si.seart.treesitter; - -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.Setter; -import lombok.experimental.FieldDefaults; - -@Getter -@Setter(value = AccessLevel.PACKAGE) -@AllArgsConstructor(access = AccessLevel.PACKAGE) -@FieldDefaults(level = AccessLevel.PRIVATE) -public class TreeCursorNode { - - String type; - String name; - int startByte; - int endByte; - Point startPoint; - Point endPoint; - boolean isNamed; - - @Override - public String toString() { - String field = (name != null) ? name + ": " : ""; - return String.format("%s%s [%s] - [%s]", field, type, startPoint, endPoint); - } -} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitter.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitter.java deleted file mode 100644 index eb7aa6a7..00000000 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/TreeSitter.java +++ /dev/null @@ -1,108 +0,0 @@ -package usi.si.seart.treesitter; - -import lombok.experimental.UtilityClass; -import usi.si.seart.treesitter.exception.query.QueryException; - -@UtilityClass -class TreeSitter { - - static native Node nodeChild(Node node, int child); - - static native Node nodeChildByFieldName(Node node, String name); - - static native int nodeChildCount(Node node); - - static native Node nodeDescendantForByteRange(Node node, int startByte, int endByte); - - static native int nodeEndByte(Node node); - - static native Point nodeEndPoint(Node node); - - static native boolean nodeEq(Node node, Node other); - - static native String nodeFieldNameForChild(Node node, int child); - - static native Node nodeFirstChildForByte(Node node, int offset); - - static native Node nodeFirstNamedChildForByte(Node node, int offset); - - static native boolean nodeHasError(Node node); - - static native boolean nodeIsExtra(Node node); - - static native boolean nodeIsMissing(Node node); - - static native boolean nodeIsNamed(Node node); - - static native boolean nodeIsNull(Node node); - - static native Node nodeParent(Node node); - - static native Node nodePrevNamedSibling(Node node); - - static native Node nodePrevSibling(Node node); - - static native Node nodeNextNamedSibling(Node node); - - static native Node nodeNextSibling(Node node); - - static native int nodeStartByte(Node node); - - static native Point nodeStartPoint(Node node); - - static native String nodeString(Node node); - - static native String nodeType(Node node); - - static native long parserNew(); - - static native void parserDelete(long parser); - - static native boolean parserSetLanguage(long parser, long language); - - static native long parserParseBytes(long parser, byte[] source, int length); - - static native long parserIncrementalParseBytes(long parser, long old_tree, byte[] source, int length); - - static native void queryDelete(long query); - - static native long queryNew(long language, String source) throws QueryException; - - static native String queryCaptureName(long pointer, int index); - - static native int queryStringCount(long query); - - static native int queryCaptureCount(long query); - - static native int queryPatternCount(long query); - - static native void queryCursorDelete(long query_cursor); - - static native long queryCursorNew(); - - static native void queryCursorExec(long query_cursor, long query, Node node); - - static native QueryMatch queryCursorNextMatch(long query_cursor); - - static native long treeCursorNew(Node node); - - static native TreeCursorNode treeCursorCurrentTreeCursorNode(long cursor); - - static native String treeCursorCurrentFieldName(long cursor); - - static native Node treeCursorCurrentNode(long cursor); - - static native void treeCursorDelete(long cursor); - - static native boolean treeCursorGotoFirstChild(long cursor); - - static native boolean treeCursorGotoNextSibling(long cursor); - - static native boolean treeCursorGotoParent(long cursor); - - static native void treeDelete(long tree); - - static native void treeEdit(long tree, InputEdit edit); - - static native Node treeRootNode(long tree); -} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/error/ABIVersionError.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/error/ABIVersionError.java deleted file mode 100644 index 008859ef..00000000 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/error/ABIVersionError.java +++ /dev/null @@ -1,13 +0,0 @@ -package usi.si.seart.treesitter.error; - -import lombok.experimental.StandardException; - -/** - * An error raised whenever there is an ABI version mismatch. - *

- * These usually occur as a result of a language being generated - * with an incompatible version of the Tree-sitter CLI. - */ -@StandardException -public class ABIVersionError extends Error { -} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/TreeSitterException.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/TreeSitterException.java deleted file mode 100644 index 58a8323d..00000000 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/TreeSitterException.java +++ /dev/null @@ -1,10 +0,0 @@ -package usi.si.seart.treesitter.exception; - -import lombok.experimental.StandardException; - -/** - * The base exception type for all tree-sitter exceptions. - */ -@StandardException -public class TreeSitterException extends RuntimeException { -} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryCaptureException.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryCaptureException.java deleted file mode 100644 index fc50310f..00000000 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryCaptureException.java +++ /dev/null @@ -1,7 +0,0 @@ -package usi.si.seart.treesitter.exception.query; - -import lombok.experimental.StandardException; - -@StandardException -public class QueryCaptureException extends QueryException { -} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryException.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryException.java deleted file mode 100644 index 60f89773..00000000 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryException.java +++ /dev/null @@ -1,11 +0,0 @@ -package usi.si.seart.treesitter.exception.query; - -import lombok.experimental.StandardException; -import usi.si.seart.treesitter.exception.TreeSitterException; - -/** - * The base exception type for all exceptions related to tree-sitter queries. - */ -@StandardException -public abstract class QueryException extends TreeSitterException { -} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryFieldException.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryFieldException.java deleted file mode 100644 index c8ffc842..00000000 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryFieldException.java +++ /dev/null @@ -1,7 +0,0 @@ -package usi.si.seart.treesitter.exception.query; - -import lombok.experimental.StandardException; - -@StandardException -public class QueryFieldException extends QueryException { -} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryNodeTypeException.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryNodeTypeException.java deleted file mode 100644 index 381b84b8..00000000 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryNodeTypeException.java +++ /dev/null @@ -1,7 +0,0 @@ -package usi.si.seart.treesitter.exception.query; - -import lombok.experimental.StandardException; - -@StandardException -public class QueryNodeTypeException extends QueryException { -} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryStructureException.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryStructureException.java deleted file mode 100644 index 240b6b66..00000000 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QueryStructureException.java +++ /dev/null @@ -1,7 +0,0 @@ -package usi.si.seart.treesitter.exception.query; - -import lombok.experimental.StandardException; - -@StandardException -public class QueryStructureException extends QueryException { -} diff --git a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QuerySyntaxException.java b/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QuerySyntaxException.java deleted file mode 100644 index 47928679..00000000 --- a/dl4se-tree-sitter/src/main/java/usi/si/seart/treesitter/exception/query/QuerySyntaxException.java +++ /dev/null @@ -1,7 +0,0 @@ -package usi.si.seart.treesitter.exception.query; - -import lombok.experimental.StandardException; - -@StandardException -public class QuerySyntaxException extends QueryException { -} diff --git a/dl4se-tree-sitter/src/main/resources/.gitkeep b/dl4se-tree-sitter/src/main/resources/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java deleted file mode 100644 index c8c7940f..00000000 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/NodeTest.java +++ /dev/null @@ -1,204 +0,0 @@ -package usi.si.seart.treesitter; - -import lombok.Cleanup; -import lombok.SneakyThrows; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import java.io.UnsupportedEncodingException; - -class NodeTest extends TestBase { - - private static final String source = "def foo(bar, baz):\n print(bar)\n print(baz)"; - private static Parser parser; - private static Tree tree; - private static Node root; - - @BeforeAll - @SneakyThrows(UnsupportedEncodingException.class) - static void beforeAll() { - parser = new Parser(Language.PYTHON); - tree = parser.parseString(source); - root = tree.getRootNode(); - } - - @AfterAll - static void afterAll() { - tree.close(); - parser.close(); - } - - @Test - void testGetChild() { - Node function = root.getChild(0); - Assertions.assertEquals(1, root.getChildCount()); - Assertions.assertEquals("module", root.getType()); - Assertions.assertEquals(0, root.getStartByte()); - Assertions.assertEquals(44, root.getEndByte()); - Assertions.assertEquals("function_definition", function.getType()); - Assertions.assertEquals(5, function.getChildCount()); - Assertions.assertThrows(IndexOutOfBoundsException.class, () -> root.getChild(-1)); - } - - @Test - void testGetChildByFieldName() { - Node function = root.getChild(0); - Node identifier = function.getChild(1); - Assertions.assertEquals(identifier, function.getChildByFieldName("name")); - Assertions.assertThrows(NullPointerException.class, () -> root.getChildByFieldName(null)); - } - - @Test - void testGetDescendantForByteRange() { - Node function = root.getChild(0); - Node def = function.getChild(0); - Node identifier = function.getChild(1); - Node parameters = function.getChild(2); - Node colon = function.getChild(3); - Node body = function.getChild(4); - Assertions.assertEquals(def, root.getDescendantForByteRange(def.getStartByte(), def.getEndByte())); - Assertions.assertEquals(identifier, root.getDescendantForByteRange(identifier.getStartByte(), identifier.getEndByte())); - Assertions.assertEquals(parameters, root.getDescendantForByteRange(parameters.getStartByte(), parameters.getEndByte())); - Assertions.assertEquals(colon, root.getDescendantForByteRange(colon.getStartByte(), colon.getEndByte())); - Assertions.assertEquals(body, root.getDescendantForByteRange(body.getStartByte(), body.getEndByte())); - Assertions.assertThrows(IllegalArgumentException.class, () -> root.getDescendantForByteRange(2, 0)); - } - - @Test - void testGetFieldNameForChild() { - Node function = root.getChild(0); - Assertions.assertNull(function.getFieldNameForChild(0)); // `def` - Assertions.assertEquals("name", function.getFieldNameForChild(1)); // "name" - Assertions.assertEquals("parameters", function.getFieldNameForChild(2)); // "parameters" - Assertions.assertNull(function.getFieldNameForChild(3)); // `:` - Assertions.assertEquals("body", function.getFieldNameForChild(4)); // "body" - Assertions.assertThrows(IndexOutOfBoundsException.class, () -> root.getFieldNameForChild(-1)); - } - - @Test - void testGetFirstChildForByte() { - Node function = root.getChild(0); - Node def = function.getChild(0); - Node identifier = function.getChild(1); - Node parameters = function.getChild(2); - Node colon = function.getChild(3); - Node body = function.getChild(4); - Assertions.assertEquals(def, function.getFirstChildForByte(def.getStartByte())); - Assertions.assertEquals(identifier, function.getFirstChildForByte(identifier.getStartByte())); - Assertions.assertEquals(parameters, function.getFirstChildForByte(parameters.getStartByte())); - Assertions.assertEquals(colon, function.getFirstChildForByte(colon.getStartByte())); - Assertions.assertEquals(body, function.getFirstChildForByte(body.getStartByte())); - Assertions.assertThrows(IndexOutOfBoundsException.class, () -> root.getFirstChildForByte(-1)); - } - - @Test - void testGetFirstNamedChildForByte() { - Node function = root.getChild(0); - Node def = function.getChild(0); - Node identifier = function.getChild(1); - Node parameters = function.getChild(2); - Node colon = function.getChild(3); - Node body = function.getChild(4); - Assertions.assertEquals(identifier, function.getFirstNamedChildForByte(def.getStartByte())); - Assertions.assertEquals(identifier, function.getFirstNamedChildForByte(identifier.getStartByte())); - Assertions.assertEquals(parameters, function.getFirstNamedChildForByte(parameters.getStartByte())); - Assertions.assertEquals(body, function.getFirstNamedChildForByte(colon.getStartByte())); - Assertions.assertEquals(body, function.getFirstNamedChildForByte(body.getStartByte())); - Assertions.assertThrows(IndexOutOfBoundsException.class, () -> root.getFirstNamedChildForByte(-1)); - } - - @Test - void testGetParent() { - Assertions.assertNull(root.getParent()); - Assertions.assertEquals(root, root.getChild(0).getParent()); - } - - @Test - void testGetNextNamedSibling() { - Node function = root.getChild(0); - Node def = function.getChild(0); - Node identifier = function.getChild(1); - Assertions.assertNull(root.getNextNamedSibling()); - Assertions.assertEquals(identifier, def.getNextNamedSibling()); - } - - @Test - void testGetNextSibling() { - Node function = root.getChild(0); - Node def = function.getChild(0); - Node identifier = function.getChild(1); - Assertions.assertNull(root.getNextSibling()); - Assertions.assertEquals(identifier, def.getNextSibling()); - } - - @Test - void testGetPrevNamedSibling() { - Node function = root.getChild(0); - Node identifier = function.getChild(1); - Node parameters = function.getChild(2); - Assertions.assertNull(root.getPrevNamedSibling()); - Assertions.assertEquals(identifier, parameters.getPrevNamedSibling()); - } - - @Test - void testGetPrevSibling() { - Node function = root.getChild(0); - Node def = function.getChild(0); - Node identifier = function.getChild(1); - Assertions.assertNull(root.getPrevSibling()); - Assertions.assertEquals(def, identifier.getPrevSibling()); - } - - @Test - @SneakyThrows(UnsupportedEncodingException.class) - void testHasError() { - @Cleanup Tree tree = parser.parseString("def foo(bar, baz):\n print(bar.)"); - Node root = tree.getRootNode(); - Node function = root.getChild(0); - Node def = function.getChild(0); - Assertions.assertTrue(root.hasError()); - Assertions.assertTrue(function.hasError()); - Assertions.assertFalse(def.hasError()); - } - - @Test - @SneakyThrows(UnsupportedEncodingException.class) - void testIsExtra() { - @Cleanup Tree tree = parser.parseString("# this is just a comment"); - Node root = tree.getRootNode(); - Node comment = root.getChild(0); - Assertions.assertFalse(root.isExtra()); - Assertions.assertTrue(comment.isExtra()); - } - - @Test - @SneakyThrows(UnsupportedEncodingException.class) - void testIsMissing() { - @Cleanup Parser parser = new Parser(Language.JAVA); - @Cleanup Tree tree = parser.parseString("class C { public static final int i = 6 }"); - Node root = tree.getRootNode(); - Assertions.assertFalse(root.isMissing()); - Assertions.assertFalse(root.getChild(0).isMissing()); - Assertions.assertFalse(root.getChild(0).getChild(2).isMissing()); - Assertions.assertFalse(root.getChild(0).getChild(2).getChild(1).isMissing()); - Assertions.assertFalse(root.getChild(0).getChild(2).getChild(1).getChild(2).isMissing()); - Assertions.assertTrue(root.getChild(0).getChild(2).getChild(1).getChild(3).isMissing()); - } - - @Test - void testIsNamed() { - Node function = root.getChild(0); - Node def = function.getChild(0); - Node identifier = function.getChild(1); - Assertions.assertFalse(def.isNamed()); - Assertions.assertTrue(identifier.isNamed()); - } - - @Test - void testIsNull() { - Assertions.assertFalse(root.isNull()); - Assertions.assertTrue(new Node().isNull()); - } -} diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/ParserTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/ParserTest.java deleted file mode 100644 index 67b06121..00000000 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/ParserTest.java +++ /dev/null @@ -1,60 +0,0 @@ -package usi.si.seart.treesitter; - -import lombok.Cleanup; -import lombok.SneakyThrows; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.nio.file.Files; -import java.nio.file.Path; - -class ParserTest extends TestBase { - - @TempDir - private static Path tmp; - private static Path tmpFile; - - private static Parser parser; - - private static final String source = "print(\"hi\")\n"; - private static final String nodeString = - "(module (expression_statement (call function: (identifier) arguments: (argument_list (string)))))"; - - @BeforeAll - static void beforeAll() throws IOException { - tmpFile = Files.createFile(tmp.resolve("print.py")); - Files.writeString(tmpFile, source); - parser = new Parser(Language.PYTHON); - } - - @AfterAll - static void afterAll() { - parser.close(); - } - - @Test - @SneakyThrows(UnsupportedEncodingException.class) - void testParseString() { - @Cleanup Tree tree = parser.parseString(source); - Assertions.assertEquals(nodeString, tree.getRootNode().getNodeString()); - } - - @Test - @SneakyThrows(IOException.class) - void testParseFile() { - @Cleanup Tree tree = parser.parseFile(tmpFile); - Assertions.assertEquals(nodeString, tree.getRootNode().getNodeString()); - } - - @Test - @SuppressWarnings("resource") - void testParserThrows() { - Assertions.assertThrows(NullPointerException.class, () -> new Parser(null)); - Assertions.assertThrows(UnsatisfiedLinkError.class, () -> new Parser(Language._INVALID_)); - } -} diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/PointTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/PointTest.java deleted file mode 100644 index 7a5ca833..00000000 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/PointTest.java +++ /dev/null @@ -1,18 +0,0 @@ -package usi.si.seart.treesitter; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -class PointTest { - - @Test - void testIsOrigin() { - Assertions.assertTrue(new Point(0, 0).isOrigin()); - Assertions.assertFalse(new Point(1, 0).isOrigin()); - Assertions.assertFalse(new Point(0, 1).isOrigin()); - Assertions.assertFalse(new Point(1, 1).isOrigin()); - Assertions.assertFalse(new Point(-1, 0).isOrigin()); - Assertions.assertFalse(new Point(0, -1).isOrigin()); - Assertions.assertFalse(new Point(-1, -1).isOrigin()); - } -} \ No newline at end of file diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryCursorTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryCursorTest.java deleted file mode 100644 index d71c9463..00000000 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryCursorTest.java +++ /dev/null @@ -1,95 +0,0 @@ -package usi.si.seart.treesitter; - -import lombok.Cleanup; -import lombok.SneakyThrows; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import java.io.UnsupportedEncodingException; -import java.util.Iterator; -import java.util.Spliterator; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - -class QueryCursorTest extends TestBase { - - private static final String source = "class Hello { /* Comment 1 */ /* Comment 2 */ /* Comment 3 */ }"; - private static final Language language = Language.JAVA; - private static Parser parser; - private static Tree tree; - private static Node root; - - @BeforeAll - @SneakyThrows(UnsupportedEncodingException.class) - static void beforeAll() { - parser = new Parser(language); - tree = parser.parseString(source); - root = tree.getRootNode(); - } - - @AfterAll - static void afterAll() { - tree.close(); - parser.close(); - } - - @Test - void testExecWithFor() { - @Cleanup Query query = new Query(language, "(block_comment) @comment"); - @Cleanup QueryCursor cursor = new QueryCursor(root, query); - int numMatches = 0; - for (QueryMatch ignored: cursor) numMatches++; - Assertions.assertEquals(3, numMatches, "Must find three matches!"); - } - - @Test - void testExecWithWhile() { - @Cleanup Query query = new Query(language, "(block_comment) @comment"); - @Cleanup QueryCursor cursor = new QueryCursor(root, query); - cursor.execute(); - int numMatches = 0; - while (cursor.nextMatch() != null) numMatches++; - Assertions.assertEquals(3, numMatches, "Must find three matches!"); - } - - @Test - void testExecWithIterator() { - @Cleanup Query query = new Query(language, "(block_comment) @comment"); - @Cleanup QueryCursor cursor = new QueryCursor(root, query); - AtomicInteger numMatches = new AtomicInteger(); - Iterator iterator = cursor.iterator(); - iterator.forEachRemaining(ignored -> numMatches.incrementAndGet()); - Assertions.assertEquals(3, numMatches.get(), "Must find three matches!"); - } - - @Test - void testExecWithStream() { - @Cleanup Query query = new Query(language, "(block_comment) @comment"); - @Cleanup QueryCursor cursor = new QueryCursor(root, query); - Spliterator spliterator = cursor.spliterator(); - Stream stream = StreamSupport.stream(spliterator, false); - Assertions.assertEquals(3, stream.count(), "Must find three matches!"); - } - - @Test - void testExecNoResultQuery() { - @Cleanup Query query = new Query(language, "(method_declaration) @method"); - @Cleanup QueryCursor cursor = new QueryCursor(root, query); - cursor.execute(); - Assertions.assertNull(cursor.nextMatch(), "Must find no matches!"); - } - - @Test - void testMultipleExecCalls() { - @Cleanup Query query = new Query(language, "(class_body) @test"); - @Cleanup QueryCursor cursor = new QueryCursor(root, query); - cursor.execute(); - cursor.execute(); - QueryMatch match = cursor.nextMatch(); - Assertions.assertNotNull(match); - Assertions.assertNull(cursor.nextMatch()); - } -} diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java deleted file mode 100644 index 3086e224..00000000 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/QueryTest.java +++ /dev/null @@ -1,62 +0,0 @@ -package usi.si.seart.treesitter; - -import lombok.Cleanup; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import usi.si.seart.treesitter.exception.query.QueryCaptureException; -import usi.si.seart.treesitter.exception.query.QueryFieldException; -import usi.si.seart.treesitter.exception.query.QueryNodeTypeException; -import usi.si.seart.treesitter.exception.query.QueryStructureException; -import usi.si.seart.treesitter.exception.query.QuerySyntaxException; - -class QueryTest extends TestBase { - - static Query query; - - @BeforeAll - static void beforeAll() { - query = new Query(Language.JAVA, "(_) @capture"); - } - - @AfterAll - static void afterAll() { - query.close(); - } - - @Test - @SuppressWarnings("resource") - void testQuery() { - Assertions.assertNotNull(query, "Query is not null"); - Assertions.assertThrows(NullPointerException.class, () -> new Query(null, null)); - Assertions.assertThrows(NullPointerException.class, () -> new Query(Language.JAVA, null)); - Assertions.assertThrows(NullPointerException.class, () -> new Query(null, "(_)")); - Assertions.assertThrows(UnsatisfiedLinkError.class, () -> new Query(Language._INVALID_, "(_)")); - Assertions.assertThrows(QueryCaptureException.class, () -> new Query(Language.JAVA, "(#eq? @key @value)")); - Assertions.assertThrows(QueryFieldException.class, () -> new Query(Language.JAVA, "(program unknown: (_))")); - Assertions.assertThrows(QueryNodeTypeException.class, () -> new Query(Language.JAVA, "(null)")); - Assertions.assertThrows(QueryStructureException.class, () -> new Query(Language.JAVA, "(program (program))")); - Assertions.assertThrows(QuerySyntaxException.class, () -> new Query(Language.JAVA, "()")); - } - - @Test - void testQueryCount() { - Assertions.assertEquals(1, query.countCaptures()); - Assertions.assertEquals(1, query.countPatterns()); - Assertions.assertEquals(0, query.countStrings()); - } - - @Test - void testQueryCaptureName() { - QueryCapture capture = new QueryCapture(new Node(), 0); - Assertions.assertEquals("capture", query.getCaptureName(capture)); - } - - @Test - void testQueryHasCaptures() { - Assertions.assertTrue(query.hasCaptures()); - @Cleanup Query query = new Query(Language.JAVA, "(_)"); - Assertions.assertFalse(query.hasCaptures()); - } -} diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TestBase.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TestBase.java deleted file mode 100644 index 9b23b398..00000000 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TestBase.java +++ /dev/null @@ -1,8 +0,0 @@ -package usi.si.seart.treesitter; - -class TestBase { - - static { - LibraryLoader.load(); - } -} diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeCursorTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeCursorTest.java deleted file mode 100644 index 2ae8d48d..00000000 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeCursorTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package usi.si.seart.treesitter; - -import lombok.Cleanup; -import lombok.SneakyThrows; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import java.io.UnsupportedEncodingException; - -class TreeCursorTest extends TestBase { - - @Test - @SneakyThrows(UnsupportedEncodingException.class) - void testWalk() { - @Cleanup Parser parser = new Parser(Language.PYTHON); - @Cleanup Tree tree = parser.parseString("def foo(bar, baz):\n print(bar)\n print(baz)"); - @Cleanup TreeCursor cursor = tree.getRootNode().walk(); - Assertions.assertEquals("module", cursor.getCurrentTreeCursorNode().getType()); - Assertions.assertEquals("module", cursor.getCurrentNode().getType()); - Assertions.assertTrue(cursor.gotoFirstChild()); - Assertions.assertEquals("function_definition", cursor.getCurrentNode().getType()); - Assertions.assertTrue(cursor.gotoFirstChild()); - - Assertions.assertEquals("def", cursor.getCurrentNode().getType()); - Assertions.assertTrue(cursor.gotoNextSibling()); - Assertions.assertEquals("identifier", cursor.getCurrentNode().getType()); - Assertions.assertTrue(cursor.gotoNextSibling()); - Assertions.assertEquals("parameters", cursor.getCurrentNode().getType()); - Assertions.assertTrue(cursor.gotoNextSibling()); - Assertions.assertEquals(":", cursor.getCurrentNode().getType()); - Assertions.assertTrue(cursor.gotoNextSibling()); - Assertions.assertEquals("block", cursor.getCurrentNode().getType()); - Assertions.assertEquals("body", cursor.getCurrentFieldName()); - Assertions.assertFalse(cursor.gotoNextSibling()); - - Assertions.assertTrue(cursor.gotoParent()); - Assertions.assertEquals("function_definition", cursor.getCurrentNode().getType()); - Assertions.assertTrue(cursor.gotoFirstChild()); - } -} diff --git a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeTest.java b/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeTest.java deleted file mode 100644 index b2d86dd7..00000000 --- a/dl4se-tree-sitter/src/test/java/usi/si/seart/treesitter/TreeTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package usi.si.seart.treesitter; - -import lombok.Cleanup; -import lombok.SneakyThrows; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import java.io.UnsupportedEncodingException; - -class TreeTest extends TestBase { - - @Test - @SneakyThrows(UnsupportedEncodingException.class) - void testTreeEdit() { - @Cleanup Parser parser = new Parser(Language.JAVA); - - Tree tree = parser.parseString("class Main {\n // This is a line comment\n}"); - - Node root = tree.getRootNode(); - Node body = root.getChild(0).getChildByFieldName("body"); - int newEndByte = 13; - Point newEndPoint = new Point(1, 1); - InputEdit inputEdit = new InputEdit( - body.getStartByte(), - body.getEndByte(), - newEndByte, - body.getStartPoint(), - body.getEndPoint(), - newEndPoint - ); - - String oldSExp = tree.getRootNode().getNodeString(); - - tree.edit(inputEdit); - - tree = parser.parseString(tree, "class Main {\n}"); - - String newSExp = tree.getRootNode().getNodeString(); - Assertions.assertNotEquals(oldSExp, newSExp); - } - -} diff --git a/dl4se-tree-sitter/tree-sitter b/dl4se-tree-sitter/tree-sitter deleted file mode 160000 index e85a279c..00000000 --- a/dl4se-tree-sitter/tree-sitter +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e85a279cf29da1b08648e27214dda20a841e57c8 diff --git a/dl4se-tree-sitter/tree-sitter-c b/dl4se-tree-sitter/tree-sitter-c deleted file mode 160000 index a584fc98..00000000 --- a/dl4se-tree-sitter/tree-sitter-c +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a584fc98ca1bbbb9788d55026f8b483bd725a60a diff --git a/dl4se-tree-sitter/tree-sitter-cpp b/dl4se-tree-sitter/tree-sitter-cpp deleted file mode 160000 index f4450914..00000000 --- a/dl4se-tree-sitter/tree-sitter-cpp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f44509141e7e483323d2ec178f2d2e6c0fc041c1 diff --git a/dl4se-tree-sitter/tree-sitter-java b/dl4se-tree-sitter/tree-sitter-java deleted file mode 160000 index ac14b4b1..00000000 --- a/dl4se-tree-sitter/tree-sitter-java +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ac14b4b1884102839455d32543ab6d53ae089ab7 diff --git a/dl4se-tree-sitter/tree-sitter-javascript b/dl4se-tree-sitter/tree-sitter-javascript deleted file mode 160000 index fdeb68ac..00000000 --- a/dl4se-tree-sitter/tree-sitter-javascript +++ /dev/null @@ -1 +0,0 @@ -Subproject commit fdeb68ac8d2bd5a78b943528bb68ceda3aade2eb diff --git a/dl4se-tree-sitter/tree-sitter-python b/dl4se-tree-sitter/tree-sitter-python deleted file mode 160000 index 2b9e9e0d..00000000 --- a/dl4se-tree-sitter/tree-sitter-python +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2b9e9e0d231d5dd9f491d47f704817baee7d5af0 diff --git a/pom.xml b/pom.xml index c9566c8a..27cc556f 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,6 @@ dl4se-model dl4se-server dl4se-src2abs - dl4se-tree-sitter dl4se-analyzer From 13951af3398c56135a1ed5c209eadb6448742d15 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 17 May 2023 09:40:51 +0200 Subject: [PATCH 0146/1089] Formatting --- dl4se-analyzer/pom.xml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dl4se-analyzer/pom.xml b/dl4se-analyzer/pom.xml index 4c6419a2..7dfc473e 100644 --- a/dl4se-analyzer/pom.xml +++ b/dl4se-analyzer/pom.xml @@ -1,7 +1,5 @@ - + 4.0.0 dl4se From a808a5b3352d00465057c6f60f16fd7206ccd7ae Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 17 May 2023 11:00:05 +0200 Subject: [PATCH 0147/1089] Fixed a mistake in one of the tests --- .../si/seart/analyzer/count/JavaCodeTokenCounterTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCodeTokenCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCodeTokenCounterTest.java index 9ec44585..5d6f7947 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCodeTokenCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCodeTokenCounterTest.java @@ -34,6 +34,10 @@ void countChildrenTest() { Node package_declaration = root.getChild(0); Node class_declaration = root.getChild(1); Long actual = counter.count(package_declaration, class_declaration); - Assertions.assertEquals(getNodes().size() - 1, actual, actual); + // Remove 1 for the comment node + Assertions.assertEquals( + getNodes().size() - 1, actual, + "Total number of code tokens should be equal to the number of input tokens without the comments!" + ); } } \ No newline at end of file From d840604e460255d4a53217bddf4510c5aef2e88f Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 17 May 2023 11:21:25 +0200 Subject: [PATCH 0148/1089] Reimplemented `TraverseCounter` Replacing the library-provided `preorderTraversal` with an equivalent manual implementation allows us to introduce support for early-stopping, which will be needed for languages like Python where it is not desirable to explore entire subtrees. --- .../seart/analyzer/count/TraverseCounter.java | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TraverseCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TraverseCounter.java index 6f4f6351..cbda88c8 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TraverseCounter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TraverseCounter.java @@ -15,22 +15,26 @@ public abstract class TraverseCounter implements Counter { AtomicLong count = new AtomicLong(); - // TODO: 16.05.23 - // This implementation will not work for languages like Python. - // tree-sitter treats Python strings as non-leaf nodes that can contain interpolations. - // Rather than editing the grammar, which would hurt users of our API, we should alter this logic. @Override public Long count(Node node) { @Cleanup TreeCursor cursor = node.walk(); - cursor.preorderTraversal(this::nodeCallback); - Long result = count.get(); - this.reset(); - return result; + while (true) { + Node current = cursor.getCurrentNode(); + nodeCallback(current); + if (shouldExplore(current) && cursor.gotoFirstChild()) { + continue; + } + while (!cursor.gotoNextSibling()) { + if (!cursor.gotoParent()) { + return count.getAndSet(0); + } + } + } } protected abstract void nodeCallback(Node node); - protected void reset() { - this.count.set(0); + protected boolean shouldExplore(Node node) { + return true; } } From 56d271ddedf68155b0d4246e379ed781d3a3f41b Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 17 May 2023 11:22:31 +0200 Subject: [PATCH 0149/1089] Added token counters for Python with tests --- .../usi/si/seart/analyzer/PythonAnalyzer.java | 7 +-- .../count/PythonCodeTokenCounter.java | 22 ++++++++++ .../analyzer/count/PythonTokenCounter.java | 34 +++++++++++++++ .../count/PythonCodeTokenCounterTest.java | 43 +++++++++++++++++++ .../count/PythonTokenCounterTest.java | 43 +++++++++++++++++++ 5 files changed, 146 insertions(+), 3 deletions(-) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/PythonCodeTokenCounter.java create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/PythonTokenCounter.java create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/PythonCodeTokenCounterTest.java create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/PythonTokenCounterTest.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java index 709af803..88d1685d 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java @@ -1,6 +1,8 @@ package usi.si.seart.analyzer; import ch.usi.si.seart.treesitter.Language; +import usi.si.seart.analyzer.count.PythonCodeTokenCounter; +import usi.si.seart.analyzer.count.PythonTokenCounter; import usi.si.seart.analyzer.enumerator.PythonBoilerplateEnumerator; import usi.si.seart.analyzer.predicate.path.PythonTestFilePredicate; import usi.si.seart.analyzer.query.multi.PythonMultiCaptureQueries; @@ -12,9 +14,8 @@ public class PythonAnalyzer extends AbstractAnalyzer { public PythonAnalyzer(LocalClone localClone, Path path) { super(localClone, path, Language.PYTHON); - // TODO: 16.05.23 Add dedicated counters for all/code-only tokens - // this.codeTokenCounter = new PythonCodeTokenCounter(); - // this.totalTokenCounter = new PythonTokenCounter(this::getSourceBytes); + this.codeTokenCounter = new PythonCodeTokenCounter(); + this.totalTokenCounter = new PythonTokenCounter(this::getSourceBytes); this.testFilePredicate = new PythonTestFilePredicate(); this.singleCaptureQueries = new PythonSingleCaptureQueries(); this.multiCaptureQueries = new PythonMultiCaptureQueries(); diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/PythonCodeTokenCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/PythonCodeTokenCounter.java new file mode 100644 index 00000000..8ece76bc --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/PythonCodeTokenCounter.java @@ -0,0 +1,22 @@ +package usi.si.seart.analyzer.count; + +import ch.usi.si.seart.treesitter.Node; + +public class PythonCodeTokenCounter extends CodeTokenCounter { + + @Override + protected void nodeCallback(Node node) { + String type = node.getType(); + boolean leafNode = node.getChildCount() == 0; + boolean isComment = type.equals("comment"); + boolean isString = type.equals("string"); + if (isString || (leafNode && !isComment)) + count.incrementAndGet(); + } + + @Override + protected boolean shouldExplore(Node node) { + String type = node.getType(); + return !type.equals("string"); + } +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/PythonTokenCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/PythonTokenCounter.java new file mode 100644 index 00000000..f847bd00 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/PythonTokenCounter.java @@ -0,0 +1,34 @@ +package usi.si.seart.analyzer.count; + +import ch.usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Range; +import usi.si.seart.analyzer.NodeMapper; + +public class PythonTokenCounter extends TokenCounter { + + public PythonTokenCounter(NodeMapper mapper) { + super(mapper); + } + + @Override + protected void nodeCallback(Node node) { + String type = node.getType(); + boolean leafNode = node.getChildCount() == 0; + if (type.equals("string")) { + count.addAndGet(1L); + } else if (leafNode && type.equals("comment")) { + Range range = node.getRange(); + String content = mapper.getContentForRange(range).substring(1); + String[] tokens = content.split("\\s+"); + count.addAndGet(tokens.length + 1L); + } else if (leafNode) { + count.addAndGet(1L); + } + } + + @Override + protected boolean shouldExplore(Node node) { + String type = node.getType(); + return !type.equals("string"); + } +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/PythonCodeTokenCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/PythonCodeTokenCounterTest.java new file mode 100644 index 00000000..11a31692 --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/PythonCodeTokenCounterTest.java @@ -0,0 +1,43 @@ +package usi.si.seart.analyzer.count; + +import ch.usi.si.seart.treesitter.Node; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import usi.si.seart.analyzer.test.PythonBaseTest; + +import java.util.HashSet; + +class PythonCodeTokenCounterTest extends PythonBaseTest { + + @Test + void countEmptyTest() { + Counter counter = new PythonCodeTokenCounter(); + Assertions.assertEquals(0, counter.count()); + Assertions.assertEquals(0, counter.count(new HashSet<>())); + } + + @Test + void countRootTest() { + Counter counter = new PythonCodeTokenCounter(); + Long actual = counter.count(tree.getRootNode()); + // Remove 1 for the comment node + Assertions.assertEquals( + getNodes().size() - 1, actual, + "Total number of code tokens should be equal to the number of input tokens without the comments!" + ); + } + + @Test + void countChildrenTest() { + Counter counter = new PythonCodeTokenCounter(); + Node module = tree.getRootNode(); + Node function = module.getChild(0); + Node[] children = function.getChildren().toArray(new Node[0]); + Long actual = counter.count(children); + // Remove 1 for the comment node + Assertions.assertEquals( + getNodes().size() - 1, actual, + "Total number of code tokens should be equal to the number of input tokens without the comments!" + ); + } +} \ No newline at end of file diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/PythonTokenCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/PythonTokenCounterTest.java new file mode 100644 index 00000000..55770081 --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/PythonTokenCounterTest.java @@ -0,0 +1,43 @@ +package usi.si.seart.analyzer.count; + +import ch.usi.si.seart.treesitter.Node; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import usi.si.seart.analyzer.test.PythonBaseTest; + +import java.util.HashSet; + +class PythonTokenCounterTest extends PythonBaseTest { + + @Test + void countEmptyTest() { + Counter counter = new PythonTokenCounter(getNodeMapper()); + Assertions.assertEquals(0, counter.count()); + Assertions.assertEquals(0, counter.count(new HashSet<>())); + } + + @Test + void countRootTest() { + Counter counter = new PythonTokenCounter(getNodeMapper()); + Long actual = counter.count(tree.getRootNode()); + // Add 2 for the individual comment words + Assertions.assertEquals( + getNodes().size() + 2, actual, + "Total number of tokens should be equal to the number of input tokens including comment tokens (words)!" + ); + } + + @Test + void countChildrenTest() { + Counter counter = new PythonTokenCounter(getNodeMapper()); + Node module = tree.getRootNode(); + Node function = module.getChild(0); + Node[] children = function.getChildren().toArray(new Node[0]); + Long actual = counter.count(children); + // Add 2 for the individual comment words + Assertions.assertEquals( + getNodes().size() + 2, actual, + "Total number of tokens should be equal to the number of input tokens including comment tokens (words)!" + ); + } +} From 9e7724fa3121026aaf99901fa2afd07c39065414 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 17 May 2023 11:33:03 +0200 Subject: [PATCH 0150/1089] Improved error messages for `count` tests --- .../analyzer/count/JavaCharacterCounterTest.java | 10 +++++----- .../analyzer/count/JavaCodeTokenCounterTest.java | 12 ++++-------- .../si/seart/analyzer/count/JavaLineCounterTest.java | 9 ++++----- .../seart/analyzer/count/JavaTokenCounterTest.java | 12 ++++++------ .../analyzer/count/PythonCodeTokenCounterTest.java | 12 ++++-------- .../seart/analyzer/count/PythonTokenCounterTest.java | 12 ++++-------- 6 files changed, 27 insertions(+), 40 deletions(-) diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCharacterCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCharacterCounterTest.java index 0e4d0c2c..ec42335d 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCharacterCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCharacterCounterTest.java @@ -9,6 +9,8 @@ class JavaCharacterCounterTest extends JavaBaseTest { + private static final String message = "Total number of characters should be equal to the joined tree string without spaces!"; + @Test void countEmptyTest() { Counter counter = new CharacterCounter(getNodeMapper()); @@ -21,10 +23,7 @@ void countRootTest(){ Counter counter = new CharacterCounter(getNodeMapper()); Long actual = counter.count(tree.getRootNode()); // Remove 2 for the space in string and comment - Assertions.assertEquals( - getJoinedTokens().length() - 2, actual, - "Total number of characters should be equal to the joined tree string without spaces!" - ); + Assertions.assertEquals(getJoinedTokens().length() - 2, actual, message); } @Test @@ -34,6 +33,7 @@ void countChildrenTest() { Node package_declaration = root.getChild(0); Node class_declaration = root.getChild(1); Long actual = counter.count(package_declaration, class_declaration); - Assertions.assertEquals(getJoinedTokens().length() - 2, actual); + // Remove 2 for the space in string and comment + Assertions.assertEquals(getJoinedTokens().length() - 2, actual, message); } } \ No newline at end of file diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCodeTokenCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCodeTokenCounterTest.java index 5d6f7947..9e15ee71 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCodeTokenCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCodeTokenCounterTest.java @@ -9,6 +9,8 @@ class JavaCodeTokenCounterTest extends JavaBaseTest { + private static final String message = "Total number of code tokens should be equal to the number of input tokens without the comments!"; + @Test void countEmptyTest() { Counter counter = new CodeTokenCounter(); @@ -21,10 +23,7 @@ void countRootTest() { Counter counter = new CodeTokenCounter(); Long actual = counter.count(tree.getRootNode()); // Remove 1 for the comment node - Assertions.assertEquals( - getNodes().size() - 1, actual, - "Total number of code tokens should be equal to the number of input tokens without the comments!" - ); + Assertions.assertEquals(getNodes().size() - 1, actual, message); } @Test @@ -35,9 +34,6 @@ void countChildrenTest() { Node class_declaration = root.getChild(1); Long actual = counter.count(package_declaration, class_declaration); // Remove 1 for the comment node - Assertions.assertEquals( - getNodes().size() - 1, actual, - "Total number of code tokens should be equal to the number of input tokens without the comments!" - ); + Assertions.assertEquals(getNodes().size() - 1, actual, message); } } \ No newline at end of file diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaLineCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaLineCounterTest.java index 1a6e588e..e9230bcf 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaLineCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaLineCounterTest.java @@ -9,6 +9,8 @@ class JavaLineCounterTest extends JavaBaseTest { + private static final String message = "Total number of lines should be equal to the number of lines reported by the `lines()` method"; + @Test void countEmptyTest() { Counter counter = new LineCounter(); @@ -20,10 +22,7 @@ void countEmptyTest() { void countRootTest() { Counter counter = new LineCounter(); Long actual = counter.count(tree.getRootNode()); - Assertions.assertEquals( - getInput().lines().count(), actual, - "Total number of lines should be equal to the number of lines reported by String method" - ); + Assertions.assertEquals(getInput().lines().count(), actual, message); } @Test @@ -34,6 +33,6 @@ void countChildrenTest() { Node class_declaration = root.getChild(1); Long actual = counter.count(package_declaration, class_declaration); // Subtract one for the lost space between package and class - Assertions.assertEquals(getInput().lines().count() - 1, actual); + Assertions.assertEquals(getInput().lines().count() - 1, actual, message); } } \ No newline at end of file diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaTokenCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaTokenCounterTest.java index 7d233b4d..ca5f38d3 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaTokenCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaTokenCounterTest.java @@ -9,6 +9,8 @@ class JavaTokenCounterTest extends JavaBaseTest { + private static final String message = "Total number of tokens should be equal to the number of input tokens including comment tokens (words)!"; + @Test void countEmptyTest() { Counter counter = new JavaTokenCounter(getNodeMapper()); @@ -20,11 +22,8 @@ void countEmptyTest() { void countRootTest() { Counter counter = new JavaTokenCounter(getNodeMapper()); Long actual = counter.count(tree.getRootNode()); - // Add 1 for the extra comment word - Assertions.assertEquals( - getNodes().size() + 2, actual, - "Total number of tokens should be equal to the number of input tokens including comment tokens (words)!" - ); + // Add 2 for the individual comment words + Assertions.assertEquals(getNodes().size() + 2, actual, message); } @Test @@ -34,6 +33,7 @@ void countChildrenTest() { Node package_declaration = root.getChild(0); Node class_declaration = root.getChild(1); Long actual = counter.count(package_declaration, class_declaration); - Assertions.assertEquals(getNodes().size() + 2, actual); + // Add 2 for the individual comment words + Assertions.assertEquals(getNodes().size() + 2, actual, message); } } \ No newline at end of file diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/PythonCodeTokenCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/PythonCodeTokenCounterTest.java index 11a31692..e3e195a8 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/PythonCodeTokenCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/PythonCodeTokenCounterTest.java @@ -9,6 +9,8 @@ class PythonCodeTokenCounterTest extends PythonBaseTest { + private static final String message = "Total number of code tokens should be equal to the number of input tokens without the comments!"; + @Test void countEmptyTest() { Counter counter = new PythonCodeTokenCounter(); @@ -21,10 +23,7 @@ void countRootTest() { Counter counter = new PythonCodeTokenCounter(); Long actual = counter.count(tree.getRootNode()); // Remove 1 for the comment node - Assertions.assertEquals( - getNodes().size() - 1, actual, - "Total number of code tokens should be equal to the number of input tokens without the comments!" - ); + Assertions.assertEquals(getNodes().size() - 1, actual, message); } @Test @@ -35,9 +34,6 @@ void countChildrenTest() { Node[] children = function.getChildren().toArray(new Node[0]); Long actual = counter.count(children); // Remove 1 for the comment node - Assertions.assertEquals( - getNodes().size() - 1, actual, - "Total number of code tokens should be equal to the number of input tokens without the comments!" - ); + Assertions.assertEquals(getNodes().size() - 1, actual, message); } } \ No newline at end of file diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/PythonTokenCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/PythonTokenCounterTest.java index 55770081..d17c0406 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/PythonTokenCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/PythonTokenCounterTest.java @@ -9,6 +9,8 @@ class PythonTokenCounterTest extends PythonBaseTest { + private static final String message = "Total number of tokens should be equal to the number of input tokens including comment tokens (words)!"; + @Test void countEmptyTest() { Counter counter = new PythonTokenCounter(getNodeMapper()); @@ -21,10 +23,7 @@ void countRootTest() { Counter counter = new PythonTokenCounter(getNodeMapper()); Long actual = counter.count(tree.getRootNode()); // Add 2 for the individual comment words - Assertions.assertEquals( - getNodes().size() + 2, actual, - "Total number of tokens should be equal to the number of input tokens including comment tokens (words)!" - ); + Assertions.assertEquals(getNodes().size() + 2, actual, message); } @Test @@ -35,9 +34,6 @@ void countChildrenTest() { Node[] children = function.getChildren().toArray(new Node[0]); Long actual = counter.count(children); // Add 2 for the individual comment words - Assertions.assertEquals( - getNodes().size() + 2, actual, - "Total number of tokens should be equal to the number of input tokens including comment tokens (words)!" - ); + Assertions.assertEquals(getNodes().size() + 2, actual, message); } } From 3a144247d1046b6af8442792b3c4b75190d57be6 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 27 Jun 2023 09:29:54 +0200 Subject: [PATCH 0151/1089] Moved `LocalClone` to its own class --- .../java/usi/si/seart/analyzer/Analyzer.java | 15 ------------- .../usi/si/seart/analyzer/LocalClone.java | 22 +++++++++++++++++++ 2 files changed, 22 insertions(+), 15 deletions(-) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/LocalClone.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java index 877199fc..b5f375c0 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java @@ -4,11 +4,9 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.experimental.FieldDefaults; -import usi.si.seart.model.GitRepo; import usi.si.seart.model.code.File; import usi.si.seart.model.code.Function; -import java.nio.file.Path; import java.util.List; public interface Analyzer extends AutoCloseable { @@ -22,17 +20,4 @@ final class Result { File file; List functions; } - - @Getter - @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) - @AllArgsConstructor - final class LocalClone { - - GitRepo gitRepo; - Path diskPath; - - public Path relativePathOf(Path path) { - return diskPath.relativize(path); - } - } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/LocalClone.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/LocalClone.java new file mode 100644 index 00000000..85b3c4d4 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/LocalClone.java @@ -0,0 +1,22 @@ +package usi.si.seart.analyzer; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.experimental.FieldDefaults; +import usi.si.seart.model.GitRepo; + +import java.nio.file.Path; + +@Getter +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +@AllArgsConstructor +public final class LocalClone { + + GitRepo gitRepo; + Path diskPath; + + public Path relativePathOf(Path path) { + return diskPath.relativize(path); + } +} From f9d8bd9024fa269af0d5c0c130c9a021e7afb519 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 27 Jun 2023 09:31:03 +0200 Subject: [PATCH 0152/1089] Upgrading `javaparser` where needed --- dl4se-crawler/pom.xml | 2 +- dl4se-server/pom.xml | 2 +- dl4se-src2abs/pom.xml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dl4se-crawler/pom.xml b/dl4se-crawler/pom.xml index 716e2b17..b35a79c1 100644 --- a/dl4se-crawler/pom.xml +++ b/dl4se-crawler/pom.xml @@ -51,7 +51,7 @@ com.github.javaparser javaparser-core - 3.24.4 + ${javaparser.version} diff --git a/dl4se-server/pom.xml b/dl4se-server/pom.xml index 22a6e63c..5ec8639f 100644 --- a/dl4se-server/pom.xml +++ b/dl4se-server/pom.xml @@ -73,7 +73,7 @@ com.github.javaparser javaparser-core - 3.24.4 + ${javaparser.version} org.springframework.cloud diff --git a/dl4se-src2abs/pom.xml b/dl4se-src2abs/pom.xml index 4d7b633c..17017063 100644 --- a/dl4se-src2abs/pom.xml +++ b/dl4se-src2abs/pom.xml @@ -26,12 +26,12 @@ com.github.javaparser javaparser-core - 3.24.4 + ${javaparser.version} com.github.javaparser javaparser-core-generators - 3.24.2 + ${javaparser.version} org.antlr From d5aba9a01331a7b71bf4ebfee94dcbd74cd028d4 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 27 Jun 2023 09:31:19 +0200 Subject: [PATCH 0153/1089] Removing old VCS mappings --- .idea/vcs.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.idea/vcs.xml b/.idea/vcs.xml index a0ee5a33..a081b18c 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -9,11 +9,5 @@ - - - - - - \ No newline at end of file From d1b31079b83e6911e798a712af6a76a5214869b9 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 27 Jun 2023 09:32:04 +0200 Subject: [PATCH 0154/1089] Bumping `jackson` version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 27cc556f..697a7ac4 100644 --- a/pom.xml +++ b/pom.xml @@ -38,7 +38,7 @@ 3.25.3 1.18.26 42.6.0 - 2.15.0 + 2.15.2 From 0a60a4bbcb6842360a29580a2edf139c2351d6ab Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 27 Jun 2023 09:35:04 +0200 Subject: [PATCH 0155/1089] Added version variable for `janino` --- dl4se-crawler/pom.xml | 4 ++-- pom.xml | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/dl4se-crawler/pom.xml b/dl4se-crawler/pom.xml index b35a79c1..3db64fc8 100644 --- a/dl4se-crawler/pom.xml +++ b/dl4se-crawler/pom.xml @@ -31,12 +31,12 @@ org.codehaus.janino janino - 3.1.8 + ${janino.version} org.codehaus.janino commons-compiler - 3.1.8 + ${janino.version} com.google.http-client diff --git a/pom.xml b/pom.xml index 697a7ac4..cd3dde79 100644 --- a/pom.xml +++ b/pom.xml @@ -37,6 +37,7 @@ 5.9.3 3.25.3 1.18.26 + 3.1.9 42.6.0 2.15.2 From baa766d4a49bd01071a741ec2996f2cff3f9af7c Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 27 Jun 2023 09:36:44 +0200 Subject: [PATCH 0156/1089] Extracting `jjwt` version variable --- dl4se-server/pom.xml | 6 +++--- pom.xml | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/dl4se-server/pom.xml b/dl4se-server/pom.xml index 5ec8639f..1067f209 100644 --- a/dl4se-server/pom.xml +++ b/dl4se-server/pom.xml @@ -51,18 +51,18 @@ io.jsonwebtoken jjwt-api - 0.11.5 + ${jjwt.version} io.jsonwebtoken jjwt-impl - 0.11.5 + ${jjwt.version} runtime io.jsonwebtoken jjwt-jackson - 0.11.5 + ${jjwt.version} runtime diff --git a/pom.xml b/pom.xml index cd3dde79..7d79a636 100644 --- a/pom.xml +++ b/pom.xml @@ -39,6 +39,7 @@ 1.18.26 3.1.9 42.6.0 + 0.11.5 2.15.2 From 67043d2eb5148a69b12972663f5546f29ffaf7b7 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 27 Jun 2023 09:37:01 +0200 Subject: [PATCH 0157/1089] Removing unused test dependency --- dl4se-server/pom.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/dl4se-server/pom.xml b/dl4se-server/pom.xml index 1067f209..2c24ebf0 100644 --- a/dl4se-server/pom.xml +++ b/dl4se-server/pom.xml @@ -128,12 +128,6 @@ spring-boot-starter-test test - - com.icegreen - greenmail-junit5 - 1.6.11 - test - From 2fd9a156edefc15cd09d036cc577216bec0ca67c Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 27 Jun 2023 10:40:47 +0200 Subject: [PATCH 0158/1089] Hoisting Spring Boot and Cloud dependencies to root-level pom --- dl4se-crawler/pom.xml | 4 ---- dl4se-server/pom.xml | 21 --------------------- pom.xml | 16 ++++++++++++++++ 3 files changed, 16 insertions(+), 25 deletions(-) diff --git a/dl4se-crawler/pom.xml b/dl4se-crawler/pom.xml index 3db64fc8..fdf94729 100644 --- a/dl4se-crawler/pom.xml +++ b/dl4se-crawler/pom.xml @@ -26,17 +26,14 @@ ch.qos.logback logback-classic - 1.4.3 org.codehaus.janino janino - ${janino.version} org.codehaus.janino commons-compiler - ${janino.version} com.google.http-client @@ -46,7 +43,6 @@ com.google.code.gson gson - 2.9.0 com.github.javaparser diff --git a/dl4se-server/pom.xml b/dl4se-server/pom.xml index 2c24ebf0..190d7b79 100644 --- a/dl4se-server/pom.xml +++ b/dl4se-server/pom.xml @@ -14,29 +14,8 @@ UTF-8 - 2.6.4 - 2021.0.1 - - - - org.springframework.boot - spring-boot-dependencies - ${springframework.version} - pom - import - - - org.springframework.cloud - spring-cloud-dependencies - ${springcloud.version} - pom - import - - - - usi.si.seart diff --git a/pom.xml b/pom.xml index 7d79a636..9ca8f741 100644 --- a/pom.xml +++ b/pom.xml @@ -41,6 +41,8 @@ 42.6.0 0.11.5 2.15.2 + 2.7.13 + 2021.0.3 @@ -59,6 +61,20 @@ pom import + + org.springframework.boot + spring-boot-dependencies + ${springframework.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${springcloud.version} + pom + import + From 23906e129de0f51b3aba993522c04e985eaa7c5e Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 27 Jun 2023 10:47:00 +0200 Subject: [PATCH 0159/1089] Added analyzer to list of crawler dependencies --- dl4se-crawler/pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dl4se-crawler/pom.xml b/dl4se-crawler/pom.xml index fdf94729..ade80d9f 100644 --- a/dl4se-crawler/pom.xml +++ b/dl4se-crawler/pom.xml @@ -23,6 +23,11 @@ dl4se-model ${project.version} + + usi.si.seart + dl4se-analyzer + ${project.version} + ch.qos.logback logback-classic From f2dbcb80c90e14b6f21b5dea68ea9dc11a40e30c Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 27 Jun 2023 10:47:56 +0200 Subject: [PATCH 0160/1089] Updated run configurations for JAR files --- .idea/runConfigurations/Crawler.xml | 2 +- .idea/runConfigurations/Server.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.idea/runConfigurations/Crawler.xml b/.idea/runConfigurations/Crawler.xml index 97ed0c02..3dca0b7e 100644 --- a/.idea/runConfigurations/Crawler.xml +++ b/.idea/runConfigurations/Crawler.xml @@ -8,7 +8,7 @@ - \ No newline at end of file diff --git a/.idea/runConfigurations/Server.xml b/.idea/runConfigurations/Server.xml index 73774c0c..afba5796 100644 --- a/.idea/runConfigurations/Server.xml +++ b/.idea/runConfigurations/Server.xml @@ -4,7 +4,7 @@ + + com.google.guava + guava-bom + ${guava.version} + pom + import + org.springframework.boot spring-boot-dependencies From 2f8d10a7b448f8d5eb2c2deba6a9a2c4e8569e63 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 3 Jul 2023 10:17:57 +0200 Subject: [PATCH 0169/1089] `GitException` now uses `@StandardException` annotation from `lombok` --- .../src/main/java/usi/si/seart/git/GitException.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/git/GitException.java b/dl4se-crawler/src/main/java/usi/si/seart/git/GitException.java index 74a537c6..094e32a5 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/git/GitException.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/git/GitException.java @@ -1,8 +1,7 @@ package usi.si.seart.git; -public class GitException extends Exception { +import lombok.experimental.StandardException; - public GitException(String message) { - super(message); - } +@StandardException +public class GitException extends Exception { } From c365bbee31ca3b1a964b6ef3cad353385dfa75e0 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 3 Jul 2023 10:18:28 +0200 Subject: [PATCH 0170/1089] Added missing static field modifiers --- dl4se-crawler/src/main/java/usi/si/seart/git/Git.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java b/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java index c94ad17d..f712fa6a 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java @@ -33,7 +33,7 @@ @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class Git { - static String repoLinkPattern = "https://github.com/%s.git"; + private static final String repoLinkPattern = "https://github.com/%s.git"; Path localDir; String name; From 80c8f81da8e87a78a96a295bff3eeaca0510a9bf Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 3 Jul 2023 10:22:47 +0200 Subject: [PATCH 0171/1089] Removed logging from `Git` class --- dl4se-crawler/src/main/java/usi/si/seart/git/Git.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java b/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java index f712fa6a..eebe6fc2 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java @@ -4,7 +4,6 @@ import lombok.Getter; import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; -import lombok.extern.slf4j.Slf4j; import usi.si.seart.collection.utils.CollectionUtils; import usi.si.seart.model.Language; import usi.si.seart.utils.StringUtils; @@ -29,7 +28,6 @@ * * @author dabico */ -@Slf4j @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class Git { @@ -308,8 +306,6 @@ private Process executeGitCommand(String... args) { command.add("git"); command.addAll(Arrays.asList(args)); - log.debug("Executing Git Command: {}", String.join(" ", command)); - ProcessBuilder builder = new ProcessBuilder(command); builder.directory(localDir.toFile()); Process process = builder.start(); From 5f5ce060aee788c1bbb2c0540eaae3438c7f77d8 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 3 Jul 2023 11:01:02 +0200 Subject: [PATCH 0172/1089] The `Git` class is now `AutoClosable` Never assume that the user will manually clean up the clone directory. Unfortunately, due to the exceptional nature of this class, it can not be used in tandem with `lombok`'s `@Cleanup` annotation. --- .../src/main/java/usi/si/seart/Crawler.java | 15 +- .../src/main/java/usi/si/seart/git/Git.java | 12 +- .../test/java/usi/si/seart/git/GitTest.java | 293 +++++++++--------- 3 files changed, 163 insertions(+), 157 deletions(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/Crawler.java b/dl4se-crawler/src/main/java/usi/si/seart/Crawler.java index a025e335..f69749d0 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/Crawler.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/Crawler.java @@ -25,6 +25,7 @@ import usi.si.seart.utils.HibernateUtils; import usi.si.seart.utils.PathUtils; +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.time.LocalDate; @@ -135,15 +136,14 @@ private static void checkRepoData(GhsGitRepo item) { saveProgress(); } - @SneakyThrows + @SneakyThrows(IOException.class) private static void updateRepoData(GitRepo repo, Set repoLanguages) { String name = repo.getName(); LocalDateTime lastCommit = repo.getLastCommit(); log.info("Updating repository: {} [Last Commit: {}]", name, lastCommit); Path cloneDir = Files.createTempDirectory(CrawlerProperties.tmpDirPrefix); - try { - Git git = new Git(name, cloneDir, lastCommit); + try (Git git = new Git(name, cloneDir, lastCommit)) { Set notMined = CollectionUtils.difference(repoLanguages, repo.getLanguages()); if (!notMined.isEmpty()) { @@ -173,8 +173,6 @@ private static void updateRepoData(GitRepo repo, Set repoLanguages) { HibernateUtils.save(repo); } catch (GitException ex) { log.error("Git operation error for: " + name, ex); - } finally { - PathUtils.forceDelete(cloneDir); } } @@ -197,15 +195,14 @@ private static void renameFile(GitRepo repo, Path oldFilePath, Path newFilePath) HibernateUtils.updateFilePathByRepoId(repo.getId(), oldFilePath, newFilePath); } - @SneakyThrows + @SneakyThrows(IOException.class) private static void mineRepoData(GitRepo repo, Set repoLanguages) { String name = repo.getName(); LocalDateTime lastUpdateGhs = repo.getLastCommit(); Path cloneDir = Files.createTempDirectory(CrawlerProperties.tmpDirPrefix); log.info("Mining repository: {} [Last Commit: {}]", name, lastUpdateGhs); - try { - Git git = new Git(name, cloneDir, true); + try (Git git = new Git(name, cloneDir, true)) { Git.Commit latest = git.getLastCommitInfo(); mineRepoDataForLanguages(repo, cloneDir, repoLanguages); @@ -217,8 +214,6 @@ private static void mineRepoData(GitRepo repo, Set repoLanguages) { HibernateUtils.save(repo); } catch (GitException ex) { log.error("Git operation error for: " + name, ex); - } finally { - PathUtils.forceDelete(cloneDir); } } diff --git a/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java b/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java index eebe6fc2..6e73d839 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java @@ -29,7 +29,7 @@ * @author dabico */ @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) -public class Git { +public class Git implements AutoCloseable { private static final String repoLinkPattern = "https://github.com/%s.git"; @@ -312,4 +312,14 @@ private Process executeGitCommand(String... args) { process.waitFor(); return process; } + + @Override + @SneakyThrows(InterruptedException.class) + public void close() throws IOException { + ProcessBuilder builder = new ProcessBuilder(); + builder.command("rm", "-rf", localDir.getFileName().toString()); + builder.directory(localDir.getParent().toFile()); + Process process = builder.start(); + process.waitFor(); + } } diff --git a/dl4se-crawler/src/test/java/usi/si/seart/git/GitTest.java b/dl4se-crawler/src/test/java/usi/si/seart/git/GitTest.java index d1060706..82892c01 100644 --- a/dl4se-crawler/src/test/java/usi/si/seart/git/GitTest.java +++ b/dl4se-crawler/src/test/java/usi/si/seart/git/GitTest.java @@ -1,7 +1,6 @@ package usi.si.seart.git; import lombok.AccessLevel; -import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; import lombok.experimental.NonFinal; import org.junit.jupiter.api.Assertions; @@ -41,24 +40,24 @@ class GitTest { .build(); @Test - @SneakyThrows({GitException.class}) - void regularCloneTest() { - new Git(testRepoName, tmp); - checkContents(tmp.toFile()); + void regularCloneTest() throws IOException, GitException { + try (Git ignored = new Git(testRepoName, tmp)) { + checkContents(tmp.toFile()); + } } @Test - @SneakyThrows({GitException.class}) - void shallowCloneTest() { - new Git(testRepoName, tmp, true); - checkContents(tmp.toFile()); + void shallowCloneTest() throws IOException, GitException { + try (Git ignored = new Git(testRepoName, tmp, true)) { + checkContents(tmp.toFile()); + } } @Test - @SneakyThrows({GitException.class}) - void shallowCloneSinceTest() { - new Git(testRepoName, tmp, LocalDateTime.of(2022, 2, 12, 0, 0)); - checkContents(tmp.toFile()); + void shallowCloneSinceTest() throws IOException, GitException { + try (Git ignored = new Git(testRepoName, tmp, LocalDateTime.of(2022, 2, 12, 0, 0))) { + checkContents(tmp.toFile()); + } } private void checkContents(File dir) { @@ -71,154 +70,154 @@ private void checkContents(File dir) { // ref: https://github.com/dabico/dl4se-crawler-test/commit/010e305c9818d7d8a985e91cf60739ac3b66d24e @Test - @SneakyThrows({GitException.class}) - void getLastCommitInfoTest() { - Git git = new Git(testRepoName, tmp, true); - Git.Commit commit = git.getLastCommitInfo(); - Assertions.assertEquals("010e305c9818d7d8a985e91cf60739ac3b66d24e", commit.getSha()); - Assertions.assertEquals(LocalDateTime.of(2022, 2, 12, 20, 19, 51), commit.getTimestamp()); + void getLastCommitInfoTest() throws IOException, GitException { + try (Git git = new Git(testRepoName, tmp, true)) { + Git.Commit commit = git.getLastCommitInfo(); + Assertions.assertEquals("010e305c9818d7d8a985e91cf60739ac3b66d24e", commit.getSha()); + Assertions.assertEquals(LocalDateTime.of(2022, 2, 12, 20, 19, 51), commit.getTimestamp()); + } } @Test - @SneakyThrows({GitException.class}) - void getLastCommitEmptyRepoTest() { - Git git = new Git(emptyRepoName, tmp); - Assertions.assertThrows(GitException.class, git::getLastCommitInfo); + void getLastCommitEmptyRepoTest() throws IOException, GitException { + try (Git git = new Git(emptyRepoName, tmp)) { + Assertions.assertThrows(GitException.class, git::getLastCommitInfo); + } } @Test - @SneakyThrows({GitException.class}) - void getDiffLowerBoundTest() { - Git git = new Git(historyRepoName, tmp); - Git.Diff diff = git.getDiff("bc74b0bbd2821c4cdb0b1943f6b3afced8d49ca7"); - // Expected diff output: - // M .gitignore - // D app.cpp - // A app.py - // R079 app.java dir/app.java - // R100 app.scala dir/app.scala - // R100 app.c program.c - Assertions.assertEquals(1, diff.getAdded().size()); - Assertions.assertEquals(1, diff.getDeleted().size()); - Assertions.assertEquals(1, diff.getModified().size()); - Assertions.assertEquals(2, diff.getRenamed().size()); - Assertions.assertEquals(1, diff.getEdited().size()); + void getDiffLowerBoundTest() throws IOException, GitException { + try (Git git = new Git(historyRepoName, tmp)) { + Git.Diff diff = git.getDiff("bc74b0bbd2821c4cdb0b1943f6b3afced8d49ca7"); + // Expected diff output: + // M .gitignore + // D app.cpp + // A app.py + // R079 app.java dir/app.java + // R100 app.scala dir/app.scala + // R100 app.c program.c + Assertions.assertEquals(1, diff.getAdded().size()); + Assertions.assertEquals(1, diff.getDeleted().size()); + Assertions.assertEquals(1, diff.getModified().size()); + Assertions.assertEquals(2, diff.getRenamed().size()); + Assertions.assertEquals(1, diff.getEdited().size()); + } } @Test - @SneakyThrows({GitException.class}) - void getDiffTestLowerAndUpperBoundTest() { - Git git = new Git(historyRepoName, tmp); - Git.Diff diff = git.getDiff( - "bc74b0bbd2821c4cdb0b1943f6b3afced8d49ca7", - "5dae826d5335bc633ce4bbae74e6b8394e563c13" - ); - // Expected diff output: - // D app.cpp - // A app.py - // R100 app.c program.c - Assertions.assertEquals(1, diff.getDeleted().size()); - Assertions.assertEquals(1, diff.getAdded().size()); - Assertions.assertEquals(0, diff.getModified().size()); - Assertions.assertEquals(1, diff.getRenamed().size()); - Assertions.assertEquals(0, diff.getEdited().size()); - diff = git.getDiff( - "db7dfcf4f141ffbf34c9acd089087e493029a973", - "225c820cb9ba921127cfc57ee358e1205efd06c9" - ); - // Expected diff output: - // R079 app.java dir/app.java - // R100 app.c program.c - Assertions.assertEquals(0, diff.getDeleted().size()); - Assertions.assertEquals(0, diff.getAdded().size()); - Assertions.assertEquals(0, diff.getModified().size()); - Assertions.assertEquals(1, diff.getRenamed().size()); - Assertions.assertEquals(1, diff.getEdited().size()); + void getDiffTestLowerAndUpperBoundTest() throws IOException, GitException { + try (Git git = new Git(historyRepoName, tmp)) { + Git.Diff diff = git.getDiff( + "bc74b0bbd2821c4cdb0b1943f6b3afced8d49ca7", + "5dae826d5335bc633ce4bbae74e6b8394e563c13" + ); + // Expected diff output: + // D app.cpp + // A app.py + // R100 app.c program.c + Assertions.assertEquals(1, diff.getDeleted().size()); + Assertions.assertEquals(1, diff.getAdded().size()); + Assertions.assertEquals(0, diff.getModified().size()); + Assertions.assertEquals(1, diff.getRenamed().size()); + Assertions.assertEquals(0, diff.getEdited().size()); + diff = git.getDiff( + "db7dfcf4f141ffbf34c9acd089087e493029a973", + "225c820cb9ba921127cfc57ee358e1205efd06c9" + ); + // Expected diff output: + // R079 app.java dir/app.java + // R100 app.c program.c + Assertions.assertEquals(0, diff.getDeleted().size()); + Assertions.assertEquals(0, diff.getAdded().size()); + Assertions.assertEquals(0, diff.getModified().size()); + Assertions.assertEquals(1, diff.getRenamed().size()); + Assertions.assertEquals(1, diff.getEdited().size()); + } } @Test - @SneakyThrows({GitException.class}) - void getDiffLowerBoundFilteredTest() { - Git git = new Git(historyRepoName, tmp); - Git.Diff diff = git.getDiff("bc74b0bbd2821c4cdb0b1943f6b3afced8d49ca7", Set.of(java, python)); - // Expected diff output: - // A app.py - // R079 app.java dir/app.java - Assertions.assertEquals(1, diff.getAdded().size()); - Assertions.assertEquals(0, diff.getDeleted().size()); - Assertions.assertEquals(0, diff.getModified().size()); - Assertions.assertEquals(0, diff.getRenamed().size()); - Assertions.assertEquals(1, diff.getEdited().size()); + void getDiffLowerBoundFilteredTest() throws IOException, GitException { + try (Git git = new Git(historyRepoName, tmp)) { + Git.Diff diff = git.getDiff("bc74b0bbd2821c4cdb0b1943f6b3afced8d49ca7", Set.of(java, python)); + // Expected diff output: + // A app.py + // R079 app.java dir/app.java + Assertions.assertEquals(1, diff.getAdded().size()); + Assertions.assertEquals(0, diff.getDeleted().size()); + Assertions.assertEquals(0, diff.getModified().size()); + Assertions.assertEquals(0, diff.getRenamed().size()); + Assertions.assertEquals(1, diff.getEdited().size()); - diff = git.getDiff("bc74b0bbd2821c4cdb0b1943f6b3afced8d49ca7", Set.of(cpp, python)); - // Expected diff output: - // D app.cpp - // A app.py - // R100 app.c program.c - Assertions.assertEquals(1, diff.getAdded().size()); - Assertions.assertEquals(1, diff.getDeleted().size()); - Assertions.assertEquals(0, diff.getModified().size()); - Assertions.assertEquals(1, diff.getRenamed().size()); - Assertions.assertEquals(0, diff.getEdited().size()); + diff = git.getDiff("bc74b0bbd2821c4cdb0b1943f6b3afced8d49ca7", Set.of(cpp, python)); + // Expected diff output: + // D app.cpp + // A app.py + // R100 app.c program.c + Assertions.assertEquals(1, diff.getAdded().size()); + Assertions.assertEquals(1, diff.getDeleted().size()); + Assertions.assertEquals(0, diff.getModified().size()); + Assertions.assertEquals(1, diff.getRenamed().size()); + Assertions.assertEquals(0, diff.getEdited().size()); + } } @Test - @SneakyThrows({GitException.class}) - void getDiffTestLowerAndUpperBoundFilteredTest() { - Git git = new Git(historyRepoName, tmp); - Git.Diff diff = git.getDiff( - "bc74b0bbd2821c4cdb0b1943f6b3afced8d49ca7", - "5dae826d5335bc633ce4bbae74e6b8394e563c13", - Set.of(java, python) - ); - // Expected diff output: - // A app.py - Assertions.assertEquals(1, diff.getAdded().size()); - Assertions.assertEquals(0, diff.getDeleted().size()); - Assertions.assertEquals(0, diff.getModified().size()); - Assertions.assertEquals(0, diff.getRenamed().size()); - Assertions.assertEquals(0, diff.getEdited().size()); + void getDiffTestLowerAndUpperBoundFilteredTest() throws IOException, GitException { + try (Git git = new Git(historyRepoName, tmp)) { + Git.Diff diff = git.getDiff( + "bc74b0bbd2821c4cdb0b1943f6b3afced8d49ca7", + "5dae826d5335bc633ce4bbae74e6b8394e563c13", + Set.of(java, python) + ); + // Expected diff output: + // A app.py + Assertions.assertEquals(1, diff.getAdded().size()); + Assertions.assertEquals(0, diff.getDeleted().size()); + Assertions.assertEquals(0, diff.getModified().size()); + Assertions.assertEquals(0, diff.getRenamed().size()); + Assertions.assertEquals(0, diff.getEdited().size()); - diff = git.getDiff( - "bc74b0bbd2821c4cdb0b1943f6b3afced8d49ca7", - "5dae826d5335bc633ce4bbae74e6b8394e563c13", - Set.of(cpp, python) - ); - // Expected diff output: - // D app.cpp - // A app.py - // R100 app.c program.c - Assertions.assertEquals(1, diff.getAdded().size()); - Assertions.assertEquals(1, diff.getDeleted().size()); - Assertions.assertEquals(0, diff.getModified().size()); - Assertions.assertEquals(1, diff.getRenamed().size()); - Assertions.assertEquals(0, diff.getEdited().size()); + diff = git.getDiff( + "bc74b0bbd2821c4cdb0b1943f6b3afced8d49ca7", + "5dae826d5335bc633ce4bbae74e6b8394e563c13", + Set.of(cpp, python) + ); + // Expected diff output: + // D app.cpp + // A app.py + // R100 app.c program.c + Assertions.assertEquals(1, diff.getAdded().size()); + Assertions.assertEquals(1, diff.getDeleted().size()); + Assertions.assertEquals(0, diff.getModified().size()); + Assertions.assertEquals(1, diff.getRenamed().size()); + Assertions.assertEquals(0, diff.getEdited().size()); - diff = git.getDiff( - "bc74b0bbd2821c4cdb0b1943f6b3afced8d49ca7", - "5dae826d5335bc633ce4bbae74e6b8394e563c13", - Set.of(java) - ); - // Expected diff output: - // - Assertions.assertEquals(0, diff.getAdded().size()); - Assertions.assertEquals(0, diff.getDeleted().size()); - Assertions.assertEquals(0, diff.getModified().size()); - Assertions.assertEquals(0, diff.getRenamed().size()); - Assertions.assertEquals(0, diff.getEdited().size()); + diff = git.getDiff( + "bc74b0bbd2821c4cdb0b1943f6b3afced8d49ca7", + "5dae826d5335bc633ce4bbae74e6b8394e563c13", + Set.of(java) + ); + // Expected diff output: + // + Assertions.assertEquals(0, diff.getAdded().size()); + Assertions.assertEquals(0, diff.getDeleted().size()); + Assertions.assertEquals(0, diff.getModified().size()); + Assertions.assertEquals(0, diff.getRenamed().size()); + Assertions.assertEquals(0, diff.getEdited().size()); + } } @Test - @SneakyThrows({GitException.class}) - void getDiffSameSHATest() { - Git git = new Git(historyRepoName, tmp); - String lastCommitSha = "bc74b0bbd2821c4cdb0b1943f6b3afced8d49ca7"; - Git.Diff diff = git.getDiff(lastCommitSha, lastCommitSha); - Assertions.assertEquals(0, diff.getAdded().size()); - Assertions.assertEquals(0, diff.getDeleted().size()); - Assertions.assertEquals(0, diff.getModified().size()); - Assertions.assertEquals(0, diff.getRenamed().size()); - Assertions.assertEquals(0, diff.getEdited().size()); + void getDiffSameSHATest() throws IOException, GitException { + try (Git git = new Git(historyRepoName, tmp)) { + String lastCommitSha = "bc74b0bbd2821c4cdb0b1943f6b3afced8d49ca7"; + Git.Diff diff = git.getDiff(lastCommitSha, lastCommitSha); + Assertions.assertEquals(0, diff.getAdded().size()); + Assertions.assertEquals(0, diff.getDeleted().size()); + Assertions.assertEquals(0, diff.getModified().size()); + Assertions.assertEquals(0, diff.getRenamed().size()); + Assertions.assertEquals(0, diff.getEdited().size()); + } } @ParameterizedTest @@ -227,15 +226,15 @@ void getDiffSameSHATest() { "0000000", "0000000000000000000000000000000000000000" }) - @SneakyThrows({GitException.class}) - void gitDiffBadSHATest(String sha) { - Git git = new Git(testRepoName, tmp); - Assertions.assertThrows(GitException.class, () -> git.getDiff(sha)); + void gitDiffBadSHATest(String sha) throws IOException, GitException { + try (Git git = new Git(testRepoName, tmp)) { + Assertions.assertThrows(GitException.class, () -> git.getDiff(sha)); + } } @Test - @SneakyThrows({IOException.class}) - void nonEmptyDirTest() { + @SuppressWarnings("resource") + void nonEmptyDirTest() throws IOException { File newFile = new File(tmp.toFile().getAbsolutePath() + File.separator + "empty_file.txt"); boolean created = newFile.createNewFile(); Assertions.assertTrue(created); @@ -243,12 +242,14 @@ void nonEmptyDirTest() { } @Test + @SuppressWarnings("resource") void nonExistingRepoTest() { String fakeRepoName = "dabico/fake-repo"; Assertions.assertThrows(GitException.class, () -> new Git(fakeRepoName, tmp, false)); } @Test + @SuppressWarnings("resource") void invalidShallowDateTest() { Assertions.assertThrows( GitException.class, () -> new Git(testRepoName, tmp, LocalDateTime.of(2022, 2, 14, 0, 0)) From 1d8a4b106e61358f57e16db390f8a66969aca1fa Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 3 Jul 2023 11:02:37 +0200 Subject: [PATCH 0173/1089] Removing `forceDelete` since it's not needed anymore It was used only in context of `Git`'s cleanup, so it makes sense for it to be localized entirely within that class. --- .../java/usi/si/seart/utils/PathUtils.java | 19 ------------------- .../usi/si/seart/utils/PathUtilsTest.java | 17 ----------------- 2 files changed, 36 deletions(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/utils/PathUtils.java b/dl4se-crawler/src/main/java/usi/si/seart/utils/PathUtils.java index ed730fb9..6123689c 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/utils/PathUtils.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/utils/PathUtils.java @@ -1,6 +1,5 @@ package usi.si.seart.utils; -import lombok.SneakyThrows; import lombok.experimental.UtilityClass; import java.nio.file.FileSystems; @@ -84,22 +83,4 @@ public String getExtension(Path path) { } return ""; } - - /** - * Forcefully delete a file, or a directory and all its contents. - * - * @implNote We suppress throws of {@link java.io.IOException IOException} and {@link InterruptedException}. - * @param path {@code Path} to file or directory that we wish to delete. - * @see ProcessBuilder - * @see Run Shell Commands in Java - */ - @SneakyThrows - public void forceDelete(Path path) { - Objects.requireNonNull(path); - ProcessBuilder builder = new ProcessBuilder(); - builder.command("rm", "-rf", path.getFileName().toString()); - builder.directory(path.getParent().toFile()); - Process process = builder.start(); - process.waitFor(); - } } diff --git a/dl4se-crawler/src/test/java/usi/si/seart/utils/PathUtilsTest.java b/dl4se-crawler/src/test/java/usi/si/seart/utils/PathUtilsTest.java index 268c1f4d..32dc0b2d 100644 --- a/dl4se-crawler/src/test/java/usi/si/seart/utils/PathUtilsTest.java +++ b/dl4se-crawler/src/test/java/usi/si/seart/utils/PathUtilsTest.java @@ -1,29 +1,12 @@ package usi.si.seart.utils; -import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import java.nio.file.Files; import java.nio.file.Path; class PathUtilsTest { - @Test - @SneakyThrows - void forceDeleteTest() { - Path temp = Files.createTempDirectory("test"); - Files.createFile(Path.of(temp.toString(), "file1.txt")); - Files.createFile(Path.of(temp.toString(), "file2.txt")); - Files.createFile(Path.of(temp.toString(), "file3.txt")); - Files.createDirectory(Path.of(temp.toString(), "empty")); - Files.createFile( - Path.of(Files.createDirectory(Path.of(temp.toString(), "nonempty")).toString(), "file4.txt") - ); - PathUtils.forceDelete(temp); - Assertions.assertFalse(temp.toFile().exists()); - } - @Test void isTestFileTest() { Path file1 = Path.of("/java/src/org/json/App.java"); From a44ab4a2fa95358b8507b3731c8f4fd4f1a631f0 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 3 Jul 2023 11:09:25 +0200 Subject: [PATCH 0174/1089] Adding `guava` to `dl4se-crawler` dependency list --- dl4se-crawler/pom.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dl4se-crawler/pom.xml b/dl4se-crawler/pom.xml index ade80d9f..2fd5295b 100644 --- a/dl4se-crawler/pom.xml +++ b/dl4se-crawler/pom.xml @@ -40,6 +40,10 @@ org.codehaus.janino commons-compiler + + com.google.guava + guava + com.google.http-client google-http-client From 9704a42d23a5749c9d2fd5b0a00dc967a2abab4d Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 3 Jul 2023 11:10:22 +0200 Subject: [PATCH 0175/1089] Replacing `getExtension` method with the one from `guava` --- .../src/main/java/usi/si/seart/Crawler.java | 2 +- .../java/usi/si/seart/utils/PathUtils.java | 20 ------------------- .../usi/si/seart/utils/PathUtilsTest.java | 20 ------------------- 3 files changed, 1 insertion(+), 41 deletions(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/Crawler.java b/dl4se-crawler/src/main/java/usi/si/seart/Crawler.java index f69749d0..9f19a4b4 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/Crawler.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/Crawler.java @@ -238,7 +238,7 @@ private static void mineRepoDataForLanguages(GitRepo repo, Path dirPath, Set 0) { - return fileName.substring(extStart); - } - } - return ""; - } } diff --git a/dl4se-crawler/src/test/java/usi/si/seart/utils/PathUtilsTest.java b/dl4se-crawler/src/test/java/usi/si/seart/utils/PathUtilsTest.java index 32dc0b2d..bf0c2eaa 100644 --- a/dl4se-crawler/src/test/java/usi/si/seart/utils/PathUtilsTest.java +++ b/dl4se-crawler/src/test/java/usi/si/seart/utils/PathUtilsTest.java @@ -28,24 +28,4 @@ void isTestFileTest() { Assertions.assertTrue(PathUtils.isTestFile(file8)); Assertions.assertTrue(PathUtils.isTestFile(file9)); } - - @Test - void getExtensionTest() { - Path path1 = Path.of("/java/src/org/json/App.java"); - Path path2 = Path.of("/App.java"); - Path path3 = Path.of("App.java"); - Path path4 = Path.of("/java/src/org.json/App.java"); - Path path5 = Path.of("/.gitignore"); - Path path6 = Path.of("/java/src/org/json"); - Path path7 = Path.of("/java/src.org/json"); - Path path8 = Path.of(""); - Assertions.assertEquals("java", PathUtils.getExtension(path1)); - Assertions.assertEquals("java", PathUtils.getExtension(path2)); - Assertions.assertEquals("java", PathUtils.getExtension(path3)); - Assertions.assertEquals("java", PathUtils.getExtension(path4)); - Assertions.assertEquals("gitignore", PathUtils.getExtension(path5)); - Assertions.assertEquals("", PathUtils.getExtension(path6)); - Assertions.assertEquals("", PathUtils.getExtension(path7)); - Assertions.assertEquals("", PathUtils.getExtension(path8)); - } } \ No newline at end of file From f270e7686694197dbfb3a22b944ba19cca307f4b Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 3 Jul 2023 11:46:08 +0200 Subject: [PATCH 0176/1089] Removing my converter abstract class in favor of the one from `guava` --- .../usi/si/seart/converter/Converter.java | 123 ------------------ .../seart/converter/DateToLDTConverter.java | 5 +- .../converter/GhsToGitRepoConverter.java | 5 +- .../usi/si/seart/converter/ConverterTest.java | 60 --------- 4 files changed, 6 insertions(+), 187 deletions(-) delete mode 100644 dl4se-crawler/src/main/java/usi/si/seart/converter/Converter.java delete mode 100644 dl4se-crawler/src/test/java/usi/si/seart/converter/ConverterTest.java diff --git a/dl4se-crawler/src/main/java/usi/si/seart/converter/Converter.java b/dl4se-crawler/src/main/java/usi/si/seart/converter/Converter.java deleted file mode 100644 index ea64e2b5..00000000 --- a/dl4se-crawler/src/main/java/usi/si/seart/converter/Converter.java +++ /dev/null @@ -1,123 +0,0 @@ -package usi.si.seart.converter; - -import lombok.AccessLevel; -import lombok.NoArgsConstructor; - -import java.util.Iterator; -import java.util.Objects; - -/** - * Based on Google's {@link com.google.common.base.Converter Converter}, albeit with some minor differences. - * A {@code Converter} maps an instance of type {@code A} to an instance of type {@code B}. - * {@code null} handling is done automatically. Each implementing class should follow a singleton pattern, - * reusing a single eagerly initialized instance throughout the application code. - * - * @param The type to convert from - * @param The type to convert to - */ -@NoArgsConstructor(access = AccessLevel.PROTECTED) -public abstract class Converter { - - private Converter reverse; - - protected abstract B forward(A a); - protected abstract A backward(B b); - - B doForward(A a) { - if (a != null) return forward(a); - else return null; - } - - A doBackward(B b) { - if (b != null) return backward(b); - else return null; - } - - /** - * Method used for performing conversions. - * - * @return The input value, converted from type {@code A} to {@code B}, or {@code null} if and only if the input is also {@code null}. - */ - public final B convert(A a) { - return doForward(a); - } - - /** - * Returns an {@code Iterable} that applies {@code convert} to each element of {@code fromIterable}. The - * conversion is done lazily. - * - *

The returned iterable's iterator supports {@code remove()} if the input iterator does. After - * a successful {@code remove()} call, {@code fromIterable} no longer contains the corresponding - * element. - * - * @param aIterable The {@code Iterable} whose instances we wish to convert. - */ - public Iterable convertAll(Iterable aIterable) { - Objects.requireNonNull(aIterable); - return () -> new Iterator<>() - { - private final Iterator aIterator = aIterable.iterator(); - - @Override - public boolean hasNext() { - return aIterator.hasNext(); - } - - @Override - public B next() { - return convert(aIterator.next()); - } - - @Override - public void remove() { - aIterator.remove(); - } - }; - } - - /** - * Method used for obtaining the reversed view of this converter. - * - * @return A {@code Converter} from {@code B} to {@code A}. - */ - public Converter reverse() { - if (this.reverse == null) { - reverse = new ReverseConverter<>(this); - } - - return reverse; - } - - private static final class ReverseConverter extends Converter { - final Converter original; - - ReverseConverter(Converter original) { - this.original = original; - } - - @Override - protected A forward(B b) { - throw new UnsupportedOperationException(); - } - - @Override - protected B backward(A a) { - throw new UnsupportedOperationException(); - } - - @Override - A doForward(B b) { - return original.doBackward(b); - } - - @Override - B doBackward(A a) { - return original.doForward(a); - } - - @Override - public Converter reverse() { - return original; - } - } -} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/converter/DateToLDTConverter.java b/dl4se-crawler/src/main/java/usi/si/seart/converter/DateToLDTConverter.java index ed891f56..f537b9db 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/converter/DateToLDTConverter.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/converter/DateToLDTConverter.java @@ -1,5 +1,6 @@ package usi.si.seart.converter; +import com.google.common.base.Converter; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; @@ -15,12 +16,12 @@ public class DateToLDTConverter extends Converter { public static final Converter instance = new DateToLDTConverter(); @Override - protected LocalDateTime forward(Date date) { + protected LocalDateTime doForward(Date date) { return LocalDateTime.ofInstant(date.toInstant(), ZoneOffset.UTC); } @Override - protected Date backward(LocalDateTime ldt) { + protected Date doBackward(LocalDateTime ldt) { return new Date(ldt.toInstant(ZoneOffset.UTC).toEpochMilli()); } } diff --git a/dl4se-crawler/src/main/java/usi/si/seart/converter/GhsToGitRepoConverter.java b/dl4se-crawler/src/main/java/usi/si/seart/converter/GhsToGitRepoConverter.java index 7f84fb5d..67e90699 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/converter/GhsToGitRepoConverter.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/converter/GhsToGitRepoConverter.java @@ -1,5 +1,6 @@ package usi.si.seart.converter; +import com.google.common.base.Converter; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; @@ -15,7 +16,7 @@ public class GhsToGitRepoConverter extends Converter { private static final Converter instance = new GhsToGitRepoConverter(); @Override - protected GitRepo forward(GhsGitRepo ghsGitRepo) { + protected GitRepo doForward(GhsGitRepo ghsGitRepo) { GitRepo.GitRepoBuilder builder = GitRepo.builder(); builder.name(ghsGitRepo.getName()); @@ -39,7 +40,7 @@ protected GitRepo forward(GhsGitRepo ghsGitRepo) { } @Override - protected GhsGitRepo backward(GitRepo repo) { + protected GhsGitRepo doBackward(GitRepo repo) { throw new UnsupportedOperationException("Backwards conversion is not supported!"); } } diff --git a/dl4se-crawler/src/test/java/usi/si/seart/converter/ConverterTest.java b/dl4se-crawler/src/test/java/usi/si/seart/converter/ConverterTest.java deleted file mode 100644 index 0f47f6ad..00000000 --- a/dl4se-crawler/src/test/java/usi/si/seart/converter/ConverterTest.java +++ /dev/null @@ -1,60 +0,0 @@ -package usi.si.seart.converter; - -import lombok.AccessLevel; -import lombok.experimental.FieldDefaults; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import java.util.List; -import java.util.Spliterator; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; - -@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) -class ConverterTest { - - static Converter intToStringConverter; - static Converter stringToIntConverter; - - private static class IntToStringConverter extends Converter { - @Override - protected String forward(Integer i) { - return i.toString(); - } - - @Override - protected Integer backward(String s) { - return Integer.parseInt(s); - } - } - - @BeforeAll - public static void before() { - intToStringConverter = new IntToStringConverter(); - stringToIntConverter = intToStringConverter.reverse(); - } - - @Test - void singleConversionTest() { - Integer i = 5; - String s = "5"; - Assertions.assertEquals(s, intToStringConverter.convert(i)); - Assertions.assertEquals(i, stringToIntConverter.convert(s)); - } - - @Test - void multipleConversionTest() { - List iList = List.of(1, 2, 3, 4); - List sList = List.of("1", "2", "3", "4"); - - Spliterator spliterator1 = intToStringConverter.convertAll(iList).spliterator(); - Spliterator spliterator2 = stringToIntConverter.convertAll(sList).spliterator(); - - List iConverted = StreamSupport.stream(spliterator1, false).collect(Collectors.toList()); - List sConverted = StreamSupport.stream(spliterator2, false).collect(Collectors.toList()); - - Assertions.assertEquals(sList, iConverted); - Assertions.assertEquals(iList, sConverted); - } -} \ No newline at end of file From 31a2c8d0d85db2b4ca05c0e5fb7686dc38d08bbe Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 3 Jul 2023 11:50:01 +0200 Subject: [PATCH 0177/1089] Added converter for `InputStream` -> `String` --- .../InputStreamToStringConverter.java | 33 +++++++++++++++++++ .../src/main/java/usi/si/seart/git/Git.java | 13 +++++--- .../java/usi/si/seart/utils/StringUtils.java | 18 ---------- .../usi/si/seart/utils/StringUtilsTest.java | 11 ------- 4 files changed, 42 insertions(+), 33 deletions(-) create mode 100644 dl4se-crawler/src/main/java/usi/si/seart/converter/InputStreamToStringConverter.java diff --git a/dl4se-crawler/src/main/java/usi/si/seart/converter/InputStreamToStringConverter.java b/dl4se-crawler/src/main/java/usi/si/seart/converter/InputStreamToStringConverter.java new file mode 100644 index 00000000..21ba712a --- /dev/null +++ b/dl4se-crawler/src/main/java/usi/si/seart/converter/InputStreamToStringConverter.java @@ -0,0 +1,33 @@ +package usi.si.seart.converter; + +import com.google.common.base.Converter; +import com.google.common.io.CharStreams; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.SneakyThrows; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class InputStreamToStringConverter extends Converter { + + @Getter + private static final Converter instance = new InputStreamToStringConverter(); + + @Override + @SneakyThrows(IOException.class) + protected String doForward(InputStream inputStream) { + try (Reader reader = new InputStreamReader(inputStream)) { + return CharStreams.toString(reader); + } + } + + @Override + protected InputStream doBackward(String s) { + throw new UnsupportedOperationException("Backwards conversion is not supported!"); + } +} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java b/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java index 6e73d839..20000f1d 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java @@ -5,10 +5,11 @@ import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; import usi.si.seart.collection.utils.CollectionUtils; +import usi.si.seart.converter.InputStreamToStringConverter; import usi.si.seart.model.Language; -import usi.si.seart.utils.StringUtils; import java.io.IOException; +import java.io.InputStream; import java.nio.file.Path; import java.time.Instant; import java.time.LocalDateTime; @@ -137,7 +138,8 @@ private Commit() throws GitException { Process process = executeGitCommand("log", "-1", "--format=%H%n%at"); checkFailure(process); - String output = StringUtils.fromInputStream(process.getInputStream()); + InputStream inputStream = process.getInputStream(); + String output = InputStreamToStringConverter.getInstance().convert(inputStream); List outputLines = output.lines().collect(Collectors.toList()); this.sha = outputLines.get(0); Instant lastUpdateInstant = Instant.ofEpochSecond(Integer.parseInt(outputLines.get(1))); @@ -270,10 +272,12 @@ private Diff(String startSHA, String endSHA, String... extensions) throws GitExc processOutput(process); } + @SuppressWarnings("DataFlowIssue") private void processOutput(Process process) throws GitException { checkFailure(process); - String output = StringUtils.fromInputStream(process.getInputStream()); + InputStream inputStream = process.getInputStream(); + String output = InputStreamToStringConverter.getInstance().convert(inputStream); output.lines().forEach(line -> { Consumer consumer; char status = line.charAt(0); @@ -295,7 +299,8 @@ private void processOutput(Process process) throws GitException { private void checkFailure(Process process) throws GitException { if (process.exitValue() != 0){ - String errorMessage = StringUtils.fromInputStream(process.getErrorStream()); + InputStream errorStream = process.getErrorStream(); + String errorMessage = InputStreamToStringConverter.getInstance().convert(errorStream); throw new GitException("Operation failed for ["+name+"]:\n" + errorMessage); } } diff --git a/dl4se-crawler/src/main/java/usi/si/seart/utils/StringUtils.java b/dl4se-crawler/src/main/java/usi/si/seart/utils/StringUtils.java index e91b52b3..2b71f6b6 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/utils/StringUtils.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/utils/StringUtils.java @@ -3,8 +3,6 @@ import lombok.SneakyThrows; import lombok.experimental.UtilityClass; -import java.io.IOException; -import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -79,20 +77,4 @@ public String normalizeSpace(String input) { return builder.toString().trim(); } - - /** - * Used to read any arbitrary {@code InputStream} into a {@code String}. - * - * @param inputStream An {@code InputStream}. - * @return The stream contents as a {@code String}. - * @apiNote Intended to be used for processing the STD/ERR output of a {@link java.lang.Process Process}. - * @implNote We suppress throws of {@link IOException}. - * @author dabico - * @see Baeldung Guide - */ - @SneakyThrows({IOException.class}) - public String fromInputStream(InputStream inputStream) { - Objects.requireNonNull(inputStream); - return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8); - } } diff --git a/dl4se-crawler/src/test/java/usi/si/seart/utils/StringUtilsTest.java b/dl4se-crawler/src/test/java/usi/si/seart/utils/StringUtilsTest.java index 6dc153a6..ff71ba00 100644 --- a/dl4se-crawler/src/test/java/usi/si/seart/utils/StringUtilsTest.java +++ b/dl4se-crawler/src/test/java/usi/si/seart/utils/StringUtilsTest.java @@ -5,9 +5,6 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import java.io.ByteArrayInputStream; -import java.io.InputStream; - class StringUtilsTest { @Test @@ -41,12 +38,4 @@ void normalizeSpaceTest(String input) { String baseline = "This is a String"; Assertions.assertEquals(baseline, StringUtils.normalizeSpace(input)); } - - @Test - void fromInputStreamTest() { - String expected = "abcd1234"; - InputStream inputStream = new ByteArrayInputStream(expected.getBytes()); - String actual = StringUtils.fromInputStream(inputStream); - Assertions.assertEquals(expected, actual); - } } \ No newline at end of file From 7aad645d0c6a5ba719b3b4f74c42e78f3671e6b7 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 3 Jul 2023 11:54:41 +0200 Subject: [PATCH 0178/1089] Naming changes for the `converter` classes Dropped the `Converter` suffix, and replaced the `instance` static field with `converter`, which makes usages of the classes more fluid and less verbose. --- dl4se-crawler/src/main/java/usi/si/seart/Crawler.java | 8 ++++---- .../{DateToLDTConverter.java => DateToLocalDateTime.java} | 4 ++-- ...hsToGitRepoConverter.java => GhsGitRepoToGitRepo.java} | 6 +++--- ...eamToStringConverter.java => InputStreamToString.java} | 4 ++-- dl4se-crawler/src/main/java/usi/si/seart/git/Git.java | 8 ++++---- 5 files changed, 15 insertions(+), 15 deletions(-) rename dl4se-crawler/src/main/java/usi/si/seart/converter/{DateToLDTConverter.java => DateToLocalDateTime.java} (77%) rename dl4se-crawler/src/main/java/usi/si/seart/converter/{GhsToGitRepoConverter.java => GhsGitRepoToGitRepo.java} (83%) rename dl4se-crawler/src/main/java/usi/si/seart/converter/{InputStreamToStringConverter.java => InputStreamToString.java} (81%) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/Crawler.java b/dl4se-crawler/src/main/java/usi/si/seart/Crawler.java index 9f19a4b4..f339d6ca 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/Crawler.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/Crawler.java @@ -8,8 +8,8 @@ import lombok.extern.slf4j.Slf4j; import usi.si.seart.collection.Tuple; import usi.si.seart.collection.utils.CollectionUtils; -import usi.si.seart.converter.DateToLDTConverter; -import usi.si.seart.converter.GhsToGitRepoConverter; +import usi.si.seart.converter.DateToLocalDateTime; +import usi.si.seart.converter.GhsGitRepoToGitRepo; import usi.si.seart.git.Git; import usi.si.seart.git.GitException; import usi.si.seart.http.HttpClient; @@ -108,7 +108,7 @@ private static void saveProgress() { private static void checkRepoData(GhsGitRepo item) { String name = item.getName(); - LocalDateTime lastUpdateGhs = DateToLDTConverter.getInstance().convert(item.getLastCommit()); + LocalDateTime lastUpdateGhs = DateToLocalDateTime.getConverter().convert(item.getLastCommit()); lastJob.setCheckpoint(lastUpdateGhs); Set repoLanguageNames = CollectionUtils.intersection(names, item.getRepoLanguages()); @@ -127,7 +127,7 @@ private static void checkRepoData(GhsGitRepo item) { item.update(repo); operation = Crawler::updateRepoData; } else { - repo = GhsToGitRepoConverter.getInstance().convert(item); + repo = GhsGitRepoToGitRepo.getConverter().convert(item); HibernateUtils.save(repo); operation = Crawler::mineRepoData; } diff --git a/dl4se-crawler/src/main/java/usi/si/seart/converter/DateToLDTConverter.java b/dl4se-crawler/src/main/java/usi/si/seart/converter/DateToLocalDateTime.java similarity index 77% rename from dl4se-crawler/src/main/java/usi/si/seart/converter/DateToLDTConverter.java rename to dl4se-crawler/src/main/java/usi/si/seart/converter/DateToLocalDateTime.java index f537b9db..798376cd 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/converter/DateToLDTConverter.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/converter/DateToLocalDateTime.java @@ -10,10 +10,10 @@ import java.util.Date; @NoArgsConstructor(access = AccessLevel.PRIVATE) -public class DateToLDTConverter extends Converter { +public class DateToLocalDateTime extends Converter { @Getter - public static final Converter instance = new DateToLDTConverter(); + private static final Converter converter = new DateToLocalDateTime(); @Override protected LocalDateTime doForward(Date date) { diff --git a/dl4se-crawler/src/main/java/usi/si/seart/converter/GhsToGitRepoConverter.java b/dl4se-crawler/src/main/java/usi/si/seart/converter/GhsGitRepoToGitRepo.java similarity index 83% rename from dl4se-crawler/src/main/java/usi/si/seart/converter/GhsToGitRepoConverter.java rename to dl4se-crawler/src/main/java/usi/si/seart/converter/GhsGitRepoToGitRepo.java index 67e90699..1c1ee74b 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/converter/GhsToGitRepoConverter.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/converter/GhsGitRepoToGitRepo.java @@ -10,10 +10,10 @@ import java.time.LocalDateTime; @NoArgsConstructor(access = AccessLevel.PRIVATE) -public class GhsToGitRepoConverter extends Converter { +public class GhsGitRepoToGitRepo extends Converter { @Getter - private static final Converter instance = new GhsToGitRepoConverter(); + private static final Converter converter = new GhsGitRepoToGitRepo(); @Override protected GitRepo doForward(GhsGitRepo ghsGitRepo) { @@ -31,7 +31,7 @@ protected GitRepo doForward(GhsGitRepo ghsGitRepo) { if (issues != null) builder.issues(issues); Long stars = ghsGitRepo.getStargazers(); if (stars != null) builder.stars(stars); - LocalDateTime lastCommit = DateToLDTConverter.getInstance().convert(ghsGitRepo.getLastCommit()); + LocalDateTime lastCommit = DateToLocalDateTime.getConverter().convert(ghsGitRepo.getLastCommit()); if (lastCommit != null) builder.lastCommit(lastCommit); String lastCommitSHA = ghsGitRepo.getLastCommitSHA(); if (lastCommitSHA != null) builder.lastCommitSHA(lastCommitSHA); diff --git a/dl4se-crawler/src/main/java/usi/si/seart/converter/InputStreamToStringConverter.java b/dl4se-crawler/src/main/java/usi/si/seart/converter/InputStreamToString.java similarity index 81% rename from dl4se-crawler/src/main/java/usi/si/seart/converter/InputStreamToStringConverter.java rename to dl4se-crawler/src/main/java/usi/si/seart/converter/InputStreamToString.java index 21ba712a..9d91b808 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/converter/InputStreamToStringConverter.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/converter/InputStreamToString.java @@ -13,10 +13,10 @@ import java.io.Reader; @NoArgsConstructor(access = AccessLevel.PRIVATE) -public class InputStreamToStringConverter extends Converter { +public class InputStreamToString extends Converter { @Getter - private static final Converter instance = new InputStreamToStringConverter(); + private static final Converter converter = new InputStreamToString(); @Override @SneakyThrows(IOException.class) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java b/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java index 20000f1d..0bc116a5 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java @@ -5,7 +5,7 @@ import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; import usi.si.seart.collection.utils.CollectionUtils; -import usi.si.seart.converter.InputStreamToStringConverter; +import usi.si.seart.converter.InputStreamToString; import usi.si.seart.model.Language; import java.io.IOException; @@ -139,7 +139,7 @@ private Commit() throws GitException { checkFailure(process); InputStream inputStream = process.getInputStream(); - String output = InputStreamToStringConverter.getInstance().convert(inputStream); + String output = InputStreamToString.getConverter().convert(inputStream); List outputLines = output.lines().collect(Collectors.toList()); this.sha = outputLines.get(0); Instant lastUpdateInstant = Instant.ofEpochSecond(Integer.parseInt(outputLines.get(1))); @@ -277,7 +277,7 @@ private void processOutput(Process process) throws GitException { checkFailure(process); InputStream inputStream = process.getInputStream(); - String output = InputStreamToStringConverter.getInstance().convert(inputStream); + String output = InputStreamToString.getConverter().convert(inputStream); output.lines().forEach(line -> { Consumer consumer; char status = line.charAt(0); @@ -300,7 +300,7 @@ private void processOutput(Process process) throws GitException { private void checkFailure(Process process) throws GitException { if (process.exitValue() != 0){ InputStream errorStream = process.getErrorStream(); - String errorMessage = InputStreamToStringConverter.getInstance().convert(errorStream); + String errorMessage = InputStreamToString.getConverter().convert(errorStream); throw new GitException("Operation failed for ["+name+"]:\n" + errorMessage); } } From db9b6dc7a74f44a58f6af65f4f762cb22824529d Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 3 Jul 2023 15:04:57 +0200 Subject: [PATCH 0179/1089] Assigning mined `Function` to a `File` prior to return --- .../src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java | 1 + 1 file changed, 1 insertion(+) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java index 62e5741f..4f100d3d 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java @@ -131,6 +131,7 @@ public void close() { public final Result analyze() { File file = extractFileEntity(); List functions = extractFunctionEntities(file); + file.setFunctions(functions); return new Analyzer.Result(file, functions); } From 7f49c9d89dd8d8000271b7089894bed92d7e6834 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 3 Jul 2023 16:08:40 +0200 Subject: [PATCH 0180/1089] Added utility method for retrieving already mined files by repo --- .../src/main/java/usi/si/seart/utils/HibernateUtils.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/utils/HibernateUtils.java b/dl4se-crawler/src/main/java/usi/si/seart/utils/HibernateUtils.java index 5a410903..f361cc80 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/utils/HibernateUtils.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/utils/HibernateUtils.java @@ -97,6 +97,15 @@ private void saveOrUpdate(Object obj) { } } + public Set getFilesByRepo(Long id) { + try (Session session = factory.openSession()) { + return session.createQuery("SELECT f FROM File f WHERE repo.id = :id", File.class) + .setParameter("id", id) + .stream() + .collect(Collectors.toSet()); + } + } + public void deleteFileByRepoIdAndPath(Long id, Path path) { Session session = factory.openSession(); Transaction transaction = null; From 7bd7ab8fc6ac23c01295f507f76660a23717a098 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 4 Jul 2023 09:12:10 +0200 Subject: [PATCH 0181/1089] New iteration of the `Crawler` class, using the `Analyzer` hierarchy This change marks a departure from individual parsing that yields a file to an optionally successful file parsing. We also make use of the newly introduced Hibernate query to skip duplicates in cancelled first-time mining. Other than that, the logic remains largely unchanged. --- .../src/main/java/usi/si/seart/Crawler.java | 93 ++++---- .../usi/si/seart/parser/AbstractParser.java | 33 --- .../usi/si/seart/parser/FallbackParser.java | 41 ---- .../java/usi/si/seart/parser/JavaParser.java | 219 ------------------ .../main/java/usi/si/seart/parser/Parser.java | 17 -- .../usi/si/seart/parser/ParsingException.java | 8 - .../usi/si/seart/parser/JavaParserTest.java | 157 ------------- 7 files changed, 48 insertions(+), 520 deletions(-) delete mode 100644 dl4se-crawler/src/main/java/usi/si/seart/parser/AbstractParser.java delete mode 100644 dl4se-crawler/src/main/java/usi/si/seart/parser/FallbackParser.java delete mode 100644 dl4se-crawler/src/main/java/usi/si/seart/parser/JavaParser.java delete mode 100644 dl4se-crawler/src/main/java/usi/si/seart/parser/Parser.java delete mode 100644 dl4se-crawler/src/main/java/usi/si/seart/parser/ParsingException.java delete mode 100644 dl4se-crawler/src/test/java/usi/si/seart/parser/JavaParserTest.java diff --git a/dl4se-crawler/src/main/java/usi/si/seart/Crawler.java b/dl4se-crawler/src/main/java/usi/si/seart/Crawler.java index f339d6ca..b260e444 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/Crawler.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/Crawler.java @@ -1,11 +1,15 @@ package usi.si.seart; +import ch.usi.si.seart.treesitter.LibraryLoader; import com.google.api.client.http.GenericUrl; import com.google.api.client.http.HttpResponse; import lombok.AccessLevel; import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; import lombok.extern.slf4j.Slf4j; +import usi.si.seart.analyzer.Analyzer; +import usi.si.seart.analyzer.AnalyzerFactory; +import usi.si.seart.analyzer.LocalClone; import usi.si.seart.collection.Tuple; import usi.si.seart.collection.utils.CollectionUtils; import usi.si.seart.converter.DateToLocalDateTime; @@ -19,11 +23,7 @@ import usi.si.seart.model.Language; import usi.si.seart.model.code.File; import usi.si.seart.model.job.CrawlJob; -import usi.si.seart.parser.FallbackParser; -import usi.si.seart.parser.Parser; -import usi.si.seart.parser.ParsingException; import usi.si.seart.utils.HibernateUtils; -import usi.si.seart.utils.PathUtils; import java.io.IOException; import java.nio.file.Files; @@ -32,6 +32,7 @@ import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; @@ -54,6 +55,8 @@ public class Crawler { static Map extensionToLanguage; static { + LibraryLoader.load(); + lastJob = HibernateUtils.getLastJob(); languages = HibernateUtils.getLanguages(); @@ -142,12 +145,13 @@ private static void updateRepoData(GitRepo repo, Set repoLanguages) { LocalDateTime lastCommit = repo.getLastCommit(); log.info("Updating repository: {} [Last Commit: {}]", name, lastCommit); - Path cloneDir = Files.createTempDirectory(CrawlerProperties.tmpDirPrefix); - try (Git git = new Git(name, cloneDir, lastCommit)) { + Path localDirectory = Files.createTempDirectory(CrawlerProperties.tmpDirPrefix); + LocalClone localClone = new LocalClone(repo, localDirectory); + try (Git git = new Git(name, localDirectory, lastCommit)) { Set notMined = CollectionUtils.difference(repoLanguages, repo.getLanguages()); if (!notMined.isEmpty()) { - mineRepoDataForLanguages(repo, cloneDir, notMined); + mineRepoDataForLanguages(localClone, notMined); repo.setLanguages(repoLanguages); HibernateUtils.save(repo); } @@ -157,18 +161,18 @@ private static void updateRepoData(GitRepo repo, Set repoLanguages) { repo.setLastCommitSHA(latest.getSha()); Git.Diff diff = git.getDiff(repo.getLastCommitSHA(), repo.getLanguages()); - diff.getAdded().forEach(path -> addFile(repo, path, cloneDir)); + diff.getAdded().forEach(path -> addFile(repo, path, localDirectory)); diff.getDeleted().forEach(path -> deleteFile(repo, path)); diff.getModified().forEach(path -> { deleteFile(repo, path); - addFile(repo, path, cloneDir); + addFile(repo, path, localDirectory); }); diff.getRenamed().forEach((key, value) -> renameFile(repo, key, value)); diff.getEdited().forEach((key, value) -> { deleteFile(repo, key); - addFile(repo, value, cloneDir); + addFile(repo, value, localDirectory); }); - diff.getCopied().forEach((key, value) -> addFile(repo, value, cloneDir)); + diff.getCopied().forEach((key, value) -> addFile(repo, value, localDirectory)); HibernateUtils.save(repo); } catch (GitException ex) { @@ -177,14 +181,10 @@ private static void updateRepoData(GitRepo repo, Set repoLanguages) { } private static void addFile(GitRepo repo, Path filePath, Path dirPath) { - Path absolute = dirPath.resolve(filePath); - File file = parseFile(absolute); - if (file != null) { - file.setPath(filePath.toString()); - file.setRepo(repo); - file.getFunctions().forEach(function -> function.setRepo(repo)); - HibernateUtils.save(file); - } + LocalClone localClone = new LocalClone(repo, dirPath); + tryAnalyze(localClone, filePath) + .map(Analyzer.Result::getFile) + .ifPresent(HibernateUtils::save); } private static void deleteFile(GitRepo repo, Path filePath) { @@ -200,12 +200,13 @@ private static void mineRepoData(GitRepo repo, Set repoLanguages) { String name = repo.getName(); LocalDateTime lastUpdateGhs = repo.getLastCommit(); - Path cloneDir = Files.createTempDirectory(CrawlerProperties.tmpDirPrefix); + Path localDirectory = Files.createTempDirectory(CrawlerProperties.tmpDirPrefix); + LocalClone localClone = new LocalClone(repo, localDirectory); log.info("Mining repository: {} [Last Commit: {}]", name, lastUpdateGhs); - try (Git git = new Git(name, cloneDir, true)) { + try (Git git = new Git(name, localDirectory, true)) { Git.Commit latest = git.getLastCommitInfo(); - mineRepoDataForLanguages(repo, cloneDir, repoLanguages); + mineRepoDataForLanguages(localClone, repoLanguages); repo.setLanguages(repoLanguages); repo.setLastCommit(latest.getTimestamp()); @@ -217,39 +218,41 @@ private static void mineRepoData(GitRepo repo, Set repoLanguages) { } } - @SneakyThrows - private static void mineRepoDataForLanguages(GitRepo repo, Path dirPath, Set languages) { + @SneakyThrows(IOException.class) + private static void mineRepoDataForLanguages(LocalClone localClone, Set languages) { + GitRepo repo = localClone.getGitRepo(); + Path localDirectory = localClone.getDiskPath(); String[] extensions = languages.stream() .map(Language::getExtensions) .flatMap(Collection::stream) .toArray(String[]::new); ExtensionBasedFileVisitor visitor = ExtensionBasedFileVisitor.forExtensions(extensions); - Files.walkFileTree(dirPath, visitor); - List paths = visitor.getVisited(); - for (Path path: paths) { - File file = parseFile(path); - if (file != null) { - file.setPath(dirPath.relativize(path).toString()); - file.setRepo(repo); - file.getFunctions().forEach(function -> function.setRepo(repo)); - HibernateUtils.save(file); - } + Files.walkFileTree(localDirectory, visitor); + Set candidates = new HashSet<>(visitor.getVisited()); + Set analyzed = HibernateUtils.getFilesByRepo(repo.getId()).stream() + .map(File::getPath) + .map(Path::of) + .map(localDirectory::resolve) + .collect(Collectors.toSet()); + Set targets = CollectionUtils.difference(candidates, analyzed); + for (Path path: targets) { + tryAnalyze(localClone, path) + .map(Analyzer.Result::getFile) + .ifPresent(HibernateUtils::save); } } - private static File parseFile(Path filePath) { + private static Optional tryAnalyze(LocalClone localClone, Path filePath) { String extension = com.google.common.io.Files.getFileExtension(filePath.toString()); Language language = extensionToLanguage.get(extension); - - Parser parser = Parser.getParser(language); - File file; - try { - file = parser.parse(filePath); - } catch (ParsingException ignored) { - parser = new FallbackParser(language); - file = parser.parse(filePath); + try (Analyzer analyzer = AnalyzerFactory.getAnalyzer(language).apply(localClone, filePath)) { + Analyzer.Result result = analyzer.analyze(); + result.getFile().setLanguage(language); + result.getFunctions().forEach(function -> function.setLanguage(language)); + return Optional.of(result); + } catch (Exception ex) { + log.error("", ex); + return Optional.empty(); } - - return file; } } diff --git a/dl4se-crawler/src/main/java/usi/si/seart/parser/AbstractParser.java b/dl4se-crawler/src/main/java/usi/si/seart/parser/AbstractParser.java deleted file mode 100644 index 993cea2f..00000000 --- a/dl4se-crawler/src/main/java/usi/si/seart/parser/AbstractParser.java +++ /dev/null @@ -1,33 +0,0 @@ -package usi.si.seart.parser; - -import lombok.AccessLevel; -import lombok.experimental.FieldDefaults; -import usi.si.seart.model.Language; -import usi.si.seart.model.code.File; -import usi.si.seart.model.code.Function; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -@FieldDefaults(level = AccessLevel.PROTECTED) -public abstract class AbstractParser implements Parser { - - File.FileBuilder fileBuilder = File.builder(); - List> functionBuilders = new ArrayList<>(); - - Language language; - - protected AbstractParser(Language language) { - this.language = language; - } - - protected File buildFileAndFunctions() { - File file = fileBuilder.build(); - List functions = functionBuilders.stream() - .map(builder -> builder.file(file).isTest(file.getIsTest()).build()) - .collect(Collectors.toList()); - file.setFunctions(functions); - return file; - } -} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/parser/FallbackParser.java b/dl4se-crawler/src/main/java/usi/si/seart/parser/FallbackParser.java deleted file mode 100644 index 39bed750..00000000 --- a/dl4se-crawler/src/main/java/usi/si/seart/parser/FallbackParser.java +++ /dev/null @@ -1,41 +0,0 @@ -package usi.si.seart.parser; - -import lombok.extern.slf4j.Slf4j; -import usi.si.seart.model.Language; -import usi.si.seart.model.code.File; -import usi.si.seart.utils.PathUtils; -import usi.si.seart.utils.StringUtils; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; - -@Slf4j -public class FallbackParser extends AbstractParser { - - public FallbackParser(Language language) { - super(language); - } - - @Override - public File parse(Path path) { - fileBuilder.isTest(PathUtils.isTestFile(path)); - fileBuilder.language(language); - - try { - String fileContents = Files.readString(path); - String normalized = StringUtils.normalizeSpace(fileContents); - - fileBuilder.content(fileContents); - fileBuilder.contentHash(StringUtils.sha256(normalized)); - fileBuilder.lines(fileContents.lines().count()); - fileBuilder.characters(fileContents.chars().count()); - fileBuilder.containsNonAscii(StringUtils.containsNonAscii(fileContents)); - - return buildFileAndFunctions(); - } catch (IOException ex) { - log.error("Could not read file: " + path, ex); - return null; - } - } -} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/parser/JavaParser.java b/dl4se-crawler/src/main/java/usi/si/seart/parser/JavaParser.java deleted file mode 100644 index 051cf383..00000000 --- a/dl4se-crawler/src/main/java/usi/si/seart/parser/JavaParser.java +++ /dev/null @@ -1,219 +0,0 @@ -package usi.si.seart.parser; - -import com.github.javaparser.JavaToken; -import com.github.javaparser.ParseProblemException; -import com.github.javaparser.StaticJavaParser; -import com.github.javaparser.ast.CompilationUnit; -import com.github.javaparser.ast.Node; -import com.github.javaparser.ast.body.CallableDeclaration; -import com.github.javaparser.ast.body.ConstructorDeclaration; -import com.github.javaparser.ast.body.MethodDeclaration; -import com.github.javaparser.ast.comments.Comment; -import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import com.github.javaparser.printer.XmlPrinter; -import lombok.extern.slf4j.Slf4j; -import usi.si.seart.collection.Tuple; -import usi.si.seart.model.Language; -import usi.si.seart.model.code.Boilerplate; -import usi.si.seart.model.code.Code; -import usi.si.seart.model.code.File; -import usi.si.seart.model.code.Function; -import usi.si.seart.utils.PathUtils; -import usi.si.seart.utils.StringUtils; - -import java.io.FileNotFoundException; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Spliterator; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; - -@Slf4j -public class JavaParser extends AbstractParser { - - private static final XmlPrinter astPrinter = new XmlPrinter(true); - - public JavaParser(Language language) { - super(language); - } - - @Override - public File parse(Path path) throws ParsingException { - fileBuilder.isTest(PathUtils.isTestFile(path)); - - try { - CompilationUnit compilationUnit = StaticJavaParser.parse(path.toFile()); - fileBuilder.isParsed(true); - new VoidVisitor().visit(compilationUnit, null); - } catch (ParseProblemException | FileNotFoundException | StackOverflowError thr) { - log.error("Parsing failed for: " + path, thr); - throw new ParsingException(thr.getMessage(), thr.getCause()); - } - - return buildFileAndFunctions(); - } - - private class VoidVisitor extends VoidVisitorAdapter { - - @Override - public void visit(CompilationUnit declaration, Object arg) { - copyToBuilder(declaration, fileBuilder); - - super.visit(declaration, arg); - } - - @Override - public void visit(MethodDeclaration declaration, Object arg) { - visit(declaration); - super.visit(declaration, arg); - } - - @Override - public void visit(ConstructorDeclaration declaration, Object arg) { - visit(declaration); - super.visit(declaration, arg); - } - - private void visit(CallableDeclaration declaration) { - Function.FunctionBuilder functionBuilder = Function.builder(); - - copyToBuilder(declaration, functionBuilder); - - functionBuilder.boilerplateType(getBoilerplateType(declaration)); - - functionBuilders.add(functionBuilder); - } - - private void copyToBuilder(Node node, Code.CodeBuilder builder) { - builder.language(language); - - String contents = node.toString(); - builder.content(contents); - - builder.ast(astPrinter.output(node)); - - builder.characters(contents.chars().count()); - - Tuple tokensCount = countTokens(node); - builder.totalTokens(tokensCount.getLeft()); - builder.codeTokens(tokensCount.getRight()); - - builder.lines(countLines(node)); - - builder.containsNonAscii(StringUtils.containsNonAscii(contents)); - - removeComments(node); - String normalized = StringUtils.normalizeSpace(node.toString()); - builder.contentHash(StringUtils.sha256(normalized)); - builder.astHash(getAstHash(node)); - } - } - - static String getAstHash(Node node) { - StringBuilder builder = new StringBuilder(); - getAstTypeNames(node, builder); - return StringUtils.sha256(builder.toString()); - } - - private static void getAstTypeNames(Node node, StringBuilder builder) { - builder.append(node.getMetaModel().getTypeName()); - List children = node.getChildNodes(); - for (Node child : children) { - getAstTypeNames(child, builder); - } - } - - static Tuple countTokens(Node node) { - if (node instanceof CompilationUnit) { - return rangeLength(node); - } else if (node instanceof CallableDeclaration) { - return countTokens((CallableDeclaration) node); - } else { - throw new UnsupportedOperationException("Token counting is not supported at this granularity level!"); - } - } - - private static Tuple countTokens(CallableDeclaration cd) { - Tuple count = rangeLength(cd); - Optional comment = cd.getComment(); - - if (comment.isPresent()) { - String jdoc = comment.get().toString(); - Long jdocLen = countWordsAndSpaces(jdoc); - count = Tuple.of(count.getLeft() + jdocLen, count.getRight()); - } - - return count; - } - - private static Tuple rangeLength(Node node) { - List tokens = getNodeTokens(node); - Map> partition = tokens.stream() - .collect(Collectors.partitioningBy(token -> token.getCategory().isWhitespaceOrComment())); - - long codeTokens = partition.get(false).size(); - long nonCodeTokens = partition.get(true).stream().mapToLong(token -> { - JavaToken.Category category = token.getCategory(); - if (category.isWhitespace()) { - return 1L; - } else { - return countWordsAndSpaces(token.getText()); - } - }).sum(); - - return Tuple.of(codeTokens + nonCodeTokens, codeTokens); - } - - private static List getNodeTokens(Node node) { - return node.getTokenRange() - .map(range -> { - Spliterator spliterator = range.spliterator(); - return StreamSupport.stream(spliterator, false).collect(Collectors.toList()); - }) - .orElse(new ArrayList<>()); - } - - private static long countWordsAndSpaces(String input) { - if (input.isBlank()) return 0L; - String normalized = StringUtils.normalizeSpace(input); - String[] words = normalized.split("\\s"); - long spaces = words.length - 1L; - return words.length + spaces; - } - - static Long countLines(Node node) { - return node.getRange() - .map(range -> (long)(range.end.line + 1 - range.begin.line)) - .orElse(0L); - } - - static Boilerplate getBoilerplateType(CallableDeclaration node) { - if (node instanceof ConstructorDeclaration) return Boilerplate.CONSTRUCTOR; - String name = node.getNameAsString(); - if (name.startsWith("set")) return Boilerplate.SETTER; - if (name.startsWith("get")) return Boilerplate.GETTER; - switch (name) { - case "equals": - case "compareTo": - return Boilerplate.COMPARISON; - case "clone": return Boilerplate.CLONER; - case "finalize": return Boilerplate.FINALIZER; - case "hashCode": return Boilerplate.HASHER; - case "readObject": - case "readObjectNoData": - return Boilerplate.DESERIALIZER; - case "toString": return Boilerplate.STRING_CONVERSION; - case "writeObject": return Boilerplate.SERIALIZER; - default: return null; - } - } - - static void removeComments(Node node) { - List comments = node.getAllContainedComments(); - node.getComment().ifPresent(comments::add); - comments.forEach(Comment::remove); - } -} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/parser/Parser.java b/dl4se-crawler/src/main/java/usi/si/seart/parser/Parser.java deleted file mode 100644 index 6b34226b..00000000 --- a/dl4se-crawler/src/main/java/usi/si/seart/parser/Parser.java +++ /dev/null @@ -1,17 +0,0 @@ -package usi.si.seart.parser; - -import usi.si.seart.model.Language; -import usi.si.seart.model.code.File; - -import java.nio.file.Path; - -public interface Parser { - File parse(Path path); - - static Parser getParser(Language language) { - switch (language.getName()) { - case "Java": return new JavaParser(language); - default: return new FallbackParser(language); - } - } -} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/parser/ParsingException.java b/dl4se-crawler/src/main/java/usi/si/seart/parser/ParsingException.java deleted file mode 100644 index f255aed4..00000000 --- a/dl4se-crawler/src/main/java/usi/si/seart/parser/ParsingException.java +++ /dev/null @@ -1,8 +0,0 @@ -package usi.si.seart.parser; - -public class ParsingException extends RuntimeException { - - public ParsingException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/dl4se-crawler/src/test/java/usi/si/seart/parser/JavaParserTest.java b/dl4se-crawler/src/test/java/usi/si/seart/parser/JavaParserTest.java deleted file mode 100644 index 336469b0..00000000 --- a/dl4se-crawler/src/test/java/usi/si/seart/parser/JavaParserTest.java +++ /dev/null @@ -1,157 +0,0 @@ -package usi.si.seart.parser; - -import com.github.javaparser.StaticJavaParser; -import com.github.javaparser.ast.Node; -import com.github.javaparser.ast.body.CallableDeclaration; -import com.github.javaparser.ast.body.ConstructorDeclaration; -import com.github.javaparser.ast.body.MethodDeclaration; -import lombok.AccessLevel; -import lombok.experimental.FieldDefaults; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.ArgumentsProvider; -import org.junit.jupiter.params.provider.ArgumentsSource; -import usi.si.seart.collection.Tuple; -import usi.si.seart.model.code.Boilerplate; - -import java.util.stream.Stream; - -class JavaParserTest { - - private static final Node noComment = StaticJavaParser.parseMethodDeclaration( - "public void method(){\nint x = 1;\n}" - ); - private static final Node lineComment = StaticJavaParser.parseMethodDeclaration( - "public void method(){\n// This is a single line comment\n}" - ); - private static final Node blockComment = StaticJavaParser.parseMethodDeclaration( - "public void method(){\n/* This is a\n* multi line comment\n*/\n}" - ); - private static final Node jdocComment = StaticJavaParser.parseMethodDeclaration( - "/** * This is a java documentation comment */\npublic void method(){}" - ); - - private static final class CountTokensArgumentProvider implements ArgumentsProvider { - - @Override - public Stream provideArguments(ExtensionContext context) { - return Stream.of( - Arguments.of(noComment, 19, 12), - Arguments.of(lineComment, 24, 7), - Arguments.of(blockComment, 28, 7), - Arguments.of(jdocComment, 26, 7) - ); - } - } - - @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) - private static final class BoilerplateTypeArgumentProvider implements ArgumentsProvider { - - MethodDeclaration md1 = StaticJavaParser.parseMethodDeclaration("public void method(){}"); - MethodDeclaration md2 = StaticJavaParser.parseMethodDeclaration("public void setX(){}"); - MethodDeclaration md3 = StaticJavaParser.parseMethodDeclaration("public void getX(){}"); - MethodDeclaration md5 = StaticJavaParser.parseMethodDeclaration("public void toString(){}"); - MethodDeclaration md6 = StaticJavaParser.parseMethodDeclaration("public void equals(){}"); - MethodDeclaration md7 = StaticJavaParser.parseMethodDeclaration("public void hashCode(){}"); - ConstructorDeclaration cd = new ConstructorDeclaration(); - - @Override - public Stream provideArguments(ExtensionContext context) { - return Stream.of( - Arguments.of(md1, null), - Arguments.of(md2, Boilerplate.SETTER), - Arguments.of(md3, Boilerplate.GETTER), - Arguments.of(md5, Boilerplate.STRING_CONVERSION), - Arguments.of(md6, Boilerplate.COMPARISON), - Arguments.of(md7, Boilerplate.HASHER), - Arguments.of(cd, Boilerplate.CONSTRUCTOR) - ); - } - } - - @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) - private static final class GetAstHashArgumentProvider implements ArgumentsProvider { - - MethodDeclaration md1 = StaticJavaParser.parseMethodDeclaration("public void method(){ x += 1; }"); - MethodDeclaration md2 = StaticJavaParser.parseMethodDeclaration("public void method(){ a += 5; }"); - MethodDeclaration md3 = StaticJavaParser.parseMethodDeclaration("/** JDoc */ public void method(){ x += 1; }"); - MethodDeclaration md4 = StaticJavaParser.parseMethodDeclaration("public void method(){ a += 5L; }"); - - @Override - public Stream provideArguments(ExtensionContext context) { - return Stream.of( - Arguments.of(md1, true), - Arguments.of(md2, true), - Arguments.of(md3, true), - Arguments.of(md4, false) - ); - } - } - - private static final class CountLinesArgumentProvider implements ArgumentsProvider { - - @Override - public Stream provideArguments(ExtensionContext context) { - return Stream.of( - Arguments.of(noComment, 3), - Arguments.of(lineComment, 3), - Arguments.of(blockComment, 5), - Arguments.of(jdocComment, 1) - ); - } - } - - private static final class RemoveAllCommentsArgumentProvider implements ArgumentsProvider { - - @Override - public Stream provideArguments(ExtensionContext context) { - return Stream.of( - Arguments.of(noComment.clone(), 0), - Arguments.of(lineComment.clone(), 1), - Arguments.of(blockComment.clone(), 1), - Arguments.of(jdocComment.clone(), 1) - ); - } - } - - @ParameterizedTest - @ArgumentsSource(CountTokensArgumentProvider.class) - void countTokensTest(Node node, long expectedLeft, long expectedRight) { - Tuple tokens = JavaParser.countTokens(node); - Assertions.assertEquals(expectedLeft, tokens.getLeft()); - Assertions.assertEquals(expectedRight, tokens.getRight()); - } - - @ParameterizedTest - @ArgumentsSource(BoilerplateTypeArgumentProvider.class) - void boilerplateTypeTest(CallableDeclaration declaration, Boilerplate expected) { - Assertions.assertEquals(expected, JavaParser.getBoilerplateType(declaration)); - } - - @ParameterizedTest - @ArgumentsSource(GetAstHashArgumentProvider.class) - void getAstHashTest(MethodDeclaration declaration, boolean expected) { - String baseline = "6abae81a5835bb1bbf4a8b2ce105271327e397ec6d453227cf8fd6043a1f2621"; // manually calculated - String result = JavaParser.getAstHash(declaration); - Assertions.assertEquals(expected, baseline.equals(result)); - } - - @ParameterizedTest - @ArgumentsSource(CountLinesArgumentProvider.class) - void countLinesTest(Node node, long expected) { - long actual = JavaParser.countLines(node); - Assertions.assertEquals(expected, actual); - } - - @ParameterizedTest - @ArgumentsSource(RemoveAllCommentsArgumentProvider.class) - void removeAllCommentsTest(Node node, int expected) { - Node original = node.clone(); - JavaParser.removeComments(node); - int actual = (original.getAllContainedComments().size() + original.getComment().map(comment -> 1).orElse(0)) - - (node.getAllContainedComments().size() + node.getComment().map(comment -> 1).orElse(0)); - Assertions.assertEquals(expected, actual); - } -} \ No newline at end of file From ff4970caf49a74af0c4504390bb8513d6d1c100e Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 4 Jul 2023 09:12:32 +0200 Subject: [PATCH 0182/1089] Removing unused `util` classes --- .../java/usi/si/seart/utils/PathUtils.java | 66 --------------- .../java/usi/si/seart/utils/StringUtils.java | 80 ------------------- .../usi/si/seart/utils/PathUtilsTest.java | 31 ------- .../usi/si/seart/utils/StringUtilsTest.java | 41 ---------- 4 files changed, 218 deletions(-) delete mode 100644 dl4se-crawler/src/main/java/usi/si/seart/utils/PathUtils.java delete mode 100644 dl4se-crawler/src/main/java/usi/si/seart/utils/StringUtils.java delete mode 100644 dl4se-crawler/src/test/java/usi/si/seart/utils/PathUtilsTest.java delete mode 100644 dl4se-crawler/src/test/java/usi/si/seart/utils/StringUtilsTest.java diff --git a/dl4se-crawler/src/main/java/usi/si/seart/utils/PathUtils.java b/dl4se-crawler/src/main/java/usi/si/seart/utils/PathUtils.java deleted file mode 100644 index e11b4372..00000000 --- a/dl4se-crawler/src/main/java/usi/si/seart/utils/PathUtils.java +++ /dev/null @@ -1,66 +0,0 @@ -package usi.si.seart.utils; - -import lombok.experimental.UtilityClass; - -import java.nio.file.FileSystems; -import java.nio.file.Path; -import java.nio.file.PathMatcher; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -@UtilityClass -public class PathUtils { - - private final PathMatcher testPathMatcher; - static { - String globPattern = Stream.of( - "**/test/**", - "**/tests/**", - "**/Test*.java", - "**/*Test.java", - "**/*Tests.java", - "**/*TestCase.java", - "**/IT*.java", - "**/*IT.java", - "**/*ITCase.java" - ).collect(Collectors.joining(",", "glob:{", "}")); - testPathMatcher = FileSystems.getDefault().getPathMatcher(globPattern); - } - - - /** - * Determine if a file is indeed a test file. We define test files as files whose: - * - *
    - *
  • - * Path contains the following directories: - *
      - *
    • {@code test}
    • - *
    • {@code tests}
    • - *
    - *
  • - *
  • - * Name matches the following patterns: - *
      - *
    • {@code Test*.java}
    • - *
    • {@code *Test.java}
    • - *
    • {@code *Tests.java}
    • - *
    • {@code *TestCase.java}
    • - *
    • {@code IT*.java}
    • - *
    • {@code *IT.java}
    • - *
    • {@code *ITCase.java}
    • - *
    - *
  • - *
- * - * @implNote We keep the matching restrictive to minimise the amount of false positives. - * For instance, using a more general pattern like {@code **test**} would match non-conforming cases such as - * {@code /src/latest/App.java}. - * @param path {@code Path} that we are testing against. - * @return Whether the path in question matches the definition of a test file. - */ - //TODO 08.03.22: Switch pattern matching based on extension - public boolean isTestFile(Path path) { - return testPathMatcher.matches(path); - } -} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/utils/StringUtils.java b/dl4se-crawler/src/main/java/usi/si/seart/utils/StringUtils.java deleted file mode 100644 index 2b71f6b6..00000000 --- a/dl4se-crawler/src/main/java/usi/si/seart/utils/StringUtils.java +++ /dev/null @@ -1,80 +0,0 @@ -package usi.si.seart.utils; - -import lombok.SneakyThrows; -import lombok.experimental.UtilityClass; - -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Objects; - -@UtilityClass -public class StringUtils { - - /** - * Simple implementation of the SHA-256 algorithm. - * - * @param input An input {@code String} of arbitrary length. - * @return A 64-character {@code String} representing the hashing algorithm result. - * @implNote We suppress throws of {@link NoSuchAlgorithmException}. - * @see Baeldung Guide - * @author dabico - */ - @SneakyThrows({NoSuchAlgorithmException.class}) - public String sha256(String input) { - Objects.requireNonNull(input); - MessageDigest md = MessageDigest.getInstance("SHA-256"); - byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8)); - StringBuilder hexString = new StringBuilder(2 * hash.length); - for (byte b : hash) { - String hex = Integer.toHexString(0xff & b); - if (hex.length() == 1) hexString.append('0'); - hexString.append(hex); - } - return hexString.toString(); - } - - /** - * Used to check if an input {@code String} contains any non-ASCII characters. - * - * @param input The input {@code String} to check against. - * @return {@code true} if it contains any non-ASCII characters, {@code false} otherwise. - * @author dabico - */ - public boolean containsNonAscii(String input) { - Objects.requireNonNull(input); - return input.chars().anyMatch(ch -> ch > 127); - } - - /** - * Used to normalize white spaces in a {@code String}. For a passed input we replace all consecutive occurrences of - * whitespace characters as defined by {@link Character#isWhitespace(char) Character.isWhiteSpace} with a single - * space character. Before returning, the resulting {@code String} is also stripped of any leading or trailing - * whitespaces. - * - * @param input An input {@code String}. - * @return The space-normalized input. - * @author dabico - */ - public String normalizeSpace(String input) { - Objects.requireNonNull(input); - if (input.isBlank()) return ""; - - StringBuilder builder = new StringBuilder(input.length()); - boolean lastWasWhitespace = false; - for (int i = 0; i < input.length(); i++) { - char current = input.charAt(i); - if (Character.isWhitespace(current)) { - if (!lastWasWhitespace) { - lastWasWhitespace = true; - builder.append(' '); - } - } else { - lastWasWhitespace = false; - builder.append(current); - } - } - - return builder.toString().trim(); - } -} diff --git a/dl4se-crawler/src/test/java/usi/si/seart/utils/PathUtilsTest.java b/dl4se-crawler/src/test/java/usi/si/seart/utils/PathUtilsTest.java deleted file mode 100644 index bf0c2eaa..00000000 --- a/dl4se-crawler/src/test/java/usi/si/seart/utils/PathUtilsTest.java +++ /dev/null @@ -1,31 +0,0 @@ -package usi.si.seart.utils; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import java.nio.file.Path; - -class PathUtilsTest { - - @Test - void isTestFileTest() { - Path file1 = Path.of("/java/src/org/json/App.java"); - Path file2 = Path.of("/java/src/org/json/TestApp.java"); - Path file3 = Path.of("/java/src/org/json/AppTest.java"); - Path file4 = Path.of("/java/src/org/json/AppTests.java"); - Path file5 = Path.of("/java/src/org/json/AppTestCase.java"); - Path file6 = Path.of("/java/test/org/json/App.java"); - Path file7 = Path.of("/java/tests/org/json/App.java"); - Path file8 = Path.of("/test/org/json/App.java"); - Path file9 = Path.of("/AppTest.java"); - Assertions.assertFalse(PathUtils.isTestFile(file1)); - Assertions.assertTrue(PathUtils.isTestFile(file2)); - Assertions.assertTrue(PathUtils.isTestFile(file3)); - Assertions.assertTrue(PathUtils.isTestFile(file4)); - Assertions.assertTrue(PathUtils.isTestFile(file5)); - Assertions.assertTrue(PathUtils.isTestFile(file6)); - Assertions.assertTrue(PathUtils.isTestFile(file7)); - Assertions.assertTrue(PathUtils.isTestFile(file8)); - Assertions.assertTrue(PathUtils.isTestFile(file9)); - } -} \ No newline at end of file diff --git a/dl4se-crawler/src/test/java/usi/si/seart/utils/StringUtilsTest.java b/dl4se-crawler/src/test/java/usi/si/seart/utils/StringUtilsTest.java deleted file mode 100644 index ff71ba00..00000000 --- a/dl4se-crawler/src/test/java/usi/si/seart/utils/StringUtilsTest.java +++ /dev/null @@ -1,41 +0,0 @@ -package usi.si.seart.utils; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -class StringUtilsTest { - - @Test - void sha256Test() { - // Expected generated from: https://passwordsgenerator.net/sha256-hash-generator/ - Assertions.assertEquals( - "7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069", - StringUtils.sha256("Hello World!") - ); - } - - @ParameterizedTest - @ValueSource(strings = { - "Ово је проба", - "Ovo je проба", - "Ово је proba" - }) - void containsNonAsciiTest(String input) { - Assertions.assertTrue(StringUtils.containsNonAscii(input)); - } - - @ParameterizedTest - @ValueSource(strings = { - "This is a String", - " This is a String ", - "This is a String", - "This\nis\ta\rString", - "\n\r This\n\n\nis a\r\r\rString \r\n" - }) - void normalizeSpaceTest(String input) { - String baseline = "This is a String"; - Assertions.assertEquals(baseline, StringUtils.normalizeSpace(input)); - } -} \ No newline at end of file From 9373ab0333e85a810909811268f55362103b6a58 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 4 Jul 2023 09:45:29 +0200 Subject: [PATCH 0183/1089] Added application-specific `toString` method to the `Git.Diff` class --- .../src/main/java/usi/si/seart/git/Git.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java b/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java index 0bc116a5..a98e4d45 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java @@ -295,6 +295,22 @@ private void processOutput(Process process) throws GitException { consumer.accept(line); }); } + + /** + * @return A simplified output of the calculated diff. + * The percentages for copied and edited files are not preserved. + */ + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + added.forEach(path -> builder.append("A\t").append(path).append('\n')); + deleted.forEach(path -> builder.append("D\t").append(path).append('\n')); + modified.forEach(path -> builder.append("M\t").append(path).append('\n')); + renamed.forEach((p1, p2) -> builder.append("R\t").append(p1).append('\t').append(p2).append('\n')); + copied.forEach((p1, p2) -> builder.append("C\t").append(p1).append('\t').append(p2).append('\n')); + edited.forEach((p1, p2) -> builder.append("E\t").append(p1).append('\t').append(p2).append('\n')); + return builder.toString(); + } } private void checkFailure(Process process) throws GitException { From 8bda4352603e7c560f565802ea3b3be2f78d8666 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 4 Jul 2023 09:45:51 +0200 Subject: [PATCH 0184/1089] Removed suppression --- dl4se-crawler/src/main/java/usi/si/seart/git/Git.java | 1 - 1 file changed, 1 deletion(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java b/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java index a98e4d45..116e9f6d 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java @@ -272,7 +272,6 @@ private Diff(String startSHA, String endSHA, String... extensions) throws GitExc processOutput(process); } - @SuppressWarnings("DataFlowIssue") private void processOutput(Process process) throws GitException { checkFailure(process); From 3015a88c13f84909ebf694c627a45fd8b35416a5 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 4 Jul 2023 10:45:38 +0200 Subject: [PATCH 0185/1089] Updated `logback` configuration --- dl4se-crawler/src/main/resources/logback.xml | 25 +++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/dl4se-crawler/src/main/resources/logback.xml b/dl4se-crawler/src/main/resources/logback.xml index 99fb72b4..ee72e983 100644 --- a/dl4se-crawler/src/main/resources/logback.xml +++ b/dl4se-crawler/src/main/resources/logback.xml @@ -1,6 +1,13 @@ - - + + + + + + + + + System.out @@ -10,7 +17,7 @@ DENY - %d{yyyy-MM-dd HH:mm:ss.SSS} | %-5level | %logger{35} | %msg%n + ${LOG_CONSOLE_PATTERN} @@ -27,18 +34,18 @@ ACCEPT - %d{yyyy-MM-dd HH:mm:ss.SSS} | %-5level | %logger{35} | %file:%line | %msg%n + ${LOG_CONSOLE_PATTERN} - ${LOG_DIR_NAME}/${LOG_FILE_NAME}.log + ${LOG_FILE_PATH} true true - ${LOG_DIR_NAME}/${LOG_FILE_NAME}_%d{yyyy-MM-dd}_%i.log.gz - 100MB - 180 + ${LOG_FILE_ARCHIVE} + ${LOG_FILE_SIZE} + ${LOG_FILE_MAX_HISTORY} DEBUG @@ -51,7 +58,7 @@ DENY - %d{yyyy-MM-dd HH:mm:ss.SSS} | %-5level | %logger{35} | %file:%line | %msg%n + ${LOG_FILE_PATTERN} From b380c0c41ec5b66d352e34232b5504e98d7b4f96 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 4 Jul 2023 11:26:23 +0200 Subject: [PATCH 0186/1089] Adding some additional logging statements to the `Crawler` --- dl4se-crawler/src/main/java/usi/si/seart/Crawler.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/Crawler.java b/dl4se-crawler/src/main/java/usi/si/seart/Crawler.java index b260e444..bf9d40cf 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/Crawler.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/Crawler.java @@ -3,6 +3,7 @@ import ch.usi.si.seart.treesitter.LibraryLoader; import com.google.api.client.http.GenericUrl; import com.google.api.client.http.HttpResponse; +import com.google.common.base.Strings; import lombok.AccessLevel; import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; @@ -161,6 +162,8 @@ private static void updateRepoData(GitRepo repo, Set repoLanguages) { repo.setLastCommitSHA(latest.getSha()); Git.Diff diff = git.getDiff(repo.getLastCommitSHA(), repo.getLanguages()); + if (!Strings.isNullOrEmpty(diff.toString())) + log.debug("Diff since last update:\n{}", diff); diff.getAdded().forEach(path -> addFile(repo, path, localDirectory)); diff.getDeleted().forEach(path -> deleteFile(repo, path)); diff.getModified().forEach(path -> { @@ -243,6 +246,7 @@ private static void mineRepoDataForLanguages(LocalClone localClone, Set tryAnalyze(LocalClone localClone, Path filePath) { + log.trace("Analyzing file: {}", localClone.relativePathOf(filePath)); String extension = com.google.common.io.Files.getFileExtension(filePath.toString()); Language language = extensionToLanguage.get(extension); try (Analyzer analyzer = AnalyzerFactory.getAnalyzer(language).apply(localClone, filePath)) { From 2e4b4f1461f7aa90f33e694269ba6b7c8d319e5f Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 4 Jul 2023 11:28:08 +0200 Subject: [PATCH 0187/1089] Be Sneaky when you throw, but also be specific so people aren't confused --- dl4se-crawler/src/main/java/usi/si/seart/http/HttpClient.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/http/HttpClient.java b/dl4se-crawler/src/main/java/usi/si/seart/http/HttpClient.java index 0f943804..1d0c2ad5 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/http/HttpClient.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/http/HttpClient.java @@ -67,13 +67,13 @@ public void initialize(HttpRequest request) { private static final HttpRequestFactory requestFactory = transport.createRequestFactory(requestInitializer); private static final Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss").create(); - @SneakyThrows + @SneakyThrows(IOException.class) public HttpResponse getRequest(GenericUrl url) { HttpRequest request = requestFactory.buildGetRequest(url); return request.execute(); } - @SneakyThrows + @SneakyThrows(IOException.class) public List getSearchResults(HttpResponse response) { String responseString = response.parseAsString(); JsonObject searchResult = gson.fromJson(responseString, JsonObject.class); From 5688e4174445f53ed2585f26163dcd50a5130d19 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 4 Jul 2023 14:13:58 +0200 Subject: [PATCH 0188/1089] Replacing direct `javax` dependencies with `jakarta` counterparts --- dl4se-model/pom.xml | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/dl4se-model/pom.xml b/dl4se-model/pom.xml index e11340a7..ff1dece3 100644 --- a/dl4se-model/pom.xml +++ b/dl4se-model/pom.xml @@ -26,21 +26,16 @@ jackson-annotations - javax.el - javax.el-api - 3.0.0 - test + jakarta.persistence + jakarta.persistence-api - org.glassfish - javax.el - 3.0.0 - test + jakarta.annotation + jakarta.annotation-api - javax.persistence - javax.persistence-api - 2.2 + jakarta.validation + jakarta.validation-api org.hibernate From 26c315b4476880ab5c283f76489dd553029abd93 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 4 Jul 2023 14:14:32 +0200 Subject: [PATCH 0189/1089] Allowing `hibernate` to inherit information from parent pom --- dl4se-model/pom.xml | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/dl4se-model/pom.xml b/dl4se-model/pom.xml index ff1dece3..2655ce6f 100644 --- a/dl4se-model/pom.xml +++ b/dl4se-model/pom.xml @@ -40,46 +40,14 @@ org.hibernate hibernate-core - 5.5.7.Final - - - org.slf4j - slf4j-api - - - - - org.hibernate - hibernate-annotations - 3.5.6-Final - - - org.slf4j - slf4j-api - - org.hibernate.validator hibernate-validator - 6.2.2.Final - - - org.slf4j - slf4j-api - - org.hibernate hibernate-jpamodelgen - 5.6.5.Final - - - org.slf4j - slf4j-api - - com.vladmihalcea From 152252e5b1c596a0867169c8b0775b6d83c03070 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 4 Jul 2023 14:15:10 +0200 Subject: [PATCH 0190/1089] Replacing `hibernate-types-55` with `hypersistence-utils-hibernate-55` --- dl4se-model/pom.xml | 6 +++--- dl4se-model/src/main/java/usi/si/seart/model/Language.java | 2 +- .../usi/si/seart/model/task/processing/CodeProcessing.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dl4se-model/pom.xml b/dl4se-model/pom.xml index 2655ce6f..19e966c7 100644 --- a/dl4se-model/pom.xml +++ b/dl4se-model/pom.xml @@ -50,9 +50,9 @@ hibernate-jpamodelgen - com.vladmihalcea - hibernate-types-55 - 2.19.2 + io.hypersistence + hypersistence-utils-hibernate-55 + 3.5.0 diff --git a/dl4se-model/src/main/java/usi/si/seart/model/Language.java b/dl4se-model/src/main/java/usi/si/seart/model/Language.java index 8c2bd35e..decf510c 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/Language.java +++ b/dl4se-model/src/main/java/usi/si/seart/model/Language.java @@ -1,7 +1,7 @@ package usi.si.seart.model; import com.fasterxml.jackson.annotation.JsonIgnore; -import com.vladmihalcea.hibernate.type.array.ListArrayType; +import io.hypersistence.utils.hibernate.type.array.ListArrayType; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; diff --git a/dl4se-model/src/main/java/usi/si/seart/model/task/processing/CodeProcessing.java b/dl4se-model/src/main/java/usi/si/seart/model/task/processing/CodeProcessing.java index 96a842a9..b7a4879c 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/task/processing/CodeProcessing.java +++ b/dl4se-model/src/main/java/usi/si/seart/model/task/processing/CodeProcessing.java @@ -1,7 +1,7 @@ package usi.si.seart.model.task.processing; import com.fasterxml.jackson.annotation.JsonProperty; -import com.vladmihalcea.hibernate.type.array.ListArrayType; +import io.hypersistence.utils.hibernate.type.array.ListArrayType; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; From 39614d8b7915b4685cadd00a1278cec0e638467b Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 4 Jul 2023 14:15:44 +0200 Subject: [PATCH 0191/1089] Adding optional dependencies for `hypersistence-utils` in `dl4se-model` --- dl4se-model/pom.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dl4se-model/pom.xml b/dl4se-model/pom.xml index 19e966c7..7f26ec0e 100644 --- a/dl4se-model/pom.xml +++ b/dl4se-model/pom.xml @@ -17,6 +17,10 @@ + + com.google.guava + guava + com.fasterxml.jackson.core jackson-databind @@ -25,6 +29,10 @@ com.fasterxml.jackson.core jackson-annotations + + com.fasterxml.jackson.module + jackson-module-jaxb-annotations + jakarta.persistence jakarta.persistence-api From 43156c62f91e216fc6de0c687febacd25c5907cf Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 4 Jul 2023 14:30:38 +0200 Subject: [PATCH 0192/1089] Removing `javaparser` dependency, which is no longer used in the crawler --- dl4se-crawler/pom.xml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/dl4se-crawler/pom.xml b/dl4se-crawler/pom.xml index 2fd5295b..5d1c85f5 100644 --- a/dl4se-crawler/pom.xml +++ b/dl4se-crawler/pom.xml @@ -53,11 +53,6 @@ com.google.code.gson gson - - com.github.javaparser - javaparser-core - ${javaparser.version} - From 5ea60e957a7f324a76e1d9c30a0fdd739889c4a4 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 4 Jul 2023 14:34:04 +0200 Subject: [PATCH 0193/1089] Ignore my autism --- dl4se-crawler/pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dl4se-crawler/pom.xml b/dl4se-crawler/pom.xml index 5d1c85f5..625d4223 100644 --- a/dl4se-crawler/pom.xml +++ b/dl4se-crawler/pom.xml @@ -40,6 +40,10 @@ org.codehaus.janino commons-compiler + + com.google.code.gson + gson + com.google.guava guava @@ -49,10 +53,6 @@ google-http-client 1.42.2 - - com.google.code.gson - gson - From 6197563fb9a5aa90eb7bb7e03e3bfb597311730b Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 4 Jul 2023 14:46:24 +0200 Subject: [PATCH 0194/1089] Replacing `application.properties` with `properties.txt` --- dl4se-crawler/src/main/java/usi/si/seart/CrawlerProperties.java | 2 +- .../main/resources/{application.properties => properties.txt} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename dl4se-crawler/src/main/resources/{application.properties => properties.txt} (59%) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/CrawlerProperties.java b/dl4se-crawler/src/main/java/usi/si/seart/CrawlerProperties.java index 60ebac3e..0879a223 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/CrawlerProperties.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/CrawlerProperties.java @@ -13,7 +13,7 @@ public class CrawlerProperties { public static final String ghsSearchUrl; static { - PropertiesReader propertiesReader = new PropertiesReader("application.properties"); + PropertiesReader propertiesReader = new PropertiesReader("properties.txt"); tmpDirPrefix = propertiesReader.getProperty("app.general.tmpDirPrefix"); String dateString = propertiesReader.getProperty("app.crawl.startDate"); startDate = LocalDate.parse(dateString); diff --git a/dl4se-crawler/src/main/resources/application.properties b/dl4se-crawler/src/main/resources/properties.txt similarity index 59% rename from dl4se-crawler/src/main/resources/application.properties rename to dl4se-crawler/src/main/resources/properties.txt index c732554d..6a461ce4 100644 --- a/dl4se-crawler/src/main/resources/application.properties +++ b/dl4se-crawler/src/main/resources/properties.txt @@ -1,3 +1,3 @@ app.general.tmpDirPrefix=dl4se app.crawl.startDate=2008-01-01 -app.crawl.ghs.searchUrl=${CODE_SEARCH_URL} \ No newline at end of file +app.crawl.ghs.searchUrl=${CODE_SEARCH_URL} From 6dc77d6f746a708ecd3158ca0b61691f5179fc3c Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 4 Jul 2023 16:35:18 +0200 Subject: [PATCH 0195/1089] Removing `CollectionUtils` in favor of using `guava` --- .../src/main/java/usi/si/seart/Crawler.java | 14 ++- .../collection/utils/CollectionUtils.java | 93 ------------------- .../src/main/java/usi/si/seart/git/Git.java | 5 +- .../collection/utils/CollectionUtilsTest.java | 52 ----------- 4 files changed, 12 insertions(+), 152 deletions(-) delete mode 100644 dl4se-crawler/src/main/java/usi/si/seart/collection/utils/CollectionUtils.java delete mode 100644 dl4se-crawler/src/test/java/usi/si/seart/collection/utils/CollectionUtilsTest.java diff --git a/dl4se-crawler/src/main/java/usi/si/seart/Crawler.java b/dl4se-crawler/src/main/java/usi/si/seart/Crawler.java index bf9d40cf..8dba114b 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/Crawler.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/Crawler.java @@ -4,6 +4,7 @@ import com.google.api.client.http.GenericUrl; import com.google.api.client.http.HttpResponse; import com.google.common.base.Strings; +import com.google.common.collect.Sets; import lombok.AccessLevel; import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; @@ -12,7 +13,6 @@ import usi.si.seart.analyzer.AnalyzerFactory; import usi.si.seart.analyzer.LocalClone; import usi.si.seart.collection.Tuple; -import usi.si.seart.collection.utils.CollectionUtils; import usi.si.seart.converter.DateToLocalDateTime; import usi.si.seart.converter.GhsGitRepoToGitRepo; import usi.si.seart.git.Git; @@ -36,6 +36,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.BiConsumer; @@ -115,8 +116,11 @@ private static void checkRepoData(GhsGitRepo item) { LocalDateTime lastUpdateGhs = DateToLocalDateTime.getConverter().convert(item.getLastCommit()); lastJob.setCheckpoint(lastUpdateGhs); - Set repoLanguageNames = CollectionUtils.intersection(names, item.getRepoLanguages()); - Set repoLanguages = CollectionUtils.getAllValuesFrom(nameToLanguage, repoLanguageNames); + Set repoLanguageNames = Sets.intersection(names, item.getRepoLanguages()); + Set repoLanguages = repoLanguageNames.stream() + .map(nameToLanguage::get) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); if (repoLanguages.isEmpty()) { log.debug("Skipping: {}. No files of interest found!", name); @@ -150,7 +154,7 @@ private static void updateRepoData(GitRepo repo, Set repoLanguages) { LocalClone localClone = new LocalClone(repo, localDirectory); try (Git git = new Git(name, localDirectory, lastCommit)) { - Set notMined = CollectionUtils.difference(repoLanguages, repo.getLanguages()); + Set notMined = Sets.difference(repoLanguages, repo.getLanguages()); if (!notMined.isEmpty()) { mineRepoDataForLanguages(localClone, notMined); repo.setLanguages(repoLanguages); @@ -237,7 +241,7 @@ private static void mineRepoDataForLanguages(LocalClone localClone, Set targets = CollectionUtils.difference(candidates, analyzed); + Set targets = Sets.difference(candidates, analyzed); for (Path path: targets) { tryAnalyze(localClone, path) .map(Analyzer.Result::getFile) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/collection/utils/CollectionUtils.java b/dl4se-crawler/src/main/java/usi/si/seart/collection/utils/CollectionUtils.java deleted file mode 100644 index 533444f7..00000000 --- a/dl4se-crawler/src/main/java/usi/si/seart/collection/utils/CollectionUtils.java +++ /dev/null @@ -1,93 +0,0 @@ -package usi.si.seart.collection.utils; - -import lombok.experimental.UtilityClass; - -import java.lang.reflect.Array; -import java.util.Collection; -import java.util.HashSet; -import java.util.Map; -import java.util.Objects; -import java.util.Set; - -@UtilityClass -public class CollectionUtils { - - /** - * Helper method used to merge two arrays into one. The resulting array contains elements from the first array, - * followed by the elements from the second array, preserving their original order of appearance. Does not modify - * the contents of the arrays passed as arguments. - * - * @param array1 The first {@link Array}. - * @param array2 The second {@link Array}. - * @param The type of elements in both arrays. - * @return The merged array. - */ - @SuppressWarnings("unchecked") - public T[] merge(T[] array1, T[] array2) { - Objects.requireNonNull(array1); - Objects.requireNonNull(array2); - Class type = array1.getClass().getComponentType(); - T[] merged = (T[]) Array.newInstance(type, array1.length + array2.length); - System.arraycopy(array1, 0, merged, 0, array1.length); - System.arraycopy(array2, 0, merged, array1.length, array2.length); - return merged; - } - - /** - * Helper method used for calculating the intersection of two sets: a set of shared items between both sets. - * Although it employs mutable operations, it ensures that the original sets are not modified by working on their - * copies. - * - * @param set1 The first {@link Set}. - * @param set2 The second {@link Set}. - * @param The type of elements in both sets. - * @return The intersection of the two sets. - */ - public Set intersection(Set set1, Set set2) { - Objects.requireNonNull(set1); - Objects.requireNonNull(set2); - Set intersection = new HashSet<>(set1); - intersection.retainAll(set2); - return intersection; - } - - /** - * Helper method used for calculating the difference of two sets: a set of items contained in the first set that are - * not part of the second set. Although it employs mutable operations, it ensures that the original sets are not - * modified by working on their copies. - * - * @param set1 The first {@link Set}. - * @param set2 The second {@link Set}. - * @param The type of elements in both sets. - * @return The difference of the first and second set. - */ - public Set difference(Set set1, Set set2) { - Objects.requireNonNull(set1); - Objects.requireNonNull(set2); - Set difference = new HashSet<>(set1); - difference.removeAll(set2); - return difference; - } - - /** - * Helper method used for retrieving all values contained in a {@code Map}. If the key does not map to any value, - * then it is simply ignored. The order of value retrieval depends on the access order of the {@code Collection} - * containing the keys. - * - * @param map A {@code Map}. - * @param keys A {@code Collection} of keys. - * @param The key type. - * @param The value type. - * @return The {@code Set} of values that are mapped my the keys. - */ - public Set getAllValuesFrom(Map map, Collection keys) { - Objects.requireNonNull(map); - Objects.requireNonNull(keys); - Set values = new HashSet<>(keys.size()); - for (K key: keys) { - V value = map.get(key); - if (value != null) values.add(value); - } - return values; - } -} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java b/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java index 116e9f6d..ccba04a2 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java @@ -1,10 +1,10 @@ package usi.si.seart.git; +import com.google.common.collect.ObjectArrays; import lombok.AccessLevel; import lombok.Getter; import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; -import usi.si.seart.collection.utils.CollectionUtils; import usi.si.seart.converter.InputStreamToString; import usi.si.seart.model.Language; @@ -268,7 +268,8 @@ private Diff(String startSHA, String endSHA) throws GitException { private Diff(String startSHA, String endSHA, String... extensions) throws GitException { String[] base = new String[] { "diff", "--name-status", "--diff-filter=ADMRC", startSHA, endSHA, "--" }; - Process process = executeGitCommand(CollectionUtils.merge(base, extensions)); + String[] command = ObjectArrays.concat(base, extensions, String.class); + Process process = executeGitCommand(command); processOutput(process); } diff --git a/dl4se-crawler/src/test/java/usi/si/seart/collection/utils/CollectionUtilsTest.java b/dl4se-crawler/src/test/java/usi/si/seart/collection/utils/CollectionUtilsTest.java deleted file mode 100644 index e846805a..00000000 --- a/dl4se-crawler/src/test/java/usi/si/seart/collection/utils/CollectionUtilsTest.java +++ /dev/null @@ -1,52 +0,0 @@ -package usi.si.seart.collection.utils; - -import lombok.AccessLevel; -import lombok.experimental.FieldDefaults; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import java.util.Map; -import java.util.Set; - -@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) -class CollectionUtilsTest { - - Set ints1 = Set.of(1, 2, 3, 4, 5, 6); - Set ints2 = Set.of(4, 5, 6, 7, 8, 9); - Set strs1 = Set.of("this", "is", "a", "utils", "test"); - Set strs2 = Set.of("this", "is", "another", "test"); - - @Test - void mergeTest() { - Integer[] empty = new Integer[]{}; - Integer[] arr1 = new Integer[] {1, 2, 3}; - Integer[] arr2 = new Integer[] {4, 5, 6}; - Assertions.assertArrayEquals(empty, CollectionUtils.merge(empty, empty)); - Assertions.assertArrayEquals(arr1, CollectionUtils.merge(empty, arr1)); - Assertions.assertArrayEquals(arr1, CollectionUtils.merge(arr1, empty)); - Assertions.assertArrayEquals(new Integer[] {1, 2, 3, 4, 5, 6}, CollectionUtils.merge(arr1, arr2)); - Assertions.assertArrayEquals(new Integer[] {1, 2, 3, 1, 2, 3}, CollectionUtils.merge(arr1, arr1)); - } - - @Test - void intersectionTest() { - Assertions.assertEquals(Set.of(4, 5, 6), CollectionUtils.intersection(ints1, ints2)); - Assertions.assertEquals(Set.of("this", "is", "test"), CollectionUtils.intersection(strs1, strs2)); - } - - @Test - void differenceTest() { - Assertions.assertEquals(Set.of(1, 2, 3), CollectionUtils.difference(ints1, ints2)); - Assertions.assertEquals(Set.of("a", "utils"), CollectionUtils.difference(strs1, strs2)); - } - - @Test - void getAllKeysFromTest() { - Map map = Map.of(0, 5, 1, 6, 2, 7, 3, 8, 4, 9); - Set keys = Set.of(0, 1, 2, 3, 4); - - Assertions.assertEquals(Set.of(5, 6, 7, 8, 9), CollectionUtils.getAllValuesFrom(map, keys)); - Assertions.assertEquals(Set.of(5, 6, 7), CollectionUtils.getAllValuesFrom(map, Set.of(0, 1, 2))); - Assertions.assertEquals(Set.of(), CollectionUtils.getAllValuesFrom(map, Set.of(5, 6, 7))); - } -} \ No newline at end of file From 1255bf6cd7ed878e885d5812a443b3daf58a6e73 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 5 Jul 2023 13:39:38 +0200 Subject: [PATCH 0196/1089] Overhaul of `toString` method for `Code` subclasses --- .../java/usi/si/seart/model/code/File.java | 23 +++++++------------ .../usi/si/seart/model/code/Function.java | 22 +++++++----------- 2 files changed, 16 insertions(+), 29 deletions(-) diff --git a/dl4se-model/src/main/java/usi/si/seart/model/code/File.java b/dl4se-model/src/main/java/usi/si/seart/model/code/File.java index b2410e89..c5d90f20 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/code/File.java +++ b/dl4se-model/src/main/java/usi/si/seart/model/code/File.java @@ -22,6 +22,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.StringJoiner; @Entity @Table( @@ -62,21 +63,13 @@ public int hashCode() { return Objects.hash(repo.getName(), path, contentHash, getClass().hashCode()); } + @Override public String toString() { - return "File(id=" + this.id + - ", repo=" + this.repo + - ", language=" + this.language + - ", path=" + this.path + - ", content=" + this.content + - ", contentHash=" + this.contentHash + - ", ast=" + this.ast + - ", astHash=" + this.astHash + - ", isParsed=" + this.isParsed + - ", totalTokens=" + this.totalTokens + - ", codeTokens=" + this.codeTokens + - ", lines=" + this.lines + - ", characters=" + this.characters + - ", isTest=" + this.isTest + - ", containsNonAscii=" + this.containsNonAscii + ")"; + return new StringJoiner(", ", File.class.getSimpleName() + "(", ")") + .add("id=" + id) + .add("repo=" + repo) + .add("path='" + path + "'") + .add("language=" + language) + .toString(); } } diff --git a/dl4se-model/src/main/java/usi/si/seart/model/code/Function.java b/dl4se-model/src/main/java/usi/si/seart/model/code/Function.java index e9c67a47..d9aaf445 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/code/Function.java +++ b/dl4se-model/src/main/java/usi/si/seart/model/code/Function.java @@ -23,6 +23,7 @@ import javax.persistence.Table; import javax.validation.constraints.NotNull; import java.util.Objects; +import java.util.StringJoiner; @Entity @Table(name = "function") @@ -60,20 +61,13 @@ public int hashCode() { return Objects.hash(repo.getName(), file.getPath(), contentHash, getClass().hashCode()); } + @Override public String toString() { - return "Function(id=" + this.id + - ", repo=" + this.repo + - ", language=" + this.language + - ", content=" + this.content + - ", contentHash=" + this.contentHash + - ", ast=" + this.ast + - ", astHash=" + this.astHash + - ", totalTokens=" + this.totalTokens + - ", codeTokens=" + this.codeTokens + - ", lines=" + this.lines + - ", characters=" + this.characters + - ", isTest=" + this.isTest + - ", boilerplateType=" + this.boilerplateType + - ", containsNonAscii=" + this.containsNonAscii + ")"; + return new StringJoiner(", ", Function.class.getSimpleName() + "(", ")") + .add("id=" + id) + .add("repo=" + repo) + .add("file=" + file) + .add("language=" + language) + .toString(); } } From c1ab7d4409d0f7fc2e46c3cfefd8d24d2c5efe0c Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 6 Jul 2023 11:57:08 +0200 Subject: [PATCH 0197/1089] MAJOR CHANGE: Crawler is migrated to a Spring Boot App Just like the title suggests, this is a major overhaul to the `dl4se-crawler` module. While the original intent was to make the crawler as "lightweight" as possible, it made configuration and the addition of new features quite hard. Spring makes data access easy (no more `HibernateUtils`), gives better separation of concerns, allows us to use dependency injection, configure logging easily, schedule the crawler without the need for any custom scripts, etc. This change also opens the door to new possibilities: - Separating crawlers to mine independently for each language - Parallelizing individual file analysis operations to do 4 at a time --- dl4se-crawler/pom.xml | 12 + .../src/main/java/usi/si/seart/Crawler.java | 266 ----------------- .../java/usi/si/seart/CrawlerProperties.java | 22 -- .../java/usi/si/seart/collection/Tuple.java | 66 ----- .../seart/converter/DateToLocalDateTime.java | 27 -- .../seart/converter/GhsGitRepoToGitRepo.java | 46 --- .../seart/converter/InputStreamToString.java | 33 --- .../usi/si/seart/crawler/Application.java | 12 + .../bean/CrawlJobInitializingBean.java | 37 +++ .../crawler/bean/NativeLibraryLoaderBean.java | 17 ++ .../seart/crawler/component/CodeCrawler.java | 272 ++++++++++++++++++ .../seart/crawler/component/HttpClient.java | 65 +++++ .../seart/crawler/config/ConverterConfig.java | 29 ++ .../seart/crawler/config/CrawlerConfig.java | 34 +++ .../si/seart/crawler/config/HttpConfig.java | 83 ++++++ .../si/seart/crawler/config/JpaConfig.java | 9 + .../seart/crawler/config/SchedulerConfig.java | 11 + .../DateToLocalDateTimeConverter.java | 15 + .../SearchResultDtoToGitRepoConverter.java | 38 +++ .../dto/SearchResultDto.java} | 23 +- .../usi/si/seart/{ => crawler}/git/Git.java | 26 +- .../seart/{ => crawler}/git/GitException.java | 2 +- .../io/ExtensionBasedFileVisitor.java | 2 +- .../repository/CrawlJobRepository.java | 13 + .../crawler/repository/FileRepository.java | 17 ++ .../crawler/repository/GitRepoRepository.java | 20 ++ .../repository/LanguageRepository.java | 7 + .../crawler/service/CrawlJobService.java | 46 +++ .../si/seart/crawler/service/FileService.java | 60 ++++ .../seart/crawler/service/GitRepoService.java | 37 +++ .../crawler/service/LanguageService.java | 29 ++ .../java/usi/si/seart/http/HttpClient.java | 106 ------- .../usi/si/seart/io/PropertiesReader.java | 81 ------ .../usi/si/seart/utils/HibernateUtils.java | 166 ----------- .../src/main/resources/application.properties | 41 +++ dl4se-crawler/src/main/resources/banner.txt | 14 + .../src/main/resources/hibernate.cfg.xml | 40 --- .../src/main/resources/hibernate.properties | 1 - dl4se-crawler/src/main/resources/logback.xml | 70 ----- .../src/main/resources/properties.txt | 3 - .../test/java/usi/si/seart/git/GitTest.java | 2 + .../io/ExtensionBasedFileVisitorTest.java | 1 + .../usi/si/seart/io/PropertiesReaderTest.java | 56 ---- .../resources/code/java/AbstractClass.java | 5 - .../test/resources/code/java/Boilerplate.java | 53 ---- .../src/test/resources/code/java/Class.java | 27 -- .../src/test/resources/code/java/Enum.java | 5 - .../test/resources/code/java/InnerClass.java | 37 --- .../test/resources/code/java/Interface.java | 5 - .../test/resources/code/java/MainClass.java | 7 - .../test/resources/code/java/TestClass.java | 17 -- .../src/test/resources/code/other/DCL.md | 29 -- .../src/test/resources/code/other/LICENSE | 21 -- .../resources/code/other/representation.pdf | Bin 278280 -> 0 bytes .../resources/code/other/requirements.txt | 7 - .../test/resources/code/python/__init__.py | 0 .../src/test/resources/code/python/se.py | 209 -------------- .../test/resources/code/python/search-data.py | 17 -- .../src/test/resources/code/python/visitor.py | 57 ---- .../src/test/resources/logback-test.xml | 28 -- .../src/test/resources/reader.properties | 9 - 61 files changed, 958 insertions(+), 1532 deletions(-) delete mode 100644 dl4se-crawler/src/main/java/usi/si/seart/Crawler.java delete mode 100644 dl4se-crawler/src/main/java/usi/si/seart/CrawlerProperties.java delete mode 100644 dl4se-crawler/src/main/java/usi/si/seart/collection/Tuple.java delete mode 100644 dl4se-crawler/src/main/java/usi/si/seart/converter/DateToLocalDateTime.java delete mode 100644 dl4se-crawler/src/main/java/usi/si/seart/converter/GhsGitRepoToGitRepo.java delete mode 100644 dl4se-crawler/src/main/java/usi/si/seart/converter/InputStreamToString.java create mode 100644 dl4se-crawler/src/main/java/usi/si/seart/crawler/Application.java create mode 100644 dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/CrawlJobInitializingBean.java create mode 100644 dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/NativeLibraryLoaderBean.java create mode 100644 dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java create mode 100644 dl4se-crawler/src/main/java/usi/si/seart/crawler/component/HttpClient.java create mode 100644 dl4se-crawler/src/main/java/usi/si/seart/crawler/config/ConverterConfig.java create mode 100644 dl4se-crawler/src/main/java/usi/si/seart/crawler/config/CrawlerConfig.java create mode 100644 dl4se-crawler/src/main/java/usi/si/seart/crawler/config/HttpConfig.java create mode 100644 dl4se-crawler/src/main/java/usi/si/seart/crawler/config/JpaConfig.java create mode 100644 dl4se-crawler/src/main/java/usi/si/seart/crawler/config/SchedulerConfig.java create mode 100644 dl4se-crawler/src/main/java/usi/si/seart/crawler/converter/DateToLocalDateTimeConverter.java create mode 100644 dl4se-crawler/src/main/java/usi/si/seart/crawler/converter/SearchResultDtoToGitRepoConverter.java rename dl4se-crawler/src/main/java/usi/si/seart/{http/payload/GhsGitRepo.java => crawler/dto/SearchResultDto.java} (76%) rename dl4se-crawler/src/main/java/usi/si/seart/{ => crawler}/git/Git.java (94%) rename dl4se-crawler/src/main/java/usi/si/seart/{ => crawler}/git/GitException.java (77%) rename dl4se-crawler/src/main/java/usi/si/seart/{ => crawler}/io/ExtensionBasedFileVisitor.java (99%) create mode 100644 dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/CrawlJobRepository.java create mode 100644 dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/FileRepository.java create mode 100644 dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/GitRepoRepository.java create mode 100644 dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/LanguageRepository.java create mode 100644 dl4se-crawler/src/main/java/usi/si/seart/crawler/service/CrawlJobService.java create mode 100644 dl4se-crawler/src/main/java/usi/si/seart/crawler/service/FileService.java create mode 100644 dl4se-crawler/src/main/java/usi/si/seart/crawler/service/GitRepoService.java create mode 100644 dl4se-crawler/src/main/java/usi/si/seart/crawler/service/LanguageService.java delete mode 100644 dl4se-crawler/src/main/java/usi/si/seart/http/HttpClient.java delete mode 100644 dl4se-crawler/src/main/java/usi/si/seart/io/PropertiesReader.java delete mode 100644 dl4se-crawler/src/main/java/usi/si/seart/utils/HibernateUtils.java create mode 100644 dl4se-crawler/src/main/resources/application.properties create mode 100644 dl4se-crawler/src/main/resources/banner.txt delete mode 100644 dl4se-crawler/src/main/resources/hibernate.cfg.xml delete mode 100644 dl4se-crawler/src/main/resources/hibernate.properties delete mode 100644 dl4se-crawler/src/main/resources/logback.xml delete mode 100644 dl4se-crawler/src/main/resources/properties.txt delete mode 100644 dl4se-crawler/src/test/java/usi/si/seart/io/PropertiesReaderTest.java delete mode 100644 dl4se-crawler/src/test/resources/code/java/AbstractClass.java delete mode 100644 dl4se-crawler/src/test/resources/code/java/Boilerplate.java delete mode 100644 dl4se-crawler/src/test/resources/code/java/Class.java delete mode 100644 dl4se-crawler/src/test/resources/code/java/Enum.java delete mode 100644 dl4se-crawler/src/test/resources/code/java/InnerClass.java delete mode 100644 dl4se-crawler/src/test/resources/code/java/Interface.java delete mode 100644 dl4se-crawler/src/test/resources/code/java/MainClass.java delete mode 100644 dl4se-crawler/src/test/resources/code/java/TestClass.java delete mode 100644 dl4se-crawler/src/test/resources/code/other/DCL.md delete mode 100644 dl4se-crawler/src/test/resources/code/other/LICENSE delete mode 100644 dl4se-crawler/src/test/resources/code/other/representation.pdf delete mode 100644 dl4se-crawler/src/test/resources/code/other/requirements.txt delete mode 100644 dl4se-crawler/src/test/resources/code/python/__init__.py delete mode 100644 dl4se-crawler/src/test/resources/code/python/se.py delete mode 100644 dl4se-crawler/src/test/resources/code/python/search-data.py delete mode 100644 dl4se-crawler/src/test/resources/code/python/visitor.py delete mode 100644 dl4se-crawler/src/test/resources/logback-test.xml delete mode 100644 dl4se-crawler/src/test/resources/reader.properties diff --git a/dl4se-crawler/pom.xml b/dl4se-crawler/pom.xml index 625d4223..3bf91a42 100644 --- a/dl4se-crawler/pom.xml +++ b/dl4se-crawler/pom.xml @@ -28,6 +28,18 @@ dl4se-analyzer ${project.version} + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-logging + + + org.springframework.boot + spring-boot-starter-data-jpa + ch.qos.logback logback-classic diff --git a/dl4se-crawler/src/main/java/usi/si/seart/Crawler.java b/dl4se-crawler/src/main/java/usi/si/seart/Crawler.java deleted file mode 100644 index 8dba114b..00000000 --- a/dl4se-crawler/src/main/java/usi/si/seart/Crawler.java +++ /dev/null @@ -1,266 +0,0 @@ -package usi.si.seart; - -import ch.usi.si.seart.treesitter.LibraryLoader; -import com.google.api.client.http.GenericUrl; -import com.google.api.client.http.HttpResponse; -import com.google.common.base.Strings; -import com.google.common.collect.Sets; -import lombok.AccessLevel; -import lombok.SneakyThrows; -import lombok.experimental.FieldDefaults; -import lombok.extern.slf4j.Slf4j; -import usi.si.seart.analyzer.Analyzer; -import usi.si.seart.analyzer.AnalyzerFactory; -import usi.si.seart.analyzer.LocalClone; -import usi.si.seart.collection.Tuple; -import usi.si.seart.converter.DateToLocalDateTime; -import usi.si.seart.converter.GhsGitRepoToGitRepo; -import usi.si.seart.git.Git; -import usi.si.seart.git.GitException; -import usi.si.seart.http.HttpClient; -import usi.si.seart.http.payload.GhsGitRepo; -import usi.si.seart.io.ExtensionBasedFileVisitor; -import usi.si.seart.model.GitRepo; -import usi.si.seart.model.Language; -import usi.si.seart.model.code.File; -import usi.si.seart.model.job.CrawlJob; -import usi.si.seart.utils.HibernateUtils; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.function.BiConsumer; -import java.util.stream.Collectors; - -@Slf4j -@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) -public class Crawler { - - static CrawlJob lastJob; - - static Set languages; - - static Set names; - static Map nameToLanguage; - - static String[] extensions; - static Map extensionToLanguage; - - static { - LibraryLoader.load(); - - lastJob = HibernateUtils.getLastJob(); - - languages = HibernateUtils.getLanguages(); - - nameToLanguage = languages.stream().map(language -> Tuple.of(language.getName(), language)) - .collect(Collectors.toMap(Tuple::getKey, Tuple::getValue)); - names = nameToLanguage.keySet(); - - extensionToLanguage = languages.stream().flatMap(language -> { - List> entries = new ArrayList<>(); - for (String extension: language.getExtensions()) { - entries.add(Tuple.of(extension, language)); - } - return entries.stream(); - }).collect(Collectors.toMap(Tuple::getKey, Tuple::getValue)); - extensions = extensionToLanguage.keySet().toArray(String[]::new); - } - - public static void main(String[] args) { - HttpClient client = new HttpClient(); - String nextUrl = CrawlerProperties.ghsSearchUrl; - LocalDate lastUpdate = lastJob.getCheckpoint().toLocalDate(); - log.info("Last mining checkpoint: {}", lastUpdate); - do { - nextUrl = iterate(client, nextUrl, lastUpdate); - } while (nextUrl != null); - log.info("Done!"); - } - - @SneakyThrows - private static String iterate(HttpClient client, String link, LocalDate lastUpdate) { - GenericUrl requestUrl = new GenericUrl(link) - .set("committedMin", lastUpdate.toString()) - .set("sort", "lastCommit") - .set("size", 100); - HttpResponse response = client.getRequest(requestUrl); - List items = client.getSearchResults(response); - Map links = client.getNavigationLinks(response); - items.forEach(Crawler::checkRepoData); - response.disconnect(); - return links.get("next"); - } - - // FIXME 06.05.22: This is only a temporary workaround until I don't figure out why the validation does not work - private static void saveProgress() { - Long id = lastJob.getId(); - LocalDateTime checkpoint = lastJob.getCheckpoint(); - if (checkpoint.isAfter(LocalDateTime.now())) return; - log.debug("Saving progress... [Checkpoint: {}]", checkpoint); - HibernateUtils.updateCrawlJobById(id, checkpoint); - } - - private static void checkRepoData(GhsGitRepo item) { - String name = item.getName(); - LocalDateTime lastUpdateGhs = DateToLocalDateTime.getConverter().convert(item.getLastCommit()); - lastJob.setCheckpoint(lastUpdateGhs); - - Set repoLanguageNames = Sets.intersection(names, item.getRepoLanguages()); - Set repoLanguages = repoLanguageNames.stream() - .map(nameToLanguage::get) - .filter(Objects::nonNull) - .collect(Collectors.toSet()); - - if (repoLanguages.isEmpty()) { - log.debug("Skipping: {}. No files of interest found!", name); - return; - } - - Optional optional = HibernateUtils.getRepoByName(name); - GitRepo repo; - BiConsumer> operation; - if (optional.isPresent()) { - repo = optional.get(); - item.update(repo); - operation = Crawler::updateRepoData; - } else { - repo = GhsGitRepoToGitRepo.getConverter().convert(item); - HibernateUtils.save(repo); - operation = Crawler::mineRepoData; - } - - operation.accept(repo, repoLanguages); - saveProgress(); - } - - @SneakyThrows(IOException.class) - private static void updateRepoData(GitRepo repo, Set repoLanguages) { - String name = repo.getName(); - LocalDateTime lastCommit = repo.getLastCommit(); - - log.info("Updating repository: {} [Last Commit: {}]", name, lastCommit); - Path localDirectory = Files.createTempDirectory(CrawlerProperties.tmpDirPrefix); - LocalClone localClone = new LocalClone(repo, localDirectory); - try (Git git = new Git(name, localDirectory, lastCommit)) { - - Set notMined = Sets.difference(repoLanguages, repo.getLanguages()); - if (!notMined.isEmpty()) { - mineRepoDataForLanguages(localClone, notMined); - repo.setLanguages(repoLanguages); - HibernateUtils.save(repo); - } - - Git.Commit latest = git.getLastCommitInfo(); - repo.setLastCommit(latest.getTimestamp()); - repo.setLastCommitSHA(latest.getSha()); - - Git.Diff diff = git.getDiff(repo.getLastCommitSHA(), repo.getLanguages()); - if (!Strings.isNullOrEmpty(diff.toString())) - log.debug("Diff since last update:\n{}", diff); - diff.getAdded().forEach(path -> addFile(repo, path, localDirectory)); - diff.getDeleted().forEach(path -> deleteFile(repo, path)); - diff.getModified().forEach(path -> { - deleteFile(repo, path); - addFile(repo, path, localDirectory); - }); - diff.getRenamed().forEach((key, value) -> renameFile(repo, key, value)); - diff.getEdited().forEach((key, value) -> { - deleteFile(repo, key); - addFile(repo, value, localDirectory); - }); - diff.getCopied().forEach((key, value) -> addFile(repo, value, localDirectory)); - - HibernateUtils.save(repo); - } catch (GitException ex) { - log.error("Git operation error for: " + name, ex); - } - } - - private static void addFile(GitRepo repo, Path filePath, Path dirPath) { - LocalClone localClone = new LocalClone(repo, dirPath); - tryAnalyze(localClone, filePath) - .map(Analyzer.Result::getFile) - .ifPresent(HibernateUtils::save); - } - - private static void deleteFile(GitRepo repo, Path filePath) { - HibernateUtils.deleteFileByRepoIdAndPath(repo.getId(), filePath); - } - - private static void renameFile(GitRepo repo, Path oldFilePath, Path newFilePath) { - HibernateUtils.updateFilePathByRepoId(repo.getId(), oldFilePath, newFilePath); - } - - @SneakyThrows(IOException.class) - private static void mineRepoData(GitRepo repo, Set repoLanguages) { - String name = repo.getName(); - LocalDateTime lastUpdateGhs = repo.getLastCommit(); - - Path localDirectory = Files.createTempDirectory(CrawlerProperties.tmpDirPrefix); - LocalClone localClone = new LocalClone(repo, localDirectory); - log.info("Mining repository: {} [Last Commit: {}]", name, lastUpdateGhs); - try (Git git = new Git(name, localDirectory, true)) { - Git.Commit latest = git.getLastCommitInfo(); - - mineRepoDataForLanguages(localClone, repoLanguages); - - repo.setLanguages(repoLanguages); - repo.setLastCommit(latest.getTimestamp()); - repo.setLastCommitSHA(latest.getSha()); - - HibernateUtils.save(repo); - } catch (GitException ex) { - log.error("Git operation error for: " + name, ex); - } - } - - @SneakyThrows(IOException.class) - private static void mineRepoDataForLanguages(LocalClone localClone, Set languages) { - GitRepo repo = localClone.getGitRepo(); - Path localDirectory = localClone.getDiskPath(); - String[] extensions = languages.stream() - .map(Language::getExtensions) - .flatMap(Collection::stream) - .toArray(String[]::new); - ExtensionBasedFileVisitor visitor = ExtensionBasedFileVisitor.forExtensions(extensions); - Files.walkFileTree(localDirectory, visitor); - Set candidates = new HashSet<>(visitor.getVisited()); - Set analyzed = HibernateUtils.getFilesByRepo(repo.getId()).stream() - .map(File::getPath) - .map(Path::of) - .map(localDirectory::resolve) - .collect(Collectors.toSet()); - Set targets = Sets.difference(candidates, analyzed); - for (Path path: targets) { - tryAnalyze(localClone, path) - .map(Analyzer.Result::getFile) - .ifPresent(HibernateUtils::save); - } - } - - private static Optional tryAnalyze(LocalClone localClone, Path filePath) { - log.trace("Analyzing file: {}", localClone.relativePathOf(filePath)); - String extension = com.google.common.io.Files.getFileExtension(filePath.toString()); - Language language = extensionToLanguage.get(extension); - try (Analyzer analyzer = AnalyzerFactory.getAnalyzer(language).apply(localClone, filePath)) { - Analyzer.Result result = analyzer.analyze(); - result.getFile().setLanguage(language); - result.getFunctions().forEach(function -> function.setLanguage(language)); - return Optional.of(result); - } catch (Exception ex) { - log.error("", ex); - return Optional.empty(); - } - } -} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/CrawlerProperties.java b/dl4se-crawler/src/main/java/usi/si/seart/CrawlerProperties.java deleted file mode 100644 index 0879a223..00000000 --- a/dl4se-crawler/src/main/java/usi/si/seart/CrawlerProperties.java +++ /dev/null @@ -1,22 +0,0 @@ -package usi.si.seart; - -import lombok.experimental.UtilityClass; -import usi.si.seart.io.PropertiesReader; - -import java.time.LocalDate; - -@UtilityClass -public class CrawlerProperties { - - public static final String tmpDirPrefix; - public static final LocalDate startDate; - public static final String ghsSearchUrl; - - static { - PropertiesReader propertiesReader = new PropertiesReader("properties.txt"); - tmpDirPrefix = propertiesReader.getProperty("app.general.tmpDirPrefix"); - String dateString = propertiesReader.getProperty("app.crawl.startDate"); - startDate = LocalDate.parse(dateString); - ghsSearchUrl = propertiesReader.getProperty("app.crawl.ghs.searchUrl"); - } -} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/collection/Tuple.java b/dl4se-crawler/src/main/java/usi/si/seart/collection/Tuple.java deleted file mode 100644 index 7524affe..00000000 --- a/dl4se-crawler/src/main/java/usi/si/seart/collection/Tuple.java +++ /dev/null @@ -1,66 +0,0 @@ -package usi.si.seart.collection; - -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.experimental.FieldDefaults; - -import java.util.Map; - -/** - * Simple implementation of a tuple class, used as a container for two values of arbitrary types. - * Tuples are immutable, and can only be created through a static factory: - *
{@code
- *      Tuple t = Tuple.of(1, "Hello!");
- * }
- * Values are subsequently accessed through getters: - *
{@code
- *      int i = t.getLeft();
- *      String msg = t.getRight();
- * }
- * This class can also be used in place of {@link Map.Entry Entry}: - *
{@code
- *      Map = Map.ofEntries(
- *          Tuple.of(1, 1L),
- *          Tuple.of(2, ""),
- *          Tuple.of(3, new Object())
- *      );
- * }
- * In terms of behaviour, it is similar to {@code UnmodifiableEntry}. - * - * @author dabico - * @param The type of the first value. - * @param The type of the second value. - */ -@Getter -@AllArgsConstructor(access = AccessLevel.PRIVATE) -@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) -public class Tuple implements Map.Entry { - - L left; - R right; - - @Override - public L getKey() { - return this.left; - } - - @Override - public R getValue() { - return this.right; - } - - @Override - public R setValue(R value) { - throw new UnsupportedOperationException("Tuple values are not modifiable!"); - } - - @Override - public String toString() { - return String.format("(%s, %s)", left.toString(), right.toString()); - } - - public static Tuple of(L left, R right) { - return new Tuple<>(left, right); - } -} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/converter/DateToLocalDateTime.java b/dl4se-crawler/src/main/java/usi/si/seart/converter/DateToLocalDateTime.java deleted file mode 100644 index 798376cd..00000000 --- a/dl4se-crawler/src/main/java/usi/si/seart/converter/DateToLocalDateTime.java +++ /dev/null @@ -1,27 +0,0 @@ -package usi.si.seart.converter; - -import com.google.common.base.Converter; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; - -import java.time.LocalDateTime; -import java.time.ZoneOffset; -import java.util.Date; - -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public class DateToLocalDateTime extends Converter { - - @Getter - private static final Converter converter = new DateToLocalDateTime(); - - @Override - protected LocalDateTime doForward(Date date) { - return LocalDateTime.ofInstant(date.toInstant(), ZoneOffset.UTC); - } - - @Override - protected Date doBackward(LocalDateTime ldt) { - return new Date(ldt.toInstant(ZoneOffset.UTC).toEpochMilli()); - } -} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/converter/GhsGitRepoToGitRepo.java b/dl4se-crawler/src/main/java/usi/si/seart/converter/GhsGitRepoToGitRepo.java deleted file mode 100644 index 1c1ee74b..00000000 --- a/dl4se-crawler/src/main/java/usi/si/seart/converter/GhsGitRepoToGitRepo.java +++ /dev/null @@ -1,46 +0,0 @@ -package usi.si.seart.converter; - -import com.google.common.base.Converter; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; -import usi.si.seart.http.payload.GhsGitRepo; -import usi.si.seart.model.GitRepo; - -import java.time.LocalDateTime; - -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public class GhsGitRepoToGitRepo extends Converter { - - @Getter - private static final Converter converter = new GhsGitRepoToGitRepo(); - - @Override - protected GitRepo doForward(GhsGitRepo ghsGitRepo) { - GitRepo.GitRepoBuilder builder = GitRepo.builder(); - - builder.name(ghsGitRepo.getName()); - builder.license(ghsGitRepo.getLicense()); - builder.isFork(ghsGitRepo.getIsFork()); - - Long commits = ghsGitRepo.getCommits(); - if (commits != null) builder.commits(commits); - Long contributors = ghsGitRepo.getContributors(); - if (contributors != null) builder.contributors(contributors); - Long issues = ghsGitRepo.getTotalIssues(); - if (issues != null) builder.issues(issues); - Long stars = ghsGitRepo.getStargazers(); - if (stars != null) builder.stars(stars); - LocalDateTime lastCommit = DateToLocalDateTime.getConverter().convert(ghsGitRepo.getLastCommit()); - if (lastCommit != null) builder.lastCommit(lastCommit); - String lastCommitSHA = ghsGitRepo.getLastCommitSHA(); - if (lastCommitSHA != null) builder.lastCommitSHA(lastCommitSHA); - - return builder.build(); - } - - @Override - protected GhsGitRepo doBackward(GitRepo repo) { - throw new UnsupportedOperationException("Backwards conversion is not supported!"); - } -} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/converter/InputStreamToString.java b/dl4se-crawler/src/main/java/usi/si/seart/converter/InputStreamToString.java deleted file mode 100644 index 9d91b808..00000000 --- a/dl4se-crawler/src/main/java/usi/si/seart/converter/InputStreamToString.java +++ /dev/null @@ -1,33 +0,0 @@ -package usi.si.seart.converter; - -import com.google.common.base.Converter; -import com.google.common.io.CharStreams; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.SneakyThrows; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; - -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public class InputStreamToString extends Converter { - - @Getter - private static final Converter converter = new InputStreamToString(); - - @Override - @SneakyThrows(IOException.class) - protected String doForward(InputStream inputStream) { - try (Reader reader = new InputStreamReader(inputStream)) { - return CharStreams.toString(reader); - } - } - - @Override - protected InputStream doBackward(String s) { - throw new UnsupportedOperationException("Backwards conversion is not supported!"); - } -} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/Application.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/Application.java new file mode 100644 index 00000000..29f6972e --- /dev/null +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/Application.java @@ -0,0 +1,12 @@ +package usi.si.seart.crawler; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/CrawlJobInitializingBean.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/CrawlJobInitializingBean.java new file mode 100644 index 00000000..89db5bdc --- /dev/null +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/CrawlJobInitializingBean.java @@ -0,0 +1,37 @@ +package usi.si.seart.crawler.bean; + +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import usi.si.seart.crawler.repository.CrawlJobRepository; +import usi.si.seart.model.job.CrawlJob; +import usi.si.seart.model.job.Job; + +import java.time.LocalDateTime; +import java.util.Optional; + +@Component +@RequiredArgsConstructor(onConstructor_ = @Autowired) +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +public class CrawlJobInitializingBean implements InitializingBean { + + Job jobType; + LocalDateTime defaultStartDateTime; + + CrawlJobRepository crawlJobRepository; + + @Override + public void afterPropertiesSet() { + Optional optional = crawlJobRepository.findByJobType(jobType); + CrawlJob crawlJob = optional.orElseGet( + () -> CrawlJob.builder() + .checkpoint(defaultStartDateTime) + .jobType(jobType) + .build() + ); + crawlJobRepository.save(crawlJob); + } +} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/NativeLibraryLoaderBean.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/NativeLibraryLoaderBean.java new file mode 100644 index 00000000..17602dcd --- /dev/null +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/NativeLibraryLoaderBean.java @@ -0,0 +1,17 @@ +package usi.si.seart.crawler.bean; + +import ch.usi.si.seart.treesitter.LibraryLoader; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class NativeLibraryLoaderBean implements InitializingBean { + + @Override + public void afterPropertiesSet() { + log.debug("Loading native libraries..."); + LibraryLoader.load(); + } +} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java new file mode 100644 index 00000000..4829c061 --- /dev/null +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java @@ -0,0 +1,272 @@ +package usi.si.seart.crawler.component; + +import com.google.api.client.http.GenericUrl; +import com.google.api.client.http.HttpResponse; +import com.google.common.base.Strings; +import com.google.common.collect.Sets; +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.experimental.FieldDefaults; +import lombok.experimental.NonFinal; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.core.convert.ConversionService; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import usi.si.seart.analyzer.Analyzer; +import usi.si.seart.analyzer.AnalyzerFactory; +import usi.si.seart.analyzer.LocalClone; +import usi.si.seart.crawler.dto.SearchResultDto; +import usi.si.seart.crawler.git.Git; +import usi.si.seart.crawler.git.GitException; +import usi.si.seart.crawler.io.ExtensionBasedFileVisitor; +import usi.si.seart.crawler.service.CrawlJobService; +import usi.si.seart.crawler.service.FileService; +import usi.si.seart.crawler.service.GitRepoService; +import usi.si.seart.crawler.service.LanguageService; +import usi.si.seart.model.GitRepo; +import usi.si.seart.model.Language; +import usi.si.seart.model.code.File; +import usi.si.seart.model.code.Function; + +import javax.annotation.PostConstruct; +import javax.persistence.EntityNotFoundException; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Duration; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.stream.Collectors; + +@Slf4j +@Component +@ConditionalOnProperty(value = "app.crawl-job.type", havingValue = "CODE") +//@ConditionalOnExpression("#{jobType == T(usi.si.seart.model.job.Job).CODE}") +@RequiredArgsConstructor(onConstructor_ = @Autowired) +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +public class CodeCrawler implements Runnable { + + Duration nextRunDelay; + HttpClient httpClient; + GenericUrl baseUrl; + + FileService fileService; + GitRepoService gitRepoService; + CrawlJobService crawlJobService; + LanguageService languageService; + ConversionService conversionService; + + @NonFinal + @Value("${app.general.tmp-dir-prefix}") + String prefix; + + Set languageNames = new HashSet<>(); + Map nameToLanguage = new HashMap<>(); + Map extensionToLanguage = new HashMap<>(); + + @PostConstruct + private void postConstruct() { + languageService.getAll().forEach(language -> { + String name = language.getName(); + List extensions = language.getExtensions(); + languageNames.add(name); + nameToLanguage.put(name, language); + extensions.forEach(extension -> extensionToLanguage.put(extension, language)); + }); + } + + @Scheduled(fixedDelayString = "${app.crawl-job.next-run-delay}") + public void run() { + GenericUrl url = baseUrl; + LocalDate checkpoint = crawlJobService.getProgress() + .getCheckpoint() + .toLocalDate(); + log.info("Last mining checkpoint: {}", checkpoint); + do { + url = fetchSearchResults(url, checkpoint); + } while (url != null); + LocalDateTime nextRun = LocalDateTime.now() + .plus(nextRunDelay) + .truncatedTo(ChronoUnit.SECONDS); + log.info("Finished! Next run scheduled for: {}", nextRun); + } + + @SneakyThrows + private GenericUrl fetchSearchResults(GenericUrl url, LocalDate checkpoint) { + GenericUrl requestUrl = url.set("committedMin", checkpoint.toString()) + .set("sort", "lastCommit") + .set("size", 100); + HttpResponse response = httpClient.getRequest(requestUrl); + List items = httpClient.getSearchResults(response); + Map links = httpClient.getNavigationLinks(response); + items.forEach(this::inspectSearchResult); + response.disconnect(); + Optional optional = Optional.ofNullable(links.get("next")); + return optional.map(GenericUrl::new).orElse(null); + } + + private void saveCrawlProgress(LocalDateTime checkpoint) { + if (checkpoint == null || checkpoint.isAfter(LocalDateTime.now())) return; + log.debug("Saving progress... [Checkpoint: {}]", checkpoint); + crawlJobService.saveProgress(checkpoint); + } + + private void inspectSearchResult(SearchResultDto item) { + String name = item.getName(); + LocalDateTime lastUpdateGhs = conversionService.convert(item.getLastCommit(), LocalDateTime.class); + + Set repoLanguageNames = Sets.intersection(languageNames, item.getRepoLanguages()); + Set repoLanguages = repoLanguageNames.stream() + .map(nameToLanguage::get) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + + if (repoLanguages.isEmpty()) { + log.debug("Skipping: {}. No files of interest found!", name); + return; + } + + GitRepo repo; + BiConsumer> operation; + try { + repo = gitRepoService.getByName(name); + item.update(repo); + operation = this::updateRepoData; + } catch (EntityNotFoundException ignored) { + repo = conversionService.convert(item, GitRepo.class); + repo = gitRepoService.createOrUpdate(repo); + operation = this::mineRepoData; + } + + operation.accept(repo, repoLanguages); + saveCrawlProgress(lastUpdateGhs); + } + + @SneakyThrows(IOException.class) + private void updateRepoData(GitRepo repo, Set repoLanguages) { + String name = repo.getName(); + LocalDateTime lastCommit = repo.getLastCommit(); + + log.info("Updating repository: {} [Last Commit: {}]", name, lastCommit); + Path localDirectory = Files.createTempDirectory(prefix); + LocalClone localClone = new LocalClone(repo, localDirectory); + try (Git git = new Git(name, localDirectory, lastCommit)) { + + Set notMined = Sets.difference(repoLanguages, repo.getLanguages()); + if (!notMined.isEmpty()) { + mineRepoData(localClone, notMined); + repo.setLanguages(repoLanguages); + gitRepoService.createOrUpdate(repo); + } + + Git.Commit latest = git.getLastCommitInfo(); + repo.setLastCommit(latest.getTimestamp()); + repo.setLastCommitSHA(latest.getSha()); + + Git.Diff diff = git.getDiff(repo.getLastCommitSHA(), repo.getLanguages()); + if (!Strings.isNullOrEmpty(diff.toString())) + log.debug("Diff since last update:\n{}", diff); + diff.getAdded().forEach(path -> addFile(localClone, path)); + diff.getDeleted().forEach(path -> deleteFile(repo, path)); + diff.getModified().forEach(path -> { + deleteFile(repo, path); + addFile(localClone, path); + }); + diff.getRenamed().forEach((key, value) -> renameFile(repo, key, value)); + diff.getEdited().forEach((key, value) -> { + deleteFile(repo, key); + addFile(localClone, value); + }); + diff.getCopied().forEach((key, value) -> addFile(localClone, value)); + + gitRepoService.createOrUpdate(repo); + } catch (GitException ex) { + log.error("Git operation error for: " + name, ex); + } + } + + private void addFile(LocalClone localClone, Path path) { + analyzeAndStore(localClone, path); + } + + private void deleteFile(GitRepo repo, Path path) { + fileService.delete(repo, path); + } + + private void renameFile(GitRepo repo, Path oldPath, Path newPath) { + fileService.rename(repo, oldPath, newPath); + } + + @SneakyThrows(IOException.class) + private void mineRepoData(GitRepo repo, Set languages) { + String name = repo.getName(); + LocalDateTime lastUpdateGhs = repo.getLastCommit(); + + Path localDirectory = Files.createTempDirectory(prefix); + LocalClone localClone = new LocalClone(repo, localDirectory); + log.info("Mining repository: {} [Last Commit: {}]", name, lastUpdateGhs); + try (Git git = new Git(name, localDirectory, true)) { + Git.Commit latest = git.getLastCommitInfo(); + + mineRepoData(localClone, languages); + + repo.setLanguages(languages); + repo.setLastCommit(latest.getTimestamp()); + repo.setLastCommitSHA(latest.getSha()); + + gitRepoService.createOrUpdate(repo); + } catch (GitException ex) { + log.error("Git operation error for: " + name, ex); + } + } + + @SneakyThrows(IOException.class) + private void mineRepoData(LocalClone localClone, Set languages) { + GitRepo repo = localClone.getGitRepo(); + Path localDirectory = localClone.getDiskPath(); + String[] extensions = languages.stream() + .map(Language::getExtensions) + .flatMap(Collection::stream) + .toArray(String[]::new); + ExtensionBasedFileVisitor visitor = ExtensionBasedFileVisitor.forExtensions(extensions); + Files.walkFileTree(localDirectory, visitor); + Set candidates = new HashSet<>(visitor.getVisited()); + Set analyzed = fileService.getAllByRepo(repo).stream() + .map(File::getPath) + .map(Path::of) + .map(localDirectory::resolve) + .collect(Collectors.toSet()); + Set targets = Sets.difference(candidates, analyzed); + targets.forEach(target -> analyzeAndStore(localClone, target)); + } + + private void analyzeAndStore(LocalClone localClone, Path path) { + log.trace("Analyzing file: {}", localClone.relativePathOf(path)); + String extension = com.google.common.io.Files.getFileExtension(path.toString()); + Language language = extensionToLanguage.get(extension); + try (Analyzer analyzer = AnalyzerFactory.getAnalyzer(language).apply(localClone, path)) { + Analyzer.Result result = analyzer.analyze(); + File file = result.getFile(); + List functions = result.getFunctions(); + file.setLanguage(language); + functions.forEach(function -> function.setLanguage(language)); + fileService.create(file); + } catch (Exception ex) { + log.error("", ex); + } + } +} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/HttpClient.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/HttpClient.java new file mode 100644 index 00000000..e6027f98 --- /dev/null +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/HttpClient.java @@ -0,0 +1,65 @@ +package usi.si.seart.crawler.component; + +import com.google.api.client.http.GenericUrl; +import com.google.api.client.http.HttpRequest; +import com.google.api.client.http.HttpRequestFactory; +import com.google.api.client.http.HttpResponse; +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.SneakyThrows; +import lombok.experimental.FieldDefaults; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import usi.si.seart.crawler.dto.SearchResultDto; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +@Component +@AllArgsConstructor(onConstructor_ = @Autowired) +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +public class HttpClient { + + Gson gson; + Pattern headerLinkPattern; + HttpRequestFactory requestFactory; + + @SneakyThrows(IOException.class) + public HttpResponse getRequest(GenericUrl url) { + HttpRequest request = requestFactory.buildGetRequest(url); + return request.execute(); + } + + @SneakyThrows(IOException.class) + public List getSearchResults(HttpResponse response) { + String responseString = response.parseAsString(); + JsonObject searchResult = gson.fromJson(responseString, JsonObject.class); + JsonArray items = searchResult.get("items").getAsJsonArray(); + return StreamSupport.stream(items.spliterator(), false) + .map(item -> gson.fromJson(item, SearchResultDto.class)) + .collect(Collectors.toList()); + } + + public Map getNavigationLinks(HttpResponse response){ + String xLinkSearch = response.getHeaders().getFirstHeaderStringValue("x-link-search"); + Map links = new HashMap<>(); + Matcher matcher = headerLinkPattern.matcher(xLinkSearch); + + while (matcher.find()) { + String rel = matcher.group(2); + String link = matcher.group(1); + links.put(rel, link); + } + + return links; + } +} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/ConverterConfig.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/ConverterConfig.java new file mode 100644 index 00000000..2b75cfe6 --- /dev/null +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/ConverterConfig.java @@ -0,0 +1,29 @@ +package usi.si.seart.crawler.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.support.ConversionServiceFactoryBean; +import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.converter.Converter; +import usi.si.seart.crawler.converter.DateToLocalDateTimeConverter; +import usi.si.seart.crawler.converter.SearchResultDtoToGitRepoConverter; + +import java.util.Set; + +@Configuration +public class ConverterConfig { + + @Bean + public ConversionService conversionService(){ + ConversionServiceFactoryBean factory = new ConversionServiceFactoryBean(); + DateToLocalDateTimeConverter dateToLocalDateTime = new DateToLocalDateTimeConverter(); + SearchResultDtoToGitRepoConverter searchResultToGitRepo = new SearchResultDtoToGitRepoConverter(dateToLocalDateTime); + Set> converters = Set.of( + dateToLocalDateTime, + searchResultToGitRepo + ); + factory.setConverters(converters); + factory.afterPropertiesSet(); + return factory.getObject(); + } +} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/CrawlerConfig.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/CrawlerConfig.java new file mode 100644 index 00000000..cd3f4ee7 --- /dev/null +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/CrawlerConfig.java @@ -0,0 +1,34 @@ +package usi.si.seart.crawler.config; + +import com.google.api.client.http.GenericUrl; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import usi.si.seart.model.job.Job; + +import java.time.Duration; +import java.time.LocalDateTime; + +@Configuration +public class CrawlerConfig { + + @Bean + public Duration nextRunDelay(@Value("${app.crawl-job.next-run-delay}") String value) { + return Duration.parse(value); + } + + @Bean + public GenericUrl baseUrl(@Value("${app.crawl-job.url}") String url) { + return new GenericUrl(url); + } + + @Bean + public Job jobType(@Value("${app.crawl-job.type}") String name) { + return Job.valueOf(name); + } + + @Bean + public LocalDateTime defaultStartDateTime(@Value("${app.crawl-job.start-date-time}") String value) { + return LocalDateTime.parse(value); + } +} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/HttpConfig.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/HttpConfig.java new file mode 100644 index 00000000..906b9e04 --- /dev/null +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/HttpConfig.java @@ -0,0 +1,83 @@ +package usi.si.seart.crawler.config; + +import com.google.api.client.http.HttpIOExceptionHandler; +import com.google.api.client.http.HttpRequestFactory; +import com.google.api.client.http.HttpRequestInitializer; +import com.google.api.client.http.javanet.NetHttpTransport; +import com.google.api.client.util.BackOff; +import com.google.api.client.util.BackOffUtils; +import com.google.api.client.util.ExponentialBackOff; +import com.google.api.client.util.Sleeper; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.regex.Pattern; + +@Configuration +public class HttpConfig { + + /** + * @return pattern for matching Link header values of various REST API responses. + * + * @see Regex definition visualisation + */ + @Bean + public Pattern headerLinkPattern() { + return Pattern.compile("<([^>]+)>;\\s?rel=\"(\\w+)\""); + } + + @Bean + public Gson gson() { + return new GsonBuilder() + .setDateFormat("yyyy-MM-dd'T'HH:mm:ss") + .create(); + } + + @Bean + public BackOff backOff() { + return new ExponentialBackOff(); + } + + @Bean + public Sleeper sleeper() { + return Sleeper.DEFAULT; + } + + @Bean + public HttpIOExceptionHandler ioExceptionHandler() { + return (request, supportsRetry) -> { + if (!supportsRetry) { + return false; + } + + try { + return BackOffUtils.next(sleeper(), backOff()); + } catch (InterruptedException exception) { + Thread.currentThread().interrupt(); + return false; + } + }; + } + + @Bean + public HttpRequestInitializer requestInitializer() { + return request -> { + int timeout = 60_000; + request.setReadTimeout(timeout); + request.setConnectTimeout(timeout); + request.setIOExceptionHandler(ioExceptionHandler()); + }; + } + + @Bean + public NetHttpTransport netHttpTransport() { + return new NetHttpTransport(); + } + + @Bean + public HttpRequestFactory requestFactory() { + return netHttpTransport().createRequestFactory(requestInitializer()); + } +} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/JpaConfig.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/JpaConfig.java new file mode 100644 index 00000000..ff6c1fa2 --- /dev/null +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/JpaConfig.java @@ -0,0 +1,9 @@ +package usi.si.seart.crawler.config; + +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EntityScan(basePackages = "usi.si.seart.model") +public class JpaConfig { +} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/SchedulerConfig.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/SchedulerConfig.java new file mode 100644 index 00000000..9a2454b1 --- /dev/null +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/SchedulerConfig.java @@ -0,0 +1,11 @@ +package usi.si.seart.crawler.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.annotation.EnableScheduling; + +@Configuration +@EnableAsync +@EnableScheduling +public class SchedulerConfig { +} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/converter/DateToLocalDateTimeConverter.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/converter/DateToLocalDateTimeConverter.java new file mode 100644 index 00000000..84378879 --- /dev/null +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/converter/DateToLocalDateTimeConverter.java @@ -0,0 +1,15 @@ +package usi.si.seart.crawler.converter; + +import org.springframework.core.convert.converter.Converter; + +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.Date; + +public class DateToLocalDateTimeConverter implements Converter { + + @Override + public LocalDateTime convert(Date source) { + return source.toInstant().atZone(ZoneOffset.UTC).toLocalDateTime(); + } +} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/converter/SearchResultDtoToGitRepoConverter.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/converter/SearchResultDtoToGitRepoConverter.java new file mode 100644 index 00000000..8e7d25e8 --- /dev/null +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/converter/SearchResultDtoToGitRepoConverter.java @@ -0,0 +1,38 @@ +package usi.si.seart.crawler.converter; + +import lombok.AllArgsConstructor; +import org.springframework.core.convert.converter.Converter; +import usi.si.seart.crawler.dto.SearchResultDto; +import usi.si.seart.model.GitRepo; + +import java.util.Date; + +@AllArgsConstructor +public class SearchResultDtoToGitRepoConverter implements Converter { + + DateToLocalDateTimeConverter dateToLocalDateTimeConverter; + + @Override + public GitRepo convert(SearchResultDto source) { + GitRepo.GitRepoBuilder builder = GitRepo.builder(); + + builder.name(source.getName()); + builder.license(source.getLicense()); + builder.isFork(source.getIsFork()); + + Long commits = source.getCommits(); + if (commits != null) builder.commits(commits); + Long contributors = source.getContributors(); + if (contributors != null) builder.contributors(contributors); + Long issues = source.getTotalIssues(); + if (issues != null) builder.issues(issues); + Long stars = source.getStargazers(); + if (stars != null) builder.stars(stars); + Date lastCommit = source.getLastCommit(); + if (lastCommit != null) builder.lastCommit(dateToLocalDateTimeConverter.convert(lastCommit)); + String lastCommitSHA = source.getLastCommitSHA(); + if (lastCommitSHA != null) builder.lastCommitSHA(lastCommitSHA); + + return builder.build(); + } +} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/http/payload/GhsGitRepo.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/dto/SearchResultDto.java similarity index 76% rename from dl4se-crawler/src/main/java/usi/si/seart/http/payload/GhsGitRepo.java rename to dl4se-crawler/src/main/java/usi/si/seart/crawler/dto/SearchResultDto.java index b0a03bde..a373db2c 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/http/payload/GhsGitRepo.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/dto/SearchResultDto.java @@ -1,4 +1,4 @@ -package usi.si.seart.http.payload; +package usi.si.seart.crawler.dto; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -10,6 +10,7 @@ import java.util.Date; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -18,7 +19,8 @@ @NoArgsConstructor @AllArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE) -public class GhsGitRepo { +public class SearchResultDto { + Long id; String name; Boolean isFork; @@ -41,12 +43,17 @@ public class GhsGitRepo { Long openIssues; Long totalPullRequests; Long openPullRequests; + Long blankLines; + Long codeLines; + Long commentLines; + List metrics; Date lastCommit; String lastCommitSHA; Boolean hasWiki; Boolean isArchived; Map languages; Set labels; + Set topics; public Set getRepoLanguages() { Set repoLanguages = new HashSet<>(); @@ -62,4 +69,16 @@ public void update(GitRepo repo) { if (totalIssues != null) repo.setIssues(totalIssues); if (stargazers != null) repo.setStars(stargazers); } + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + @FieldDefaults(level = AccessLevel.PRIVATE) + public static class MetricDto { + String language; + Long blankLines; + Long codeLines; + Long commentLines; + } } diff --git a/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/git/Git.java similarity index 94% rename from dl4se-crawler/src/main/java/usi/si/seart/git/Git.java rename to dl4se-crawler/src/main/java/usi/si/seart/crawler/git/Git.java index ccba04a2..0e8b3e31 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/git/Git.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/git/Git.java @@ -1,15 +1,17 @@ -package usi.si.seart.git; +package usi.si.seart.crawler.git; import com.google.common.collect.ObjectArrays; +import com.google.common.io.CharStreams; import lombok.AccessLevel; import lombok.Getter; import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; -import usi.si.seart.converter.InputStreamToString; import usi.si.seart.model.Language; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; import java.nio.file.Path; import java.time.Instant; import java.time.LocalDateTime; @@ -123,10 +125,6 @@ public Git.Commit getLastCommitInfo() throws GitException { /** * Class used to represent a Git commit. - * - * @implNote I used a dedicated class here as opposed to a {@link usi.si.seart.collection.Tuple Tuple} to allow for - * extensibility in the future. Given that we use {@code git log} we can extract all other kinds of information, - * such as the commit title, message, information about the author etc. */ @Getter @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) @@ -138,8 +136,7 @@ private Commit() throws GitException { Process process = executeGitCommand("log", "-1", "--format=%H%n%at"); checkFailure(process); - InputStream inputStream = process.getInputStream(); - String output = InputStreamToString.getConverter().convert(inputStream); + String output = stringifyInputStream(process.getInputStream()); List outputLines = output.lines().collect(Collectors.toList()); this.sha = outputLines.get(0); Instant lastUpdateInstant = Instant.ofEpochSecond(Integer.parseInt(outputLines.get(1))); @@ -276,8 +273,7 @@ private Diff(String startSHA, String endSHA, String... extensions) throws GitExc private void processOutput(Process process) throws GitException { checkFailure(process); - InputStream inputStream = process.getInputStream(); - String output = InputStreamToString.getConverter().convert(inputStream); + String output = stringifyInputStream(process.getInputStream()); output.lines().forEach(line -> { Consumer consumer; char status = line.charAt(0); @@ -315,8 +311,7 @@ public String toString() { private void checkFailure(Process process) throws GitException { if (process.exitValue() != 0){ - InputStream errorStream = process.getErrorStream(); - String errorMessage = InputStreamToString.getConverter().convert(errorStream); + String errorMessage = stringifyInputStream(process.getErrorStream()); throw new GitException("Operation failed for ["+name+"]:\n" + errorMessage); } } @@ -334,6 +329,13 @@ private Process executeGitCommand(String... args) { return process; } + @SneakyThrows(IOException.class) + public String stringifyInputStream(InputStream source) { + try (Reader reader = new InputStreamReader(source)) { + return CharStreams.toString(reader); + } + } + @Override @SneakyThrows(InterruptedException.class) public void close() throws IOException { diff --git a/dl4se-crawler/src/main/java/usi/si/seart/git/GitException.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/git/GitException.java similarity index 77% rename from dl4se-crawler/src/main/java/usi/si/seart/git/GitException.java rename to dl4se-crawler/src/main/java/usi/si/seart/crawler/git/GitException.java index 094e32a5..e6e4294c 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/git/GitException.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/git/GitException.java @@ -1,4 +1,4 @@ -package usi.si.seart.git; +package usi.si.seart.crawler.git; import lombok.experimental.StandardException; diff --git a/dl4se-crawler/src/main/java/usi/si/seart/io/ExtensionBasedFileVisitor.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/io/ExtensionBasedFileVisitor.java similarity index 99% rename from dl4se-crawler/src/main/java/usi/si/seart/io/ExtensionBasedFileVisitor.java rename to dl4se-crawler/src/main/java/usi/si/seart/crawler/io/ExtensionBasedFileVisitor.java index d76f9fe3..7fbd0d27 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/io/ExtensionBasedFileVisitor.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/io/ExtensionBasedFileVisitor.java @@ -1,4 +1,4 @@ -package usi.si.seart.io; +package usi.si.seart.crawler.io; import lombok.AccessLevel; import lombok.Getter; diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/CrawlJobRepository.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/CrawlJobRepository.java new file mode 100644 index 00000000..bfa02c4e --- /dev/null +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/CrawlJobRepository.java @@ -0,0 +1,13 @@ +package usi.si.seart.crawler.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import usi.si.seart.model.job.CrawlJob; +import usi.si.seart.model.job.Job; + +import javax.validation.constraints.NotNull; +import java.util.Optional; + +public interface CrawlJobRepository extends JpaRepository { + + Optional findByJobType(@NotNull Job jobType); +} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/FileRepository.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/FileRepository.java new file mode 100644 index 00000000..3b6a25ba --- /dev/null +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/FileRepository.java @@ -0,0 +1,17 @@ +package usi.si.seart.crawler.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import usi.si.seart.model.GitRepo; +import usi.si.seart.model.code.File; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.List; +import java.util.Optional; + +public interface FileRepository extends JpaRepository { + + List findAllByRepo(@NotNull GitRepo repo); + + Optional findByRepoAndPath(@NotNull GitRepo repo, @NotBlank String path); +} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/GitRepoRepository.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/GitRepoRepository.java new file mode 100644 index 00000000..11576076 --- /dev/null +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/GitRepoRepository.java @@ -0,0 +1,20 @@ +package usi.si.seart.crawler.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import usi.si.seart.model.GitRepo; + +import javax.validation.constraints.NotNull; +import java.util.Optional; + +public interface GitRepoRepository extends JpaRepository, JpaSpecificationExecutor { + + @Query( + "SELECT r FROM GitRepo r " + + "LEFT JOIN FETCH r.languages " + + "WHERE lower(r.name) = lower(:name)" + ) + Optional findByNameIgnoreCaseFetchLanguages(@NotNull @Param("name") String name); +} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/LanguageRepository.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/LanguageRepository.java new file mode 100644 index 00000000..e0887d72 --- /dev/null +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/LanguageRepository.java @@ -0,0 +1,7 @@ +package usi.si.seart.crawler.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import usi.si.seart.model.Language; + +public interface LanguageRepository extends JpaRepository { +} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/CrawlJobService.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/CrawlJobService.java new file mode 100644 index 00000000..16a9dfae --- /dev/null +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/CrawlJobService.java @@ -0,0 +1,46 @@ +package usi.si.seart.crawler.service; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.experimental.FieldDefaults; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import usi.si.seart.crawler.repository.CrawlJobRepository; +import usi.si.seart.model.job.CrawlJob; +import usi.si.seart.model.job.Job; + +import java.time.LocalDateTime; +import java.util.Optional; + +public interface CrawlJobService { + + CrawlJob getProgress(); + void saveProgress(LocalDateTime checkpoint); + + @Service + @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) + @AllArgsConstructor(onConstructor_ = @Autowired) + class CrawlJobServiceImpl implements CrawlJobService { + + CrawlJobRepository crawlJobRepository; + + Job jobType; + + @Override + @Transactional + public CrawlJob getProgress() { + Optional optional = crawlJobRepository.findByJobType(jobType); + return optional.orElseThrow(IllegalStateException::new); + } + + @Override + @Transactional + public void saveProgress(LocalDateTime checkpoint) { + Optional optional = crawlJobRepository.findByJobType(jobType); + CrawlJob crawlJob = optional.orElseThrow(IllegalStateException::new); + crawlJob.setCheckpoint(checkpoint); + crawlJobRepository.save(crawlJob); + } + } +} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/FileService.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/FileService.java new file mode 100644 index 00000000..eaa0e95c --- /dev/null +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/FileService.java @@ -0,0 +1,60 @@ +package usi.si.seart.crawler.service; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.experimental.FieldDefaults; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import usi.si.seart.crawler.repository.FileRepository; +import usi.si.seart.model.GitRepo; +import usi.si.seart.model.code.File; + +import javax.persistence.EntityNotFoundException; +import java.nio.file.Path; +import java.util.List; +import java.util.Optional; + +public interface FileService { + + List getAllByRepo(GitRepo gitRepo); + File create(File file); + void delete(GitRepo gitRepo, Path path); + void rename(GitRepo gitRepo, Path oldPath, Path newPath); + + @Service + @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) + @AllArgsConstructor(onConstructor_ = @Autowired) + class FileServiceImpl implements FileService { + + FileRepository fileRepository; + + @Override + public List getAllByRepo(GitRepo gitRepo) { + return fileRepository.findAllByRepo(gitRepo); + } + + @Override + @Transactional + public File create(File file) { + return fileRepository.save(file); + } + + @Override + @Transactional + public void delete(GitRepo gitRepo, Path path) { + Optional optional = fileRepository.findByRepoAndPath(gitRepo, path.toString()); + File file = optional.orElseThrow(EntityNotFoundException::new); + fileRepository.delete(file); + } + + @Override + @Transactional + public void rename(GitRepo gitRepo, Path oldPath, Path newPath) { + Optional optional = fileRepository.findByRepoAndPath(gitRepo, oldPath.toString()); + File file = optional.orElseThrow(EntityNotFoundException::new); + file.setPath(newPath.toString()); + fileRepository.save(file); + } + } +} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/GitRepoService.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/GitRepoService.java new file mode 100644 index 00000000..771be2f9 --- /dev/null +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/GitRepoService.java @@ -0,0 +1,37 @@ +package usi.si.seart.crawler.service; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.experimental.FieldDefaults; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import usi.si.seart.crawler.repository.GitRepoRepository; +import usi.si.seart.model.GitRepo; + +import javax.persistence.EntityNotFoundException; + +public interface GitRepoService { + + GitRepo getByName(String name); + GitRepo createOrUpdate(GitRepo gitRepo); + + @Service + @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) + @AllArgsConstructor(onConstructor_ = @Autowired) + class GitRepoServiceImpl implements GitRepoService { + + GitRepoRepository gitRepoRepository; + + @Override + public GitRepo getByName(String name) { + return gitRepoRepository.findByNameIgnoreCaseFetchLanguages(name).orElseThrow(EntityNotFoundException::new); + } + + @Override + @Transactional + public GitRepo createOrUpdate(GitRepo gitRepo) { + return gitRepoRepository.save(gitRepo); + } + } +} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/LanguageService.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/LanguageService.java new file mode 100644 index 00000000..2f0e597c --- /dev/null +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/LanguageService.java @@ -0,0 +1,29 @@ +package usi.si.seart.crawler.service; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.experimental.FieldDefaults; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import usi.si.seart.crawler.repository.LanguageRepository; +import usi.si.seart.model.Language; + +import java.util.List; + +public interface LanguageService { + + List getAll(); + + @Service + @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) + @AllArgsConstructor(onConstructor_ = @Autowired) + class LanguageServiceImpl implements LanguageService { + + LanguageRepository languageRepository; + + @Override + public List getAll() { + return languageRepository.findAll(); + } + } +} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/http/HttpClient.java b/dl4se-crawler/src/main/java/usi/si/seart/http/HttpClient.java deleted file mode 100644 index 1d0c2ad5..00000000 --- a/dl4se-crawler/src/main/java/usi/si/seart/http/HttpClient.java +++ /dev/null @@ -1,106 +0,0 @@ -package usi.si.seart.http; - -import com.google.api.client.http.GenericUrl; -import com.google.api.client.http.HttpIOExceptionHandler; -import com.google.api.client.http.HttpRequest; -import com.google.api.client.http.HttpRequestFactory; -import com.google.api.client.http.HttpRequestInitializer; -import com.google.api.client.http.HttpResponse; -import com.google.api.client.http.HttpTransport; -import com.google.api.client.http.javanet.NetHttpTransport; -import com.google.api.client.util.BackOff; -import com.google.api.client.util.BackOffUtils; -import com.google.api.client.util.ExponentialBackOff; -import com.google.api.client.util.Sleeper; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import lombok.SneakyThrows; -import usi.si.seart.http.payload.GhsGitRepo; - -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; - -public class HttpClient { - - private static final class RetryHandler implements HttpIOExceptionHandler { - - BackOff backOff = new ExponentialBackOff(); - Sleeper sleeper = Sleeper.DEFAULT; - - @Override - public boolean handleIOException(HttpRequest request, boolean supportsRetry) throws IOException { - if (!supportsRetry) { - return false; - } - - try { - return BackOffUtils.next(sleeper, backOff); - } catch (InterruptedException exception) { - Thread.currentThread().interrupt(); - return false; - } - } - } - - private static final class RequestInitializer implements HttpRequestInitializer { - - private static final int TIMEOUT = 60_000; - - @Override - public void initialize(HttpRequest request) { - request.setReadTimeout(TIMEOUT); - request.setConnectTimeout(TIMEOUT); - request.setIOExceptionHandler(new RetryHandler()); - } - } - - private static final HttpTransport transport = new NetHttpTransport(); - private static final HttpRequestInitializer requestInitializer = new RequestInitializer(); - private static final HttpRequestFactory requestFactory = transport.createRequestFactory(requestInitializer); - private static final Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss").create(); - - @SneakyThrows(IOException.class) - public HttpResponse getRequest(GenericUrl url) { - HttpRequest request = requestFactory.buildGetRequest(url); - return request.execute(); - } - - @SneakyThrows(IOException.class) - public List getSearchResults(HttpResponse response) { - String responseString = response.parseAsString(); - JsonObject searchResult = gson.fromJson(responseString, JsonObject.class); - JsonArray items = searchResult.get("items").getAsJsonArray(); - return StreamSupport.stream(items.spliterator(), false) - .map(item -> gson.fromJson(item, GhsGitRepo.class)) - .collect(Collectors.toList()); - } - - /** - * Pattern for matching Link header values of various REST API responses. - * - * @see Regex definition visualisation - */ - private static final Pattern HEADER_LINK = Pattern.compile("<([^>]+)>;\\s?rel=\"(\\w+)\""); - - public Map getNavigationLinks(HttpResponse response){ - String xLinkSearch = response.getHeaders().getFirstHeaderStringValue("x-link-search"); - Map links = new HashMap<>(); - Matcher matcher = HEADER_LINK.matcher(xLinkSearch); - - while (matcher.find()) { - String rel = matcher.group(2); - String link = matcher.group(1); - links.put(rel, link); - } - - return links; - } -} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/io/PropertiesReader.java b/dl4se-crawler/src/main/java/usi/si/seart/io/PropertiesReader.java deleted file mode 100644 index 68d70412..00000000 --- a/dl4se-crawler/src/main/java/usi/si/seart/io/PropertiesReader.java +++ /dev/null @@ -1,81 +0,0 @@ -package usi.si.seart.io; - -import lombok.AccessLevel; -import lombok.SneakyThrows; -import lombok.experimental.FieldDefaults; - -import java.io.InputStream; -import java.util.Properties; -import java.util.function.Function; -import java.util.function.UnaryOperator; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Class used for reading {@code Properties} files. It has the added benefit of being able to resolve references to - * other file properties, system properties and environment variables, with the resolution precedence maintaining the - * aforementioned order. The property values themselves remain preserved as they were written in the file, with the - * resolution taking place once {@link #getProperty} is called. Only ${...} is supported for property - * referencing. Nested resolution (i.e. ${...${...}...}) is not supported. - * - * @author dabico - * @see System#getProperty(String) System.getProperty - * @see System#getenv(String) System.getenv - * @see Properties - * @see Matcher - * @see Pattern Definition - */ -@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) -public class PropertiesReader { - - static Pattern referencePattern = Pattern.compile("\\$\\{([^}]+)\\}"); - - Properties properties; - Function resolver; - - @SneakyThrows - public PropertiesReader(String fileName) { - this.properties = new Properties(); - InputStream is = getClass().getClassLoader().getResourceAsStream(fileName); - this.properties.load(is); - - UnaryOperator resolver1 = resolver(this.properties::getProperty); - UnaryOperator resolver2 = resolver(System::getProperty); - UnaryOperator resolver3 = resolver(System::getenv); - resolver = resolver1.andThen(resolver2).andThen(resolver3); - } - - /** - * Searches for the property with the specified key in this property list, performing resolutions if the property - * value contains references to other properties or variables. The method returns null if the property is not found. - * - * @param key The property key. - * @return The resolved property value. - */ - public String getProperty(String key) { - String value = this.properties.getProperty(key); - if (value != null) return resolver.apply(value); - else return null; - } - - private UnaryOperator resolver(UnaryOperator mapper) { - return str -> { - Matcher matcher = referencePattern.matcher(str); - - if (str.matches(".*"+referencePattern.pattern()+".*")) { - StringBuilder builder = new StringBuilder(); - - while (matcher.find()) { - String name = matcher.group(1); - String value = mapper.apply(name); - if (value != null) matcher.appendReplacement(builder, Matcher.quoteReplacement(value)); - } - - matcher.appendTail(builder); - return builder.toString(); - } - - return str; - }; - } -} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/utils/HibernateUtils.java b/dl4se-crawler/src/main/java/usi/si/seart/utils/HibernateUtils.java deleted file mode 100644 index f361cc80..00000000 --- a/dl4se-crawler/src/main/java/usi/si/seart/utils/HibernateUtils.java +++ /dev/null @@ -1,166 +0,0 @@ -package usi.si.seart.utils; - -import lombok.experimental.UtilityClass; -import lombok.extern.slf4j.Slf4j; -import org.hibernate.Hibernate; -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.hibernate.Transaction; -import org.hibernate.cfg.Configuration; -import usi.si.seart.CrawlerProperties; -import usi.si.seart.model.GitRepo; -import usi.si.seart.model.Language; -import usi.si.seart.model.code.File; -import usi.si.seart.model.job.CrawlJob; -import usi.si.seart.model.job.Job; - -import javax.persistence.PersistenceException; -import java.nio.file.Path; -import java.time.LocalDateTime; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -@Slf4j -@UtilityClass -@SuppressWarnings("TryFinallyCanBeTryWithResources") -public class HibernateUtils { - - private static final SessionFactory factory = new Configuration().configure().buildSessionFactory(); - - public CrawlJob getLastJob() { - try (Session session = factory.openSession()) { - Optional lastJobOptional = session.createQuery( - "SELECT c FROM CrawlJob c WHERE c.jobType = usi.si.seart.model.job.Job.CODE", CrawlJob.class - ).uniqueResultOptional(); - - if (lastJobOptional.isPresent()) { - CrawlJob lastJob = lastJobOptional.get(); - session.evict(lastJob); - return lastJob; - } else { - CrawlJob startJob = CrawlJob.builder() - .checkpoint(CrawlerProperties.startDate.atStartOfDay()) - .jobType(Job.CODE) - .build(); - save(startJob); - return getLastJob(); - } - } - } - - public Set getLanguages() { - try (Session session = factory.openSession()) { - return session.createQuery("SELECT l FROM Language l", Language.class) - .stream() - .collect(Collectors.toSet()); - } - } - - public Optional getRepoByName(String name) { - try (Session session = factory.openSession()) { - Optional result = session.createQuery("SELECT r FROM GitRepo r WHERE r.name = :name", GitRepo.class) - .setParameter("name", name) - .uniqueResultOptional(); - return result.map(repo -> { - Hibernate.initialize(repo.getLanguages()); - return repo; - }); - } - } - - public void save(CrawlJob crawlJob) { - saveOrUpdate(crawlJob); - } - - public void save(GitRepo repo) { - saveOrUpdate(repo); - } - - public void save(File file) { - saveOrUpdate(file); - } - - private void saveOrUpdate(Object obj) { - Session session = factory.openSession(); - Transaction transaction = null; - try { - transaction = session.beginTransaction(); - session.saveOrUpdate(obj); - session.flush(); - transaction.commit(); - } catch (PersistenceException ex) { - log.error("Error while persisting: " + obj.getClass().getName(), ex); - if (transaction != null) transaction.rollback(); - } finally { - session.close(); - } - } - - public Set getFilesByRepo(Long id) { - try (Session session = factory.openSession()) { - return session.createQuery("SELECT f FROM File f WHERE repo.id = :id", File.class) - .setParameter("id", id) - .stream() - .collect(Collectors.toSet()); - } - } - - public void deleteFileByRepoIdAndPath(Long id, Path path) { - Session session = factory.openSession(); - Transaction transaction = null; - try { - transaction = session.beginTransaction(); - session.createQuery("DELETE FROM File WHERE repo.id = :id AND path = :path") - .setParameter("id", id) - .setParameter("path", path.toString()) - .executeUpdate(); - session.flush(); - transaction.commit(); - } catch (PersistenceException ex) { - log.error("Exception occurred while deleting File[repo.id="+id+", path="+path+"]!", ex); - if (transaction != null) transaction.rollback(); - } finally { - session.close(); - } - } - - public void updateFilePathByRepoId(Long id, Path before, Path after) { - Session session = factory.openSession(); - Transaction transaction = null; - try { - transaction = session.beginTransaction(); - session.createQuery("UPDATE File SET path = :after WHERE repo.id = :id AND path = :before") - .setParameter("id", id) - .setParameter("before", before.toString()) - .setParameter("after", after.toString()) - .executeUpdate(); - session.flush(); - transaction.commit(); - } catch (PersistenceException ex) { - log.error("Exception occurred while updating File[repo.id="+id+", path="+before+"]!", ex); - if (transaction != null) transaction.rollback(); - } finally { - session.close(); - } - } - - public void updateCrawlJobById(Long id, LocalDateTime checkpoint) { - Session session = factory.openSession(); - Transaction transaction = null; - try { - transaction = session.beginTransaction(); - session.createQuery("UPDATE CrawlJob SET checkpoint = :checkpoint WHERE id = :id") - .setParameter("id", id) - .setParameter("checkpoint", checkpoint) - .executeUpdate(); - session.flush(); - transaction.commit(); - } catch (PersistenceException ex) { - log.error("Exception occurred while updating CrawlJob[id="+id+"]!", ex); - if (transaction != null) transaction.rollback(); - } finally { - session.close(); - } - } -} diff --git a/dl4se-crawler/src/main/resources/application.properties b/dl4se-crawler/src/main/resources/application.properties new file mode 100644 index 00000000..717ad600 --- /dev/null +++ b/dl4se-crawler/src/main/resources/application.properties @@ -0,0 +1,41 @@ +# Spring Configuration +spring.application.name=@project.name@ + +# Banner Configuration +spring.banner.location=classpath:banner.txt + +# Main Method Configuration +spring.main.web-application-type=none + +# Scheduler Configuration +spring.task.scheduling.thread-name-prefix=crawler- +spring.task.scheduling.pool.size=1 + +# Logging Configuration +logging.level.root=INFO +logging.level.usi.si.seart.crawler=INFO +logging.file.name=logs/crawler.log +logging.logback.rollingpolicy.max-history=180 +logging.logback.rollingpolicy.max-file-size=100MB +logging.logback.rollingpolicy.total-size-cap=5GB + +# JPA Configuration +spring.jpa.database=postgresql +spring.jpa.open-in-view=false +spring.jpa.hibernate.ddl-auto=none +spring.jpa.properties.hibernate.jdbc.time_zone=UTC +spring.jpa.properties.hibernate.jdbc.fetch_size=500 +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL95Dialect + +# Spring Datasource Configuration +spring.datasource.url=jdbc:postgresql://${DATABASE_HOST:localhost}:${DATABASE_PORT:5432}/${DATABASE_NAME:dl4se} +spring.datasource.username=${DATABASE_USER:dl4se_admin} +spring.datasource.password=${DATABASE_PASS:Lugano2022} +spring.datasource.driver-class-name=org.postgresql.Driver + +# Application Configuration +app.general.tmp-dir-prefix=crawler- +app.crawl-job.next-run-delay=PT6H +app.crawl-job.url=${CRAWLER_URL:https://seart-ghs.si.usi.ch/api/r/search} +app.crawl-job.start-date-time=2008-01-01T00:00:00.00 +app.crawl-job.type=${CRAWLER_JOB:CODE} diff --git a/dl4se-crawler/src/main/resources/banner.txt b/dl4se-crawler/src/main/resources/banner.txt new file mode 100644 index 00000000..2ab86e69 --- /dev/null +++ b/dl4se-crawler/src/main/resources/banner.txt @@ -0,0 +1,14 @@ +MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMo +MMMMMMMMMMMMNy/-.``.-/smMMMMMMs-----------oMMo oo +o++++oo+:. `ooooooosoooooo+ +MMMMMMMMMMMs` .+yhhyo:` yMMMMM+ /ssssssssdMMo +soo y+ `-oh- -m +MMMMMMMMMMd .NMMMMMMMNmMMMMMM+ yMMMMMMMMMMMo .d h- y+ :m` -m +MMMMMMMMMMd .NMMMMMMMMMMMMMMM+ yMMMMMMMMMMMo h- .d` y+ `N. -m +MMMMMMMMMMMo `/ydMMMMMMMMMMMM+ yMMMMMMMMMMMo oo +s y+ oh -m +MMMMMMMMMMMMNs:` .:odMMMMMMM+ .-------mMMMo -d h: yo.....-:+s+ -m +MMMMMMMMMMMMMMMMmhs/. .yMMMMM+ /sssssssNMMMo `d- .d` yy/////mo` -m +MMMMMMMMMMMMMMMMMMMMMd. hMMMM+ yMMMMMMMMMMMo ss........sy y+ `d+ -m +MMMMMMMMMMMMMMMMMMMMMM+ +MMMM+ yMMMMMMMMMMMo :d//////////h/ y+ `ys -m +MMMMMMMMMMNsmMMMMMMMMm. hMMMM+ yMMMMMMMMMMMo `d. .m. y+ sh` -m +MMMMMMMMMN/ ./osyso: .hMMMMM+ :oooooooooMMo y+ +h y+ +d. -m +MMMMMMMMMMMNyo:-...-/ohMMMMMMMs////////////MMo .o o- +: :o` .o +MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMo diff --git a/dl4se-crawler/src/main/resources/hibernate.cfg.xml b/dl4se-crawler/src/main/resources/hibernate.cfg.xml deleted file mode 100644 index b0935a65..00000000 --- a/dl4se-crawler/src/main/resources/hibernate.cfg.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - org.postgresql.Driver - jdbc:postgresql://${DATABASE_HOST}:${DATABASE_PORT}/${DATABASE_NAME} - ${DATABASE_USER} - ${DATABASE_PASS} - - - 1 - - - org.hibernate.dialect.PostgreSQL95Dialect - - - org.hibernate.cache.internal.DisabledCaching - - - false - false - false - - - none - - - - - - - - - - \ No newline at end of file diff --git a/dl4se-crawler/src/main/resources/hibernate.properties b/dl4se-crawler/src/main/resources/hibernate.properties deleted file mode 100644 index a22fe63c..00000000 --- a/dl4se-crawler/src/main/resources/hibernate.properties +++ /dev/null @@ -1 +0,0 @@ -hibernate.types.print.banner=false \ No newline at end of file diff --git a/dl4se-crawler/src/main/resources/logback.xml b/dl4se-crawler/src/main/resources/logback.xml deleted file mode 100644 index ee72e983..00000000 --- a/dl4se-crawler/src/main/resources/logback.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - System.out - - INFO - ACCEPT - DENY - - - ${LOG_CONSOLE_PATTERN} - - - - - System.err - - WARN - - - - logger.startsWith("usi.si.seart") - - DENY - ACCEPT - - - ${LOG_CONSOLE_PATTERN} - - - - - ${LOG_FILE_PATH} - true - true - - ${LOG_FILE_ARCHIVE} - ${LOG_FILE_SIZE} - ${LOG_FILE_MAX_HISTORY} - - - DEBUG - - - - logger.startsWith("usi.si.seart") - - ACCEPT - DENY - - - ${LOG_FILE_PATTERN} - - - - - - - - - \ No newline at end of file diff --git a/dl4se-crawler/src/main/resources/properties.txt b/dl4se-crawler/src/main/resources/properties.txt deleted file mode 100644 index 6a461ce4..00000000 --- a/dl4se-crawler/src/main/resources/properties.txt +++ /dev/null @@ -1,3 +0,0 @@ -app.general.tmpDirPrefix=dl4se -app.crawl.startDate=2008-01-01 -app.crawl.ghs.searchUrl=${CODE_SEARCH_URL} diff --git a/dl4se-crawler/src/test/java/usi/si/seart/git/GitTest.java b/dl4se-crawler/src/test/java/usi/si/seart/git/GitTest.java index 82892c01..6a5533c1 100644 --- a/dl4se-crawler/src/test/java/usi/si/seart/git/GitTest.java +++ b/dl4se-crawler/src/test/java/usi/si/seart/git/GitTest.java @@ -9,6 +9,8 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EmptySource; import org.junit.jupiter.params.provider.ValueSource; +import usi.si.seart.crawler.git.Git; +import usi.si.seart.crawler.git.GitException; import usi.si.seart.model.Language; import java.io.File; diff --git a/dl4se-crawler/src/test/java/usi/si/seart/io/ExtensionBasedFileVisitorTest.java b/dl4se-crawler/src/test/java/usi/si/seart/io/ExtensionBasedFileVisitorTest.java index 71ae5302..6c5ed085 100644 --- a/dl4se-crawler/src/test/java/usi/si/seart/io/ExtensionBasedFileVisitorTest.java +++ b/dl4se-crawler/src/test/java/usi/si/seart/io/ExtensionBasedFileVisitorTest.java @@ -8,6 +8,7 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.ArgumentsProvider; import org.junit.jupiter.params.provider.ArgumentsSource; +import usi.si.seart.crawler.io.ExtensionBasedFileVisitor; import java.io.IOException; import java.nio.file.Files; diff --git a/dl4se-crawler/src/test/java/usi/si/seart/io/PropertiesReaderTest.java b/dl4se-crawler/src/test/java/usi/si/seart/io/PropertiesReaderTest.java deleted file mode 100644 index 33771139..00000000 --- a/dl4se-crawler/src/test/java/usi/si/seart/io/PropertiesReaderTest.java +++ /dev/null @@ -1,56 +0,0 @@ -package usi.si.seart.io; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import java.util.List; -import java.util.stream.Collectors; - -class PropertiesReaderTest { - - PropertiesReader propertiesReader = new PropertiesReader("reader.properties"); - - static String user = System.getenv("DB_USER"); - static String pass = System.getProperty("db.password"); - static String srvr = System.getenv("DB_SERVER"); - static String port = System.getenv("DB_PORT"); - - @Test - void getPropertyTest() { - - Assertions.assertNull(propertiesReader.getProperty("app.property.nonexistant")); - - List expected = List.of( - "", - "dl4se_properties", - "this is a test for the properties parsing", - "2022-01-01", - user, - pass, - "jdbc:postgresql://"+srvr+"/"+port, - "dl4se_properties", - "The "+user+" is testing dl4se_properties with "+pass - ); - - List properties = List.of( - "app.property.empty", - "app.property.name", - "app.property.description", - "app.property.date", - "app.property.db.user", - "app.property.db.password", - "app.property.db.url", - "app.property.name.copy", - "app.property.multiple" - ); - - List actual = properties.stream() - .map(propertiesReader::getProperty) - .collect(Collectors.toList()); - - Assertions.assertEquals(expected.size(), actual.size()); - for (int i = 0; i < actual.size(); i++) { - Assertions.assertEquals(expected.get(i), actual.get(i)); - } - } -} \ No newline at end of file diff --git a/dl4se-crawler/src/test/resources/code/java/AbstractClass.java b/dl4se-crawler/src/test/resources/code/java/AbstractClass.java deleted file mode 100644 index 0fb5545e..00000000 --- a/dl4se-crawler/src/test/resources/code/java/AbstractClass.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.example; - -public abstract class Shape { - public abstract double getArea(); -} \ No newline at end of file diff --git a/dl4se-crawler/src/test/resources/code/java/Boilerplate.java b/dl4se-crawler/src/test/resources/code/java/Boilerplate.java deleted file mode 100644 index 25e97c2c..00000000 --- a/dl4se-crawler/src/test/resources/code/java/Boilerplate.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.example; - -public class Boilerplate { - String key; - String value; - - Boilerplate(final String key, final String value) { - this.key = key; - this.value = value; - } - - public static Boilerplate.BoilerplateBuilder builder() { - return new Boilerplate.BoilerplateBuilder(); - } - - public String getKey() { - return this.key; - } - - public String getValue() { - return this.value; - } - - public void setKey(final String key) { - this.key = key; - } - - public void setValue(final String value) { - this.value = value; - } - - public static class BoilerplateBuilder { - private String key; - private String value; - - BoilerplateBuilder() { - } - - public Boilerplate.BoilerplateBuilder key(final String key) { - this.key = key; - return this; - } - - public Boilerplate.BoilerplateBuilder id(final String value) { - this.value = value; - return this; - } - - public Boilerplate build() { - return new Boilerplate(this.key, this.value); - } - } -} \ No newline at end of file diff --git a/dl4se-crawler/src/test/resources/code/java/Class.java b/dl4se-crawler/src/test/resources/code/java/Class.java deleted file mode 100644 index d0f60031..00000000 --- a/dl4se-crawler/src/test/resources/code/java/Class.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.example; - -class Circle { - - private static final double PI = 3.14159; - private double radius; - - public Circle() { - radius = 0.0; - } - - public Circle(double r) { - radius = r; - } - - public void setRadius(double r) { - radius = r; - } - - public double getRadius() { - return radius; - } - - public double getArea() { - return PI * radius * radius; - } -} \ No newline at end of file diff --git a/dl4se-crawler/src/test/resources/code/java/Enum.java b/dl4se-crawler/src/test/resources/code/java/Enum.java deleted file mode 100644 index 1e5711a6..00000000 --- a/dl4se-crawler/src/test/resources/code/java/Enum.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.example; - -public enum Enum { - ONE, TWO, THREE, FOUR -} \ No newline at end of file diff --git a/dl4se-crawler/src/test/resources/code/java/InnerClass.java b/dl4se-crawler/src/test/resources/code/java/InnerClass.java deleted file mode 100644 index f928d838..00000000 --- a/dl4se-crawler/src/test/resources/code/java/InnerClass.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.example; - -public class DataStructure { - - private final static int SIZE = 15; - private int[] arrayOfInts = new int[SIZE]; - - public DataStructure() { - for (int i = 0; i < SIZE; i++) { - arrayOfInts[i] = i; - } - } - - public void printEven() { - DataStructureIterator iterator = this.new EvenIterator(); - while (iterator.hasNext()) { - System.out.print(iterator.next() + " "); - } - System.out.println(); - } - - interface DataStructureIterator extends java.util.Iterator { } - - private class EvenIterator implements DataStructureIterator { - private int nextIndex = 0; - - public boolean hasNext() { - return (nextIndex <= SIZE - 1); - } - - public Integer next() { - Integer retValue = Integer.valueOf(arrayOfInts[nextIndex]); - nextIndex += 2; - return retValue; - } - } -} \ No newline at end of file diff --git a/dl4se-crawler/src/test/resources/code/java/Interface.java b/dl4se-crawler/src/test/resources/code/java/Interface.java deleted file mode 100644 index b2fc0240..00000000 --- a/dl4se-crawler/src/test/resources/code/java/Interface.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.example; - -public interface Closeable { - public void close(); -} \ No newline at end of file diff --git a/dl4se-crawler/src/test/resources/code/java/MainClass.java b/dl4se-crawler/src/test/resources/code/java/MainClass.java deleted file mode 100644 index 8fe27fa0..00000000 --- a/dl4se-crawler/src/test/resources/code/java/MainClass.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.example; - -public class App { - public static void main(String[] args) { - System.out.println("Hello World!"); - } -} \ No newline at end of file diff --git a/dl4se-crawler/src/test/resources/code/java/TestClass.java b/dl4se-crawler/src/test/resources/code/java/TestClass.java deleted file mode 100644 index 5c26b11b..00000000 --- a/dl4se-crawler/src/test/resources/code/java/TestClass.java +++ /dev/null @@ -1,17 +0,0 @@ -package usi.si.seart.utils; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -public class TestClass { - - @Test - public void testMax() { - Assertions.assertEquals(5, Math.max(3, 5)); - } - - @Test - public void minTest() { - Assertions.assertEquals(3, Math.min(3, 5)); - } -} diff --git a/dl4se-crawler/src/test/resources/code/other/DCL.md b/dl4se-crawler/src/test/resources/code/other/DCL.md deleted file mode 100644 index 171ce530..00000000 --- a/dl4se-crawler/src/test/resources/code/other/DCL.md +++ /dev/null @@ -1,29 +0,0 @@ -## Explain the concept of a class loader. How could one use a class loader to load and execute bytecode that is generated on the fly. - -The class loader is itself a class used for dynamically loading classes from compiled class files into a Java program. - - ---- - -## Explain when class loading happens - -Class loading is lazily executed at runtime by virtue of a class loader. - ---- - -## Explain how to load multiple identically named classes - -Due to the fact that each class type is a tuple of the class name and the defining class loader, it is possible to have multiple namespaces in a Java program (each corresponding to its own dedicated class loader). - ---- - -## Explain how to unload a class - -To unload a class in a Java program, the variables containing: - -- The `ClassLoader` instance -- The loaded `Class` metadata instance -- Instance of the class itself - -Need to be set to `null`. -After that, the garbage collector can safely unload the class. \ No newline at end of file diff --git a/dl4se-crawler/src/test/resources/code/other/LICENSE b/dl4se-crawler/src/test/resources/code/other/LICENSE deleted file mode 100644 index 753c49bf..00000000 --- a/dl4se-crawler/src/test/resources/code/other/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021 Ozren Dabić - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/dl4se-crawler/src/test/resources/code/other/representation.pdf b/dl4se-crawler/src/test/resources/code/other/representation.pdf deleted file mode 100644 index 4c41082e6ce78fa15c605d0512253c3e7ad6384f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 278280 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 List[str]: - def split_camel_case(s: str): - return sub('([A-Z][a-z]+)', r' \1', sub('([A-Z]+)', r' \1', s)).split() - - stage_1 = text.split("_") - stage_2 = chain.from_iterable([split_camel_case(word) for word in stage_1]) - stage_3 = [word.lower() for word in stage_2] - stage_4 = [text.translate(str.maketrans('', '', punctuation)) for text in stage_3] - stage_5 = [word for word in stage_4 if word not in SearchEngine._stopwords] - return stage_5 - - def __to_bow__(self, tokens: List[str]) -> List[Tuple[Number, Number]]: - return self._dictionary.doc2bow(tokens) - - def __top_n__(self, similarities: Iterable[float]) -> DataFrame: - sorted_idx_sim_pairs = sorted(enumerate(similarities), key=lambda x: x[1], reverse=True) - top_n_idx_sim_pairs = sorted_idx_sim_pairs[:self._n] - top_n_idx = [idx_sim_pair[0] for idx_sim_pair in top_n_idx_sim_pairs] - result = self._data.loc[top_n_idx][SearchEngine._ret_cols] - return result - - def freq_query(self, query: str) -> DataFrame: - query_tokens = SearchEngine.__normalize_text__(query) - query_bow = self.__to_bow__(query_tokens) - sims = self._freq_index[query_bow] - return self.__top_n__(sims) - - def tfidf_query(self, query: str) -> DataFrame: - query_tokens = SearchEngine.__normalize_text__(query) - query_bow = self.__to_bow__(query_tokens) - sims = self._tfidf_index[self._tfidf[query_bow]] - return self.__top_n__(sims) - - def lsi_query(self, query: str) -> DataFrame: - query_tokens = SearchEngine.__normalize_text__(query) - query_bow = self.__to_bow__(query_tokens) - sims = abs(self._lsi_index[self._lsi[query_bow]]) - return self.__top_n__(sims) - - def doc2vec_query(self, query: str) -> DataFrame: - query_tokens = SearchEngine.__normalize_text__(query) - inferred = self._d2v.infer_vector(query_tokens) - top_n_idx_sim_pairs = self._d2v.dv.most_similar([inferred], topn=self._n) - top_n_idx = [idx_sim_pair[0] for idx_sim_pair in top_n_idx_sim_pairs] - result = self._data.loc[top_n_idx][SearchEngine._ret_cols] - return result - - def query(self, embedding: Embeddings, query: str) -> DataFrame: - if embedding == Embeddings.FREQ: - return self.freq_query(query) - elif embedding == Embeddings.TFIDF: - return self.tfidf_query(query) - elif embedding == Embeddings.LSI: - return self.lsi_query(query) - elif embedding == Embeddings.D2V: - return self.doc2vec_query(query) - else: - raise ValueError(f"Specified embedding not supported: {embedding}") - - def lsi_infer_query(self, query: str) -> List[float]: - query_tokens = SearchEngine.__normalize_text__(query) - query_bow = self.__to_bow__(query_tokens) - return [tup[1] for tup in self._lsi[query_bow]] - - def doc2vec_infer_query(self, query: str) -> Iterable: - query_tokens = SearchEngine.__normalize_text__(query) - return self._d2v.infer_vector(query_tokens) - - def lsi_corpus_vector(self, idx: int) -> List[float]: - return [tup[1] for tup in self._corpus_lsi[idx]] - - def doc2vec_vector(self, document: List[str]) -> Iterable: - return self._d2v.infer_vector(document) diff --git a/dl4se-crawler/src/test/resources/code/python/search-data.py b/dl4se-crawler/src/test/resources/code/python/search-data.py deleted file mode 100644 index 83a29a90..00000000 --- a/dl4se-crawler/src/test/resources/code/python/search-data.py +++ /dev/null @@ -1,17 +0,0 @@ -# !/usr/bin/env python - -from sys import argv -from pandas import read_csv -from se import SearchEngine, Embeddings -from utils import print_table - - -if __name__ == '__main__': - data = read_csv("./data.csv", keep_default_na=False) - se = SearchEngine(data) - query = argv[1] - print(f"Showing results for \"{query}\":\n") - for embedding in Embeddings: - print(f"{embedding}:") - result = se.query(embedding, query) - print_table(result) diff --git a/dl4se-crawler/src/test/resources/code/python/visitor.py b/dl4se-crawler/src/test/resources/code/python/visitor.py deleted file mode 100644 index aefc3fdc..00000000 --- a/dl4se-crawler/src/test/resources/code/python/visitor.py +++ /dev/null @@ -1,57 +0,0 @@ -from typing import Any -from re import split -from ast import get_docstring -from ast import NodeVisitor, ClassDef, FunctionDef -from utils import empty_df - - -class VoidVisitor(NodeVisitor): - """ - As the name suggests, this visitor class does not return anything. - All visited class and function nodes of a target python file are stored in its DataFrame structure. - """ - - def __init__(self): - self.df = empty_df() - - @staticmethod - def __normalize_whitespace__(text: str) -> str: - """ - Normalizes multiple consecutive instances of all whitespace types - (space, newline and carriage return) into a single space character. - """ - return " ".join(text.split()) - - @staticmethod - def __valid_name__(name: str) -> bool: - """ - Checks if a name string does not adhere to blacklist specifications. - """ - lower = name.lower() - return lower != "main" and "test" not in lower and not lower.startswith("_") - - def __visit__(self, node, mode: str) -> Any: - """ - Generic visit function. - """ - name = node.name - line = node.lineno - comment = get_docstring(node) - if comment: - comment = split(r"\n\n", comment)[0] - comment = VoidVisitor.__normalize_whitespace__(comment) - if VoidVisitor.__valid_name__(name): - self.df = self.df.append({ - "name": name, - "line": line, - "type": mode, - "comment": comment - }, ignore_index=True) - - def visit_ClassDef(self, node: ClassDef) -> Any: - self.__visit__(node, "class") - for method in [method for method in node.body if isinstance(method, FunctionDef)]: - self.__visit__(method, "method") - - def visit_FunctionDef(self, node: FunctionDef) -> Any: - self.__visit__(node, "function") diff --git a/dl4se-crawler/src/test/resources/logback-test.xml b/dl4se-crawler/src/test/resources/logback-test.xml deleted file mode 100644 index 0b3c831c..00000000 --- a/dl4se-crawler/src/test/resources/logback-test.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - System.out - - DEBUG - ACCEPT - DENY - - - [%d{yyyy-MM-dd HH:mm:ss.SSS}] [%level] [%thread] %logger{10} %msg%n - - - - System.err - - ERROR - ACCEPT - DENY - - - [%d{yyyy-MM-dd HH:mm:ss.SSS}] [%level] [%thread] %logger{10} [%file:%line] %msg%n - - - - - - - \ No newline at end of file diff --git a/dl4se-crawler/src/test/resources/reader.properties b/dl4se-crawler/src/test/resources/reader.properties deleted file mode 100644 index 107da739..00000000 --- a/dl4se-crawler/src/test/resources/reader.properties +++ /dev/null @@ -1,9 +0,0 @@ -app.property.empty= -app.property.name=dl4se_properties -app.property.description=this is a test for the properties parsing -app.property.date=2022-01-01 -app.property.db.user=${DB_USER} -app.property.db.password=${db.password} -app.property.db.url=jdbc:postgresql://${DB_SERVER}/${DB_PORT} -app.property.name.copy=${app.property.name} -app.property.multiple=The ${DB_USER} is testing ${app.property.name} with ${db.password} From 5f7415c1c68de381fb2182c3a62146f0e4382996 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 6 Jul 2023 15:26:38 +0200 Subject: [PATCH 0198/1089] Removing `jobType` bean declaration in favor of `@Value` injection --- .../seart/crawler/bean/CrawlJobInitializingBean.java | 5 +++++ .../usi/si/seart/crawler/config/CrawlerConfig.java | 6 ------ .../si/seart/crawler/service/CrawlJobService.java | 12 ++++++++---- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/CrawlJobInitializingBean.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/CrawlJobInitializingBean.java index 89db5bdc..ede22387 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/CrawlJobInitializingBean.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/CrawlJobInitializingBean.java @@ -3,8 +3,10 @@ import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import lombok.experimental.FieldDefaults; +import lombok.experimental.NonFinal; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import usi.si.seart.crawler.repository.CrawlJobRepository; import usi.si.seart.model.job.CrawlJob; @@ -18,7 +20,10 @@ @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class CrawlJobInitializingBean implements InitializingBean { + @NonFinal + @Value("${app.crawl-job.type}") Job jobType; + LocalDateTime defaultStartDateTime; CrawlJobRepository crawlJobRepository; diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/CrawlerConfig.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/CrawlerConfig.java index cd3f4ee7..2ea525d7 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/CrawlerConfig.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/CrawlerConfig.java @@ -4,7 +4,6 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import usi.si.seart.model.job.Job; import java.time.Duration; import java.time.LocalDateTime; @@ -22,11 +21,6 @@ public GenericUrl baseUrl(@Value("${app.crawl-job.url}") String url) { return new GenericUrl(url); } - @Bean - public Job jobType(@Value("${app.crawl-job.type}") String name) { - return Job.valueOf(name); - } - @Bean public LocalDateTime defaultStartDateTime(@Value("${app.crawl-job.start-date-time}") String value) { return LocalDateTime.parse(value); diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/CrawlJobService.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/CrawlJobService.java index 16a9dfae..34a158e5 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/CrawlJobService.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/CrawlJobService.java @@ -1,9 +1,11 @@ package usi.si.seart.crawler.service; import lombok.AccessLevel; -import lombok.AllArgsConstructor; +import lombok.RequiredArgsConstructor; import lombok.experimental.FieldDefaults; +import lombok.experimental.NonFinal; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import usi.si.seart.crawler.repository.CrawlJobRepository; @@ -20,13 +22,15 @@ public interface CrawlJobService { @Service @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) - @AllArgsConstructor(onConstructor_ = @Autowired) + @RequiredArgsConstructor(onConstructor_ = @Autowired) class CrawlJobServiceImpl implements CrawlJobService { - CrawlJobRepository crawlJobRepository; - + @NonFinal + @Value("${app.crawl-job.type}") Job jobType; + CrawlJobRepository crawlJobRepository; + @Override @Transactional public CrawlJob getProgress() { From c7d38deadf1fcdde364a8e4779163350908274ec Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 6 Jul 2023 16:35:13 +0200 Subject: [PATCH 0199/1089] Removing MS precision for `start-date-time` --- dl4se-crawler/src/main/resources/application.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dl4se-crawler/src/main/resources/application.properties b/dl4se-crawler/src/main/resources/application.properties index 717ad600..dfc68f89 100644 --- a/dl4se-crawler/src/main/resources/application.properties +++ b/dl4se-crawler/src/main/resources/application.properties @@ -37,5 +37,5 @@ spring.datasource.driver-class-name=org.postgresql.Driver app.general.tmp-dir-prefix=crawler- app.crawl-job.next-run-delay=PT6H app.crawl-job.url=${CRAWLER_URL:https://seart-ghs.si.usi.ch/api/r/search} -app.crawl-job.start-date-time=2008-01-01T00:00:00.00 +app.crawl-job.start-date-time=2008-01-01T00:00:00 app.crawl-job.type=${CRAWLER_JOB:CODE} From 731811bde6c288b59d6cb17485e98dcf46e47dea Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 6 Jul 2023 16:38:14 +0200 Subject: [PATCH 0200/1089] As of 4.23.0 "Hub de-commissioned and de-coupled from operations" Will not be updated in docker-compose at this moment since we are using 4.9, but we will do so later. --- liquibase/migrate.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/liquibase/migrate.sh b/liquibase/migrate.sh index eb2487e0..5cf0f368 100755 --- a/liquibase/migrate.sh +++ b/liquibase/migrate.sh @@ -5,5 +5,4 @@ liquibase \ --password="$DATABASE_PASS" \ --url="jdbc:postgresql://$DATABASE_HOST:$DATABASE_PORT/$DATABASE_NAME" \ --changeLogFile="liquibase/changelog.xml" \ - --hub-mode=off \ update \ No newline at end of file From b4ba61cd9cb530ac97506ba6194bf975cbac6bec Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 7 Jul 2023 14:28:04 +0200 Subject: [PATCH 0201/1089] Changing `Validator` init in tests to avoid adding `javax.el` --- .../seart/validation/constraints/AllNullOrNotNullTest.java | 6 +++++- .../si/seart/validation/constraints/NullOrNotBlankTest.java | 6 +++++- .../si/seart/validation/constraints/NullOrRangeTest.java | 6 +++++- .../usi/si/seart/validation/constraints/OWASPEmailTest.java | 6 +++++- .../usi/si/seart/validation/constraints/PasswordTest.java | 6 +++++- 5 files changed, 25 insertions(+), 5 deletions(-) diff --git a/dl4se-model/src/test/java/usi/si/seart/validation/constraints/AllNullOrNotNullTest.java b/dl4se-model/src/test/java/usi/si/seart/validation/constraints/AllNullOrNotNullTest.java index 9859ac5b..d0072761 100644 --- a/dl4se-model/src/test/java/usi/si/seart/validation/constraints/AllNullOrNotNullTest.java +++ b/dl4se-model/src/test/java/usi/si/seart/validation/constraints/AllNullOrNotNullTest.java @@ -4,6 +4,7 @@ import lombok.AllArgsConstructor; import lombok.Cleanup; import lombok.experimental.FieldDefaults; +import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; @@ -21,7 +22,10 @@ class AllNullOrNotNullTest { @BeforeAll static void setUp() { - @Cleanup ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); + @Cleanup ValidatorFactory factory = Validation.byDefaultProvider() + .configure() + .messageInterpolator(new ParameterMessageInterpolator()) + .buildValidatorFactory(); validator = factory.getValidator(); } diff --git a/dl4se-model/src/test/java/usi/si/seart/validation/constraints/NullOrNotBlankTest.java b/dl4se-model/src/test/java/usi/si/seart/validation/constraints/NullOrNotBlankTest.java index 98a69fd7..e0733a4b 100644 --- a/dl4se-model/src/test/java/usi/si/seart/validation/constraints/NullOrNotBlankTest.java +++ b/dl4se-model/src/test/java/usi/si/seart/validation/constraints/NullOrNotBlankTest.java @@ -2,6 +2,7 @@ import lombok.AllArgsConstructor; import lombok.Cleanup; +import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; @@ -21,7 +22,10 @@ class NullOrNotBlankTest { @BeforeAll static void setUp() { - @Cleanup ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); + @Cleanup ValidatorFactory factory = Validation.byDefaultProvider() + .configure() + .messageInterpolator(new ParameterMessageInterpolator()) + .buildValidatorFactory(); validator = factory.getValidator(); } diff --git a/dl4se-model/src/test/java/usi/si/seart/validation/constraints/NullOrRangeTest.java b/dl4se-model/src/test/java/usi/si/seart/validation/constraints/NullOrRangeTest.java index 96ae5e2a..2d282ed7 100644 --- a/dl4se-model/src/test/java/usi/si/seart/validation/constraints/NullOrRangeTest.java +++ b/dl4se-model/src/test/java/usi/si/seart/validation/constraints/NullOrRangeTest.java @@ -2,6 +2,7 @@ import lombok.AllArgsConstructor; import lombok.Cleanup; +import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; @@ -22,7 +23,10 @@ class NullOrRangeTest { @BeforeAll static void setUp() { - @Cleanup ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); + @Cleanup ValidatorFactory factory = Validation.byDefaultProvider() + .configure() + .messageInterpolator(new ParameterMessageInterpolator()) + .buildValidatorFactory(); validator = factory.getValidator(); } diff --git a/dl4se-model/src/test/java/usi/si/seart/validation/constraints/OWASPEmailTest.java b/dl4se-model/src/test/java/usi/si/seart/validation/constraints/OWASPEmailTest.java index ab853117..fe15f906 100644 --- a/dl4se-model/src/test/java/usi/si/seart/validation/constraints/OWASPEmailTest.java +++ b/dl4se-model/src/test/java/usi/si/seart/validation/constraints/OWASPEmailTest.java @@ -2,6 +2,7 @@ import lombok.AllArgsConstructor; import lombok.Cleanup; +import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; @@ -20,7 +21,10 @@ class OWASPEmailTest { @BeforeAll static void setUp() { - @Cleanup ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); + @Cleanup ValidatorFactory factory = Validation.byDefaultProvider() + .configure() + .messageInterpolator(new ParameterMessageInterpolator()) + .buildValidatorFactory(); validator = factory.getValidator(); } diff --git a/dl4se-model/src/test/java/usi/si/seart/validation/constraints/PasswordTest.java b/dl4se-model/src/test/java/usi/si/seart/validation/constraints/PasswordTest.java index b705d169..6c222720 100644 --- a/dl4se-model/src/test/java/usi/si/seart/validation/constraints/PasswordTest.java +++ b/dl4se-model/src/test/java/usi/si/seart/validation/constraints/PasswordTest.java @@ -2,6 +2,7 @@ import lombok.AllArgsConstructor; import lombok.Cleanup; +import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; @@ -20,7 +21,10 @@ class PasswordTest { @BeforeAll static void setUp() { - @Cleanup ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); + @Cleanup ValidatorFactory factory = Validation.byDefaultProvider() + .configure() + .messageInterpolator(new ParameterMessageInterpolator()) + .buildValidatorFactory(); validator = factory.getValidator(); } From 175cf08fb24cd62f45517868f0b891ba5ac45af1 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 7 Jul 2023 14:31:02 +0200 Subject: [PATCH 0202/1089] Reverting select changes form c1ab7d4409d0f7fc2e46c3cfefd8d24d2c5efe0c I thought these files were for testing the parsers that we no longer use, but they are in fact meant for the extension file visitor tests. Restoring. --- .../resources/code/java/AbstractClass.java | 5 + .../test/resources/code/java/Boilerplate.java | 53 +++++ .../src/test/resources/code/java/Class.java | 27 +++ .../src/test/resources/code/java/Enum.java | 5 + .../test/resources/code/java/InnerClass.java | 37 ++++ .../test/resources/code/java/Interface.java | 5 + .../test/resources/code/java/MainClass.java | 7 + .../test/resources/code/java/TestClass.java | 17 ++ .../src/test/resources/code/other/DCL.md | 29 +++ .../src/test/resources/code/other/LICENSE | 21 ++ .../resources/code/other/representation.pdf | Bin 0 -> 278280 bytes .../resources/code/other/requirements.txt | 7 + .../test/resources/code/python/__init__.py | 0 .../src/test/resources/code/python/se.py | 209 ++++++++++++++++++ .../test/resources/code/python/search-data.py | 17 ++ .../src/test/resources/code/python/visitor.py | 57 +++++ 16 files changed, 496 insertions(+) create mode 100644 dl4se-crawler/src/test/resources/code/java/AbstractClass.java create mode 100644 dl4se-crawler/src/test/resources/code/java/Boilerplate.java create mode 100644 dl4se-crawler/src/test/resources/code/java/Class.java create mode 100644 dl4se-crawler/src/test/resources/code/java/Enum.java create mode 100644 dl4se-crawler/src/test/resources/code/java/InnerClass.java create mode 100644 dl4se-crawler/src/test/resources/code/java/Interface.java create mode 100644 dl4se-crawler/src/test/resources/code/java/MainClass.java create mode 100644 dl4se-crawler/src/test/resources/code/java/TestClass.java create mode 100644 dl4se-crawler/src/test/resources/code/other/DCL.md create mode 100644 dl4se-crawler/src/test/resources/code/other/LICENSE create mode 100644 dl4se-crawler/src/test/resources/code/other/representation.pdf create mode 100644 dl4se-crawler/src/test/resources/code/other/requirements.txt create mode 100644 dl4se-crawler/src/test/resources/code/python/__init__.py create mode 100644 dl4se-crawler/src/test/resources/code/python/se.py create mode 100644 dl4se-crawler/src/test/resources/code/python/search-data.py create mode 100644 dl4se-crawler/src/test/resources/code/python/visitor.py diff --git a/dl4se-crawler/src/test/resources/code/java/AbstractClass.java b/dl4se-crawler/src/test/resources/code/java/AbstractClass.java new file mode 100644 index 00000000..0fb5545e --- /dev/null +++ b/dl4se-crawler/src/test/resources/code/java/AbstractClass.java @@ -0,0 +1,5 @@ +package org.example; + +public abstract class Shape { + public abstract double getArea(); +} \ No newline at end of file diff --git a/dl4se-crawler/src/test/resources/code/java/Boilerplate.java b/dl4se-crawler/src/test/resources/code/java/Boilerplate.java new file mode 100644 index 00000000..25e97c2c --- /dev/null +++ b/dl4se-crawler/src/test/resources/code/java/Boilerplate.java @@ -0,0 +1,53 @@ +package org.example; + +public class Boilerplate { + String key; + String value; + + Boilerplate(final String key, final String value) { + this.key = key; + this.value = value; + } + + public static Boilerplate.BoilerplateBuilder builder() { + return new Boilerplate.BoilerplateBuilder(); + } + + public String getKey() { + return this.key; + } + + public String getValue() { + return this.value; + } + + public void setKey(final String key) { + this.key = key; + } + + public void setValue(final String value) { + this.value = value; + } + + public static class BoilerplateBuilder { + private String key; + private String value; + + BoilerplateBuilder() { + } + + public Boilerplate.BoilerplateBuilder key(final String key) { + this.key = key; + return this; + } + + public Boilerplate.BoilerplateBuilder id(final String value) { + this.value = value; + return this; + } + + public Boilerplate build() { + return new Boilerplate(this.key, this.value); + } + } +} \ No newline at end of file diff --git a/dl4se-crawler/src/test/resources/code/java/Class.java b/dl4se-crawler/src/test/resources/code/java/Class.java new file mode 100644 index 00000000..d0f60031 --- /dev/null +++ b/dl4se-crawler/src/test/resources/code/java/Class.java @@ -0,0 +1,27 @@ +package org.example; + +class Circle { + + private static final double PI = 3.14159; + private double radius; + + public Circle() { + radius = 0.0; + } + + public Circle(double r) { + radius = r; + } + + public void setRadius(double r) { + radius = r; + } + + public double getRadius() { + return radius; + } + + public double getArea() { + return PI * radius * radius; + } +} \ No newline at end of file diff --git a/dl4se-crawler/src/test/resources/code/java/Enum.java b/dl4se-crawler/src/test/resources/code/java/Enum.java new file mode 100644 index 00000000..1e5711a6 --- /dev/null +++ b/dl4se-crawler/src/test/resources/code/java/Enum.java @@ -0,0 +1,5 @@ +package org.example; + +public enum Enum { + ONE, TWO, THREE, FOUR +} \ No newline at end of file diff --git a/dl4se-crawler/src/test/resources/code/java/InnerClass.java b/dl4se-crawler/src/test/resources/code/java/InnerClass.java new file mode 100644 index 00000000..f928d838 --- /dev/null +++ b/dl4se-crawler/src/test/resources/code/java/InnerClass.java @@ -0,0 +1,37 @@ +package org.example; + +public class DataStructure { + + private final static int SIZE = 15; + private int[] arrayOfInts = new int[SIZE]; + + public DataStructure() { + for (int i = 0; i < SIZE; i++) { + arrayOfInts[i] = i; + } + } + + public void printEven() { + DataStructureIterator iterator = this.new EvenIterator(); + while (iterator.hasNext()) { + System.out.print(iterator.next() + " "); + } + System.out.println(); + } + + interface DataStructureIterator extends java.util.Iterator { } + + private class EvenIterator implements DataStructureIterator { + private int nextIndex = 0; + + public boolean hasNext() { + return (nextIndex <= SIZE - 1); + } + + public Integer next() { + Integer retValue = Integer.valueOf(arrayOfInts[nextIndex]); + nextIndex += 2; + return retValue; + } + } +} \ No newline at end of file diff --git a/dl4se-crawler/src/test/resources/code/java/Interface.java b/dl4se-crawler/src/test/resources/code/java/Interface.java new file mode 100644 index 00000000..b2fc0240 --- /dev/null +++ b/dl4se-crawler/src/test/resources/code/java/Interface.java @@ -0,0 +1,5 @@ +package org.example; + +public interface Closeable { + public void close(); +} \ No newline at end of file diff --git a/dl4se-crawler/src/test/resources/code/java/MainClass.java b/dl4se-crawler/src/test/resources/code/java/MainClass.java new file mode 100644 index 00000000..8fe27fa0 --- /dev/null +++ b/dl4se-crawler/src/test/resources/code/java/MainClass.java @@ -0,0 +1,7 @@ +package org.example; + +public class App { + public static void main(String[] args) { + System.out.println("Hello World!"); + } +} \ No newline at end of file diff --git a/dl4se-crawler/src/test/resources/code/java/TestClass.java b/dl4se-crawler/src/test/resources/code/java/TestClass.java new file mode 100644 index 00000000..5c26b11b --- /dev/null +++ b/dl4se-crawler/src/test/resources/code/java/TestClass.java @@ -0,0 +1,17 @@ +package usi.si.seart.utils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class TestClass { + + @Test + public void testMax() { + Assertions.assertEquals(5, Math.max(3, 5)); + } + + @Test + public void minTest() { + Assertions.assertEquals(3, Math.min(3, 5)); + } +} diff --git a/dl4se-crawler/src/test/resources/code/other/DCL.md b/dl4se-crawler/src/test/resources/code/other/DCL.md new file mode 100644 index 00000000..171ce530 --- /dev/null +++ b/dl4se-crawler/src/test/resources/code/other/DCL.md @@ -0,0 +1,29 @@ +## Explain the concept of a class loader. How could one use a class loader to load and execute bytecode that is generated on the fly. + +The class loader is itself a class used for dynamically loading classes from compiled class files into a Java program. + + +--- + +## Explain when class loading happens + +Class loading is lazily executed at runtime by virtue of a class loader. + +--- + +## Explain how to load multiple identically named classes + +Due to the fact that each class type is a tuple of the class name and the defining class loader, it is possible to have multiple namespaces in a Java program (each corresponding to its own dedicated class loader). + +--- + +## Explain how to unload a class + +To unload a class in a Java program, the variables containing: + +- The `ClassLoader` instance +- The loaded `Class` metadata instance +- Instance of the class itself + +Need to be set to `null`. +After that, the garbage collector can safely unload the class. \ No newline at end of file diff --git a/dl4se-crawler/src/test/resources/code/other/LICENSE b/dl4se-crawler/src/test/resources/code/other/LICENSE new file mode 100644 index 00000000..753c49bf --- /dev/null +++ b/dl4se-crawler/src/test/resources/code/other/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Ozren Dabić + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dl4se-crawler/src/test/resources/code/other/representation.pdf b/dl4se-crawler/src/test/resources/code/other/representation.pdf new file mode 100644 index 0000000000000000000000000000000000000000..4c41082e6ce78fa15c605d0512253c3e7ad6384f GIT binary patch literal 278280 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 List[str]: + def split_camel_case(s: str): + return sub('([A-Z][a-z]+)', r' \1', sub('([A-Z]+)', r' \1', s)).split() + + stage_1 = text.split("_") + stage_2 = chain.from_iterable([split_camel_case(word) for word in stage_1]) + stage_3 = [word.lower() for word in stage_2] + stage_4 = [text.translate(str.maketrans('', '', punctuation)) for text in stage_3] + stage_5 = [word for word in stage_4 if word not in SearchEngine._stopwords] + return stage_5 + + def __to_bow__(self, tokens: List[str]) -> List[Tuple[Number, Number]]: + return self._dictionary.doc2bow(tokens) + + def __top_n__(self, similarities: Iterable[float]) -> DataFrame: + sorted_idx_sim_pairs = sorted(enumerate(similarities), key=lambda x: x[1], reverse=True) + top_n_idx_sim_pairs = sorted_idx_sim_pairs[:self._n] + top_n_idx = [idx_sim_pair[0] for idx_sim_pair in top_n_idx_sim_pairs] + result = self._data.loc[top_n_idx][SearchEngine._ret_cols] + return result + + def freq_query(self, query: str) -> DataFrame: + query_tokens = SearchEngine.__normalize_text__(query) + query_bow = self.__to_bow__(query_tokens) + sims = self._freq_index[query_bow] + return self.__top_n__(sims) + + def tfidf_query(self, query: str) -> DataFrame: + query_tokens = SearchEngine.__normalize_text__(query) + query_bow = self.__to_bow__(query_tokens) + sims = self._tfidf_index[self._tfidf[query_bow]] + return self.__top_n__(sims) + + def lsi_query(self, query: str) -> DataFrame: + query_tokens = SearchEngine.__normalize_text__(query) + query_bow = self.__to_bow__(query_tokens) + sims = abs(self._lsi_index[self._lsi[query_bow]]) + return self.__top_n__(sims) + + def doc2vec_query(self, query: str) -> DataFrame: + query_tokens = SearchEngine.__normalize_text__(query) + inferred = self._d2v.infer_vector(query_tokens) + top_n_idx_sim_pairs = self._d2v.dv.most_similar([inferred], topn=self._n) + top_n_idx = [idx_sim_pair[0] for idx_sim_pair in top_n_idx_sim_pairs] + result = self._data.loc[top_n_idx][SearchEngine._ret_cols] + return result + + def query(self, embedding: Embeddings, query: str) -> DataFrame: + if embedding == Embeddings.FREQ: + return self.freq_query(query) + elif embedding == Embeddings.TFIDF: + return self.tfidf_query(query) + elif embedding == Embeddings.LSI: + return self.lsi_query(query) + elif embedding == Embeddings.D2V: + return self.doc2vec_query(query) + else: + raise ValueError(f"Specified embedding not supported: {embedding}") + + def lsi_infer_query(self, query: str) -> List[float]: + query_tokens = SearchEngine.__normalize_text__(query) + query_bow = self.__to_bow__(query_tokens) + return [tup[1] for tup in self._lsi[query_bow]] + + def doc2vec_infer_query(self, query: str) -> Iterable: + query_tokens = SearchEngine.__normalize_text__(query) + return self._d2v.infer_vector(query_tokens) + + def lsi_corpus_vector(self, idx: int) -> List[float]: + return [tup[1] for tup in self._corpus_lsi[idx]] + + def doc2vec_vector(self, document: List[str]) -> Iterable: + return self._d2v.infer_vector(document) diff --git a/dl4se-crawler/src/test/resources/code/python/search-data.py b/dl4se-crawler/src/test/resources/code/python/search-data.py new file mode 100644 index 00000000..83a29a90 --- /dev/null +++ b/dl4se-crawler/src/test/resources/code/python/search-data.py @@ -0,0 +1,17 @@ +# !/usr/bin/env python + +from sys import argv +from pandas import read_csv +from se import SearchEngine, Embeddings +from utils import print_table + + +if __name__ == '__main__': + data = read_csv("./data.csv", keep_default_na=False) + se = SearchEngine(data) + query = argv[1] + print(f"Showing results for \"{query}\":\n") + for embedding in Embeddings: + print(f"{embedding}:") + result = se.query(embedding, query) + print_table(result) diff --git a/dl4se-crawler/src/test/resources/code/python/visitor.py b/dl4se-crawler/src/test/resources/code/python/visitor.py new file mode 100644 index 00000000..aefc3fdc --- /dev/null +++ b/dl4se-crawler/src/test/resources/code/python/visitor.py @@ -0,0 +1,57 @@ +from typing import Any +from re import split +from ast import get_docstring +from ast import NodeVisitor, ClassDef, FunctionDef +from utils import empty_df + + +class VoidVisitor(NodeVisitor): + """ + As the name suggests, this visitor class does not return anything. + All visited class and function nodes of a target python file are stored in its DataFrame structure. + """ + + def __init__(self): + self.df = empty_df() + + @staticmethod + def __normalize_whitespace__(text: str) -> str: + """ + Normalizes multiple consecutive instances of all whitespace types + (space, newline and carriage return) into a single space character. + """ + return " ".join(text.split()) + + @staticmethod + def __valid_name__(name: str) -> bool: + """ + Checks if a name string does not adhere to blacklist specifications. + """ + lower = name.lower() + return lower != "main" and "test" not in lower and not lower.startswith("_") + + def __visit__(self, node, mode: str) -> Any: + """ + Generic visit function. + """ + name = node.name + line = node.lineno + comment = get_docstring(node) + if comment: + comment = split(r"\n\n", comment)[0] + comment = VoidVisitor.__normalize_whitespace__(comment) + if VoidVisitor.__valid_name__(name): + self.df = self.df.append({ + "name": name, + "line": line, + "type": mode, + "comment": comment + }, ignore_index=True) + + def visit_ClassDef(self, node: ClassDef) -> Any: + self.__visit__(node, "class") + for method in [method for method in node.body if isinstance(method, FunctionDef)]: + self.__visit__(method, "method") + + def visit_FunctionDef(self, node: FunctionDef) -> Any: + self.__visit__(node, "function") From 82576a49e4e61e739b97ff198794b71ef6e0f392 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 7 Jul 2023 16:19:45 +0200 Subject: [PATCH 0203/1089] Removing holdover `surefire` config that is no longer used in tests --- dl4se-crawler/pom.xml | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/dl4se-crawler/pom.xml b/dl4se-crawler/pom.xml index 3bf91a42..c4ad4d60 100644 --- a/dl4se-crawler/pom.xml +++ b/dl4se-crawler/pom.xml @@ -69,19 +69,6 @@ - - maven-surefire-plugin - - - password123 - - - dabico - server.si.usi.ch - 12345 - - - maven-shade-plugin From e5702aac6823b56bc05b207ad8ea0e0ccebcf8bc Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 7 Jul 2023 16:20:12 +0200 Subject: [PATCH 0204/1089] Reverting the `exec` plugin which should never be used in favor of JARs --- dl4se-crawler/pom.xml | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/dl4se-crawler/pom.xml b/dl4se-crawler/pom.xml index c4ad4d60..4009d5a1 100644 --- a/dl4se-crawler/pom.xml +++ b/dl4se-crawler/pom.xml @@ -103,21 +103,6 @@
- - org.codehaus.mojo - exec-maven-plugin - 1.2.1 - - - - java - - - - - ${app.mainClass} - - From fe9768d45c28e5dc795dbda4e9d39ce180a8d7a0 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 7 Jul 2023 16:24:30 +0200 Subject: [PATCH 0205/1089] Updated main class property --- dl4se-crawler/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dl4se-crawler/pom.xml b/dl4se-crawler/pom.xml index 4009d5a1..41c59437 100644 --- a/dl4se-crawler/pom.xml +++ b/dl4se-crawler/pom.xml @@ -14,7 +14,7 @@ UTF-8 - usi.si.seart.Crawler + usi.si.seart.crawler.Application @@ -98,7 +98,7 @@ true - ${app.mainClass} + ${project.module.mainClass} From 43c59cb326bdf81e041a625bad34b26de5ac614e Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 7 Jul 2023 16:32:23 +0200 Subject: [PATCH 0206/1089] Updating crawler build Dockerfile --- deployment/crawler/Dockerfile | 19 +++++++++++-------- deployment/crawler/entrypoint.sh | 22 ---------------------- 2 files changed, 11 insertions(+), 30 deletions(-) delete mode 100644 deployment/crawler/entrypoint.sh diff --git a/deployment/crawler/Dockerfile b/deployment/crawler/Dockerfile index 4ccecb22..318cd17d 100644 --- a/deployment/crawler/Dockerfile +++ b/deployment/crawler/Dockerfile @@ -1,20 +1,23 @@ -FROM maven:3.8.4-jdk-11-slim AS build +FROM maven:3.9.3-eclipse-temurin-11-alpine AS build COPY ./pom.xml /pom.xml +COPY ./dl4se-analyzer /dl4se-analyzer COPY ./dl4se-crawler /dl4se-crawler COPY ./dl4se-model /dl4se-model COPY ./dl4se-server /dl4se-server COPY ./dl4se-src2abs /dl4se-src2abs -RUN mvn -e --no-transfer-progress clean package -pl dl4se-crawler -am -DskipTests +RUN mvn -e \ + --no-transfer-progress \ + clean \ + package \ + -pl dl4se-crawler \ + -am -DskipTests -FROM adoptopenjdk/openjdk11:jre-11.0.11_9-alpine +FROM eclipse-temurin:11.0.19_7-jre-alpine COPY --from=build /dl4se-crawler/target/dl4se-crawler-*.jar /crawler.jar -COPY ./deployment/crawler/entrypoint.sh ./ -RUN chmod 777 ./entrypoint.sh +RUN apk update --quiet && apk add --no-cache git libstdc++ -RUN apk update && apk add git - -ENTRYPOINT ["/entrypoint.sh"] \ No newline at end of file +ENTRYPOINT java -jar crawler.jar \ No newline at end of file diff --git a/deployment/crawler/entrypoint.sh b/deployment/crawler/entrypoint.sh deleted file mode 100644 index 0c482bcb..00000000 --- a/deployment/crawler/entrypoint.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env sh - -while : ; -do - java \ - -DDATABASE_HOST="$DATABASE_HOST" \ - -DDATABASE_NAME="$DATABASE_NAME" \ - -DDATABASE_PASS="$DATABASE_PASS" \ - -DDATABASE_PORT="$DATABASE_PORT" \ - -DDATABASE_USER="$DATABASE_USER" \ - -Dfile.encoding=UTF-8 \ - -jar crawler.jar - EXIT_CODE=$? - if [ $EXIT_CODE -eq 0 ] ;\ - then - echo "Restarting in 6 hours from now..." - sleep 21600 - else - echo "An error has occurred, exiting..." - exit $EXIT_CODE - fi -done \ No newline at end of file From 05d22319772a768bec21d81601cc397ef3d00967 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 7 Jul 2023 16:33:43 +0200 Subject: [PATCH 0207/1089] Updating `postgres` image version --- deployment/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment/docker-compose.yml b/deployment/docker-compose.yml index 88aa197b..e8940d90 100644 --- a/deployment/docker-compose.yml +++ b/deployment/docker-compose.yml @@ -4,7 +4,7 @@ services: dl4se-db: container_name: dl4se-db - image: postgres:14.2-alpine + image: postgres:15.3-alpine volumes: - data:/var/lib/postgresql/data networks: [ default ] From d3ab0ae488777ca86a8d72fe1c77cdae475ea953 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 7 Jul 2023 16:34:04 +0200 Subject: [PATCH 0208/1089] Updating `liquibase` image version --- deployment/docker-compose.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/deployment/docker-compose.yml b/deployment/docker-compose.yml index e8940d90..dfc78013 100644 --- a/deployment/docker-compose.yml +++ b/deployment/docker-compose.yml @@ -23,8 +23,13 @@ services: dl4se-liquibase: container_name: dl4se-liquibase - image: liquibase/liquibase:4.9 - command: --username=${DATABASE_USER} --password=${DATABASE_PASS} --url=jdbc:postgresql://dl4se-db:${DATABASE_PORT}/${DATABASE_NAME} --changeLogFile=changelog.xml --hub-mode=off update + image: liquibase/liquibase:4.23-alpine + command: + --username=${DATABASE_USER} + --password=${DATABASE_PASS} + --url=jdbc:postgresql://dl4se-db:${DATABASE_PORT}/${DATABASE_NAME} + --changeLogFile=changelog.xml + update volumes: - ../liquibase/changelog.xml:/liquibase/changelog.xml - ../liquibase/scripts/:/liquibase/scripts/ From 1acacd020a38db5d27229613969318fcffeca7af Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 7 Jul 2023 16:34:27 +0200 Subject: [PATCH 0209/1089] Updating compose version --- deployment/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment/docker-compose.yml b/deployment/docker-compose.yml index dfc78013..55175158 100644 --- a/deployment/docker-compose.yml +++ b/deployment/docker-compose.yml @@ -1,4 +1,4 @@ -version: '3.5' +version: '3.9' services: From 303a567f0e5ce83e2559294d03ab80355de1f9e0 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 10 Jul 2023 10:17:40 +0200 Subject: [PATCH 0210/1089] Removing useless setting from run configuration --- .idea/runConfigurations/Crawler.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.idea/runConfigurations/Crawler.xml b/.idea/runConfigurations/Crawler.xml index 3dca0b7e..7138e42a 100644 --- a/.idea/runConfigurations/Crawler.xml +++ b/.idea/runConfigurations/Crawler.xml @@ -4,9 +4,6 @@ - - - - - maven-shade-plugin - - - package - - shade - - - - - - - \ No newline at end of file + diff --git a/dl4se-model/pom.xml b/dl4se-model/pom.xml index 7f26ec0e..ff49e3e4 100644 --- a/dl4se-model/pom.xml +++ b/dl4se-model/pom.xml @@ -66,17 +66,6 @@ - - maven-shade-plugin - - - package - - shade - - - - org.codehaus.mojo build-helper-maven-plugin From f63f4a895a5848e622b250349cb2018c4a8011ad Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 11 Jul 2023 11:33:28 +0200 Subject: [PATCH 0215/1089] Bumping `java-tree-sitter` to apply the new patch --- dl4se-analyzer/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dl4se-analyzer/pom.xml b/dl4se-analyzer/pom.xml index 33ffad6d..75d587eb 100644 --- a/dl4se-analyzer/pom.xml +++ b/dl4se-analyzer/pom.xml @@ -25,7 +25,7 @@ ch.usi.si.seart java-tree-sitter - 1.0.0 + 1.0.1 From 42580f5d81c9ad8a3c5b7fef06f171a7d466e905 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 11 Jul 2023 11:34:04 +0200 Subject: [PATCH 0216/1089] Replacing the `jar` and `shade` plugins with `spring-boot-maven-plugin` --- dl4se-crawler/pom.xml | 33 +++++++-------------------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/dl4se-crawler/pom.xml b/dl4se-crawler/pom.xml index 41c59437..4f031618 100644 --- a/dl4se-crawler/pom.xml +++ b/dl4se-crawler/pom.xml @@ -70,39 +70,20 @@ - maven-shade-plugin + org.springframework.boot + spring-boot-maven-plugin + ${springframework.version} + + ${project.module.mainClass} + - package - shade + repackage - - - - *:* - - META-INF/*.SF - META-INF/*.DSA - META-INF/*.RSA - - - - - - maven-jar-plugin - - - - true - ${project.module.mainClass} - - - - From 4b5653d9d7e5d44829483b53ca706926c5fc52d5 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 11 Jul 2023 14:56:46 +0200 Subject: [PATCH 0217/1089] Added a basic default error handler to the Crawler scheduling config --- .../seart/crawler/config/SchedulerConfig.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/SchedulerConfig.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/SchedulerConfig.java index 9a2454b1..ae4f8e1f 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/SchedulerConfig.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/SchedulerConfig.java @@ -1,11 +1,29 @@ package usi.si.seart.crawler.config; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.task.TaskSchedulerCustomizer; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; +import org.springframework.util.ErrorHandler; @Configuration @EnableAsync @EnableScheduling -public class SchedulerConfig { +public class SchedulerConfig implements TaskSchedulerCustomizer { + + @Override + public void customize(ThreadPoolTaskScheduler taskScheduler) { + taskScheduler.setErrorHandler(new SchedulerErrorHandler()); + } + + @Slf4j + private static class SchedulerErrorHandler implements ErrorHandler { + + @Override + public void handleError(Throwable throwable) { + log.error("Unhandled exception occurred while performing a scheduled job.", throwable); + } + } } From 33c7da74db8df74925aa0cb015a0ada5711d2928 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 12 Jul 2023 09:21:41 +0200 Subject: [PATCH 0218/1089] Removed unused annotation --- .../main/java/usi/si/seart/crawler/config/SchedulerConfig.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/SchedulerConfig.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/SchedulerConfig.java index ae4f8e1f..184298b4 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/SchedulerConfig.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/SchedulerConfig.java @@ -3,13 +3,11 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.boot.task.TaskSchedulerCustomizer; import org.springframework.context.annotation.Configuration; -import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.util.ErrorHandler; @Configuration -@EnableAsync @EnableScheduling public class SchedulerConfig implements TaskSchedulerCustomizer { From 66fc470ae6cbb40368a6822b5af64fc08f95a2c7 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 12 Jul 2023 09:47:23 +0200 Subject: [PATCH 0219/1089] Do not mutate `baseUrl` --- .../main/java/usi/si/seart/crawler/component/CodeCrawler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java index 4829c061..a457e76c 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java @@ -91,7 +91,7 @@ private void postConstruct() { @Scheduled(fixedDelayString = "${app.crawl-job.next-run-delay}") public void run() { - GenericUrl url = baseUrl; + GenericUrl url = baseUrl.clone(); LocalDate checkpoint = crawlJobService.getProgress() .getCheckpoint() .toLocalDate(); From 50088e6fbfbb3d19c602f7f853cabcf4cb464275 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 12 Jul 2023 10:27:53 +0200 Subject: [PATCH 0220/1089] Updated condition expression --- .../java/usi/si/seart/crawler/component/CodeCrawler.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java index a457e76c..a00d5c69 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java @@ -12,7 +12,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.core.convert.ConversionService; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @@ -54,8 +54,9 @@ @Slf4j @Component -@ConditionalOnProperty(value = "app.crawl-job.type", havingValue = "CODE") -//@ConditionalOnExpression("#{jobType == T(usi.si.seart.model.job.Job).CODE}") +@ConditionalOnExpression( + "#{T(usi.si.seart.model.job.Job).valueOf('${app.crawl-job.type}') == T(usi.si.seart.model.job.Job).CODE}" +) @RequiredArgsConstructor(onConstructor_ = @Autowired) @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class CodeCrawler implements Runnable { From 0331c77bb5b683bfb41a6ab5061eb0edf84793c1 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 12 Jul 2023 14:12:22 +0200 Subject: [PATCH 0221/1089] Updated logging configuration to enforce better naming --- dl4se-crawler/src/main/resources/application.properties | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dl4se-crawler/src/main/resources/application.properties b/dl4se-crawler/src/main/resources/application.properties index dfc68f89..1ae7810c 100644 --- a/dl4se-crawler/src/main/resources/application.properties +++ b/dl4se-crawler/src/main/resources/application.properties @@ -14,10 +14,12 @@ spring.task.scheduling.pool.size=1 # Logging Configuration logging.level.root=INFO logging.level.usi.si.seart.crawler=INFO -logging.file.name=logs/crawler.log +logging.file.path=logs +logging.file.name=${logging.file.path}/crawler.log logging.logback.rollingpolicy.max-history=180 logging.logback.rollingpolicy.max-file-size=100MB logging.logback.rollingpolicy.total-size-cap=5GB +logging.logback.rollingpolicy.file-name-pattern=${logging.file.path}/crawler_%d{yyyy-MM-dd}_%i.log.gz # JPA Configuration spring.jpa.database=postgresql From 0e0c5d6c859d52befaf19f9e49f0e2e0271ac78d Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 12 Jul 2023 14:14:41 +0200 Subject: [PATCH 0222/1089] Adding back the Bean definition for `jobType` --- .../si/seart/crawler/bean/CrawlJobInitializingBean.java | 9 ++------- .../java/usi/si/seart/crawler/config/CrawlerConfig.java | 6 ++++++ .../usi/si/seart/crawler/service/CrawlJobService.java | 8 ++------ 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/CrawlJobInitializingBean.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/CrawlJobInitializingBean.java index ede22387..fcdd1a3f 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/CrawlJobInitializingBean.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/CrawlJobInitializingBean.java @@ -1,12 +1,10 @@ package usi.si.seart.crawler.bean; import lombok.AccessLevel; -import lombok.RequiredArgsConstructor; +import lombok.AllArgsConstructor; import lombok.experimental.FieldDefaults; -import lombok.experimental.NonFinal; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import usi.si.seart.crawler.repository.CrawlJobRepository; import usi.si.seart.model.job.CrawlJob; @@ -16,14 +14,11 @@ import java.util.Optional; @Component -@RequiredArgsConstructor(onConstructor_ = @Autowired) +@AllArgsConstructor(onConstructor_ = @Autowired) @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class CrawlJobInitializingBean implements InitializingBean { - @NonFinal - @Value("${app.crawl-job.type}") Job jobType; - LocalDateTime defaultStartDateTime; CrawlJobRepository crawlJobRepository; diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/CrawlerConfig.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/CrawlerConfig.java index 2ea525d7..dd76caec 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/CrawlerConfig.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/CrawlerConfig.java @@ -4,6 +4,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import usi.si.seart.model.job.Job; import java.time.Duration; import java.time.LocalDateTime; @@ -11,6 +12,11 @@ @Configuration public class CrawlerConfig { + @Bean + public Job jobType(@Value("${app.crawl-job.type}") Job jobType) { + return jobType; + } + @Bean public Duration nextRunDelay(@Value("${app.crawl-job.next-run-delay}") String value) { return Duration.parse(value); diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/CrawlJobService.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/CrawlJobService.java index 34a158e5..10924c11 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/CrawlJobService.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/CrawlJobService.java @@ -1,11 +1,9 @@ package usi.si.seart.crawler.service; import lombok.AccessLevel; -import lombok.RequiredArgsConstructor; +import lombok.AllArgsConstructor; import lombok.experimental.FieldDefaults; -import lombok.experimental.NonFinal; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import usi.si.seart.crawler.repository.CrawlJobRepository; @@ -22,11 +20,9 @@ public interface CrawlJobService { @Service @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) - @RequiredArgsConstructor(onConstructor_ = @Autowired) + @AllArgsConstructor(onConstructor_ = @Autowired) class CrawlJobServiceImpl implements CrawlJobService { - @NonFinal - @Value("${app.crawl-job.type}") Job jobType; CrawlJobRepository crawlJobRepository; From 5adaea48a6c819a3c774ff7021811e0ef7a3746d Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 12 Jul 2023 16:30:52 +0200 Subject: [PATCH 0223/1089] Bugfix: Fixing cases when lines start with tabs in `NodePrinter` --- .../main/java/usi/si/seart/analyzer/printer/NodePrinter.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java index 980a44ad..07cf7b5d 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java @@ -19,7 +19,9 @@ public String print(Node node) { Range range = node.getRange(); String content = mapper.getContentForRange(range); int offset = node.getStartPoint().getColumn(); - List lines = content.lines().collect(Collectors.toList()); + List lines = content.lines() + .map(line -> line.replace("\t", " ")) + .collect(Collectors.toList()); for (int i = 1; i < lines.size(); i++) { String line = lines.get(i); if (line.length() > offset) From 3a1ec55f9e396b2a52905cdb34b785bfd30cdb7a Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 13 Jul 2023 09:45:26 +0200 Subject: [PATCH 0224/1089] Renamed server temporary directory volume --- deployment/docker-compose.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deployment/docker-compose.yml b/deployment/docker-compose.yml index 84bfd1eb..189cda53 100644 --- a/deployment/docker-compose.yml +++ b/deployment/docker-compose.yml @@ -86,7 +86,7 @@ services: WEBSITE_URL: http://localhost:${WEBSITE_PORT} volumes: - ./logs:/logs - - tmp-server:/tmp + - server-tmp:/tmp depends_on: dl4se-liquibase: condition: service_completed_successfully @@ -124,8 +124,8 @@ services: volumes: data: name: dl4se-data - tmp-server: - name: dl4se-tmp-server + server-tmp: + name: dl4se-server-tmp networks: default: From 053d6783a83cae3929e9c80755e17b877a095007 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 13 Jul 2023 09:54:18 +0200 Subject: [PATCH 0225/1089] Added mechanism for re-parsing functions to create standalone AST --- .../si/seart/analyzer/AbstractAnalyzer.java | 33 ++++++++++++++----- .../usi/si/seart/analyzer/JavaAnalyzer.java | 24 ++++++++++++++ 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java index 4f100d3d..2e0bb5c8 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java @@ -6,6 +6,7 @@ import ch.usi.si.seart.treesitter.Query; import ch.usi.si.seart.treesitter.Tree; import lombok.AccessLevel; +import lombok.Cleanup; import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; import usi.si.seart.analyzer.count.CharacterCounter; @@ -33,6 +34,7 @@ import usi.si.seart.model.code.Function; import java.io.IOException; +import java.io.UnsupportedEncodingException; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -169,12 +171,7 @@ protected List extractFunctionEntities(File file) { return functions; } - // TODO: 25.01.23 Parse content again for the AST - // - use the same parser instance to construct a new tree from the content - // - in case we are dealing with Java, wrap the content with `class _ {\n...}` (define protected `wrap`) - // - define extraction of the targets from the wrapper - // (just getChildren or more specific getChild(0).getChildByFieldName("body")) - // - stream over them and do the same as before + @SneakyThrows(UnsupportedEncodingException.class) protected Function extractFunctionEntity(List> match) { List nodes = match.stream() .map(Tuple::getValue) @@ -184,10 +181,18 @@ protected Function extractFunctionEntity(List> match) { .map(Tuple::getValue) .findFirst() .orElseThrow(IllegalStateException::new); + + String content = nodePrinter.print(nodes); + String wrapped = wrapContent(content); + @Cleanup Tree intermediate = parser.parseString(wrapped); + List unwrapped = unwrapNodes(intermediate); + Printer astPrinter = getAstPrinter(); + String ast = astPrinter.print(unwrapped); + return Function.builder() .repo(localClone.getGitRepo()) - .ast(syntaxTreePrinter.print(nodes)) - .content(nodePrinter.print(nodes)) + .ast(ast) + .content(content) .astHash(syntaxTreeHasher.hash(nodes)) .contentHash(contentHasher.hash(nodes)) .symbolicExpression(expressionPrinter.print(nodes)) @@ -200,4 +205,16 @@ protected Function extractFunctionEntity(List> match) { .boilerplateType(boilerplateEnumerator.asEnum(function)) .build(); } + + protected String wrapContent(String content) { + return content; + } + + protected List unwrapNodes(Tree tree) { + return tree.getRootNode().getChildren(); + } + + protected Printer getAstPrinter() { + return syntaxTreePrinter; + } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java index 0f9b8e85..8e52a35d 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java @@ -1,13 +1,19 @@ package usi.si.seart.analyzer; import ch.usi.si.seart.treesitter.Language; +import ch.usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Point; +import ch.usi.si.seart.treesitter.Tree; import usi.si.seart.analyzer.count.JavaTokenCounter; import usi.si.seart.analyzer.enumerator.JavaBoilerplateEnumerator; import usi.si.seart.analyzer.predicate.path.JavaTestFilePredicate; +import usi.si.seart.analyzer.printer.OffsetSyntaxTreePrinter; +import usi.si.seart.analyzer.printer.Printer; import usi.si.seart.analyzer.query.multi.JavaMultiCaptureQueries; import usi.si.seart.analyzer.query.single.JavaSingleCaptureQueries; import java.nio.file.Path; +import java.util.List; public class JavaAnalyzer extends AbstractAnalyzer { @@ -19,4 +25,22 @@ public JavaAnalyzer(LocalClone localClone, Path path) { this.multiCaptureQueries = new JavaMultiCaptureQueries(); this.boilerplateEnumerator = new JavaBoilerplateEnumerator(this::getSourceBytes); } + + @Override + protected String wrapContent(String content) { + return "class _ {\n" + content + "\n}\n"; + } + + @Override + protected List unwrapNodes(Tree tree) { + Node root = tree.getRootNode(); + Node declaration = root.getChild(0); + Node body = declaration.getChildByFieldName("body"); + return body.getChildren(); + } + + @Override + protected Printer getAstPrinter() { + return new OffsetSyntaxTreePrinter(new Point(-1, 0)); + } } From 95d5aa86534de856f005de599938838767868d32 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 13 Jul 2023 13:22:23 +0200 Subject: [PATCH 0226/1089] Changed signature of `create` in `FileService` --- .../main/java/usi/si/seart/crawler/service/FileService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/FileService.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/FileService.java index eaa0e95c..eee78781 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/FileService.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/FileService.java @@ -18,7 +18,7 @@ public interface FileService { List getAllByRepo(GitRepo gitRepo); - File create(File file); + void create(File file); void delete(GitRepo gitRepo, Path path); void rename(GitRepo gitRepo, Path oldPath, Path newPath); @@ -36,8 +36,8 @@ public List getAllByRepo(GitRepo gitRepo) { @Override @Transactional - public File create(File file) { - return fileRepository.save(file); + public void create(File file) { + fileRepository.save(file); } @Override From 779aff7533aefd9d4bbb47e372b566bb675d1c98 Mon Sep 17 00:00:00 2001 From: dabico Date: Sun, 16 Jul 2023 09:26:36 +0200 Subject: [PATCH 0227/1089] Removing transaction boundaries where they are not needed --- .../java/usi/si/seart/crawler/service/CrawlJobService.java | 3 --- .../main/java/usi/si/seart/crawler/service/FileService.java | 4 ---- .../java/usi/si/seart/crawler/service/GitRepoService.java | 2 -- 3 files changed, 9 deletions(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/CrawlJobService.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/CrawlJobService.java index 10924c11..bbe1812c 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/CrawlJobService.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/CrawlJobService.java @@ -5,7 +5,6 @@ import lombok.experimental.FieldDefaults; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import usi.si.seart.crawler.repository.CrawlJobRepository; import usi.si.seart.model.job.CrawlJob; import usi.si.seart.model.job.Job; @@ -28,14 +27,12 @@ class CrawlJobServiceImpl implements CrawlJobService { CrawlJobRepository crawlJobRepository; @Override - @Transactional public CrawlJob getProgress() { Optional optional = crawlJobRepository.findByJobType(jobType); return optional.orElseThrow(IllegalStateException::new); } @Override - @Transactional public void saveProgress(LocalDateTime checkpoint) { Optional optional = crawlJobRepository.findByJobType(jobType); CrawlJob crawlJob = optional.orElseThrow(IllegalStateException::new); diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/FileService.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/FileService.java index eee78781..1e39c418 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/FileService.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/FileService.java @@ -5,7 +5,6 @@ import lombok.experimental.FieldDefaults; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import usi.si.seart.crawler.repository.FileRepository; import usi.si.seart.model.GitRepo; import usi.si.seart.model.code.File; @@ -35,13 +34,11 @@ public List getAllByRepo(GitRepo gitRepo) { } @Override - @Transactional public void create(File file) { fileRepository.save(file); } @Override - @Transactional public void delete(GitRepo gitRepo, Path path) { Optional optional = fileRepository.findByRepoAndPath(gitRepo, path.toString()); File file = optional.orElseThrow(EntityNotFoundException::new); @@ -49,7 +46,6 @@ public void delete(GitRepo gitRepo, Path path) { } @Override - @Transactional public void rename(GitRepo gitRepo, Path oldPath, Path newPath) { Optional optional = fileRepository.findByRepoAndPath(gitRepo, oldPath.toString()); File file = optional.orElseThrow(EntityNotFoundException::new); diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/GitRepoService.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/GitRepoService.java index 771be2f9..1f83a833 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/GitRepoService.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/GitRepoService.java @@ -5,7 +5,6 @@ import lombok.experimental.FieldDefaults; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import usi.si.seart.crawler.repository.GitRepoRepository; import usi.si.seart.model.GitRepo; @@ -29,7 +28,6 @@ public GitRepo getByName(String name) { } @Override - @Transactional public GitRepo createOrUpdate(GitRepo gitRepo) { return gitRepoRepository.save(gitRepo); } From 974b570adfdf8fc97d3beb70297344dc291460ed Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 14 Aug 2023 10:50:11 +0200 Subject: [PATCH 0228/1089] Removing the cascade settings for `GitRepo` --- dl4se-model/src/main/java/usi/si/seart/model/GitRepo.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dl4se-model/src/main/java/usi/si/seart/model/GitRepo.java b/dl4se-model/src/main/java/usi/si/seart/model/GitRepo.java index 52ffd0f4..61dae6b8 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/GitRepo.java +++ b/dl4se-model/src/main/java/usi/si/seart/model/GitRepo.java @@ -14,7 +14,6 @@ import usi.si.seart.model.code.File; import usi.si.seart.model.code.Function; -import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; @@ -101,13 +100,13 @@ public class GitRepo { @Builder.Default Boolean isUnavailable = false; - @OneToMany(mappedBy = "repo", cascade = CascadeType.ALL, orphanRemoval = true) + @OneToMany(mappedBy = "repo") @ToString.Exclude @JsonIgnore @Builder.Default List files = new ArrayList<>(); - @OneToMany(mappedBy = "repo", cascade = CascadeType.ALL, orphanRemoval = true) + @OneToMany(mappedBy = "repo") @ToString.Exclude @JsonIgnore @Builder.Default From 32418c9d3e0e7f94299e65419353af541fbeeb6f Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 14 Aug 2023 10:51:19 +0200 Subject: [PATCH 0229/1089] Restricting cascades of `Function` to `PERSIST` and `MERGE` only --- dl4se-model/src/main/java/usi/si/seart/model/code/File.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dl4se-model/src/main/java/usi/si/seart/model/code/File.java b/dl4se-model/src/main/java/usi/si/seart/model/code/File.java index c5d90f20..5b266f22 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/code/File.java +++ b/dl4se-model/src/main/java/usi/si/seart/model/code/File.java @@ -45,7 +45,7 @@ public class File extends Code { @JsonProperty(value = "is_parsed") Boolean isParsed = false; - @OneToMany(mappedBy = "file", cascade = CascadeType.ALL, orphanRemoval = true) + @OneToMany(mappedBy = "file", cascade = {CascadeType.PERSIST, CascadeType.MERGE}) @Singular @JsonIgnore List functions = new ArrayList<>(); From a4d492d00676c856cf09d52e8fcb97f8ad80dd01 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 14 Aug 2023 10:51:28 +0200 Subject: [PATCH 0230/1089] ignore this commit --- dl4se-model/src/main/java/usi/si/seart/model/code/File.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dl4se-model/src/main/java/usi/si/seart/model/code/File.java b/dl4se-model/src/main/java/usi/si/seart/model/code/File.java index 5b266f22..02f40e89 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/code/File.java +++ b/dl4se-model/src/main/java/usi/si/seart/model/code/File.java @@ -27,7 +27,7 @@ @Entity @Table( name = "file", - uniqueConstraints = {@UniqueConstraint(columnNames = {"repo_id", "path"})} + uniqueConstraints = @UniqueConstraint(columnNames = {"repo_id", "path"}) ) @Getter @Setter From ac2d1dc0752752f09d2c751c802a7e00444d4900 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 16 Aug 2023 14:05:55 +0200 Subject: [PATCH 0231/1089] Upgrading Spring Boot patch version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8de3aae7..9001c4e0 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,7 @@ 42.6.0 0.11.5 2.15.2 - 2.7.13 + 2.7.14 2021.0.3 From b308808a84aa20fdfb21b809f7866c54d72d86bf Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 16 Aug 2023 15:44:51 +0200 Subject: [PATCH 0232/1089] Fix: Safer implementation of `JavaTokenCounter` --- dl4se-analyzer/pom.xml | 4 ++++ .../si/seart/analyzer/count/JavaTokenCounter.java | 12 ++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/dl4se-analyzer/pom.xml b/dl4se-analyzer/pom.xml index 75d587eb..a61d8b18 100644 --- a/dl4se-analyzer/pom.xml +++ b/dl4se-analyzer/pom.xml @@ -27,5 +27,9 @@ java-tree-sitter 1.0.1 + + org.apache.commons + commons-lang3 + diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/JavaTokenCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/JavaTokenCounter.java index f8f32eb7..50e5c524 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/JavaTokenCounter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/JavaTokenCounter.java @@ -2,6 +2,7 @@ import ch.usi.si.seart.treesitter.Node; import ch.usi.si.seart.treesitter.Range; +import org.apache.commons.lang3.StringUtils; import usi.si.seart.analyzer.NodeMapper; public class JavaTokenCounter extends TokenCounter { @@ -17,17 +18,16 @@ protected void nodeCallback(Node node) { String[] tokens; Range range = node.getRange(); String content = mapper.getContentForRange(range); - String type = node.getType(); - switch (type) { + switch (node.getType()) { case "block_comment": - int idxLo = (content.startsWith("/**")) ? 3 : 2; - int idxHi = content.length() - 2; - content = content.substring(idxLo, idxHi); + content = StringUtils.substringBetween(content, "/*", "*/").trim(); + if (content.startsWith("*")) + content = content.substring(1).trim(); tokens = content.split("\\s+"); count.addAndGet(tokens.length + 2L); break; case "line_comment": - content = content.substring(2); + content = StringUtils.substringAfter(content, "//").trim(); tokens = content.split("\\s+"); count.addAndGet(tokens.length + 1L); break; From 6a18cf6a7dea09234e88c1bcce469ccbca9dd0d6 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 16 Aug 2023 15:59:47 +0200 Subject: [PATCH 0233/1089] Using a far superior split method --- .../usi/si/seart/analyzer/count/JavaTokenCounter.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/JavaTokenCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/JavaTokenCounter.java index 50e5c524..da143bc2 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/JavaTokenCounter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/JavaTokenCounter.java @@ -20,15 +20,15 @@ protected void nodeCallback(Node node) { String content = mapper.getContentForRange(range); switch (node.getType()) { case "block_comment": - content = StringUtils.substringBetween(content, "/*", "*/").trim(); + content = StringUtils.substringBetween(content, "/*", "*/"); if (content.startsWith("*")) - content = content.substring(1).trim(); - tokens = content.split("\\s+"); + content = content.substring(1); + tokens = StringUtils.split(content); count.addAndGet(tokens.length + 2L); break; case "line_comment": - content = StringUtils.substringAfter(content, "//").trim(); - tokens = content.split("\\s+"); + content = StringUtils.substringAfter(content, "//"); + tokens = StringUtils.split(content); count.addAndGet(tokens.length + 1L); break; default: From 207e35c7638dedfdd8be35aa38c49bc70f4bd313 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 16 Aug 2023 16:14:56 +0200 Subject: [PATCH 0234/1089] Same improvements to `PythonTokenCounter` --- .../usi/si/seart/analyzer/count/PythonTokenCounter.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/PythonTokenCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/PythonTokenCounter.java index f847bd00..2faf46cf 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/PythonTokenCounter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/PythonTokenCounter.java @@ -2,6 +2,7 @@ import ch.usi.si.seart.treesitter.Node; import ch.usi.si.seart.treesitter.Range; +import org.apache.commons.lang3.StringUtils; import usi.si.seart.analyzer.NodeMapper; public class PythonTokenCounter extends TokenCounter { @@ -18,8 +19,9 @@ protected void nodeCallback(Node node) { count.addAndGet(1L); } else if (leafNode && type.equals("comment")) { Range range = node.getRange(); - String content = mapper.getContentForRange(range).substring(1); - String[] tokens = content.split("\\s+"); + String content = mapper.getContentForRange(range); + content = StringUtils.substringAfter(content, "#"); + String[] tokens = StringUtils.split(content); count.addAndGet(tokens.length + 1L); } else if (leafNode) { count.addAndGet(1L); From eff3ccaa936da2679b31a88917f42149c7e08bf6 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 16 Aug 2023 16:23:01 +0200 Subject: [PATCH 0235/1089] Upgrading `postgres` docker image --- deployment/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment/docker-compose.yml b/deployment/docker-compose.yml index 189cda53..dae656ac 100644 --- a/deployment/docker-compose.yml +++ b/deployment/docker-compose.yml @@ -4,7 +4,7 @@ services: dl4se-db: container_name: dl4se-db - image: postgres:15.3-alpine + image: postgres:15.4-alpine volumes: - data:/var/lib/postgresql/data networks: [ default ] From 694b5e93ea3d8aec18c87b6fdc02912668a6420f Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 16 Aug 2023 16:23:36 +0200 Subject: [PATCH 0236/1089] Upgrading `liquibase` docker image --- deployment/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment/docker-compose.yml b/deployment/docker-compose.yml index dae656ac..2dc94163 100644 --- a/deployment/docker-compose.yml +++ b/deployment/docker-compose.yml @@ -23,7 +23,7 @@ services: dl4se-liquibase: container_name: dl4se-liquibase - image: liquibase/liquibase:4.23-alpine + image: liquibase/liquibase:4.23.1-alpine command: --username=${DATABASE_USER} --password=${DATABASE_PASS} From 7babf072b04c0b04350056909e4bb3574b6dd539 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 16 Aug 2023 16:25:45 +0200 Subject: [PATCH 0237/1089] Upgrading `eclipse-temurin` docker image for crawler --- deployment/crawler/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment/crawler/Dockerfile b/deployment/crawler/Dockerfile index 67a38591..af853771 100644 --- a/deployment/crawler/Dockerfile +++ b/deployment/crawler/Dockerfile @@ -14,7 +14,7 @@ RUN mvn -e \ -pl dl4se-crawler \ -am -DskipTests -FROM eclipse-temurin:11.0.19_7-jre-alpine +FROM eclipse-temurin:11.0.20_8-jre-alpine COPY --from=build /dl4se-crawler/target/dl4se-crawler-*.jar /crawler.jar From 29505077afaa8889194962f179151596f5bea213 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 17 Aug 2023 13:39:58 +0200 Subject: [PATCH 0238/1089] The `COMPOSE_PROJECT_NAME` now resides in the config file itself --- deployment/.env.template | 2 -- deployment/docker-compose.yml | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/deployment/.env.template b/deployment/.env.template index 997cb813..9d833eec 100644 --- a/deployment/.env.template +++ b/deployment/.env.template @@ -1,5 +1,3 @@ -COMPOSE_PROJECT_NAME=dl4se - DATABASE_NAME=$DATABASE_NAME DATABASE_USER=$DATABASE_USER DATABASE_PASS=$DATABASE_PASS diff --git a/deployment/docker-compose.yml b/deployment/docker-compose.yml index 2dc94163..ead4da3f 100644 --- a/deployment/docker-compose.yml +++ b/deployment/docker-compose.yml @@ -1,4 +1,5 @@ version: '3.9' +name: 'dl4se' services: From 860441d043cc4b3f65e9ff4428a59b20c459ca51 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 17 Aug 2023 13:51:54 +0200 Subject: [PATCH 0239/1089] Update `.gitignore` --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 05c1a98d..791ceb3a 100644 --- a/.gitignore +++ b/.gitignore @@ -290,6 +290,8 @@ dist ### Docker Compose *.prod.yml +*.temp.yml +*.override.yml ### C template # Object files From 695e5471601525051745e761100cba4bf2cfb6c4 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 25 Aug 2023 10:18:14 +0200 Subject: [PATCH 0240/1089] Fix: offset is now the minimum between column and number of spaces --- .../si/seart/analyzer/printer/NodePrinter.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java index 07cf7b5d..bda4c9b9 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java @@ -18,14 +18,15 @@ public NodePrinter(NodeMapper mapper) { public String print(Node node) { Range range = node.getRange(); String content = mapper.getContentForRange(range); - int offset = node.getStartPoint().getColumn(); List lines = content.lines() .map(line -> line.replace("\t", " ")) .collect(Collectors.toList()); for (int i = 1; i < lines.size(); i++) { String line = lines.get(i); - if (line.length() > offset) - lines.set(i, line.substring(offset)); + int spaces = countStartSpaces(line); + int column = node.getStartPoint().getColumn(); + int offset = Math.min(spaces, column); + lines.set(i, line.substring(offset)); } return String.join("\n", lines); } @@ -34,4 +35,13 @@ public String print(Node node) { protected Collector resultCollector() { return Collectors.joining("\n"); } + + private int countStartSpaces(String line) { + int count = 0; + for (char c : line.toCharArray()) { + if (c == ' ') count++; + else break; + } + return count; + } } From 4a65a2554de12d3e5f064ab04c96803aee060b24 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 28 Aug 2023 10:44:06 +0200 Subject: [PATCH 0241/1089] Documentation formatting, ignore this commit --- .../crawler/io/ExtensionBasedFileVisitor.java | 46 +++++++++++-------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/io/ExtensionBasedFileVisitor.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/io/ExtensionBasedFileVisitor.java index 7fbd0d27..6b2711b2 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/io/ExtensionBasedFileVisitor.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/io/ExtensionBasedFileVisitor.java @@ -16,7 +16,8 @@ import java.util.Objects; /** - * Class used to traverse a directory structure, and save references to all files whose extension matches at least one + * Class used to traverse a directory structure, + * and save references to all files whose extension matches at least one * of the extensions specified in the constructor. * Creating with no extensions specified will match all files. * Use as follows: @@ -28,7 +29,7 @@ * List javaFiles = visitor.getVisited(); * } * - * @see java.nio.file.SimpleFileVisitor SimpleFileVisitor + * @see SimpleFileVisitor SimpleFileVisitor * @see java.nio.file.Files#walkFileTree(Path, java.nio.file.FileVisitor) Files.walkFileTree * @author dabico */ @@ -41,11 +42,13 @@ public class ExtensionBasedFileVisitor extends SimpleFileVisitor { List visited; /** - * Static factory used for creating instances of the class. We use it in order to enforce pre-conditions before any + * Static factory used for creating instances of the class. + * We use it in order to enforce pre-conditions before any * actual class instances are created. * - * @param extensions File extension names. Must not be {@code null} or contain any {@code null} values, empty or - * blank strings. + * @param extensions File extension names. + * Must not be {@code null} or contain any + * {@code null} values, empty or blank strings. * @return A new instance of the class. */ public static ExtensionBasedFileVisitor forExtensions(String... extensions) { @@ -78,11 +81,12 @@ private PathMatcher compileMatcher(String... extensions) { /** * {@inheritDoc} * - * If the file extension matches the visitor pattern, then it is recorded in the list of visited files. + * If the file extension matches the visitor pattern, + * then it is recorded in the list of visited files. * - * @param path a reference to the file - * @param attrs the file's basic attributes - * @return the visit result + * @param path a reference to the file. + * @param attrs the file's basic attributes. + * @return the visit result. */ @Override public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) { @@ -97,8 +101,8 @@ public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) { * * Unlike its superclass, this variant just silently ignores the exception. * - * @param path a reference to the file - * @param ex the I/O exception that prevented the file from being visited + * @param path a reference to the file. + * @param ex the I/O exception that prevented the file from being visited. */ @Override public FileVisitResult visitFileFailed(Path path, IOException ex) { @@ -107,10 +111,11 @@ public FileVisitResult visitFileFailed(Path path, IOException ex) { /** * Invoked for a directory before entries in the directory are visited. - * Always returns {@link FileVisitResult#CONTINUE CONTINUE} to ensure that directory contents are visited. + * Always returns {@link FileVisitResult#CONTINUE CONTINUE} + * to ensure that directory contents are visited. * - * @param path a reference to the directory - * @param attrs the directory's basic attributes + * @param path a reference to the directory. + * @param attrs the directory's basic attributes. */ @Override public FileVisitResult preVisitDirectory(Path path, BasicFileAttributes attrs) { @@ -118,13 +123,14 @@ public FileVisitResult preVisitDirectory(Path path, BasicFileAttributes attrs) { } /** - * Invoked for a directory after entries in the directory, and all of their descendants, have been visited. - * Always returns {@link FileVisitResult#CONTINUE CONTINUE}, signifying that all contents have been visited. + * Invoked for a directory after entries in the directory, + * and all of their descendants, have been visited. + * Always returns {@link FileVisitResult#CONTINUE CONTINUE}, + * signifying that all contents have been visited. * - * @param dir a reference to the directory - * @param ex {@code null} if the iteration of the directory completes without - * an error; otherwise the I/O exception that caused the iteration - * of the directory to complete prematurely + * @param dir a reference to the directory. + * @param ex {@code null} if the iteration of the directory completes without an error; + * otherwise the I/O exception that caused the iteration of the directory to complete prematurely. */ @Override public FileVisitResult postVisitDirectory(Path dir, IOException ex) { From f92b3d6f8a18ee67d1206f13ff08f3da802595a6 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 28 Aug 2023 13:46:04 +0200 Subject: [PATCH 0242/1089] Added support for mining exclusions --- .../seart/crawler/component/CodeCrawler.java | 18 ++++++++++++++++-- .../src/main/resources/application.properties | 1 + 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java index a00d5c69..8ed36c9b 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java @@ -35,8 +35,10 @@ import javax.annotation.PostConstruct; import javax.persistence.EntityNotFoundException; import java.io.IOException; +import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.PathMatcher; import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; @@ -50,6 +52,7 @@ import java.util.Optional; import java.util.Set; import java.util.function.BiConsumer; +import java.util.function.Predicate; import java.util.stream.Collectors; @Slf4j @@ -75,6 +78,13 @@ public class CodeCrawler implements Runnable { @Value("${app.general.tmp-dir-prefix}") String prefix; + @NonFinal + @Value("${app.crawl-job.ignore-pattern}") + String ignorePattern; + + @NonFinal + PathMatcher ignoreMatcher = FileSystems.getDefault().getPathMatcher("glob:"); + Set languageNames = new HashSet<>(); Map nameToLanguage = new HashMap<>(); Map extensionToLanguage = new HashMap<>(); @@ -88,6 +98,8 @@ private void postConstruct() { nameToLanguage.put(name, language); extensions.forEach(extension -> extensionToLanguage.put(extension, language)); }); + if (!ignorePattern.isBlank()) + ignoreMatcher = FileSystems.getDefault().getPathMatcher("glob:" + ignorePattern); } @Scheduled(fixedDelayString = "${app.crawl-job.next-run-delay}") @@ -251,8 +263,10 @@ private void mineRepoData(LocalClone localClone, Set languages) { .map(Path::of) .map(localDirectory::resolve) .collect(Collectors.toSet()); - Set targets = Sets.difference(candidates, analyzed); - targets.forEach(target -> analyzeAndStore(localClone, target)); + Set filtered = Sets.difference(candidates, analyzed).stream() + .filter(Predicate.not(ignoreMatcher::matches)) + .collect(Collectors.toSet()); + filtered.forEach(target -> analyzeAndStore(localClone, target)); } private void analyzeAndStore(LocalClone localClone, Path path) { diff --git a/dl4se-crawler/src/main/resources/application.properties b/dl4se-crawler/src/main/resources/application.properties index 1ae7810c..5b19cdfd 100644 --- a/dl4se-crawler/src/main/resources/application.properties +++ b/dl4se-crawler/src/main/resources/application.properties @@ -41,3 +41,4 @@ app.crawl-job.next-run-delay=PT6H app.crawl-job.url=${CRAWLER_URL:https://seart-ghs.si.usi.ch/api/r/search} app.crawl-job.start-date-time=2008-01-01T00:00:00 app.crawl-job.type=${CRAWLER_JOB:CODE} +app.crawl-job.ignore-pattern= From 29adac419d0da1d6260cf0cae7edffb1a93c89c4 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 1 Sep 2023 15:40:11 +0200 Subject: [PATCH 0243/1089] Added support for repository exclusions Excluding objects by pattern matching is not enough, we should also have a mechanism for excluding entire projects. This should be used sparingly though. --- .../usi/si/seart/crawler/component/CodeCrawler.java | 10 ++++++++++ .../src/main/resources/application.properties | 1 + 2 files changed, 11 insertions(+) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java index 8ed36c9b..1774d75f 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java @@ -82,6 +82,10 @@ public class CodeCrawler implements Runnable { @Value("${app.crawl-job.ignore-pattern}") String ignorePattern; + @NonFinal + @Value("${app.crawl-job.ignore-projects}") + List ignoreProjects; + @NonFinal PathMatcher ignoreMatcher = FileSystems.getDefault().getPathMatcher("glob:"); @@ -140,6 +144,12 @@ private void saveCrawlProgress(LocalDateTime checkpoint) { private void inspectSearchResult(SearchResultDto item) { String name = item.getName(); + + if (ignoreProjects.contains(name)) { + log.debug("Skipping: {}. Repository is set to be ignored by crawler!", name); + return; + } + LocalDateTime lastUpdateGhs = conversionService.convert(item.getLastCommit(), LocalDateTime.class); Set repoLanguageNames = Sets.intersection(languageNames, item.getRepoLanguages()); diff --git a/dl4se-crawler/src/main/resources/application.properties b/dl4se-crawler/src/main/resources/application.properties index 5b19cdfd..3e3f3594 100644 --- a/dl4se-crawler/src/main/resources/application.properties +++ b/dl4se-crawler/src/main/resources/application.properties @@ -41,4 +41,5 @@ app.crawl-job.next-run-delay=PT6H app.crawl-job.url=${CRAWLER_URL:https://seart-ghs.si.usi.ch/api/r/search} app.crawl-job.start-date-time=2008-01-01T00:00:00 app.crawl-job.type=${CRAWLER_JOB:CODE} +app.crawl-job.ignore-projects= app.crawl-job.ignore-pattern= From 8b604beeb1d8141d2a0c8ac618bf63255718d3e5 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 4 Sep 2023 09:26:46 +0200 Subject: [PATCH 0244/1089] Abstracted away the streaming logic for `NodePredicate` --- .../si/seart/analyzer/predicate/node/NodePredicate.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/NodePredicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/NodePredicate.java index c9986fac..36a0a158 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/NodePredicate.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/NodePredicate.java @@ -7,13 +7,18 @@ import java.util.stream.Stream; public abstract class NodePredicate implements Predicate { + public abstract boolean test(Node node); public boolean test(Node... nodes) { - return Stream.of(nodes).anyMatch(this); + return test(Stream.of(nodes)); } public boolean test(Collection nodes) { - return nodes.stream().anyMatch(this); + return test(nodes.stream()); + } + + protected boolean test(Stream nodes) { + return nodes.anyMatch(this); } } From 3985dd70228c2282bd849877b1b49f5c595f7fec Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 4 Sep 2023 09:27:48 +0200 Subject: [PATCH 0245/1089] Abstracted away the streaming logic for `AbstractPrinter` --- .../si/seart/analyzer/printer/AbstractPrinter.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/AbstractPrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/AbstractPrinter.java index b7bd16af..ab3a8502 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/AbstractPrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/AbstractPrinter.java @@ -11,16 +11,16 @@ public abstract class AbstractPrinter implements Printer { @Override public String print(Node... nodes) { - return Stream.of(nodes) - .map(this::print) - .collect(resultCollector()); + return print(Stream.of(nodes)); } @Override public String print(Collection nodes) { - return nodes.stream() - .map(this::print) - .collect(resultCollector()); + return print(nodes.stream()); + } + + protected String print(Stream nodes) { + return nodes.map(this::print).collect(resultCollector()); } protected Collector resultCollector() { From 8b681047925b3b45bc9487ea36b92829e49f7889 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 4 Sep 2023 09:35:08 +0200 Subject: [PATCH 0246/1089] Abstracted away the streaming logic into `AbstractCounter` --- .../seart/analyzer/count/AbstractCounter.java | 21 +++++++++++++++++++ .../usi/si/seart/analyzer/count/Counter.java | 12 +++-------- .../si/seart/analyzer/count/LineCounter.java | 2 +- .../seart/analyzer/count/TraverseCounter.java | 2 +- 4 files changed, 26 insertions(+), 11 deletions(-) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/AbstractCounter.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/AbstractCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/AbstractCounter.java new file mode 100644 index 00000000..c4c38419 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/AbstractCounter.java @@ -0,0 +1,21 @@ +package usi.si.seart.analyzer.count; + +import ch.usi.si.seart.treesitter.Node; + +import java.util.Collection; +import java.util.stream.Stream; + +public abstract class AbstractCounter implements Counter { + + public Long count(Node... nodes) { + return count(Stream.of(nodes)); + } + + public Long count(Collection nodes) { + return count(nodes.stream()); + } + + protected Long count(Stream nodes) { + return nodes.mapToLong(this::count).sum(); + } +} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/Counter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/Counter.java index 9ea66255..ce6affc5 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/Counter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/Counter.java @@ -3,16 +3,10 @@ import ch.usi.si.seart.treesitter.Node; import java.util.Collection; -import java.util.stream.Stream; public interface Counter { - Long count(Node node); - - default Long count(Node... nodes) { - return Stream.of(nodes).mapToLong(this::count).sum(); - } - default Long count(Collection nodes) { - return nodes.stream().mapToLong(this::count).sum(); - } + Long count(Node node); + Long count(Node... nodes); + Long count(Collection nodes); } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/LineCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/LineCounter.java index c69b4679..2c2688f9 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/LineCounter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/LineCounter.java @@ -4,7 +4,7 @@ import ch.usi.si.seart.treesitter.Point; import ch.usi.si.seart.treesitter.Range; -public class LineCounter implements Counter { +public class LineCounter extends AbstractCounter { @Override public Long count(Node node) { diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TraverseCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TraverseCounter.java index cbda88c8..1baf141d 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TraverseCounter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TraverseCounter.java @@ -11,7 +11,7 @@ @FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) @NoArgsConstructor(access = AccessLevel.PROTECTED) -public abstract class TraverseCounter implements Counter { +public abstract class TraverseCounter extends AbstractCounter { AtomicLong count = new AtomicLong(); From 6e00ab69a0ab3e4855b51869146a4b5a619bcb52 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 4 Sep 2023 10:58:36 +0200 Subject: [PATCH 0247/1089] Bump `java-tree-sitter` minor version: `1.0.1` -> `1.2.0` --- dl4se-analyzer/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dl4se-analyzer/pom.xml b/dl4se-analyzer/pom.xml index a61d8b18..262f0c0e 100644 --- a/dl4se-analyzer/pom.xml +++ b/dl4se-analyzer/pom.xml @@ -25,7 +25,7 @@ ch.usi.si.seart java-tree-sitter - 1.0.1 + 1.2.0 org.apache.commons From b19773ceec676c34e383d2599184fa73c56c856e Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 4 Sep 2023 10:59:32 +0200 Subject: [PATCH 0248/1089] Replace usages of deprecated APIs from `java-tree-sitter` --- .../si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java | 7 ++++++- .../usi/si/seart/analyzer/printer/SyntaxTreePrinter.java | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java index b12371e1..47689ca9 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java @@ -1,8 +1,11 @@ package usi.si.seart.analyzer.printer; import ch.usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.OffsetTreeCursor; import ch.usi.si.seart.treesitter.Point; +import ch.usi.si.seart.treesitter.printer.TreePrinter; import lombok.AllArgsConstructor; +import lombok.Cleanup; @AllArgsConstructor public class OffsetSyntaxTreePrinter extends AbstractPrinter { @@ -11,6 +14,8 @@ public class OffsetSyntaxTreePrinter extends AbstractPrinter { @Override public String print(Node node) { - return new ch.usi.si.seart.treesitter.SyntaxTreePrinter(node, offset).printSubtree(); + @Cleanup OffsetTreeCursor cursor = new OffsetTreeCursor(node, offset); + TreePrinter printer = new ch.usi.si.seart.treesitter.printer.SyntaxTreePrinter(cursor); + return printer.print(); } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java index 4ab8cf7f..16b0c996 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java @@ -1,11 +1,16 @@ package usi.si.seart.analyzer.printer; import ch.usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.TreeCursor; +import ch.usi.si.seart.treesitter.printer.TreePrinter; +import lombok.Cleanup; public class SyntaxTreePrinter extends AbstractPrinter { @Override public String print(Node node) { - return new ch.usi.si.seart.treesitter.SyntaxTreePrinter(node).printSubtree(); + @Cleanup TreeCursor cursor = node.walk(); + TreePrinter printer = new ch.usi.si.seart.treesitter.printer.SyntaxTreePrinter(cursor); + return printer.print(); } } From a656a25a7c745a808f6e3ca2fe9a0957d29b13bf Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 4 Sep 2023 11:01:19 +0200 Subject: [PATCH 0249/1089] `OffsetSyntaxTreePrinter` now extends `SyntaxTreePrinter` --- .../usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java index 47689ca9..f74365c0 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java @@ -8,7 +8,7 @@ import lombok.Cleanup; @AllArgsConstructor -public class OffsetSyntaxTreePrinter extends AbstractPrinter { +public class OffsetSyntaxTreePrinter extends SyntaxTreePrinter { private final Point offset; From 78e2a1328d97f5c2eb70f1d526c1e0edbe95035b Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 4 Sep 2023 11:04:12 +0200 Subject: [PATCH 0250/1089] Improved `SyntaxTreePrinter` hierarchy --- .../seart/analyzer/printer/OffsetSyntaxTreePrinter.java | 9 +++------ .../usi/si/seart/analyzer/printer/SyntaxTreePrinter.java | 6 +++++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java index f74365c0..286a2a7a 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java @@ -3,9 +3,8 @@ import ch.usi.si.seart.treesitter.Node; import ch.usi.si.seart.treesitter.OffsetTreeCursor; import ch.usi.si.seart.treesitter.Point; -import ch.usi.si.seart.treesitter.printer.TreePrinter; +import ch.usi.si.seart.treesitter.TreeCursor; import lombok.AllArgsConstructor; -import lombok.Cleanup; @AllArgsConstructor public class OffsetSyntaxTreePrinter extends SyntaxTreePrinter { @@ -13,9 +12,7 @@ public class OffsetSyntaxTreePrinter extends SyntaxTreePrinter { private final Point offset; @Override - public String print(Node node) { - @Cleanup OffsetTreeCursor cursor = new OffsetTreeCursor(node, offset); - TreePrinter printer = new ch.usi.si.seart.treesitter.printer.SyntaxTreePrinter(cursor); - return printer.print(); + protected TreeCursor getCursor(Node node) { + return new OffsetTreeCursor(node, offset); } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java index 16b0c996..0af1bf54 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java @@ -9,8 +9,12 @@ public class SyntaxTreePrinter extends AbstractPrinter { @Override public String print(Node node) { - @Cleanup TreeCursor cursor = node.walk(); + @Cleanup TreeCursor cursor = getCursor(node); TreePrinter printer = new ch.usi.si.seart.treesitter.printer.SyntaxTreePrinter(cursor); return printer.print(); } + + protected TreeCursor getCursor(Node node) { + return node.walk(); + } } From 11f868b4d42565cf6d4edc20f551e4cdfce7ccbd Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 4 Sep 2023 14:39:12 +0200 Subject: [PATCH 0251/1089] Bump `java-tree-sitter` patch version: `1.2.0` -> `1.2.1` --- dl4se-analyzer/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dl4se-analyzer/pom.xml b/dl4se-analyzer/pom.xml index 262f0c0e..c7527e69 100644 --- a/dl4se-analyzer/pom.xml +++ b/dl4se-analyzer/pom.xml @@ -25,7 +25,7 @@ ch.usi.si.seart java-tree-sitter - 1.2.0 + 1.2.1 org.apache.commons From 288edd57e7af8c9c044da6819cbcf2db656d4959 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 4 Sep 2023 15:01:31 +0200 Subject: [PATCH 0252/1089] Add `MinimumSizeLimitCollector` abstract class --- .../stream/MinimumSizeLimitCollector.java | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/util/stream/MinimumSizeLimitCollector.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/util/stream/MinimumSizeLimitCollector.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/util/stream/MinimumSizeLimitCollector.java new file mode 100644 index 00000000..32396157 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/util/stream/MinimumSizeLimitCollector.java @@ -0,0 +1,60 @@ +package usi.si.seart.analyzer.util.stream; + +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; + +import java.util.Collections; +import java.util.Set; +import java.util.StringJoiner; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiConsumer; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collector; + +@RequiredArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +public abstract class MinimumSizeLimitCollector implements Collector { + + int limit; + AtomicInteger count = new AtomicInteger(); + + @Override + public Supplier supplier() { + return () -> new StringJoiner(getDelimiter()); + } + + @Override + public BiConsumer accumulator() { + return (joiner, sequence) -> { + count.incrementAndGet(); + joiner.add(sequence); + }; + } + + @Override + public BinaryOperator combiner() { + return StringJoiner::merge; + } + + @Override + public Function finisher() { + return (joiner) -> { + String joined = joiner.toString(); + return (count.get() >= limit) ? getPrefix() + joined + getSuffix() : joined; + }; + } + + @Override + public Set characteristics() { + return Collections.emptySet(); + } + + protected abstract String getDelimiter(); + + protected abstract String getPrefix(); + + protected abstract String getSuffix(); +} From 2b66d18267288b9b4ecae6751e0659e5871cb6e2 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 4 Sep 2023 15:02:15 +0200 Subject: [PATCH 0253/1089] Integrating new collector class --- .../printer/SymbolicExpressionPrinter.java | 40 ++++--------------- 1 file changed, 8 insertions(+), 32 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinter.java index 5e07d4c9..ea7c3d26 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinter.java @@ -1,14 +1,8 @@ package usi.si.seart.analyzer.printer; import ch.usi.si.seart.treesitter.Node; +import usi.si.seart.analyzer.util.stream.MinimumSizeLimitCollector; -import java.util.Collections; -import java.util.Set; -import java.util.StringJoiner; -import java.util.function.BiConsumer; -import java.util.function.BinaryOperator; -import java.util.function.Function; -import java.util.function.Supplier; import java.util.stream.Collector; public class SymbolicExpressionPrinter extends AbstractPrinter { @@ -20,39 +14,21 @@ public String print(Node node) { @Override protected Collector resultCollector() { - return new Collector() { - - int count = 0; - - @Override - public Supplier supplier() { - return () -> new StringJoiner(" "); - } - - @Override - public BiConsumer accumulator() { - return (joiner, sequence) -> { - count++; - joiner.add(sequence); - }; - } + return new MinimumSizeLimitCollector(2) { @Override - public BinaryOperator combiner() { - return StringJoiner::merge; + protected String getDelimiter() { + return " "; } @Override - public Function finisher() { - return (joiner) -> { - String joined = joiner.toString(); - return (count > 1) ? "(" + joined + ")" : joined; - }; + protected String getPrefix() { + return "("; } @Override - public Set characteristics() { - return Collections.emptySet(); + protected String getSuffix() { + return ")"; } }; } From 1576b6841e3e2a70f5bd15c7d92b90227307c4ec Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 4 Sep 2023 15:13:01 +0200 Subject: [PATCH 0254/1089] `SyntaxTreePrinter` now prints XML instead of human-readable ASTs --- .../analyzer/printer/SyntaxTreePrinter.java | 45 +++- .../printer/OffsetSyntaxTreePrinterTest.java | 126 ++++++--- .../printer/SyntaxTreePrinterTest.java | 252 ++++++++++++------ 3 files changed, 299 insertions(+), 124 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java index 0af1bf54..b4e22287 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java @@ -3,18 +3,57 @@ import ch.usi.si.seart.treesitter.Node; import ch.usi.si.seart.treesitter.TreeCursor; import ch.usi.si.seart.treesitter.printer.TreePrinter; +import ch.usi.si.seart.treesitter.printer.XMLPrinter; import lombok.Cleanup; +import usi.si.seart.analyzer.util.stream.MinimumSizeLimitCollector; + +import java.util.stream.Collector; +import java.util.stream.Stream; public class SyntaxTreePrinter extends AbstractPrinter { + private static final int BEGIN_INDEX = XMLPrinter.PROLOG.length(); + public static final String TAG_OPEN = ""; + public static final String TAG_CLOSE = ""; + @Override public String print(Node node) { - @Cleanup TreeCursor cursor = getCursor(node); - TreePrinter printer = new ch.usi.si.seart.treesitter.printer.SyntaxTreePrinter(cursor); - return printer.print(); + return print(Stream.of(node)); } protected TreeCursor getCursor(Node node) { return node.walk(); } + + @Override + protected String print(Stream nodes) { + return nodes.map(this::printWithoutProlog).collect(resultCollector()); + } + + private String printWithoutProlog(Node node) { + @Cleanup TreeCursor cursor = getCursor(node); + TreePrinter printer = new XMLPrinter(cursor); + return printer.print().substring(BEGIN_INDEX); + } + + @Override + protected Collector resultCollector() { + return new MinimumSizeLimitCollector(1) { + + @Override + protected String getDelimiter() { + return ""; + } + + @Override + protected String getPrefix() { + return XMLPrinter.PROLOG + TAG_OPEN; + } + + @Override + protected String getSuffix() { + return TAG_CLOSE; + } + }; + } } diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinterTest.java index 63f9aa50..e6944bff 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinterTest.java @@ -15,26 +15,49 @@ void idempotencyTest() { Node method = root.getChild(1).getChildByFieldName("body").getChild(1); String actual = printer.print(method); String expected = - "method_declaration [3:4] - [6:5]\n" + - " modifiers [3:4] - [3:17]\n" + - " type: void_type [3:18] - [3:22]\n" + - " name: identifier [3:23] - [3:27]\n" + - " parameters: formal_parameters [3:27] - [3:42]\n" + - " formal_parameter [3:28] - [3:41]\n" + - " type: array_type [3:28] - [3:36]\n" + - " element: type_identifier [3:28] - [3:34]\n" + - " dimensions: dimensions [3:34] - [3:36]\n" + - " name: identifier [3:37] - [3:41]\n" + - " body: block [3:43] - [6:5]\n" + - " line_comment [4:8] - [4:22]\n" + - " expression_statement [5:8] - [5:44]\n" + - " method_invocation [5:8] - [5:43]\n" + - " object: field_access [5:8] - [5:18]\n" + - " object: identifier [5:8] - [5:14]\n" + - " field: identifier [5:15] - [5:18]\n" + - " name: identifier [5:19] - [5:26]\n" + - " arguments: argument_list [5:26] - [5:43]\n" + - " string_literal [5:27] - [5:42]\n"; + "" + + OffsetSyntaxTreePrinter.TAG_OPEN + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + OffsetSyntaxTreePrinter.TAG_CLOSE; Assertions.assertEquals(expected, actual); } @@ -45,26 +68,49 @@ void offsetTest() { Node method = root.getChild(1).getChildByFieldName("body").getChild(1); String actual = printer.print(method); String expected = - "method_declaration [2:2] - [5:3]\n" + - " modifiers [2:2] - [2:15]\n" + - " type: void_type [2:16] - [2:20]\n" + - " name: identifier [2:21] - [2:25]\n" + - " parameters: formal_parameters [2:25] - [2:40]\n" + - " formal_parameter [2:26] - [2:39]\n" + - " type: array_type [2:26] - [2:34]\n" + - " element: type_identifier [2:26] - [2:32]\n" + - " dimensions: dimensions [2:32] - [2:34]\n" + - " name: identifier [2:35] - [2:39]\n" + - " body: block [2:41] - [5:3]\n" + - " line_comment [3:6] - [3:20]\n" + - " expression_statement [4:6] - [4:42]\n" + - " method_invocation [4:6] - [4:41]\n" + - " object: field_access [4:6] - [4:16]\n" + - " object: identifier [4:6] - [4:12]\n" + - " field: identifier [4:13] - [4:16]\n" + - " name: identifier [4:17] - [4:24]\n" + - " arguments: argument_list [4:24] - [4:41]\n" + - " string_literal [4:25] - [4:40]\n"; + "" + + OffsetSyntaxTreePrinter.TAG_OPEN + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + OffsetSyntaxTreePrinter.TAG_CLOSE; Assertions.assertEquals(expected, actual); } } \ No newline at end of file diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java index 73cc9896..7ea05840 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java @@ -22,37 +22,71 @@ void printRootTest() { Node root = tree.getRootNode(); String actual = printer.print(root); String expected = - "program [0:0] - [7:1]\n" + - " package_declaration [0:0] - [0:18]\n" + - " scoped_identifier [0:8] - [0:17]\n" + - " scope: scoped_identifier [0:8] - [0:14]\n" + - " scope: identifier [0:8] - [0:10]\n" + - " name: identifier [0:11] - [0:14]\n" + - " name: identifier [0:15] - [0:17]\n" + - " class_declaration [2:0] - [7:1]\n" + - " modifiers [2:0] - [2:6]\n" + - " name: identifier [2:13] - [2:17]\n" + - " body: class_body [2:18] - [7:1]\n" + - " method_declaration [3:4] - [6:5]\n" + - " modifiers [3:4] - [3:17]\n" + - " type: void_type [3:18] - [3:22]\n" + - " name: identifier [3:23] - [3:27]\n" + - " parameters: formal_parameters [3:27] - [3:42]\n" + - " formal_parameter [3:28] - [3:41]\n" + - " type: array_type [3:28] - [3:36]\n" + - " element: type_identifier [3:28] - [3:34]\n" + - " dimensions: dimensions [3:34] - [3:36]\n" + - " name: identifier [3:37] - [3:41]\n" + - " body: block [3:43] - [6:5]\n" + - " line_comment [4:8] - [4:22]\n" + - " expression_statement [5:8] - [5:44]\n" + - " method_invocation [5:8] - [5:43]\n" + - " object: field_access [5:8] - [5:18]\n" + - " object: identifier [5:8] - [5:14]\n" + - " field: identifier [5:15] - [5:18]\n" + - " name: identifier [5:19] - [5:26]\n" + - " arguments: argument_list [5:26] - [5:43]\n" + - " string_literal [5:27] - [5:42]\n"; + "" + + SyntaxTreePrinter.TAG_OPEN + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + SyntaxTreePrinter.TAG_CLOSE ; Assertions.assertEquals(expected, actual); } @@ -63,26 +97,49 @@ void printChildTest() { Node method = root.getChild(1).getChildByFieldName("body").getChild(1); String actual = printer.print(method); String expected = - "method_declaration [3:4] - [6:5]\n" + - " modifiers [3:4] - [3:17]\n" + - " type: void_type [3:18] - [3:22]\n" + - " name: identifier [3:23] - [3:27]\n" + - " parameters: formal_parameters [3:27] - [3:42]\n" + - " formal_parameter [3:28] - [3:41]\n" + - " type: array_type [3:28] - [3:36]\n" + - " element: type_identifier [3:28] - [3:34]\n" + - " dimensions: dimensions [3:34] - [3:36]\n" + - " name: identifier [3:37] - [3:41]\n" + - " body: block [3:43] - [6:5]\n" + - " line_comment [4:8] - [4:22]\n" + - " expression_statement [5:8] - [5:44]\n" + - " method_invocation [5:8] - [5:43]\n" + - " object: field_access [5:8] - [5:18]\n" + - " object: identifier [5:8] - [5:14]\n" + - " field: identifier [5:15] - [5:18]\n" + - " name: identifier [5:19] - [5:26]\n" + - " arguments: argument_list [5:26] - [5:43]\n" + - " string_literal [5:27] - [5:42]\n"; + "" + + SyntaxTreePrinter.TAG_OPEN + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + SyntaxTreePrinter.TAG_CLOSE; Assertions.assertEquals(expected, actual); } @@ -94,36 +151,69 @@ void printMultipleTest() { Node class_declaration = root.getChild(1); String actual = printer.print(package_declaration, class_declaration); String expected = - "package_declaration [0:0] - [0:18]\n" + - " scoped_identifier [0:8] - [0:17]\n" + - " scope: scoped_identifier [0:8] - [0:14]\n" + - " scope: identifier [0:8] - [0:10]\n" + - " name: identifier [0:11] - [0:14]\n" + - " name: identifier [0:15] - [0:17]\n" + - "class_declaration [2:0] - [7:1]\n" + - " modifiers [2:0] - [2:6]\n" + - " name: identifier [2:13] - [2:17]\n" + - " body: class_body [2:18] - [7:1]\n" + - " method_declaration [3:4] - [6:5]\n" + - " modifiers [3:4] - [3:17]\n" + - " type: void_type [3:18] - [3:22]\n" + - " name: identifier [3:23] - [3:27]\n" + - " parameters: formal_parameters [3:27] - [3:42]\n" + - " formal_parameter [3:28] - [3:41]\n" + - " type: array_type [3:28] - [3:36]\n" + - " element: type_identifier [3:28] - [3:34]\n" + - " dimensions: dimensions [3:34] - [3:36]\n" + - " name: identifier [3:37] - [3:41]\n" + - " body: block [3:43] - [6:5]\n" + - " line_comment [4:8] - [4:22]\n" + - " expression_statement [5:8] - [5:44]\n" + - " method_invocation [5:8] - [5:43]\n" + - " object: field_access [5:8] - [5:18]\n" + - " object: identifier [5:8] - [5:14]\n" + - " field: identifier [5:15] - [5:18]\n" + - " name: identifier [5:19] - [5:26]\n" + - " arguments: argument_list [5:26] - [5:43]\n" + - " string_literal [5:27] - [5:42]\n"; + "" + + SyntaxTreePrinter.TAG_OPEN + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + SyntaxTreePrinter.TAG_CLOSE; Assertions.assertEquals(expected, actual); } } \ No newline at end of file From c60e336c80fec67a368feddf0a39d8d099b20caa Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 5 Sep 2023 09:39:35 +0200 Subject: [PATCH 0255/1089] Added static factories for `counter` classes --- .../si/seart/analyzer/count/CodeTokenCounter.java | 7 +++++++ .../usi/si/seart/analyzer/count/TokenCounter.java | 12 ++++++++++++ 2 files changed, 19 insertions(+) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CodeTokenCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CodeTokenCounter.java index a71af870..e531c703 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CodeTokenCounter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CodeTokenCounter.java @@ -1,5 +1,6 @@ package usi.si.seart.analyzer.count; +import ch.usi.si.seart.treesitter.Language; import ch.usi.si.seart.treesitter.Node; public class CodeTokenCounter extends TraverseCounter { @@ -10,4 +11,10 @@ protected void nodeCallback(Node node) { boolean isComment = node.getType().contains("comment"); if (leafNode && !isComment) count.incrementAndGet(); } + + public static CodeTokenCounter getInstance(Language language) { + if (Language.PYTHON.equals(language)) + return new PythonCodeTokenCounter(); + return new CodeTokenCounter(); + } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TokenCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TokenCounter.java index 80e43852..aa05aefa 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TokenCounter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TokenCounter.java @@ -1,5 +1,6 @@ package usi.si.seart.analyzer.count; +import ch.usi.si.seart.treesitter.Language; import ch.usi.si.seart.treesitter.Node; import ch.usi.si.seart.treesitter.Range; import usi.si.seart.analyzer.NodeMapper; @@ -25,4 +26,15 @@ protected void nodeCallback(Node node) { } } } + + public static TokenCounter getInstance(Language language, NodeMapper mapper) { + switch (language) { + case JAVA: + return new JavaTokenCounter(mapper); + case PYTHON: + return new PythonTokenCounter(mapper); + default: + return new TokenCounter(mapper) {}; + } + } } From 225977d281d432076606152a228f7d7889adfe3c Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 5 Sep 2023 09:40:12 +0200 Subject: [PATCH 0256/1089] Added static factories for `query` classes --- .../query/multi/MultiCaptureQueries.java | 27 +++++++++++++++++++ .../query/single/SingleCaptureQueries.java | 18 +++++++++++++ 2 files changed, 45 insertions(+) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java index 0484cb31..d5c7d5d0 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java @@ -13,6 +13,7 @@ import usi.si.seart.analyzer.util.Tuple; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -42,4 +43,30 @@ public List>> execute(Node node, String pattern) { return tuples; }).collect(Collectors.toList()); } + + public static MultiCaptureQueries getInstance(Language language) { + switch (language) { + case JAVA: + return new JavaMultiCaptureQueries(); + case PYTHON: + return new PythonMultiCaptureQueries(); + default: + return new MultiCaptureQueries(null) { + + @Override + public void verify(Query query) { + } + + @Override + public List>> getCallableDeclarations(Node node) { + return Collections.emptyList(); + } + + @Override + public List>> execute(Node node, String pattern) { + return Collections.emptyList(); + } + }; + } + } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/SingleCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/SingleCaptureQueries.java index 893e21a1..9bee21d0 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/SingleCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/SingleCaptureQueries.java @@ -12,6 +12,7 @@ import usi.si.seart.analyzer.query.Queries; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -34,4 +35,21 @@ public List execute(Node node, String pattern) { .map(QueryCapture::getNode) .collect(Collectors.toList()); } + + public static SingleCaptureQueries getInstance(Language language) { + switch (language) { + case JAVA: + return new JavaSingleCaptureQueries(); + case PYTHON: + return new PythonSingleCaptureQueries(); + default: + return new SingleCaptureQueries(null) { + + @Override + public List getComments(Node node) { + return Collections.emptyList(); + } + }; + } + } } From edbd72aaa28a500f9fbd782b223dc918556327f9 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 5 Sep 2023 09:43:11 +0200 Subject: [PATCH 0257/1089] Added static factories for `predicate.path` classes --- .../analyzer/predicate/path/TestFilePredicate.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/path/TestFilePredicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/path/TestFilePredicate.java index 64418cd8..81fc2d79 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/path/TestFilePredicate.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/path/TestFilePredicate.java @@ -1,5 +1,7 @@ package usi.si.seart.analyzer.predicate.path; +import ch.usi.si.seart.treesitter.Language; + import java.nio.file.FileSystems; import java.nio.file.Path; import java.nio.file.PathMatcher; @@ -13,4 +15,15 @@ public boolean test(Path path) { PathMatcher matcher = FileSystems.getDefault().getPathMatcher(glob); return matcher.matches(path); } + + public static Predicate getInstance(Language language) { + switch (language) { + case JAVA: + return new JavaTestFilePredicate(); + case PYTHON: + return new PythonTestFilePredicate(); + default: + return new TestFilePredicate() {}; + } + } } From f495a2795e967cbe327adf0377e329b12edd6cce Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 5 Sep 2023 09:46:52 +0200 Subject: [PATCH 0258/1089] Added static factories for `enumerator` classes --- .../analyzer/enumerator/BoilerplateEnumerator.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/BoilerplateEnumerator.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/BoilerplateEnumerator.java index e1e3df41..c89bb31d 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/BoilerplateEnumerator.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/BoilerplateEnumerator.java @@ -1,5 +1,6 @@ package usi.si.seart.analyzer.enumerator; +import ch.usi.si.seart.treesitter.Language; import usi.si.seart.analyzer.NodeMapper; import usi.si.seart.model.code.Boilerplate; @@ -10,4 +11,15 @@ public abstract class BoilerplateEnumerator implements Enumerator { protected BoilerplateEnumerator(NodeMapper mapper) { this.mapper = mapper; } + + public static Enumerator getInstance(Language language, NodeMapper mapper) { + switch (language) { + case JAVA: + return new JavaBoilerplateEnumerator(mapper); + case PYTHON: + return new PythonBoilerplateEnumerator(mapper); + default: + return node -> null; + } + } } From f8b608257e71076103122ab9b1aa601d7b2b5095 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 5 Sep 2023 09:50:42 +0200 Subject: [PATCH 0259/1089] `Analyzer` components now initialized via factories --- .../si/seart/analyzer/AbstractAnalyzer.java | 66 +++++++------------ .../usi/si/seart/analyzer/JavaAnalyzer.java | 10 --- .../usi/si/seart/analyzer/PythonAnalyzer.java | 12 ---- 3 files changed, 24 insertions(+), 64 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java index 2e0bb5c8..36e835b0 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java @@ -3,7 +3,6 @@ import ch.usi.si.seart.treesitter.Language; import ch.usi.si.seart.treesitter.Node; import ch.usi.si.seart.treesitter.Parser; -import ch.usi.si.seart.treesitter.Query; import ch.usi.si.seart.treesitter.Tree; import lombok.AccessLevel; import lombok.Cleanup; @@ -14,6 +13,7 @@ import usi.si.seart.analyzer.count.Counter; import usi.si.seart.analyzer.count.LineCounter; import usi.si.seart.analyzer.count.TokenCounter; +import usi.si.seart.analyzer.enumerator.BoilerplateEnumerator; import usi.si.seart.analyzer.enumerator.Enumerator; import usi.si.seart.analyzer.hash.ContentHasher; import usi.si.seart.analyzer.hash.Hasher; @@ -39,9 +39,10 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import java.util.function.Predicate; import java.util.stream.Collectors; -@FieldDefaults(level = AccessLevel.PROTECTED) +@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) public abstract class AbstractAnalyzer implements Analyzer { Language language; @@ -52,56 +53,27 @@ public abstract class AbstractAnalyzer implements Analyzer { Path path; String source; - Counter lineCounter = new LineCounter(); - Counter codeTokenCounter = new CodeTokenCounter(); + Counter lineCounter; Counter totalTokenCounter; + Counter codeTokenCounter; Counter characterCounter; Hasher contentHasher; - Hasher syntaxTreeHasher = new SyntaxTreeHasher(); + Hasher syntaxTreeHasher; - NodePredicate containsError = new ContainsErrorPredicate(); + NodePredicate containsError; NodePredicate containsNonAscii; - TestFilePredicate testFilePredicate = new TestFilePredicate() {}; + Predicate testFilePredicate; Printer nodePrinter; - Printer syntaxTreePrinter = new SyntaxTreePrinter(); - Printer expressionPrinter = new SymbolicExpressionPrinter(); + Printer syntaxTreePrinter; + Printer expressionPrinter; - SingleCaptureQueries singleCaptureQueries = new SingleCaptureQueries(null) { - @Override - public void verify(Query query) { - } - - @Override - public List getComments(Node node) { - return List.of(); - } - - @Override - public List execute(Node node, String pattern) { - return List.of(); - } - }; - - MultiCaptureQueries multiCaptureQueries = new MultiCaptureQueries(null) { - @Override - public void verify(Query query) { - } - - @Override - public List>> getCallableDeclarations(Node node) { - return List.of(); - } - - @Override - public List>> execute(Node node, String pattern) { - return List.of(); - } - }; + SingleCaptureQueries singleCaptureQueries; + MultiCaptureQueries multiCaptureQueries; - Enumerator boilerplateEnumerator = node -> null; + Enumerator boilerplateEnumerator; @SneakyThrows(IOException.class) protected AbstractAnalyzer(LocalClone localClone, Path path, Language language) { @@ -112,11 +84,21 @@ protected AbstractAnalyzer(LocalClone localClone, Path path, Language language) this.source = Files.readString(path); this.tree = parser.parseString(source); NodeMapper mapper = this::getSourceBytes; - this.totalTokenCounter = new TokenCounter(mapper){}; + this.lineCounter = new LineCounter(); + this.totalTokenCounter = TokenCounter.getInstance(language, mapper); + this.codeTokenCounter = CodeTokenCounter.getInstance(language); this.characterCounter = new CharacterCounter(mapper); this.contentHasher = new ContentHasher(mapper); + this.syntaxTreeHasher = new SyntaxTreeHasher(); + this.containsError = new ContainsErrorPredicate(); this.containsNonAscii = new ContainsNonAsciiPredicate(mapper); + this.testFilePredicate = TestFilePredicate.getInstance(language); this.nodePrinter = new NodePrinter(mapper); + this.syntaxTreePrinter = new SyntaxTreePrinter(); + this.expressionPrinter = new SymbolicExpressionPrinter(); + this.singleCaptureQueries = SingleCaptureQueries.getInstance(language); + this.multiCaptureQueries = MultiCaptureQueries.getInstance(language); + this.boilerplateEnumerator = BoilerplateEnumerator.getInstance(language, mapper); } protected final byte[] getSourceBytes() { diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java index 8e52a35d..a0f0a273 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java @@ -4,13 +4,8 @@ import ch.usi.si.seart.treesitter.Node; import ch.usi.si.seart.treesitter.Point; import ch.usi.si.seart.treesitter.Tree; -import usi.si.seart.analyzer.count.JavaTokenCounter; -import usi.si.seart.analyzer.enumerator.JavaBoilerplateEnumerator; -import usi.si.seart.analyzer.predicate.path.JavaTestFilePredicate; import usi.si.seart.analyzer.printer.OffsetSyntaxTreePrinter; import usi.si.seart.analyzer.printer.Printer; -import usi.si.seart.analyzer.query.multi.JavaMultiCaptureQueries; -import usi.si.seart.analyzer.query.single.JavaSingleCaptureQueries; import java.nio.file.Path; import java.util.List; @@ -19,11 +14,6 @@ public class JavaAnalyzer extends AbstractAnalyzer { public JavaAnalyzer(LocalClone localClone, Path path) { super(localClone, path, Language.JAVA); - this.totalTokenCounter = new JavaTokenCounter(this::getSourceBytes); - this.testFilePredicate = new JavaTestFilePredicate(); - this.singleCaptureQueries = new JavaSingleCaptureQueries(); - this.multiCaptureQueries = new JavaMultiCaptureQueries(); - this.boilerplateEnumerator = new JavaBoilerplateEnumerator(this::getSourceBytes); } @Override diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java index 88d1685d..0f60e227 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java @@ -1,12 +1,6 @@ package usi.si.seart.analyzer; import ch.usi.si.seart.treesitter.Language; -import usi.si.seart.analyzer.count.PythonCodeTokenCounter; -import usi.si.seart.analyzer.count.PythonTokenCounter; -import usi.si.seart.analyzer.enumerator.PythonBoilerplateEnumerator; -import usi.si.seart.analyzer.predicate.path.PythonTestFilePredicate; -import usi.si.seart.analyzer.query.multi.PythonMultiCaptureQueries; -import usi.si.seart.analyzer.query.single.PythonSingleCaptureQueries; import java.nio.file.Path; @@ -14,11 +8,5 @@ public class PythonAnalyzer extends AbstractAnalyzer { public PythonAnalyzer(LocalClone localClone, Path path) { super(localClone, path, Language.PYTHON); - this.codeTokenCounter = new PythonCodeTokenCounter(); - this.totalTokenCounter = new PythonTokenCounter(this::getSourceBytes); - this.testFilePredicate = new PythonTestFilePredicate(); - this.singleCaptureQueries = new PythonSingleCaptureQueries(); - this.multiCaptureQueries = new PythonMultiCaptureQueries(); - this.boilerplateEnumerator = new PythonBoilerplateEnumerator(this::getSourceBytes); } } From afcf16684da68de089e8d09069d61ed00af577c5 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 5 Sep 2023 10:02:51 +0200 Subject: [PATCH 0260/1089] Removing reference to class --- .../test/java/usi/si/seart/analyzer/hash/JavaHasherTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaHasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaHasherTest.java index 0614d365..3eeb3ef3 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaHasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaHasherTest.java @@ -3,6 +3,7 @@ import lombok.SneakyThrows; import usi.si.seart.analyzer.test.JavaBaseTest; +import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.List; @@ -91,7 +92,8 @@ protected List getNodes() { @SneakyThrows({NoSuchAlgorithmException.class}) protected String sha256(String input) { MessageDigest md = MessageDigest.getInstance("SHA-256"); - byte[] hash = md.digest(input.getBytes(SHA256Hasher.DEFAULT_CHARSET)); + byte[] bytes = input.getBytes(StandardCharsets.UTF_16LE); + byte[] hash = md.digest(bytes); return SHA256Hasher.bytesToHex(hash); } } From 8164230eecd51db8618817ed160595d471e93d1b Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 5 Sep 2023 10:05:43 +0200 Subject: [PATCH 0261/1089] Variable extract, ignore commit --- .../main/java/usi/si/seart/analyzer/hash/ContentHasher.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java index dba84f67..6e4772a6 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java @@ -24,7 +24,8 @@ protected void update(Node node) { boolean isComment = current.getType().contains("comment"); if (leafNode && !isComment) { Range range = current.getRange(); - md.update(mapper.getBytesForRange(range)); + byte[] bytes = mapper.getBytesForRange(range); + md.update(bytes); } }); } From 8746729de8834fb5c0c69e98c8b7dab9b80063c8 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 5 Sep 2023 10:14:20 +0200 Subject: [PATCH 0262/1089] The `DEFAULT_CHARSET` variable is now part of `NodeMapper` --- .../src/main/java/usi/si/seart/analyzer/NodeMapper.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/NodeMapper.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/NodeMapper.java index 7673d047..b168cf88 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/NodeMapper.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/NodeMapper.java @@ -2,10 +2,14 @@ import ch.usi.si.seart.treesitter.Range; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.Arrays; public interface NodeMapper { + Charset DEFAULT_CHARSET = StandardCharsets.UTF_16LE; + byte[] getBytes(); default byte[] getBytesForRange(Range range) { @@ -16,6 +20,6 @@ default byte[] getBytesForRange(Range range) { default String getContentForRange(Range range) { byte[] bytes = getBytesForRange(range); - return new String(bytes, Settings.DEFAULT_CHARSET); + return new String(bytes, DEFAULT_CHARSET); } } From edaee958a22b6816f25a779e9bf22e5b16a572ad Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 5 Sep 2023 10:15:51 +0200 Subject: [PATCH 0263/1089] Update `BaseTest` to provide charset override --- .../test/java/usi/si/seart/analyzer/test/BaseTest.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java index edeb8da0..f1fc0661 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java @@ -10,7 +10,7 @@ import usi.si.seart.analyzer.NodeMapper; import java.io.UnsupportedEncodingException; -import java.nio.charset.StandardCharsets; +import java.nio.charset.Charset; import java.util.List; public abstract class BaseTest { @@ -48,7 +48,11 @@ void tearDown() { protected abstract String getInput(); protected byte[] getBytes() { - return getInput().getBytes(StandardCharsets.UTF_16LE); + return getInput().getBytes(getCharset()); + } + + protected Charset getCharset() { + return NodeMapper.DEFAULT_CHARSET; } protected NodeMapper getNodeMapper() { From cf5fe161f051548496ba1b81fea7ffa9e48b0a75 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 5 Sep 2023 10:17:16 +0200 Subject: [PATCH 0264/1089] `AbstractAnalyzer` now uses the `NodeMapper` charset --- .../src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java index 36e835b0..2d28fdcf 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java @@ -102,7 +102,7 @@ protected AbstractAnalyzer(LocalClone localClone, Path path, Language language) } protected final byte[] getSourceBytes() { - return source.getBytes(Settings.DEFAULT_CHARSET); + return source.getBytes(NodeMapper.DEFAULT_CHARSET); } @Override From 6d39c2e7da4d183cb0a94d2dc478dfb94e196e67 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 5 Sep 2023 10:19:17 +0200 Subject: [PATCH 0265/1089] `Hasher` implementations now use different byte mappings - `ContentHasher` depends on the `NodeMapper`-defined `Charset` - `SyntaxTreeHasher` depends on the system `Charset` --- .../main/java/usi/si/seart/analyzer/hash/SHA256Hasher.java | 4 ---- .../java/usi/si/seart/analyzer/hash/SyntaxTreeHasher.java | 2 +- .../java/usi/si/seart/analyzer/hash/JavaHasherTest.java | 3 +-- .../si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java | 6 ++++++ 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SHA256Hasher.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SHA256Hasher.java index eae40249..a84ef800 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SHA256Hasher.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SHA256Hasher.java @@ -3,16 +3,12 @@ import ch.usi.si.seart.treesitter.Node; import lombok.SneakyThrows; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Collection; public abstract class SHA256Hasher implements Hasher { - public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_16LE; - protected final MessageDigest md; @SneakyThrows(NoSuchAlgorithmException.class) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SyntaxTreeHasher.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SyntaxTreeHasher.java index aac9779e..384e3582 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SyntaxTreeHasher.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SyntaxTreeHasher.java @@ -17,7 +17,7 @@ protected void update(Node node) { boolean isComment = current.getType().contains("comment"); if (leafNode && !isComment) { String type = current.getType(); - byte[] bytes = type.getBytes(DEFAULT_CHARSET); + byte[] bytes = type.getBytes(); md.update(bytes); } }); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaHasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaHasherTest.java index 3eeb3ef3..8dca368d 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaHasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaHasherTest.java @@ -3,7 +3,6 @@ import lombok.SneakyThrows; import usi.si.seart.analyzer.test.JavaBaseTest; -import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.List; @@ -92,7 +91,7 @@ protected List getNodes() { @SneakyThrows({NoSuchAlgorithmException.class}) protected String sha256(String input) { MessageDigest md = MessageDigest.getInstance("SHA-256"); - byte[] bytes = input.getBytes(StandardCharsets.UTF_16LE); + byte[] bytes = input.getBytes(getCharset()); byte[] hash = md.digest(bytes); return SHA256Hasher.bytesToHex(hash); } diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java index 4b6a03a7..ec20d13c 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java @@ -6,6 +6,7 @@ import org.junit.jupiter.api.Test; import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; import java.util.HashSet; class JavaSyntaxTreeHasherTest extends JavaHasherTest { @@ -54,4 +55,9 @@ void noCommentImpactTest() { String second = hasher.hash(other.getRootNode()); Assertions.assertEquals(first, second, "Comments should not impact the hashing result!"); } + + @Override + protected Charset getCharset() { + return Charset.defaultCharset(); + } } \ No newline at end of file From e9a6ea22eced5f5fa33d4f3f45df1ee64a0aa179 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 5 Sep 2023 10:19:24 +0200 Subject: [PATCH 0266/1089] Removed `Settings` --- .../src/main/java/usi/si/seart/analyzer/Settings.java | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Settings.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Settings.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Settings.java deleted file mode 100644 index bc161b63..00000000 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Settings.java +++ /dev/null @@ -1,8 +0,0 @@ -package usi.si.seart.analyzer; - -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; - -public interface Settings { - Charset DEFAULT_CHARSET = StandardCharsets.UTF_16LE; -} From 62ed9f892f0f883962878e824deba359f9a959cb Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 5 Sep 2023 11:16:54 +0200 Subject: [PATCH 0267/1089] Introducing `FunctionSyntaxTreePrinter` for recalculating function ASTs The protected methods of `AbstractAnalyzer` have been moved to their own private inner class. Why is it an inner class? To make use of the existing members more efficiently. Why is its factory part of the `AbstractAnalyzer` and not the class itself? Language limitations! This will change once ported to Java 17. --- .../si/seart/analyzer/AbstractAnalyzer.java | 79 +++++++++++++++---- .../usi/si/seart/analyzer/JavaAnalyzer.java | 24 ------ 2 files changed, 64 insertions(+), 39 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java index 2d28fdcf..d81a4c4f 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java @@ -3,6 +3,7 @@ import ch.usi.si.seart.treesitter.Language; import ch.usi.si.seart.treesitter.Node; import ch.usi.si.seart.treesitter.Parser; +import ch.usi.si.seart.treesitter.Point; import ch.usi.si.seart.treesitter.Tree; import lombok.AccessLevel; import lombok.Cleanup; @@ -23,6 +24,7 @@ import usi.si.seart.analyzer.predicate.node.NodePredicate; import usi.si.seart.analyzer.predicate.path.TestFilePredicate; import usi.si.seart.analyzer.printer.NodePrinter; +import usi.si.seart.analyzer.printer.OffsetSyntaxTreePrinter; import usi.si.seart.analyzer.printer.Printer; import usi.si.seart.analyzer.printer.SymbolicExpressionPrinter; import usi.si.seart.analyzer.printer.SyntaxTreePrinter; @@ -38,6 +40,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -153,7 +156,6 @@ protected List extractFunctionEntities(File file) { return functions; } - @SneakyThrows(UnsupportedEncodingException.class) protected Function extractFunctionEntity(List> match) { List nodes = match.stream() .map(Tuple::getValue) @@ -164,17 +166,13 @@ protected Function extractFunctionEntity(List> match) { .findFirst() .orElseThrow(IllegalStateException::new); - String content = nodePrinter.print(nodes); - String wrapped = wrapContent(content); - @Cleanup Tree intermediate = parser.parseString(wrapped); - List unwrapped = unwrapNodes(intermediate); - Printer astPrinter = getAstPrinter(); - String ast = astPrinter.print(unwrapped); + Printer standalone = getStandalonePrinter(language); + String ast = standalone.print(nodes); return Function.builder() .repo(localClone.getGitRepo()) .ast(ast) - .content(content) + .content(nodePrinter.print(nodes)) .astHash(syntaxTreeHasher.hash(nodes)) .contentHash(contentHasher.hash(nodes)) .symbolicExpression(expressionPrinter.print(nodes)) @@ -188,15 +186,66 @@ protected Function extractFunctionEntity(List> match) { .build(); } - protected String wrapContent(String content) { - return content; + FunctionSyntaxTreePrinter getStandalonePrinter(Language language) { + if (Language.JAVA.equals(language)) { + return new FunctionSyntaxTreePrinter() { + + @Override + protected String wrap(String content) { + return "class _ {\n" + content + "\n}\n"; + } + + @Override + protected List getTargets(Tree tree) { + Node root = tree.getRootNode(); + Node declaration = root.getChild(0); + Node body = declaration.getChildByFieldName("body"); + return body.getChildren(); + } + + @Override + protected Printer getAstPrinter() { + return new OffsetSyntaxTreePrinter(new Point(-1, 0)); + } + }; + } else { + return new FunctionSyntaxTreePrinter() {}; + } } - protected List unwrapNodes(Tree tree) { - return tree.getRootNode().getChildren(); - } + private abstract class FunctionSyntaxTreePrinter implements Printer { + + protected String wrap(String content) { + return content; + } - protected Printer getAstPrinter() { - return syntaxTreePrinter; + protected List getTargets(Tree tree) { + return tree.getRootNode().getChildren(); + } + + protected Printer getAstPrinter() { + return syntaxTreePrinter; + } + + @Override + public String print(Node node) { + return print(List.of(node)); + } + + @Override + public String print(Node... nodes) { + return print(List.of(nodes)); + } + + @Override + @SneakyThrows(UnsupportedEncodingException.class) + public String print(Collection nodes) { + String content = nodePrinter.print(nodes); + String wrapped = wrap(content); + @Cleanup Tree tree = parser.parseString(wrapped); + List targets = getTargets(tree); + Printer astPrinter = getAstPrinter(); + return astPrinter.print(targets); + } } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java index a0f0a273..c2d3f7d8 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java @@ -1,36 +1,12 @@ package usi.si.seart.analyzer; import ch.usi.si.seart.treesitter.Language; -import ch.usi.si.seart.treesitter.Node; -import ch.usi.si.seart.treesitter.Point; -import ch.usi.si.seart.treesitter.Tree; -import usi.si.seart.analyzer.printer.OffsetSyntaxTreePrinter; -import usi.si.seart.analyzer.printer.Printer; import java.nio.file.Path; -import java.util.List; public class JavaAnalyzer extends AbstractAnalyzer { public JavaAnalyzer(LocalClone localClone, Path path) { super(localClone, path, Language.JAVA); } - - @Override - protected String wrapContent(String content) { - return "class _ {\n" + content + "\n}\n"; - } - - @Override - protected List unwrapNodes(Tree tree) { - Node root = tree.getRootNode(); - Node declaration = root.getChild(0); - Node body = declaration.getChildByFieldName("body"); - return body.getChildren(); - } - - @Override - protected Printer getAstPrinter() { - return new OffsetSyntaxTreePrinter(new Point(-1, 0)); - } } From 44f1a3a70f55ca6499e652ebb0e4d558984c8540 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 5 Sep 2023 11:32:16 +0200 Subject: [PATCH 0268/1089] `Analyzer` now constitutes a single concrete class No more need for implementors, factories or interfaces --- .../si/seart/analyzer/AbstractAnalyzer.java | 251 ------------------ .../java/usi/si/seart/analyzer/Analyzer.java | 246 ++++++++++++++++- .../si/seart/analyzer/AnalyzerFactory.java | 26 -- .../usi/si/seart/analyzer/JavaAnalyzer.java | 12 - .../usi/si/seart/analyzer/PythonAnalyzer.java | 12 - 5 files changed, 243 insertions(+), 304 deletions(-) delete mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java delete mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AnalyzerFactory.java delete mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java delete mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java deleted file mode 100644 index d81a4c4f..00000000 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AbstractAnalyzer.java +++ /dev/null @@ -1,251 +0,0 @@ -package usi.si.seart.analyzer; - -import ch.usi.si.seart.treesitter.Language; -import ch.usi.si.seart.treesitter.Node; -import ch.usi.si.seart.treesitter.Parser; -import ch.usi.si.seart.treesitter.Point; -import ch.usi.si.seart.treesitter.Tree; -import lombok.AccessLevel; -import lombok.Cleanup; -import lombok.SneakyThrows; -import lombok.experimental.FieldDefaults; -import usi.si.seart.analyzer.count.CharacterCounter; -import usi.si.seart.analyzer.count.CodeTokenCounter; -import usi.si.seart.analyzer.count.Counter; -import usi.si.seart.analyzer.count.LineCounter; -import usi.si.seart.analyzer.count.TokenCounter; -import usi.si.seart.analyzer.enumerator.BoilerplateEnumerator; -import usi.si.seart.analyzer.enumerator.Enumerator; -import usi.si.seart.analyzer.hash.ContentHasher; -import usi.si.seart.analyzer.hash.Hasher; -import usi.si.seart.analyzer.hash.SyntaxTreeHasher; -import usi.si.seart.analyzer.predicate.node.ContainsErrorPredicate; -import usi.si.seart.analyzer.predicate.node.ContainsNonAsciiPredicate; -import usi.si.seart.analyzer.predicate.node.NodePredicate; -import usi.si.seart.analyzer.predicate.path.TestFilePredicate; -import usi.si.seart.analyzer.printer.NodePrinter; -import usi.si.seart.analyzer.printer.OffsetSyntaxTreePrinter; -import usi.si.seart.analyzer.printer.Printer; -import usi.si.seart.analyzer.printer.SymbolicExpressionPrinter; -import usi.si.seart.analyzer.printer.SyntaxTreePrinter; -import usi.si.seart.analyzer.query.multi.MultiCaptureQueries; -import usi.si.seart.analyzer.query.single.SingleCaptureQueries; -import usi.si.seart.analyzer.util.Tuple; -import usi.si.seart.model.code.Boilerplate; -import usi.si.seart.model.code.File; -import usi.si.seart.model.code.Function; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) -public abstract class AbstractAnalyzer implements Analyzer { - - Language language; - Parser parser; - Tree tree; - - LocalClone localClone; - Path path; - String source; - - Counter lineCounter; - Counter totalTokenCounter; - Counter codeTokenCounter; - Counter characterCounter; - - Hasher contentHasher; - Hasher syntaxTreeHasher; - - NodePredicate containsError; - NodePredicate containsNonAscii; - - Predicate testFilePredicate; - - Printer nodePrinter; - Printer syntaxTreePrinter; - Printer expressionPrinter; - - SingleCaptureQueries singleCaptureQueries; - MultiCaptureQueries multiCaptureQueries; - - Enumerator boilerplateEnumerator; - - @SneakyThrows(IOException.class) - protected AbstractAnalyzer(LocalClone localClone, Path path, Language language) { - this.language = language; - this.parser = new Parser(language); - this.localClone = localClone; - this.path = path; - this.source = Files.readString(path); - this.tree = parser.parseString(source); - NodeMapper mapper = this::getSourceBytes; - this.lineCounter = new LineCounter(); - this.totalTokenCounter = TokenCounter.getInstance(language, mapper); - this.codeTokenCounter = CodeTokenCounter.getInstance(language); - this.characterCounter = new CharacterCounter(mapper); - this.contentHasher = new ContentHasher(mapper); - this.syntaxTreeHasher = new SyntaxTreeHasher(); - this.containsError = new ContainsErrorPredicate(); - this.containsNonAscii = new ContainsNonAsciiPredicate(mapper); - this.testFilePredicate = TestFilePredicate.getInstance(language); - this.nodePrinter = new NodePrinter(mapper); - this.syntaxTreePrinter = new SyntaxTreePrinter(); - this.expressionPrinter = new SymbolicExpressionPrinter(); - this.singleCaptureQueries = SingleCaptureQueries.getInstance(language); - this.multiCaptureQueries = MultiCaptureQueries.getInstance(language); - this.boilerplateEnumerator = BoilerplateEnumerator.getInstance(language, mapper); - } - - protected final byte[] getSourceBytes() { - return source.getBytes(NodeMapper.DEFAULT_CHARSET); - } - - @Override - public void close() { - tree.close(); - parser.close(); - } - - @Override - public final Result analyze() { - File file = extractFileEntity(); - List functions = extractFunctionEntities(file); - file.setFunctions(functions); - return new Analyzer.Result(file, functions); - } - - protected File extractFileEntity() { - Node node = tree.getRootNode(); - return File.builder() - .repo(localClone.getGitRepo()) - .path(localClone.relativePathOf(path).toString()) - .content(nodePrinter.print(node)) - .contentHash(contentHasher.hash(node)) - .ast(syntaxTreePrinter.print(node)) - .astHash(syntaxTreeHasher.hash(node)) - .symbolicExpression(expressionPrinter.print(node)) - .totalTokens(totalTokenCounter.count(node)) - .codeTokens(codeTokenCounter.count(node)) - .lines(lineCounter.count(node)) - .characters(characterCounter.count(node)) - .containsNonAscii(containsNonAscii.test(node)) - .containsError(containsError.test(node)) - .isTest(testFilePredicate.test(path)) - .build(); - } - - protected List extractFunctionEntities(File file) { - List>> matches = multiCaptureQueries.getCallableDeclarations(tree.getRootNode()); - List functions = new ArrayList<>(matches.size()); - for (List> match: matches) { - Function function = extractFunctionEntity(match); - // These operations are invariant by - // nature and should not be overridden - function.setFile(file); - function.setIsTest(file.getIsTest()); - functions.add(function); - } - return functions; - } - - protected Function extractFunctionEntity(List> match) { - List nodes = match.stream() - .map(Tuple::getValue) - .collect(Collectors.toList()); - Node function = match.stream() - .filter(tuple -> tuple.getKey().equals("target")) - .map(Tuple::getValue) - .findFirst() - .orElseThrow(IllegalStateException::new); - - Printer standalone = getStandalonePrinter(language); - String ast = standalone.print(nodes); - - return Function.builder() - .repo(localClone.getGitRepo()) - .ast(ast) - .content(nodePrinter.print(nodes)) - .astHash(syntaxTreeHasher.hash(nodes)) - .contentHash(contentHasher.hash(nodes)) - .symbolicExpression(expressionPrinter.print(nodes)) - .totalTokens(totalTokenCounter.count(nodes)) - .codeTokens(codeTokenCounter.count(nodes)) - .lines(lineCounter.count(nodes)) - .characters(characterCounter.count(nodes)) - .containsNonAscii(containsNonAscii.test(nodes)) - .containsError(containsError.test(nodes)) - .boilerplateType(boilerplateEnumerator.asEnum(function)) - .build(); - } - - FunctionSyntaxTreePrinter getStandalonePrinter(Language language) { - if (Language.JAVA.equals(language)) { - return new FunctionSyntaxTreePrinter() { - - @Override - protected String wrap(String content) { - return "class _ {\n" + content + "\n}\n"; - } - - @Override - protected List getTargets(Tree tree) { - Node root = tree.getRootNode(); - Node declaration = root.getChild(0); - Node body = declaration.getChildByFieldName("body"); - return body.getChildren(); - } - - @Override - protected Printer getAstPrinter() { - return new OffsetSyntaxTreePrinter(new Point(-1, 0)); - } - }; - } else { - return new FunctionSyntaxTreePrinter() {}; - } - } - - private abstract class FunctionSyntaxTreePrinter implements Printer { - - protected String wrap(String content) { - return content; - } - - protected List getTargets(Tree tree) { - return tree.getRootNode().getChildren(); - } - - protected Printer getAstPrinter() { - return syntaxTreePrinter; - } - - @Override - public String print(Node node) { - return print(List.of(node)); - } - - @Override - public String print(Node... nodes) { - return print(List.of(nodes)); - } - - @Override - @SneakyThrows(UnsupportedEncodingException.class) - public String print(Collection nodes) { - String content = nodePrinter.print(nodes); - String wrapped = wrap(content); - @Cleanup Tree tree = parser.parseString(wrapped); - List targets = getTargets(tree); - Printer astPrinter = getAstPrinter(); - return astPrinter.print(targets); - } - } -} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java index b5f375c0..3f6fcbe5 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java @@ -1,23 +1,263 @@ package usi.si.seart.analyzer; +import ch.usi.si.seart.treesitter.Language; +import ch.usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Parser; +import ch.usi.si.seart.treesitter.Point; +import ch.usi.si.seart.treesitter.Tree; import lombok.AccessLevel; import lombok.AllArgsConstructor; +import lombok.Cleanup; import lombok.Getter; +import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; +import usi.si.seart.analyzer.count.CharacterCounter; +import usi.si.seart.analyzer.count.CodeTokenCounter; +import usi.si.seart.analyzer.count.Counter; +import usi.si.seart.analyzer.count.LineCounter; +import usi.si.seart.analyzer.count.TokenCounter; +import usi.si.seart.analyzer.enumerator.BoilerplateEnumerator; +import usi.si.seart.analyzer.enumerator.Enumerator; +import usi.si.seart.analyzer.hash.ContentHasher; +import usi.si.seart.analyzer.hash.Hasher; +import usi.si.seart.analyzer.hash.SyntaxTreeHasher; +import usi.si.seart.analyzer.predicate.node.ContainsErrorPredicate; +import usi.si.seart.analyzer.predicate.node.ContainsNonAsciiPredicate; +import usi.si.seart.analyzer.predicate.node.NodePredicate; +import usi.si.seart.analyzer.predicate.path.TestFilePredicate; +import usi.si.seart.analyzer.printer.NodePrinter; +import usi.si.seart.analyzer.printer.OffsetSyntaxTreePrinter; +import usi.si.seart.analyzer.printer.Printer; +import usi.si.seart.analyzer.printer.SymbolicExpressionPrinter; +import usi.si.seart.analyzer.printer.SyntaxTreePrinter; +import usi.si.seart.analyzer.query.multi.MultiCaptureQueries; +import usi.si.seart.analyzer.query.single.SingleCaptureQueries; +import usi.si.seart.analyzer.util.Tuple; +import usi.si.seart.model.code.Boilerplate; import usi.si.seart.model.code.File; import usi.si.seart.model.code.Function; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; -public interface Analyzer extends AutoCloseable { +@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) +public class Analyzer implements AutoCloseable { - Result analyze(); + Language language; + Parser parser; + Tree tree; + + LocalClone localClone; + Path path; + String source; + + Counter lineCounter; + Counter totalTokenCounter; + Counter codeTokenCounter; + Counter characterCounter; + + Hasher contentHasher; + Hasher syntaxTreeHasher; + + NodePredicate containsError; + NodePredicate containsNonAscii; + + Predicate testFilePredicate; + + Printer nodePrinter; + Printer syntaxTreePrinter; + Printer expressionPrinter; + + SingleCaptureQueries singleCaptureQueries; + MultiCaptureQueries multiCaptureQueries; + + Enumerator boilerplateEnumerator; + + public Analyzer(LocalClone localClone, Path path, String languageName) throws IOException { + this(localClone, path, Language.valueOf(languageName)); + } + + public Analyzer(LocalClone localClone, Path path, Language language) throws IOException { + this.language = language; + this.parser = new Parser(language); + this.localClone = localClone; + this.path = path; + this.source = Files.readString(path); + this.tree = parser.parseString(source); + NodeMapper mapper = this::getSourceBytes; + this.lineCounter = new LineCounter(); + this.totalTokenCounter = TokenCounter.getInstance(language, mapper); + this.codeTokenCounter = CodeTokenCounter.getInstance(language); + this.characterCounter = new CharacterCounter(mapper); + this.contentHasher = new ContentHasher(mapper); + this.syntaxTreeHasher = new SyntaxTreeHasher(); + this.containsError = new ContainsErrorPredicate(); + this.containsNonAscii = new ContainsNonAsciiPredicate(mapper); + this.testFilePredicate = TestFilePredicate.getInstance(language); + this.nodePrinter = new NodePrinter(mapper); + this.syntaxTreePrinter = new SyntaxTreePrinter(); + this.expressionPrinter = new SymbolicExpressionPrinter(); + this.singleCaptureQueries = SingleCaptureQueries.getInstance(language); + this.multiCaptureQueries = MultiCaptureQueries.getInstance(language); + this.boilerplateEnumerator = BoilerplateEnumerator.getInstance(language, mapper); + } + + protected final byte[] getSourceBytes() { + return source.getBytes(NodeMapper.DEFAULT_CHARSET); + } + + @Override + public void close() { + tree.close(); + parser.close(); + } @Getter @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) @AllArgsConstructor - final class Result { + public static final class Result { File file; List functions; } + + public final Result analyze() { + File file = extractFileEntity(); + List functions = extractFunctionEntities(file); + file.setFunctions(functions); + return new Result(file, functions); + } + + protected File extractFileEntity() { + Node node = tree.getRootNode(); + return File.builder() + .repo(localClone.getGitRepo()) + .path(localClone.relativePathOf(path).toString()) + .content(nodePrinter.print(node)) + .contentHash(contentHasher.hash(node)) + .ast(syntaxTreePrinter.print(node)) + .astHash(syntaxTreeHasher.hash(node)) + .symbolicExpression(expressionPrinter.print(node)) + .totalTokens(totalTokenCounter.count(node)) + .codeTokens(codeTokenCounter.count(node)) + .lines(lineCounter.count(node)) + .characters(characterCounter.count(node)) + .containsNonAscii(containsNonAscii.test(node)) + .containsError(containsError.test(node)) + .isTest(testFilePredicate.test(path)) + .build(); + } + + protected List extractFunctionEntities(File file) { + List>> matches = multiCaptureQueries.getCallableDeclarations(tree.getRootNode()); + List functions = new ArrayList<>(matches.size()); + for (List> match: matches) { + Function function = extractFunctionEntity(match); + // These operations are invariant by + // nature and should not be overridden + function.setFile(file); + function.setIsTest(file.getIsTest()); + functions.add(function); + } + return functions; + } + + protected Function extractFunctionEntity(List> match) { + List nodes = match.stream() + .map(Tuple::getValue) + .collect(Collectors.toList()); + Node function = match.stream() + .filter(tuple -> tuple.getKey().equals("target")) + .map(Tuple::getValue) + .findFirst() + .orElseThrow(IllegalStateException::new); + + Printer standalone = getStandalonePrinter(language); + String ast = standalone.print(nodes); + + return Function.builder() + .repo(localClone.getGitRepo()) + .ast(ast) + .content(nodePrinter.print(nodes)) + .astHash(syntaxTreeHasher.hash(nodes)) + .contentHash(contentHasher.hash(nodes)) + .symbolicExpression(expressionPrinter.print(nodes)) + .totalTokens(totalTokenCounter.count(nodes)) + .codeTokens(codeTokenCounter.count(nodes)) + .lines(lineCounter.count(nodes)) + .characters(characterCounter.count(nodes)) + .containsNonAscii(containsNonAscii.test(nodes)) + .containsError(containsError.test(nodes)) + .boilerplateType(boilerplateEnumerator.asEnum(function)) + .build(); + } + + FunctionSyntaxTreePrinter getStandalonePrinter(Language language) { + if (Language.JAVA.equals(language)) { + return new FunctionSyntaxTreePrinter() { + + @Override + protected String wrap(String content) { + return "class _ {\n" + content + "\n}\n"; + } + + @Override + protected List getTargets(Tree tree) { + Node root = tree.getRootNode(); + Node declaration = root.getChild(0); + Node body = declaration.getChildByFieldName("body"); + return body.getChildren(); + } + + @Override + protected Printer getAstPrinter() { + return new OffsetSyntaxTreePrinter(new Point(-1, 0)); + } + }; + } else { + return new FunctionSyntaxTreePrinter() {}; + } + } + + private abstract class FunctionSyntaxTreePrinter implements Printer { + + protected String wrap(String content) { + return content; + } + + protected List getTargets(Tree tree) { + return tree.getRootNode().getChildren(); + } + + protected Printer getAstPrinter() { + return syntaxTreePrinter; + } + + @Override + public String print(Node node) { + return print(List.of(node)); + } + + @Override + public String print(Node... nodes) { + return print(List.of(nodes)); + } + + @Override + @SneakyThrows(UnsupportedEncodingException.class) + public String print(Collection nodes) { + String content = nodePrinter.print(nodes); + String wrapped = wrap(content); + @Cleanup Tree tree = parser.parseString(wrapped); + List targets = getTargets(tree); + Printer astPrinter = getAstPrinter(); + return astPrinter.print(targets); + } + } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AnalyzerFactory.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AnalyzerFactory.java deleted file mode 100644 index a913c73c..00000000 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/AnalyzerFactory.java +++ /dev/null @@ -1,26 +0,0 @@ -package usi.si.seart.analyzer; - -import lombok.experimental.UtilityClass; -import usi.si.seart.model.Language; - -import java.nio.file.Path; -import java.util.function.BiFunction; - -@UtilityClass -public class AnalyzerFactory { - - public BiFunction getAnalyzer(Language language) { - return getAnalyzer(language.getName()); - } - - private BiFunction getAnalyzer(String name) { - switch (name) { - case "Java": - return JavaAnalyzer::new; - case "Python": - return PythonAnalyzer::new; - default: - throw new UnsupportedOperationException("The language [" + name + "] is not supported!"); - } - } -} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java deleted file mode 100644 index c2d3f7d8..00000000 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/JavaAnalyzer.java +++ /dev/null @@ -1,12 +0,0 @@ -package usi.si.seart.analyzer; - -import ch.usi.si.seart.treesitter.Language; - -import java.nio.file.Path; - -public class JavaAnalyzer extends AbstractAnalyzer { - - public JavaAnalyzer(LocalClone localClone, Path path) { - super(localClone, path, Language.JAVA); - } -} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java deleted file mode 100644 index 0f60e227..00000000 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/PythonAnalyzer.java +++ /dev/null @@ -1,12 +0,0 @@ -package usi.si.seart.analyzer; - -import ch.usi.si.seart.treesitter.Language; - -import java.nio.file.Path; - -public class PythonAnalyzer extends AbstractAnalyzer { - - public PythonAnalyzer(LocalClone localClone, Path path) { - super(localClone, path, Language.PYTHON); - } -} From d89405c50ed4d2cf9c93eaad5e2a7b3a12a4aeab Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 5 Sep 2023 11:32:32 +0200 Subject: [PATCH 0269/1089] Updated `CodeCrawler` to use new `Analyzer` --- .../main/java/usi/si/seart/crawler/component/CodeCrawler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java index 1774d75f..daf823f4 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java @@ -17,7 +17,6 @@ import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import usi.si.seart.analyzer.Analyzer; -import usi.si.seart.analyzer.AnalyzerFactory; import usi.si.seart.analyzer.LocalClone; import usi.si.seart.crawler.dto.SearchResultDto; import usi.si.seart.crawler.git.Git; @@ -283,7 +282,8 @@ private void analyzeAndStore(LocalClone localClone, Path path) { log.trace("Analyzing file: {}", localClone.relativePathOf(path)); String extension = com.google.common.io.Files.getFileExtension(path.toString()); Language language = extensionToLanguage.get(extension); - try (Analyzer analyzer = AnalyzerFactory.getAnalyzer(language).apply(localClone, path)) { + String name = language.getName().toUpperCase(); + try (Analyzer analyzer = new Analyzer(localClone, path, name)) { Analyzer.Result result = analyzer.analyze(); File file = result.getFile(); List functions = result.getFunctions(); From 8c183ea3eb288afa8f7edb95c9158ca83192b752 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 5 Sep 2023 11:33:48 +0200 Subject: [PATCH 0270/1089] Removing useless `protected` method --- .../src/main/java/usi/si/seart/analyzer/Analyzer.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java index 3f6fcbe5..2e5e6dec 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java @@ -91,7 +91,7 @@ public Analyzer(LocalClone localClone, Path path, Language language) throws IOEx this.path = path; this.source = Files.readString(path); this.tree = parser.parseString(source); - NodeMapper mapper = this::getSourceBytes; + NodeMapper mapper = () -> source.getBytes(NodeMapper.DEFAULT_CHARSET); this.lineCounter = new LineCounter(); this.totalTokenCounter = TokenCounter.getInstance(language, mapper); this.codeTokenCounter = CodeTokenCounter.getInstance(language); @@ -109,10 +109,6 @@ public Analyzer(LocalClone localClone, Path path, Language language) throws IOEx this.boilerplateEnumerator = BoilerplateEnumerator.getInstance(language, mapper); } - protected final byte[] getSourceBytes() { - return source.getBytes(NodeMapper.DEFAULT_CHARSET); - } - @Override public void close() { tree.close(); From 667102ecc4a3883ebb9f6bb3c1bf46ab565c14c7 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 5 Sep 2023 11:35:29 +0200 Subject: [PATCH 0271/1089] Changing member method visibility from protected and package to private --- .../src/main/java/usi/si/seart/analyzer/Analyzer.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java index 2e5e6dec..5727fd13 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java @@ -130,7 +130,7 @@ public final Result analyze() { return new Result(file, functions); } - protected File extractFileEntity() { + private File extractFileEntity() { Node node = tree.getRootNode(); return File.builder() .repo(localClone.getGitRepo()) @@ -150,7 +150,7 @@ protected File extractFileEntity() { .build(); } - protected List extractFunctionEntities(File file) { + private List extractFunctionEntities(File file) { List>> matches = multiCaptureQueries.getCallableDeclarations(tree.getRootNode()); List functions = new ArrayList<>(matches.size()); for (List> match: matches) { @@ -164,7 +164,7 @@ protected List extractFunctionEntities(File file) { return functions; } - protected Function extractFunctionEntity(List> match) { + private Function extractFunctionEntity(List> match) { List nodes = match.stream() .map(Tuple::getValue) .collect(Collectors.toList()); @@ -194,7 +194,7 @@ protected Function extractFunctionEntity(List> match) { .build(); } - FunctionSyntaxTreePrinter getStandalonePrinter(Language language) { + private FunctionSyntaxTreePrinter getStandalonePrinter(Language language) { if (Language.JAVA.equals(language)) { return new FunctionSyntaxTreePrinter() { From 7ef2b4a6b67aec7942d0b0b17a55c96bfd7aceac Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 5 Sep 2023 11:43:47 +0200 Subject: [PATCH 0272/1089] Removing unused `SingleCaptureQueries` member from `Analyzer` --- .../src/main/java/usi/si/seart/analyzer/Analyzer.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java index 5727fd13..6809dbbe 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java @@ -31,7 +31,6 @@ import usi.si.seart.analyzer.printer.SymbolicExpressionPrinter; import usi.si.seart.analyzer.printer.SyntaxTreePrinter; import usi.si.seart.analyzer.query.multi.MultiCaptureQueries; -import usi.si.seart.analyzer.query.single.SingleCaptureQueries; import usi.si.seart.analyzer.util.Tuple; import usi.si.seart.model.code.Boilerplate; import usi.si.seart.model.code.File; @@ -75,7 +74,6 @@ public class Analyzer implements AutoCloseable { Printer syntaxTreePrinter; Printer expressionPrinter; - SingleCaptureQueries singleCaptureQueries; MultiCaptureQueries multiCaptureQueries; Enumerator boilerplateEnumerator; @@ -104,7 +102,6 @@ public Analyzer(LocalClone localClone, Path path, Language language) throws IOEx this.nodePrinter = new NodePrinter(mapper); this.syntaxTreePrinter = new SyntaxTreePrinter(); this.expressionPrinter = new SymbolicExpressionPrinter(); - this.singleCaptureQueries = SingleCaptureQueries.getInstance(language); this.multiCaptureQueries = MultiCaptureQueries.getInstance(language); this.boilerplateEnumerator = BoilerplateEnumerator.getInstance(language, mapper); } From 4333f3334c9f82c13001589b3e8682e4f8c9e194 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 5 Sep 2023 11:44:19 +0200 Subject: [PATCH 0273/1089] Switching default field access to `private` in `Analyzer` --- .../src/main/java/usi/si/seart/analyzer/Analyzer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java index 6809dbbe..3b991956 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java @@ -46,7 +46,7 @@ import java.util.function.Predicate; import java.util.stream.Collectors; -@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class Analyzer implements AutoCloseable { Language language; From 9369c660aeb268e8c073487e762de8da91b7c80c Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 5 Sep 2023 12:05:45 +0200 Subject: [PATCH 0274/1089] Removing comments from SQL migrations --- liquibase/scripts/00_init.sql | 5 ----- liquibase/scripts/01_user.sql | 4 ---- 2 files changed, 9 deletions(-) diff --git a/liquibase/scripts/00_init.sql b/liquibase/scripts/00_init.sql index 3e8ed84a..c4120f71 100644 --- a/liquibase/scripts/00_init.sql +++ b/liquibase/scripts/00_init.sql @@ -1,7 +1,5 @@ --- ID GENERATION SEQUENCE CREATE SEQUENCE hibernate_sequence START 1 INCREMENT 1; --- TABLES CREATE TABLE "crawl_job" ( "id" bigint PRIMARY KEY NOT NULL, "checkpoint" timestamp NOT NULL, @@ -74,7 +72,6 @@ CREATE TABLE "function" ( "boilerplate_type" text ); --- FOREIGN KEYS ALTER TABLE "git_repo_language" ADD FOREIGN KEY ("repo_id") REFERENCES "git_repo" ("id") ON DELETE CASCADE; ALTER TABLE "git_repo_language" ADD FOREIGN KEY ("lang_id") REFERENCES "language" ("id"); ALTER TABLE "file" ADD FOREIGN KEY ("repo_id") REFERENCES "git_repo" ("id") ON DELETE CASCADE; @@ -83,7 +80,6 @@ ALTER TABLE "function" ADD FOREIGN KEY ("repo_id") REFERENCES "git_repo" ("id") ALTER TABLE "function" ADD FOREIGN KEY ("lang_id") REFERENCES "language" ("id"); ALTER TABLE "function" ADD FOREIGN KEY ("file_id") REFERENCES "file" ("id") ON DELETE CASCADE; --- INDEXES CREATE INDEX "git_repo_language_idx" ON "git_repo_language" (repo_id, lang_id); CREATE INDEX "file_repo_id_idx" ON "file" (repo_id); CREATE INDEX "file_lang_id_idx" ON "file" (lang_id); @@ -91,7 +87,6 @@ CREATE INDEX "function_repo_id_idx" ON "function" (repo_id); CREATE INDEX "function_lang_id_idx" ON "function" (lang_id); CREATE INDEX "function_file_id_idx" ON "function" (file_id); --- ADD LANGUAGES INSERT INTO language(id, name, extensions) VALUES (nextval('hibernate_sequence'), 'Java', '{java}'), diff --git a/liquibase/scripts/01_user.sql b/liquibase/scripts/01_user.sql index 81a9e3bd..6803e43a 100644 --- a/liquibase/scripts/01_user.sql +++ b/liquibase/scripts/01_user.sql @@ -1,4 +1,3 @@ --- TABLES CREATE TABLE "configuration" ( "key" text PRIMARY KEY NOT NULL, "value" text NOT NULL, @@ -82,14 +81,12 @@ CREATE TABLE "processing" ( "abstract_idioms" text[] NOT NULL ); --- FOREIGN KEYS ALTER TABLE "token" ADD FOREIGN KEY ("user_id") REFERENCES "user" ("id") ON DELETE CASCADE; ALTER TABLE "task" ADD FOREIGN KEY ("user_id") REFERENCES "user" ("id"); ALTER TABLE "query" ADD FOREIGN KEY ("task_id") REFERENCES "task" ("id") ON DELETE CASCADE; ALTER TABLE "query" ADD FOREIGN KEY ("lang_id") REFERENCES "language" ("id"); ALTER TABLE "processing" ADD FOREIGN KEY ("task_id") REFERENCES "task" ("id") ON DELETE CASCADE; --- INDEXES CREATE INDEX "token_user_id_idx" ON "token" (user_id); CREATE INDEX "task_user_id_idx" ON "task" (user_id); CREATE INDEX "task_expired_idx" ON "task" (finished, expired) WHERE finished IS NOT NULL AND expired = false; @@ -102,7 +99,6 @@ CREATE INDEX "file_ast_hash_idx" ON "file" (ast_hash); CREATE INDEX "function_ast_hash_idx" ON "function" (ast_hash); CREATE INDEX "git_repo_stats_idx" ON "git_repo" (commits, contributors, issues, stars) INCLUDE (is_fork, license); --- ADD CONFIGURATION PROPERTIES INSERT INTO configuration(key, value, last_update) VALUES ('request_limit', '3', now()), From d9d5edb2b37a0d807be0fa6521113322c8bbe1db Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 5 Sep 2023 14:25:44 +0200 Subject: [PATCH 0275/1089] `LanguageRepository` now has a `findByNameIgnoreCase` method --- .../usi/si/seart/crawler/repository/LanguageRepository.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/LanguageRepository.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/LanguageRepository.java index e0887d72..8b04e282 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/LanguageRepository.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/LanguageRepository.java @@ -3,5 +3,10 @@ import org.springframework.data.jpa.repository.JpaRepository; import usi.si.seart.model.Language; +import javax.validation.constraints.NotBlank; +import java.util.Optional; + public interface LanguageRepository extends JpaRepository { + + Optional findByNameIgnoreCase(@NotBlank String name); } From fd1dc91d1d14bb627c2a57fe3cbebbddd2f81f19 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 5 Sep 2023 14:35:18 +0200 Subject: [PATCH 0276/1089] Languages are now initialized by a startup task in the crawler Rather than relying on migrations, it is tenfold better to have a dedicated configuration file that is read each time the server starts. In this way, we can add languages on the fly, as well as change the supported extensions of existing languages. This does however mean that there is a miss-match possibility between the DB and this file, whereas entries removed from this file remain in the DB. We should configure the crawler to only mine languages mentioned in this file. --- .../bean/LanguageInitializingBean.java | 41 +++++++++++++++++++ .../src/main/resources/languages.yaml | 4 ++ liquibase/scripts/00_init.sql | 5 --- 3 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/LanguageInitializingBean.java create mode 100644 dl4se-crawler/src/main/resources/languages.yaml diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/LanguageInitializingBean.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/LanguageInitializingBean.java new file mode 100644 index 00000000..6ac3412b --- /dev/null +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/LanguageInitializingBean.java @@ -0,0 +1,41 @@ +package usi.si.seart.crawler.bean; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.experimental.FieldDefaults; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.stereotype.Component; +import org.yaml.snakeyaml.Yaml; +import usi.si.seart.crawler.repository.LanguageRepository; +import usi.si.seart.model.Language; + +import java.io.InputStream; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Supplier; + +@Component +@AllArgsConstructor(onConstructor_ = @Autowired) +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +public class LanguageInitializingBean implements InitializingBean { + + LanguageRepository languageRepository; + + @Override + public void afterPropertiesSet() throws Exception { + Resource resource = new ClassPathResource("languages.yaml"); + InputStream inputStream = resource.getInputStream(); + Map> map = new Yaml().load(inputStream); + map.forEach((name, extensions) -> { + Optional optional = languageRepository.findByNameIgnoreCase(name); + Supplier supplier = () -> Language.builder().name(name).build(); + Language language = optional.orElseGet(supplier); + language.setExtensions(extensions); + languageRepository.save(language); + }); + } +} diff --git a/dl4se-crawler/src/main/resources/languages.yaml b/dl4se-crawler/src/main/resources/languages.yaml new file mode 100644 index 00000000..dab16700 --- /dev/null +++ b/dl4se-crawler/src/main/resources/languages.yaml @@ -0,0 +1,4 @@ +Java: + - java +Python: + - py diff --git a/liquibase/scripts/00_init.sql b/liquibase/scripts/00_init.sql index c4120f71..0328f821 100644 --- a/liquibase/scripts/00_init.sql +++ b/liquibase/scripts/00_init.sql @@ -86,8 +86,3 @@ CREATE INDEX "file_lang_id_idx" ON "file" (lang_id); CREATE INDEX "function_repo_id_idx" ON "function" (repo_id); CREATE INDEX "function_lang_id_idx" ON "function" (lang_id); CREATE INDEX "function_file_id_idx" ON "function" (file_id); - -INSERT INTO language(id, name, extensions) -VALUES - (nextval('hibernate_sequence'), 'Java', '{java}'), - (nextval('hibernate_sequence'), 'Python', '{py}'); From e812acbfc9169d2a40e983f4ec6eadafe7e7dd00 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 5 Sep 2023 15:14:41 +0200 Subject: [PATCH 0277/1089] Minor improvement to `ignore` property group --- .../si/seart/crawler/component/CodeCrawler.java | 17 ++++------------- .../si/seart/crawler/config/CrawlerConfig.java | 10 ++++++++++ .../src/main/resources/application.properties | 4 ++-- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java index daf823f4..c6b743ac 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java @@ -34,10 +34,8 @@ import javax.annotation.PostConstruct; import javax.persistence.EntityNotFoundException; import java.io.IOException; -import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.PathMatcher; import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; @@ -73,21 +71,16 @@ public class CodeCrawler implements Runnable { LanguageService languageService; ConversionService conversionService; + Predicate analyzeFilePredicate; + @NonFinal @Value("${app.general.tmp-dir-prefix}") String prefix; @NonFinal - @Value("${app.crawl-job.ignore-pattern}") - String ignorePattern; - - @NonFinal - @Value("${app.crawl-job.ignore-projects}") + @Value("${app.crawl-job.ignore.project-names}") List ignoreProjects; - @NonFinal - PathMatcher ignoreMatcher = FileSystems.getDefault().getPathMatcher("glob:"); - Set languageNames = new HashSet<>(); Map nameToLanguage = new HashMap<>(); Map extensionToLanguage = new HashMap<>(); @@ -101,8 +94,6 @@ private void postConstruct() { nameToLanguage.put(name, language); extensions.forEach(extension -> extensionToLanguage.put(extension, language)); }); - if (!ignorePattern.isBlank()) - ignoreMatcher = FileSystems.getDefault().getPathMatcher("glob:" + ignorePattern); } @Scheduled(fixedDelayString = "${app.crawl-job.next-run-delay}") @@ -273,7 +264,7 @@ private void mineRepoData(LocalClone localClone, Set languages) { .map(localDirectory::resolve) .collect(Collectors.toSet()); Set filtered = Sets.difference(candidates, analyzed).stream() - .filter(Predicate.not(ignoreMatcher::matches)) + .filter(analyzeFilePredicate) .collect(Collectors.toSet()); filtered.forEach(target -> analyzeAndStore(localClone, target)); } diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/CrawlerConfig.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/CrawlerConfig.java index dd76caec..cd830463 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/CrawlerConfig.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/CrawlerConfig.java @@ -6,8 +6,12 @@ import org.springframework.context.annotation.Configuration; import usi.si.seart.model.job.Job; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.PathMatcher; import java.time.Duration; import java.time.LocalDateTime; +import java.util.function.Predicate; @Configuration public class CrawlerConfig { @@ -31,4 +35,10 @@ public GenericUrl baseUrl(@Value("${app.crawl-job.url}") String url) { public LocalDateTime defaultStartDateTime(@Value("${app.crawl-job.start-date-time}") String value) { return LocalDateTime.parse(value); } + + @Bean + public Predicate analyzeFilePredicate(@Value("${app.crawl-job.ignore.file-pattern}") String value) { + PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher("glob:" + value); + return Predicate.not(pathMatcher::matches); + } } diff --git a/dl4se-crawler/src/main/resources/application.properties b/dl4se-crawler/src/main/resources/application.properties index 3e3f3594..5ffddd6d 100644 --- a/dl4se-crawler/src/main/resources/application.properties +++ b/dl4se-crawler/src/main/resources/application.properties @@ -41,5 +41,5 @@ app.crawl-job.next-run-delay=PT6H app.crawl-job.url=${CRAWLER_URL:https://seart-ghs.si.usi.ch/api/r/search} app.crawl-job.start-date-time=2008-01-01T00:00:00 app.crawl-job.type=${CRAWLER_JOB:CODE} -app.crawl-job.ignore-projects= -app.crawl-job.ignore-pattern= +app.crawl-job.ignore.project-names= +app.crawl-job.ignore.file-pattern= From 683c1e0f45d2402e8b64bfad33ac7077fbcd3cde Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 5 Sep 2023 15:36:20 +0200 Subject: [PATCH 0278/1089] Reimplementing `FileService` deletion method with derived query --- .../java/usi/si/seart/crawler/repository/FileRepository.java | 2 ++ .../main/java/usi/si/seart/crawler/service/FileService.java | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/FileRepository.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/FileRepository.java index 3b6a25ba..0a818860 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/FileRepository.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/FileRepository.java @@ -14,4 +14,6 @@ public interface FileRepository extends JpaRepository { List findAllByRepo(@NotNull GitRepo repo); Optional findByRepoAndPath(@NotNull GitRepo repo, @NotBlank String path); + + void deleteByRepoAndPath(@NotNull GitRepo repo, @NotBlank String path); } diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/FileService.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/FileService.java index 1e39c418..8b8f20e5 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/FileService.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/FileService.java @@ -40,9 +40,7 @@ public void create(File file) { @Override public void delete(GitRepo gitRepo, Path path) { - Optional optional = fileRepository.findByRepoAndPath(gitRepo, path.toString()); - File file = optional.orElseThrow(EntityNotFoundException::new); - fileRepository.delete(file); + fileRepository.deleteByRepoAndPath(gitRepo, path.toString()); } @Override From bcfb337133621964cea0428ed7da730a3811bc8a Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 5 Sep 2023 16:13:41 +0200 Subject: [PATCH 0279/1089] Reimplementing `FileService` update method with derived query --- .../si/seart/crawler/repository/FileRepository.java | 12 ++++++++++-- .../usi/si/seart/crawler/service/FileService.java | 7 +------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/FileRepository.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/FileRepository.java index 0a818860..f45182dc 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/FileRepository.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/FileRepository.java @@ -1,19 +1,27 @@ package usi.si.seart.crawler.repository; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import usi.si.seart.model.GitRepo; import usi.si.seart.model.code.File; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import java.util.List; -import java.util.Optional; public interface FileRepository extends JpaRepository { List findAllByRepo(@NotNull GitRepo repo); - Optional findByRepoAndPath(@NotNull GitRepo repo, @NotBlank String path); + @Modifying + @Query("UPDATE File SET path = :new WHERE repo = :repo AND path = :old") + void updatePathByRepo( + @Param(value = "repo") @NotNull GitRepo repo, + @Param(value = "old") @NotBlank String oldPath, + @Param(value = "new") @NotBlank String newPath + ); void deleteByRepoAndPath(@NotNull GitRepo repo, @NotBlank String path); } diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/FileService.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/FileService.java index 8b8f20e5..55054b50 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/FileService.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/FileService.java @@ -9,10 +9,8 @@ import usi.si.seart.model.GitRepo; import usi.si.seart.model.code.File; -import javax.persistence.EntityNotFoundException; import java.nio.file.Path; import java.util.List; -import java.util.Optional; public interface FileService { @@ -45,10 +43,7 @@ public void delete(GitRepo gitRepo, Path path) { @Override public void rename(GitRepo gitRepo, Path oldPath, Path newPath) { - Optional optional = fileRepository.findByRepoAndPath(gitRepo, oldPath.toString()); - File file = optional.orElseThrow(EntityNotFoundException::new); - file.setPath(newPath.toString()); - fileRepository.save(file); + fileRepository.updatePathByRepo(gitRepo, oldPath.toString(), newPath.toString()); } } } From c1c28b3685eed4c3b691f2991f872040f4ff1f3f Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 5 Sep 2023 16:15:37 +0200 Subject: [PATCH 0280/1089] Modifying methods of `FileService` are now transactional --- .../main/java/usi/si/seart/crawler/service/FileService.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/FileService.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/FileService.java index 55054b50..3291ec6b 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/FileService.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/FileService.java @@ -5,6 +5,7 @@ import lombok.experimental.FieldDefaults; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import usi.si.seart.crawler.repository.FileRepository; import usi.si.seart.model.GitRepo; import usi.si.seart.model.code.File; @@ -37,11 +38,13 @@ public void create(File file) { } @Override + @Transactional public void delete(GitRepo gitRepo, Path path) { fileRepository.deleteByRepoAndPath(gitRepo, path.toString()); } @Override + @Transactional public void rename(GitRepo gitRepo, Path oldPath, Path newPath) { fileRepository.updatePathByRepo(gitRepo, oldPath.toString(), newPath.toString()); } From 794b3425ad4a74cc46de4775f6d38f61365f6b25 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 6 Sep 2023 12:11:31 +0200 Subject: [PATCH 0281/1089] Update logic in `CodeCrawler` now also takes the blacklist into account --- .../seart/crawler/component/CodeCrawler.java | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java index c6b743ac..eb00865f 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java @@ -193,18 +193,35 @@ private void updateRepoData(GitRepo repo, Set repoLanguages) { Git.Diff diff = git.getDiff(repo.getLastCommitSHA(), repo.getLanguages()); if (!Strings.isNullOrEmpty(diff.toString())) log.debug("Diff since last update:\n{}", diff); - diff.getAdded().forEach(path -> addFile(localClone, path)); + diff.getAdded().stream() + .filter(analyzeFilePredicate) + .forEach(path -> addFile(localClone, path)); diff.getDeleted().forEach(path -> deleteFile(repo, path)); diff.getModified().forEach(path -> { deleteFile(repo, path); - addFile(localClone, path); + if (analyzeFilePredicate.test(path)) + addFile(localClone, path); + }); + diff.getRenamed().forEach((key, value) -> { + boolean validOld = analyzeFilePredicate.test(key); + boolean validNew = analyzeFilePredicate.test(value); + if (validOld && validNew) + renameFile(repo, key, value); + else if (validOld) + deleteFile(repo, key); + else if (validNew) + addFile(localClone, value); }); - diff.getRenamed().forEach((key, value) -> renameFile(repo, key, value)); diff.getEdited().forEach((key, value) -> { deleteFile(repo, key); - addFile(localClone, value); + if (analyzeFilePredicate.test(value)) + addFile(localClone, value); }); - diff.getCopied().forEach((key, value) -> addFile(localClone, value)); + diff.getCopied() + .values() + .stream() + .filter(analyzeFilePredicate) + .forEach(value -> addFile(localClone, value)); gitRepoService.createOrUpdate(repo); } catch (GitException ex) { From 9ab31740cf3b186ee188e4fdb59fcd4df33ee648 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 6 Sep 2023 13:23:57 +0200 Subject: [PATCH 0282/1089] Bump `java-tree-sitter` minor version: `1.2.1` -> `1.3.0` --- dl4se-analyzer/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dl4se-analyzer/pom.xml b/dl4se-analyzer/pom.xml index c7527e69..14b5a38d 100644 --- a/dl4se-analyzer/pom.xml +++ b/dl4se-analyzer/pom.xml @@ -25,7 +25,7 @@ ch.usi.si.seart java-tree-sitter - 1.2.1 + 1.3.0 org.apache.commons From 827a99fd95f2a916402e4a822089b06c55a7d6bd Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 6 Sep 2023 13:25:27 +0200 Subject: [PATCH 0283/1089] Removing usages of deprecated code --- .../src/main/java/usi/si/seart/analyzer/Analyzer.java | 7 ++----- .../src/test/java/usi/si/seart/analyzer/test/BaseTest.java | 5 +---- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java index 3b991956..a696d814 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java @@ -9,7 +9,6 @@ import lombok.AllArgsConstructor; import lombok.Cleanup; import lombok.Getter; -import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; import usi.si.seart.analyzer.count.CharacterCounter; import usi.si.seart.analyzer.count.CodeTokenCounter; @@ -37,7 +36,6 @@ import usi.si.seart.model.code.Function; import java.io.IOException; -import java.io.UnsupportedEncodingException; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -88,7 +86,7 @@ public Analyzer(LocalClone localClone, Path path, Language language) throws IOEx this.localClone = localClone; this.path = path; this.source = Files.readString(path); - this.tree = parser.parseString(source); + this.tree = parser.parse(source); NodeMapper mapper = () -> source.getBytes(NodeMapper.DEFAULT_CHARSET); this.lineCounter = new LineCounter(); this.totalTokenCounter = TokenCounter.getInstance(language, mapper); @@ -243,11 +241,10 @@ public String print(Node... nodes) { } @Override - @SneakyThrows(UnsupportedEncodingException.class) public String print(Collection nodes) { String content = nodePrinter.print(nodes); String wrapped = wrap(content); - @Cleanup Tree tree = parser.parseString(wrapped); + @Cleanup Tree tree = parser.parse(wrapped); List targets = getTargets(tree); Printer astPrinter = getAstPrinter(); return astPrinter.print(targets); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java index f1fc0661..6077af8f 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java @@ -4,12 +4,10 @@ import ch.usi.si.seart.treesitter.LibraryLoader; import ch.usi.si.seart.treesitter.Parser; import ch.usi.si.seart.treesitter.Tree; -import lombok.SneakyThrows; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import usi.si.seart.analyzer.NodeMapper; -import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.util.List; @@ -32,9 +30,8 @@ void setUpParser() { parser = new Parser(getLanguage()); } - @SneakyThrows(UnsupportedEncodingException.class) void setUpTree() { - tree = parser.parseString(getInput()); + tree = parser.parse(getInput()); } @AfterEach From 605b51e7dd46ce29a34620b0983bb00e8cad0605 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 6 Sep 2023 15:32:57 +0200 Subject: [PATCH 0284/1089] Added a `@Hash` annotation for the hash value columns --- .../java/usi/si/seart/model/code/Code.java | 5 +- .../si/seart/validation/constraints/Hash.java | 40 ++++++++++++ .../validation/constraints/HashTest.java | 61 +++++++++++++++++++ 3 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 dl4se-model/src/main/java/usi/si/seart/validation/constraints/Hash.java create mode 100644 dl4se-model/src/test/java/usi/si/seart/validation/constraints/HashTest.java diff --git a/dl4se-model/src/main/java/usi/si/seart/model/code/Code.java b/dl4se-model/src/main/java/usi/si/seart/model/code/Code.java index 4a3b1614..63fd4b91 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/code/Code.java +++ b/dl4se-model/src/main/java/usi/si/seart/model/code/Code.java @@ -12,6 +12,7 @@ import lombok.experimental.SuperBuilder; import usi.si.seart.model.GitRepo; import usi.si.seart.model.Language; +import usi.si.seart.validation.constraints.Hash; import javax.persistence.Column; import javax.persistence.Entity; @@ -52,7 +53,7 @@ public abstract class Code { @NotNull String content; - @NotNull + @Hash @Column(name = "content_hash") @JsonProperty(value = "content_hash") String contentHash; @@ -60,7 +61,7 @@ public abstract class Code { @NotNull String ast; - @NotNull + @Hash @Column(name = "ast_hash") @JsonProperty(value = "ast_hash") String astHash; diff --git a/dl4se-model/src/main/java/usi/si/seart/validation/constraints/Hash.java b/dl4se-model/src/main/java/usi/si/seart/validation/constraints/Hash.java new file mode 100644 index 00000000..42f0bbb9 --- /dev/null +++ b/dl4se-model/src/main/java/usi/si/seart/validation/constraints/Hash.java @@ -0,0 +1,40 @@ +package usi.si.seart.validation.constraints; + +import org.hibernate.validator.constraints.CompositionType; +import org.hibernate.validator.constraints.ConstraintComposition; +import org.hibernate.validator.constraints.Length; + +import javax.validation.Constraint; +import javax.validation.Payload; +import javax.validation.ReportAsSingleViolation; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Pattern; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.CONSTRUCTOR; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.ElementType.TYPE_USE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Documented +@ConstraintComposition(CompositionType.AND) +@NotBlank +@Length(min = 32, max = 128) +@Pattern(regexp = "^[0-9a-fA-F]+$") +@Constraint(validatedBy = { }) +@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE }) +@Retention(RUNTIME) +@ReportAsSingleViolation +public @interface Hash { + + String message() default "Not a valid hash"; + + Class[] groups() default { }; + + Class< ? extends Payload>[] payload() default { }; +} diff --git a/dl4se-model/src/test/java/usi/si/seart/validation/constraints/HashTest.java b/dl4se-model/src/test/java/usi/si/seart/validation/constraints/HashTest.java new file mode 100644 index 00000000..c918cb38 --- /dev/null +++ b/dl4se-model/src/test/java/usi/si/seart/validation/constraints/HashTest.java @@ -0,0 +1,61 @@ +package usi.si.seart.validation.constraints; + +import lombok.AllArgsConstructor; +import lombok.Cleanup; +import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; +import org.junit.jupiter.params.provider.ValueSource; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; +import java.util.Set; + +class HashTest { + + static Validator validator; + + @BeforeAll + static void setUp() { + @Cleanup ValidatorFactory factory = Validation.byDefaultProvider() + .configure() + .messageInterpolator(new ParameterMessageInterpolator()) + .buildValidatorFactory(); + validator = factory.getValidator(); + } + + @AllArgsConstructor + private static final class Contract { + @Hash + String hash; + } + + @ParameterizedTest + @NullAndEmptySource + @ValueSource(strings = { + "1f9e046a", // Adler32 + "xa0a9f2a6772942557ab5355d76af442f8f65e01", + "#a0a9f2a6772942557ab5355d76af442f8f65e01" + }) + void invalidTest(String value) { + Set> violations = validator.validate(new Contract(value)); + Assertions.assertFalse(violations.isEmpty()); + } + + @ParameterizedTest + @ValueSource(strings = { + "65a8e27d8879283831b664bd8b7f0ad4", // MD5 + "0a0a9f2a6772942557ab5355d76af442f8f65e01", // SHA-1 + "dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f", // SHA-256 + "374d794a95cdcfd8b35993185fef9ba368f160d8daf432d08ba9f1ed1e5abe6c" + + "c69291e0fa2fe0006a52570ef18c19def4e617c33ce52ef0a6e5fbe318cb0387" // SHA-512 + }) + void validTest(String value) { + Set> violations = validator.validate(new Contract(value)); + Assertions.assertTrue(violations.isEmpty()); + } +} From 5cea20672ba32e47dd4e38670a50b5252b74495a Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 6 Sep 2023 16:02:40 +0200 Subject: [PATCH 0285/1089] Validation messages are now stored in a properties file --- .../si/seart/validation/constraints/AllNullOrNotNull.java | 2 +- .../main/java/usi/si/seart/validation/constraints/Hash.java | 2 +- .../usi/si/seart/validation/constraints/NullOrNotBlank.java | 2 +- .../usi/si/seart/validation/constraints/NullOrRange.java | 2 +- .../usi/si/seart/validation/constraints/OWASPEmail.java | 2 +- .../java/usi/si/seart/validation/constraints/Password.java | 2 +- .../src/main/resources/ValidationMessages.properties | 6 ++++++ 7 files changed, 12 insertions(+), 6 deletions(-) create mode 100644 dl4se-model/src/main/resources/ValidationMessages.properties diff --git a/dl4se-model/src/main/java/usi/si/seart/validation/constraints/AllNullOrNotNull.java b/dl4se-model/src/main/java/usi/si/seart/validation/constraints/AllNullOrNotNull.java index 0482172a..60cefcb2 100644 --- a/dl4se-model/src/main/java/usi/si/seart/validation/constraints/AllNullOrNotNull.java +++ b/dl4se-model/src/main/java/usi/si/seart/validation/constraints/AllNullOrNotNull.java @@ -20,7 +20,7 @@ String[] fields(); - String message() default "All fields must contain either a non-null value, or null"; + String message() default "{usi.si.seart.validation.constraints.AllNullOrNotNull.message}"; Class[] groups() default {}; diff --git a/dl4se-model/src/main/java/usi/si/seart/validation/constraints/Hash.java b/dl4se-model/src/main/java/usi/si/seart/validation/constraints/Hash.java index 42f0bbb9..f24e2d85 100644 --- a/dl4se-model/src/main/java/usi/si/seart/validation/constraints/Hash.java +++ b/dl4se-model/src/main/java/usi/si/seart/validation/constraints/Hash.java @@ -32,7 +32,7 @@ @ReportAsSingleViolation public @interface Hash { - String message() default "Not a valid hash"; + String message() default "{usi.si.seart.validation.constraints.Hash.message}"; Class[] groups() default { }; diff --git a/dl4se-model/src/main/java/usi/si/seart/validation/constraints/NullOrNotBlank.java b/dl4se-model/src/main/java/usi/si/seart/validation/constraints/NullOrNotBlank.java index a70d3bbc..788c4b74 100644 --- a/dl4se-model/src/main/java/usi/si/seart/validation/constraints/NullOrNotBlank.java +++ b/dl4se-model/src/main/java/usi/si/seart/validation/constraints/NullOrNotBlank.java @@ -30,7 +30,7 @@ @ReportAsSingleViolation public @interface NullOrNotBlank { - String message() default "Value is neither unset, nor does it contain a single non-whitespace character"; + String message() default "{usi.si.seart.validation.constraints.NullOrNotBlank.message}"; Class[] groups() default { }; diff --git a/dl4se-model/src/main/java/usi/si/seart/validation/constraints/NullOrRange.java b/dl4se-model/src/main/java/usi/si/seart/validation/constraints/NullOrRange.java index 9c9458cd..c949f020 100644 --- a/dl4se-model/src/main/java/usi/si/seart/validation/constraints/NullOrRange.java +++ b/dl4se-model/src/main/java/usi/si/seart/validation/constraints/NullOrRange.java @@ -35,7 +35,7 @@ @OverridesAttribute(constraint = Range.class, name = "max") long max() default Long.MAX_VALUE; - String message() default "Value is neither unset, nor within the valid value range"; + String message() default "{usi.si.seart.validation.constraints.NullOrRange.message}"; Class[] groups() default { }; diff --git a/dl4se-model/src/main/java/usi/si/seart/validation/constraints/OWASPEmail.java b/dl4se-model/src/main/java/usi/si/seart/validation/constraints/OWASPEmail.java index 851fda8d..39e29e64 100644 --- a/dl4se-model/src/main/java/usi/si/seart/validation/constraints/OWASPEmail.java +++ b/dl4se-model/src/main/java/usi/si/seart/validation/constraints/OWASPEmail.java @@ -37,7 +37,7 @@ @ReportAsSingleViolation public @interface OWASPEmail { - String message() default "Not a valid email address"; + String message() default "{usi.si.seart.validation.constraints.OWASPEmail.message}"; Class[] groups() default { }; diff --git a/dl4se-model/src/main/java/usi/si/seart/validation/constraints/Password.java b/dl4se-model/src/main/java/usi/si/seart/validation/constraints/Password.java index 79744994..e974d871 100644 --- a/dl4se-model/src/main/java/usi/si/seart/validation/constraints/Password.java +++ b/dl4se-model/src/main/java/usi/si/seart/validation/constraints/Password.java @@ -38,7 +38,7 @@ @OverridesAttribute(constraint = Pattern.class, name = "regexp") String regexp() default "^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?\\d).{6,20}$"; - String message() default "Not a valid password"; + String message() default "{usi.si.seart.validation.constraints.Password.message}"; Class[] groups() default { }; diff --git a/dl4se-model/src/main/resources/ValidationMessages.properties b/dl4se-model/src/main/resources/ValidationMessages.properties new file mode 100644 index 00000000..88343c64 --- /dev/null +++ b/dl4se-model/src/main/resources/ValidationMessages.properties @@ -0,0 +1,6 @@ +usi.si.seart.validation.constraints.AllNullOrNotNull.message=All fields must contain either a non-null value, or null +usi.si.seart.validation.constraints.Hash.message=Not a valid hash +usi.si.seart.validation.constraints.NullOrNotBlank.message=Value is neither unset, nor does it contain a single non-whitespace character +usi.si.seart.validation.constraints.NullOrRange.message=Value is neither unset, nor within the valid value range +usi.si.seart.validation.constraints.OWASPEmail.message=Not an OWASP-compliant email address +usi.si.seart.validation.constraints.Password.message=Not a valid password From d1d25a4c27056db3b2e8bc258a405234470c03ba Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 6 Sep 2023 16:16:26 +0200 Subject: [PATCH 0286/1089] Updating root-level plugin versions --- pom.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index 9001c4e0..bb42261b 100644 --- a/pom.xml +++ b/pom.xml @@ -114,15 +114,15 @@ maven-clean-plugin - 3.1.0 + 3.3.1 maven-resources-plugin - 3.2.0 + 3.3.1 maven-compiler-plugin - 3.8.1 + 3.9.0 11 11 @@ -130,19 +130,19 @@ maven-surefire-plugin - 3.0.0-M5 + 3.1.2 maven-shade-plugin - 3.2.4 + 3.5.0 maven-jar-plugin - 3.2.2 + 3.3.0 maven-install-plugin - 3.0.0-M1 + 3.1.1 From 0276d643448c0d929cab192d48a0df4314370261 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 6 Sep 2023 16:17:50 +0200 Subject: [PATCH 0287/1089] Bumping `build-helper-maven-plugin` --- dl4se-model/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dl4se-model/pom.xml b/dl4se-model/pom.xml index ff49e3e4..354fd0cc 100644 --- a/dl4se-model/pom.xml +++ b/dl4se-model/pom.xml @@ -69,7 +69,7 @@ org.codehaus.mojo build-helper-maven-plugin - 3.0.0 + 3.4.0 add-source From f28068f25da5257e66cdff646c133f4f2a430931 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 6 Sep 2023 16:21:50 +0200 Subject: [PATCH 0288/1089] Bumping `hypersistence-utils-hibernate` patch version `3.5.0` -> `3.5.2` --- dl4se-model/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dl4se-model/pom.xml b/dl4se-model/pom.xml index 354fd0cc..3581a2cb 100644 --- a/dl4se-model/pom.xml +++ b/dl4se-model/pom.xml @@ -60,7 +60,7 @@ io.hypersistence hypersistence-utils-hibernate-55 - 3.5.0 + 3.5.2 From 2ce6ceaf6475f347dd0370ba8b3363af0b7f7737 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 6 Sep 2023 16:25:39 +0200 Subject: [PATCH 0289/1089] Collapsing `source` and `target` configurations into just `release` --- pom.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index bb42261b..49cd3e3e 100644 --- a/pom.xml +++ b/pom.xml @@ -124,8 +124,7 @@ maven-compiler-plugin 3.9.0 - 11 - 11 + 11 From 87a4ce86e1bfa99f8946b0b8886dbbc35c01ee41 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 6 Sep 2023 16:37:30 +0200 Subject: [PATCH 0290/1089] Bumping Spring Boot patch version `2.17.4` -> `2.17.5` --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 49cd3e3e..a8e1d3ed 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,7 @@ 42.6.0 0.11.5 2.15.2 - 2.7.14 + 2.7.15 2021.0.3 From 0adcd06251e420cfa21d2cfba7e25babc460a1ea Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 6 Sep 2023 16:39:10 +0200 Subject: [PATCH 0291/1089] Bumping Spring Cloud patch version `2021.0.3` -> `2021.0.8` --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a8e1d3ed..f7bf7466 100644 --- a/pom.xml +++ b/pom.xml @@ -43,7 +43,7 @@ 0.11.5 2.15.2 2.7.15 - 2021.0.3 + 2021.0.8 From 5d65b7431fac750f149e0698fb7327b7fe29ac54 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 6 Sep 2023 16:41:32 +0200 Subject: [PATCH 0292/1089] Bumping Janino patch version `3.1.9` -> `3.1.10` --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f7bf7466..f07a512c 100644 --- a/pom.xml +++ b/pom.xml @@ -38,7 +38,7 @@ 3.25.3 1.18.26 32.1.1-jre - 3.1.9 + 3.1.10 42.6.0 0.11.5 2.15.2 From 043664a562c6ffcdbcc65878596721da7090f731 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 6 Sep 2023 16:45:51 +0200 Subject: [PATCH 0293/1089] Bumping Guava patch version `32.1.1-jre` -> `32.1.2-jre` --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f07a512c..c383d1c6 100644 --- a/pom.xml +++ b/pom.xml @@ -37,7 +37,7 @@ 5.9.3 3.25.3 1.18.26 - 32.1.1-jre + 32.1.2-jre 3.1.10 42.6.0 0.11.5 From 2fffdf3ccf677421e33acb1d41418eb473f47c2d Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 6 Sep 2023 16:49:46 +0200 Subject: [PATCH 0294/1089] Bumping Lombok patch version `1.18.26` -> `1.18.28` --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c383d1c6..e41fcea3 100644 --- a/pom.xml +++ b/pom.xml @@ -36,7 +36,7 @@ UTF-8 5.9.3 3.25.3 - 1.18.26 + 1.18.28 32.1.2-jre 3.1.10 42.6.0 From 12f7daab9eab014a91106bed9fe8e85b64194b35 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 6 Sep 2023 16:50:02 +0200 Subject: [PATCH 0295/1089] Bumping JavaParser patch version `3.25.3` -> `3.25.5` --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e41fcea3..8626c7d4 100644 --- a/pom.xml +++ b/pom.xml @@ -35,7 +35,7 @@ 1.0.0 UTF-8 5.9.3 - 3.25.3 + 3.25.5 1.18.28 32.1.2-jre 3.1.10 From 7c95f12b12942a2e46a0d36e69ca936bf5bf441b Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 6 Sep 2023 16:50:33 +0200 Subject: [PATCH 0296/1089] Bumping JUnit minor version `5.9.3` -> `5.10.0` --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8626c7d4..a994065f 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ 1.0.0 UTF-8 - 5.9.3 + 5.10.0 3.25.5 1.18.28 32.1.2-jre From 160ac41948ca6458ecb438d131770647bfb3d020 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 6 Sep 2023 16:50:56 +0200 Subject: [PATCH 0297/1089] Bumping `maven-compiler-plugin` yet again --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a994065f..8c420127 100644 --- a/pom.xml +++ b/pom.xml @@ -122,7 +122,7 @@ maven-compiler-plugin - 3.9.0 + 3.11.0 11 From baf98b5697ad2b83cff9d9a11b3ab260e19fc67d Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 6 Sep 2023 16:52:37 +0200 Subject: [PATCH 0298/1089] Replaced `@Singular` with `@Builder.Default` in `File` --- dl4se-model/src/main/java/usi/si/seart/model/code/File.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dl4se-model/src/main/java/usi/si/seart/model/code/File.java b/dl4se-model/src/main/java/usi/si/seart/model/code/File.java index 02f40e89..50641084 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/code/File.java +++ b/dl4se-model/src/main/java/usi/si/seart/model/code/File.java @@ -7,7 +7,6 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import lombok.Singular; import lombok.experimental.FieldDefaults; import lombok.experimental.SuperBuilder; @@ -46,7 +45,7 @@ public class File extends Code { Boolean isParsed = false; @OneToMany(mappedBy = "file", cascade = {CascadeType.PERSIST, CascadeType.MERGE}) - @Singular + @Builder.Default @JsonIgnore List functions = new ArrayList<>(); From 7782ed16c20187c23cb61b9ca7917a57ab58b729 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 6 Sep 2023 16:54:09 +0200 Subject: [PATCH 0299/1089] Replaced `@Singular` with `@Builder.Default` in `User` --- dl4se-model/src/main/java/usi/si/seart/model/user/User.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dl4se-model/src/main/java/usi/si/seart/model/user/User.java b/dl4se-model/src/main/java/usi/si/seart/model/user/User.java index 1e9a34c8..717728bb 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/user/User.java +++ b/dl4se-model/src/main/java/usi/si/seart/model/user/User.java @@ -7,7 +7,6 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import lombok.Singular; import lombok.SneakyThrows; import lombok.ToString; import lombok.experimental.FieldDefaults; @@ -88,7 +87,7 @@ public class User { Role role; @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) - @Singular + @Builder.Default @ToString.Exclude @JsonIgnore List tasks = new ArrayList<>(); From ca8c8c52e6e768364850d94daad052b3d0738eeb Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 6 Sep 2023 17:00:09 +0200 Subject: [PATCH 0300/1089] More removals of deprecated API usages --- .../enumerator/JavaBoilerplateEnumeratorTest.java | 5 +---- .../enumerator/PythonBoilerplateEnumeratorTest.java | 8 ++------ .../usi/si/seart/analyzer/hash/JavaContentHasherTest.java | 5 +---- .../si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java | 5 +---- .../predicate/node/ContainsErrorPredicateTest.java | 8 ++------ .../predicate/node/ContainsNonAsciiPredicateTest.java | 5 +---- 6 files changed, 8 insertions(+), 28 deletions(-) diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java index ba2b1e5f..728b943d 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java @@ -5,7 +5,6 @@ import ch.usi.si.seart.treesitter.Parser; import ch.usi.si.seart.treesitter.Tree; import lombok.Cleanup; -import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.params.ParameterizedTest; @@ -14,7 +13,6 @@ import org.junit.jupiter.params.provider.ArgumentsSource; import usi.si.seart.model.code.Boilerplate; -import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; import java.util.stream.Stream; @@ -48,13 +46,12 @@ public Stream provideArguments(ExtensionContext context) { @ParameterizedTest(name = "[{index}] {1}") @ArgumentsSource(JavaCodeProvider.class) - @SneakyThrows(UnsupportedEncodingException.class) void asEnumTest(String source, Boilerplate expected) { BoilerplateEnumerator enumerator = new JavaBoilerplateEnumerator( () -> source.getBytes(StandardCharsets.UTF_16LE) ); @Cleanup Parser parser = new Parser(Language.JAVA); - @Cleanup Tree tree = parser.parseString(source); + @Cleanup Tree tree = parser.parse(source); Node root = tree.getRootNode(); Node class_declaration = root.getChild(0); Node class_body = class_declaration.getChildByFieldName("body"); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java index ab58d622..1fc7a6ec 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java @@ -5,7 +5,6 @@ import ch.usi.si.seart.treesitter.Parser; import ch.usi.si.seart.treesitter.Tree; import lombok.Cleanup; -import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.params.ParameterizedTest; @@ -14,7 +13,6 @@ import org.junit.jupiter.params.provider.ArgumentsSource; import usi.si.seart.model.code.Boilerplate; -import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.stream.Stream; @@ -120,11 +118,10 @@ public Stream provideArguments(ExtensionContext extensionCo @ParameterizedTest(name = "[{index}] {1}") @ArgumentsSource(PythonCodeProvider.class) - @SneakyThrows(UnsupportedEncodingException.class) void asEnumTest(List sources, Boilerplate expected) { @Cleanup Parser parser = new Parser(Language.PYTHON); for (String source: sources) { - @Cleanup Tree tree = parser.parseString(source); + @Cleanup Tree tree = parser.parse(source); Node root = tree.getRootNode(); Node function_definition = root.getChild(0); BoilerplateEnumerator enumerator = new PythonBoilerplateEnumerator( @@ -150,10 +147,9 @@ public Stream provideArguments(ExtensionContext context) { @ParameterizedTest(name = "[{index}] {1}") @ArgumentsSource(PythonCodeProviderSpecial.class) - @SneakyThrows(UnsupportedEncodingException.class) void asEnumTestSpecial(String source, Boilerplate expected) { @Cleanup Parser parser = new Parser(Language.PYTHON); - @Cleanup Tree tree = parser.parseString(source); + @Cleanup Tree tree = parser.parse(source); Node root = tree.getRootNode(); Node decorated_definition = root.getChild(0); Node function_definition = decorated_definition.getChildByFieldName("definition"); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaContentHasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaContentHasherTest.java index f58000d0..54669356 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaContentHasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaContentHasherTest.java @@ -1,11 +1,9 @@ package usi.si.seart.analyzer.hash; import ch.usi.si.seart.treesitter.Tree; -import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; import java.util.HashSet; @@ -35,7 +33,6 @@ void idempotencyTest() { } @Test - @SneakyThrows(UnsupportedEncodingException.class) void noCommentImpactTest() { String input_2 = "package ch.usi.si;\n" + @@ -51,7 +48,7 @@ void noCommentImpactTest() { "}"; byte[] bytes_2 = input_2.getBytes(StandardCharsets.UTF_16LE); - Tree other = parser.parseString(input_2); + Tree other = parser.parse(input_2); ContentHasher hasher_1 = new ContentHasher(getNodeMapper()); ContentHasher hasher_2 = new ContentHasher(() -> bytes_2); String first = hasher_1.hash(tree.getRootNode()); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java index ec20d13c..3fd84b3f 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java @@ -1,11 +1,9 @@ package usi.si.seart.analyzer.hash; import ch.usi.si.seart.treesitter.Tree; -import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.util.HashSet; @@ -35,7 +33,6 @@ void idempotencyTest() { } @Test - @SneakyThrows(UnsupportedEncodingException.class) void noCommentImpactTest() { String input_2 = "package ch.usi.si;\n" + @@ -49,7 +46,7 @@ void noCommentImpactTest() { " System.out.println(\"Hello, World!\");\n" + " }\n" + "}"; - Tree other = parser.parseString(input_2); + Tree other = parser.parse(input_2); Hasher hasher = new SyntaxTreeHasher(); String first = hasher.hash(tree.getRootNode()); String second = hasher.hash(other.getRootNode()); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicateTest.java index 9e0fe3b9..29b0e234 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicateTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicateTest.java @@ -5,11 +5,9 @@ import ch.usi.si.seart.treesitter.Parser; import ch.usi.si.seart.treesitter.Tree; import lombok.Cleanup; -import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import java.io.UnsupportedEncodingException; import java.util.HashSet; class ContainsErrorPredicateTest extends PredicateTest { @@ -29,10 +27,9 @@ void containsNoErrorTest() { } @Test - @SneakyThrows(UnsupportedEncodingException.class) void containsErrorTest() { @Cleanup Parser parser = new Parser(Language.C); - Tree error = parser.parseString(getInput()); + Tree error = parser.parse(getInput()); Node root = error.getRootNode(); NodePredicate predicate = new ContainsErrorPredicate(); boolean result = predicate.test(root); @@ -40,10 +37,9 @@ void containsErrorTest() { } @Test - @SneakyThrows(UnsupportedEncodingException.class) void anyContainsErrorTest() { @Cleanup Parser parser = new Parser(Language.C); - Tree error = parser.parseString(getInput()); + Tree error = parser.parse(getInput()); Node root = error.getRootNode(); Node declaration = root.getChild(0); Node function_definition = root.getChild(1); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicateTest.java index 4384a805..387cbe70 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicateTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicateTest.java @@ -2,11 +2,9 @@ import ch.usi.si.seart.treesitter.Node; import ch.usi.si.seart.treesitter.Tree; -import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; import java.util.HashSet; @@ -20,7 +18,6 @@ void emptyInputTest() { } @Test - @SneakyThrows(UnsupportedEncodingException.class) void containsOnlyAsciiTest() { String input_2 = "package ch.usi.si;\n" + @@ -36,7 +33,7 @@ void containsOnlyAsciiTest() { "}"; byte[] bytes_2 = input_2.getBytes(StandardCharsets.UTF_16LE); NodePredicate predicate = new ContainsNonAsciiPredicate(() -> bytes_2); - Tree tree = parser.parseString(input_2); + Tree tree = parser.parse(input_2); boolean result = predicate.test(tree.getRootNode()); Assertions.assertFalse(result); } From be7da55f38426518910d94be11b8643f29e4312e Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 6 Sep 2023 17:02:06 +0200 Subject: [PATCH 0301/1089] Added missing `@builder.Default` annotation to `CodeTaskDto` --- .../src/main/java/usi/si/seart/dto/task/CodeTaskDto.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dl4se-server/src/main/java/usi/si/seart/dto/task/CodeTaskDto.java b/dl4se-server/src/main/java/usi/si/seart/dto/task/CodeTaskDto.java index 275f99ff..9e638be0 100644 --- a/dl4se-server/src/main/java/usi/si/seart/dto/task/CodeTaskDto.java +++ b/dl4se-server/src/main/java/usi/si/seart/dto/task/CodeTaskDto.java @@ -25,10 +25,12 @@ public class CodeTaskDto { @Valid @NotNull @JsonSetter(nulls = Nulls.SKIP) + @Builder.Default CodeQueryDto query = new FileQueryDto(); @Valid @NotNull @JsonSetter(nulls = Nulls.SKIP) + @Builder.Default CodeProcessingDto processing = new CodeProcessingDto(); } From 929332ff17a185c6096b3e340a18365af408c120 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 6 Sep 2023 17:04:35 +0200 Subject: [PATCH 0302/1089] Fixing minor compiler warning in test --- .../java/usi/si/seart/io/ExtensionBasedFileVisitorTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dl4se-crawler/src/test/java/usi/si/seart/io/ExtensionBasedFileVisitorTest.java b/dl4se-crawler/src/test/java/usi/si/seart/io/ExtensionBasedFileVisitorTest.java index 6c5ed085..aab70028 100644 --- a/dl4se-crawler/src/test/java/usi/si/seart/io/ExtensionBasedFileVisitorTest.java +++ b/dl4se-crawler/src/test/java/usi/si/seart/io/ExtensionBasedFileVisitorTest.java @@ -72,6 +72,7 @@ void invalidExtensionsTest(String[] extensions) { @Test void nullExtensionsTest() { - Assertions.assertThrows(NullPointerException.class, () -> ExtensionBasedFileVisitor.forExtensions(null)); + String[] invalid = null; + Assertions.assertThrows(NullPointerException.class, () -> ExtensionBasedFileVisitor.forExtensions(invalid)); } } \ No newline at end of file From 1eae015dbef6e2823221bb231987783b2e50f11c Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 6 Sep 2023 17:11:55 +0200 Subject: [PATCH 0303/1089] Replacing usages of `@Singular` with `@Builder.Default` in `Language` --- .../src/test/java/usi/si/seart/git/GitTest.java | 16 ++++++++++------ .../main/java/usi/si/seart/model/Language.java | 4 ++-- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/dl4se-crawler/src/test/java/usi/si/seart/git/GitTest.java b/dl4se-crawler/src/test/java/usi/si/seart/git/GitTest.java index 6a5533c1..1edc41cf 100644 --- a/dl4se-crawler/src/test/java/usi/si/seart/git/GitTest.java +++ b/dl4se-crawler/src/test/java/usi/si/seart/git/GitTest.java @@ -17,6 +17,8 @@ import java.io.IOException; import java.nio.file.Path; import java.time.LocalDateTime; +import java.util.Collections; +import java.util.List; import java.util.Set; @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) @@ -32,13 +34,15 @@ class GitTest { // https://github.com/dabico/dl4se-history String historyRepoName = "dabico/dl4se-history"; - Language java = Language.builder().extension("java").build(); - Language python = Language.builder().extension("py").build(); + Language java = Language.builder().extensions(Collections.singletonList("java")).build(); + Language python = Language.builder().extensions(Collections.singletonList("py")).build(); Language cpp = Language.builder() - .extension("c") - .extension("cc") - .extension("cpp") - .extension("cxx") + .extensions(List.of( + "c", + "cc", + "cpp", + "cxx" + )) .build(); @Test diff --git a/dl4se-model/src/main/java/usi/si/seart/model/Language.java b/dl4se-model/src/main/java/usi/si/seart/model/Language.java index decf510c..ce7bb675 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/Language.java +++ b/dl4se-model/src/main/java/usi/si/seart/model/Language.java @@ -8,7 +8,6 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import lombok.Singular; import lombok.ToString; import lombok.experimental.FieldDefaults; import org.hibernate.annotations.Type; @@ -55,12 +54,13 @@ public class Language { @NotEmpty @Type(type = "list-array") @Column(columnDefinition = "text[]") - @Singular + @Builder.Default @ToString.Exclude @JsonIgnore List<@NotNull String> extensions = new ArrayList<>(); @ManyToMany(mappedBy = "languages") + @Builder.Default @ToString.Exclude @JsonIgnore Set repos = new HashSet<>(); From ba86a1ca3247b3852fcca71458e8be9270e49061 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 6 Sep 2023 17:12:44 +0200 Subject: [PATCH 0304/1089] Replacing `@Singular` with `@Builder.Default` in CodeProcessing --- .../usi/si/seart/model/task/processing/CodeProcessing.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dl4se-model/src/main/java/usi/si/seart/model/task/processing/CodeProcessing.java b/dl4se-model/src/main/java/usi/si/seart/model/task/processing/CodeProcessing.java index b7a4879c..f5047e68 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/task/processing/CodeProcessing.java +++ b/dl4se-model/src/main/java/usi/si/seart/model/task/processing/CodeProcessing.java @@ -3,10 +3,10 @@ import com.fasterxml.jackson.annotation.JsonProperty; import io.hypersistence.utils.hibernate.type.array.ListArrayType; import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import lombok.Singular; import lombok.experimental.FieldDefaults; import lombok.experimental.SuperBuilder; import org.hibernate.Hibernate; @@ -68,7 +68,7 @@ public class CodeProcessing extends Processing { @NotNull @Type(type = "list-array") - @Singular + @Builder.Default @Column(name = "abstract_idioms") @JsonProperty(value = "abstract_idioms") List<@NotBlank String> abstractIdioms = new ArrayList<>(); From 257bd35a910b6bdc1bd867b0b39ca8ed83a27ab2 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 7 Sep 2023 09:51:22 +0200 Subject: [PATCH 0305/1089] liquibase migration command now has env vars set by default --- dl4se-model/src/main/java/usi/si/seart/model/GitRepo.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dl4se-model/src/main/java/usi/si/seart/model/GitRepo.java b/dl4se-model/src/main/java/usi/si/seart/model/GitRepo.java index 61dae6b8..422e76c6 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/GitRepo.java +++ b/dl4se-model/src/main/java/usi/si/seart/model/GitRepo.java @@ -13,6 +13,7 @@ import org.hibernate.annotations.DynamicUpdate; import usi.si.seart.model.code.File; import usi.si.seart.model.code.Function; +import usi.si.seart.validation.constraints.NullOrNotBlank; import javax.persistence.Column; import javax.persistence.Entity; @@ -57,6 +58,7 @@ public class GitRepo { @Column(unique = true) String name; + @NullOrNotBlank String license; @NotNull From 52baf61cefd3378d62e486809283ce764ca4e4bb Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 7 Sep 2023 09:53:20 +0200 Subject: [PATCH 0306/1089] Refactored `getRepoLanguages` as `getAllLanguages` --- .../usi/si/seart/crawler/component/CodeCrawler.java | 2 +- .../usi/si/seart/crawler/dto/SearchResultDto.java | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java index eb00865f..20361df6 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java @@ -142,7 +142,7 @@ private void inspectSearchResult(SearchResultDto item) { LocalDateTime lastUpdateGhs = conversionService.convert(item.getLastCommit(), LocalDateTime.class); - Set repoLanguageNames = Sets.intersection(languageNames, item.getRepoLanguages()); + Set repoLanguageNames = Sets.intersection(languageNames, item.getAllLanguages()); Set repoLanguages = repoLanguageNames.stream() .map(nameToLanguage::get) .filter(Objects::nonNull) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/dto/SearchResultDto.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/dto/SearchResultDto.java index a373db2c..b612d694 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/dto/SearchResultDto.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/dto/SearchResultDto.java @@ -9,10 +9,11 @@ import usi.si.seart.model.GitRepo; import java.util.Date; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; @Getter @Setter @@ -55,11 +56,11 @@ public class SearchResultDto { Set labels; Set topics; - public Set getRepoLanguages() { - Set repoLanguages = new HashSet<>(); - repoLanguages.add(mainLanguage); - repoLanguages.addAll(languages.keySet()); - return repoLanguages; + public Set getAllLanguages() { + return Stream.concat( + languages.keySet().stream(), + Stream.of(mainLanguage) + ).collect(Collectors.toSet()); } public void update(GitRepo repo) { From d5acd82a11512f1257e8882e14bb255713b4cbc5 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 7 Sep 2023 10:20:39 +0200 Subject: [PATCH 0307/1089] ID values for `GitRepo` are now re-used from GHS This will no doubt make several things easier: - Migration to `db_link` at a later time - Availability checks through GHS --- .../crawler/converter/SearchResultDtoToGitRepoConverter.java | 1 + dl4se-model/src/main/java/usi/si/seart/model/GitRepo.java | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/converter/SearchResultDtoToGitRepoConverter.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/converter/SearchResultDtoToGitRepoConverter.java index 8e7d25e8..6ce7dcd8 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/converter/SearchResultDtoToGitRepoConverter.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/converter/SearchResultDtoToGitRepoConverter.java @@ -16,6 +16,7 @@ public class SearchResultDtoToGitRepoConverter implements Converter Date: Thu, 7 Sep 2023 17:49:56 +0200 Subject: [PATCH 0308/1089] Bumping minor version of `java-tree-sitter` `1.3.0` -> `1.4.0` --- dl4se-analyzer/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dl4se-analyzer/pom.xml b/dl4se-analyzer/pom.xml index 14b5a38d..9d6f6e5c 100644 --- a/dl4se-analyzer/pom.xml +++ b/dl4se-analyzer/pom.xml @@ -25,7 +25,7 @@ ch.usi.si.seart java-tree-sitter - 1.3.0 + 1.4.0 org.apache.commons From 5d5a0f079bc4de290224a958f69721b211649db7 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 7 Sep 2023 17:50:08 +0200 Subject: [PATCH 0309/1089] Replacing usage of deprecated API --- .../si/seart/analyzer/printer/SymbolicExpressionPrinter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinter.java index ea7c3d26..c41a0bd0 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinter.java @@ -9,7 +9,7 @@ public class SymbolicExpressionPrinter extends AbstractPrinter { @Override public String print(Node node) { - return node.getNodeString(); + return new ch.usi.si.seart.treesitter.printer.SymbolicExpressionPrinter(node.walk()).print(); } @Override From b2963f9940186819656ab32ec0d27cfb4c28b4f8 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 7 Sep 2023 17:53:01 +0200 Subject: [PATCH 0310/1089] Convert instance field in `JavaHasherTest` to static --- .../usi/si/seart/analyzer/hash/JavaContentHasherTest.java | 4 ++-- .../test/java/usi/si/seart/analyzer/hash/JavaHasherTest.java | 2 +- .../usi/si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaContentHasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaContentHasherTest.java index 54669356..f730ae5e 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaContentHasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaContentHasherTest.java @@ -12,8 +12,8 @@ class JavaContentHasherTest extends JavaHasherTest { @Test void emptyTest() { Hasher hasher = new ContentHasher(getNodeMapper()); - Assertions.assertEquals(empty, hasher.hash()); - Assertions.assertEquals(empty, hasher.hash(new HashSet<>())); + Assertions.assertEquals(EMPTY, hasher.hash()); + Assertions.assertEquals(EMPTY, hasher.hash(new HashSet<>())); } @Test diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaHasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaHasherTest.java index 8dca368d..b4ec7419 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaHasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaHasherTest.java @@ -10,7 +10,7 @@ public abstract class JavaHasherTest extends JavaBaseTest { // https://crypto.stackexchange.com/a/26135 - protected String empty = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; + protected static final String EMPTY = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; @Override protected List getTokens() { diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java index 3fd84b3f..5be49487 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java @@ -12,8 +12,8 @@ class JavaSyntaxTreeHasherTest extends JavaHasherTest { @Test void emptyTest() { Hasher hasher = new SyntaxTreeHasher(); - Assertions.assertEquals(empty, hasher.hash()); - Assertions.assertEquals(empty, hasher.hash(new HashSet<>())); + Assertions.assertEquals(EMPTY, hasher.hash()); + Assertions.assertEquals(EMPTY, hasher.hash(new HashSet<>())); } @Test From 0e2fea733bec804a56181b761b27ad0df342a029 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 8 Sep 2023 09:36:32 +0200 Subject: [PATCH 0311/1089] Updating liquibase XML schema to latest version --- liquibase/changelog.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/liquibase/changelog.xml b/liquibase/changelog.xml index c3a7f654..3bbb6614 100644 --- a/liquibase/changelog.xml +++ b/liquibase/changelog.xml @@ -3,6 +3,6 @@ xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog - http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd"> + http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.23.xsd"> From 4f84b642cfa31882aa977662635aab14463dac99 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 8 Sep 2023 09:58:43 +0200 Subject: [PATCH 0312/1089] Added liquibase header comment to SQL files --- liquibase/scripts/00_init.sql | 2 ++ liquibase/scripts/01_user.sql | 2 ++ liquibase/scripts/02_view.sql | 2 ++ 3 files changed, 6 insertions(+) diff --git a/liquibase/scripts/00_init.sql b/liquibase/scripts/00_init.sql index 0328f821..5114c41d 100644 --- a/liquibase/scripts/00_init.sql +++ b/liquibase/scripts/00_init.sql @@ -1,3 +1,5 @@ +-- liquibase formatted sql + CREATE SEQUENCE hibernate_sequence START 1 INCREMENT 1; CREATE TABLE "crawl_job" ( diff --git a/liquibase/scripts/01_user.sql b/liquibase/scripts/01_user.sql index 6803e43a..264d6d25 100644 --- a/liquibase/scripts/01_user.sql +++ b/liquibase/scripts/01_user.sql @@ -1,3 +1,5 @@ +-- liquibase formatted sql + CREATE TABLE "configuration" ( "key" text PRIMARY KEY NOT NULL, "value" text NOT NULL, diff --git a/liquibase/scripts/02_view.sql b/liquibase/scripts/02_view.sql index 7be78291..5b1022fc 100644 --- a/liquibase/scripts/02_view.sql +++ b/liquibase/scripts/02_view.sql @@ -1,3 +1,5 @@ +-- liquibase formatted sql + CREATE MATERIALIZED VIEW table_counts AS SELECT 'user' AS "table", COUNT(id) FROM "user" UNION From 4e6a8bd06d9db352f32b2c7a2475ed77d24f01dc Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 8 Sep 2023 10:09:54 +0200 Subject: [PATCH 0313/1089] Removing the `is_parsed` column which is no longer used It has been replaced in favor of the more flexible `has_error`. I think it's removal is overdue, and the column just slipped my notice. --- .../src/main/java/usi/si/seart/model/code/File.java | 9 --------- liquibase/scripts/00_init.sql | 1 - 2 files changed, 10 deletions(-) diff --git a/dl4se-model/src/main/java/usi/si/seart/model/code/File.java b/dl4se-model/src/main/java/usi/si/seart/model/code/File.java index 50641084..db186971 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/code/File.java +++ b/dl4se-model/src/main/java/usi/si/seart/model/code/File.java @@ -1,7 +1,6 @@ package usi.si.seart.model.code; import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @@ -11,13 +10,11 @@ import lombok.experimental.SuperBuilder; import javax.persistence.CascadeType; -import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.OneToMany; import javax.persistence.Table; import javax.persistence.UniqueConstraint; import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -38,12 +35,6 @@ public class File extends Code { @NotBlank String path; - @NotNull - @Column(name = "is_parsed") - @Builder.Default - @JsonProperty(value = "is_parsed") - Boolean isParsed = false; - @OneToMany(mappedBy = "file", cascade = {CascadeType.PERSIST, CascadeType.MERGE}) @Builder.Default @JsonIgnore diff --git a/liquibase/scripts/00_init.sql b/liquibase/scripts/00_init.sql index 5114c41d..d096acdc 100644 --- a/liquibase/scripts/00_init.sql +++ b/liquibase/scripts/00_init.sql @@ -38,7 +38,6 @@ CREATE TABLE "file" ( "repo_id" bigint NOT NULL, "lang_id" bigint NOT NULL, "path" text NOT NULL, - "is_parsed" boolean NOT NULL, "content" text NOT NULL, "content_hash" text NOT NULL, "ast" text NOT NULL, From bff6998e2293a7ab49ba9bb007b6a316e977098c Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 8 Sep 2023 10:28:26 +0200 Subject: [PATCH 0314/1089] Removing `Tuple` and replacing it with `Pair` from Apache commons lang --- .../java/usi/si/seart/analyzer/Analyzer.java | 12 +-- .../query/multi/JavaMultiCaptureQueries.java | 4 +- .../query/multi/MultiCaptureQueries.java | 16 ++-- .../multi/PythonMultiCaptureQueries.java | 4 +- .../usi/si/seart/analyzer/util/Tuple.java | 94 ------------------- .../usi/si/seart/analyzer/util/TupleTest.java | 14 --- 6 files changed, 18 insertions(+), 126 deletions(-) delete mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/util/Tuple.java delete mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/util/TupleTest.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java index a696d814..9fba6f88 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java @@ -10,6 +10,7 @@ import lombok.Cleanup; import lombok.Getter; import lombok.experimental.FieldDefaults; +import org.apache.commons.lang3.tuple.Pair; import usi.si.seart.analyzer.count.CharacterCounter; import usi.si.seart.analyzer.count.CodeTokenCounter; import usi.si.seart.analyzer.count.Counter; @@ -30,7 +31,6 @@ import usi.si.seart.analyzer.printer.SymbolicExpressionPrinter; import usi.si.seart.analyzer.printer.SyntaxTreePrinter; import usi.si.seart.analyzer.query.multi.MultiCaptureQueries; -import usi.si.seart.analyzer.util.Tuple; import usi.si.seart.model.code.Boilerplate; import usi.si.seart.model.code.File; import usi.si.seart.model.code.Function; @@ -146,9 +146,9 @@ private File extractFileEntity() { } private List extractFunctionEntities(File file) { - List>> matches = multiCaptureQueries.getCallableDeclarations(tree.getRootNode()); + List>> matches = multiCaptureQueries.getCallableDeclarations(tree.getRootNode()); List functions = new ArrayList<>(matches.size()); - for (List> match: matches) { + for (List> match: matches) { Function function = extractFunctionEntity(match); // These operations are invariant by // nature and should not be overridden @@ -159,13 +159,13 @@ private List extractFunctionEntities(File file) { return functions; } - private Function extractFunctionEntity(List> match) { + private Function extractFunctionEntity(List> match) { List nodes = match.stream() - .map(Tuple::getValue) + .map(Pair::getValue) .collect(Collectors.toList()); Node function = match.stream() .filter(tuple -> tuple.getKey().equals("target")) - .map(Tuple::getValue) + .map(Pair::getValue) .findFirst() .orElseThrow(IllegalStateException::new); diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/JavaMultiCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/JavaMultiCaptureQueries.java index 0e89bdf6..b84e2331 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/JavaMultiCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/JavaMultiCaptureQueries.java @@ -2,7 +2,7 @@ import ch.usi.si.seart.treesitter.Language; import ch.usi.si.seart.treesitter.Node; -import usi.si.seart.analyzer.util.Tuple; +import org.apache.commons.lang3.tuple.Pair; import java.util.List; @@ -23,7 +23,7 @@ public JavaMultiCaptureQueries() { } @Override - public List>> getCallableDeclarations(Node node) { + public List>> getCallableDeclarations(Node node) { return execute( node, "([(line_comment)(block_comment)]* @additional . (method_declaration) @target)" + diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java index d5c7d5d0..ecb88f8d 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java @@ -9,8 +9,8 @@ import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Cleanup; +import org.apache.commons.lang3.tuple.Pair; import usi.si.seart.analyzer.query.Queries; -import usi.si.seart.analyzer.util.Tuple; import java.util.ArrayList; import java.util.Collections; @@ -20,24 +20,24 @@ import java.util.stream.StreamSupport; @AllArgsConstructor(access = AccessLevel.PROTECTED) -public abstract class MultiCaptureQueries implements Queries>>> { +public abstract class MultiCaptureQueries implements Queries>>> { private final Language language; - public abstract List>> getCallableDeclarations(Node node); + public abstract List>> getCallableDeclarations(Node node); - public List>> execute(Node node, String pattern) { + public List>> execute(Node node, String pattern) { @Cleanup Query query = new Query(language, pattern); verify(query); @Cleanup QueryCursor cursor = new QueryCursor(node, query); Stream matches = StreamSupport.stream(cursor.spliterator(), false); return matches.map(match -> { QueryCapture[] captures = match.getCaptures(); - List> tuples = new ArrayList<>(captures.length); + List> tuples = new ArrayList<>(captures.length); for (QueryCapture capture: captures) { Node capturedNode = capture.getNode(); String captureName = query.getCaptureName(capture); - Tuple tuple = Tuple.of(captureName, capturedNode); + Pair tuple = Pair.of(captureName, capturedNode); tuples.add(tuple); } return tuples; @@ -58,12 +58,12 @@ public void verify(Query query) { } @Override - public List>> getCallableDeclarations(Node node) { + public List>> getCallableDeclarations(Node node) { return Collections.emptyList(); } @Override - public List>> execute(Node node, String pattern) { + public List>> execute(Node node, String pattern) { return Collections.emptyList(); } }; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/PythonMultiCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/PythonMultiCaptureQueries.java index 8d54f6aa..173c05a4 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/PythonMultiCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/PythonMultiCaptureQueries.java @@ -2,7 +2,7 @@ import ch.usi.si.seart.treesitter.Language; import ch.usi.si.seart.treesitter.Node; -import usi.si.seart.analyzer.util.Tuple; +import org.apache.commons.lang3.tuple.Pair; import java.util.List; @@ -20,7 +20,7 @@ public PythonMultiCaptureQueries() { } @Override - public List>> getCallableDeclarations(Node node) { + public List>> getCallableDeclarations(Node node) { return execute(node, "(_ (decorator)* @additional (function_definition) @target)"); } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/util/Tuple.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/util/Tuple.java deleted file mode 100644 index 1174993c..00000000 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/util/Tuple.java +++ /dev/null @@ -1,94 +0,0 @@ -package usi.si.seart.analyzer.util; - -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.experimental.FieldDefaults; - -import java.util.Map; -import java.util.Objects; - -/** - * Simple implementation of a tuple class, - * used as a container for two values of arbitrary types. - * Tuples are immutable, and can only be created through a static factory: - *
{@code
- *      Tuple t = Tuple.of(1, "Hello!");
- * }
- * The left and right side are subsequently accessed through dedicated getters: - *
{@code
- *      int i = t.getLeft();
- *      String msg = t.getRight();
- * }
- * Instances can also be used in place of {@link Map.Entry}: - *
{@code
- *      Map = Map.ofEntries(
- *          Tuple.of(1, 1L),
- *          Tuple.of(2, ""),
- *          Tuple.of(3, new Object())
- *      );
- * }
- * Which means that you can also access tuple data as you would a map entry: - *
{@code
- *      int i = t.getKey();
- *      String msg = t.getValue();
- * }
- * In terms of overall behaviour, it is similar to a {@code UnmodifiableEntry}. - * - * @author dabico - * @param The type of the first value. - * @param The type of the second value. - */ -@Getter -@AllArgsConstructor(access = AccessLevel.PRIVATE) -@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) -public class Tuple implements Map.Entry { - - L left; - R right; - - @Override - public L getKey() { - return left; - } - - @Override - public R getValue() { - return right; - } - - @Override - public R setValue(R value) { - throw new UnsupportedOperationException("Tuple values are not modifiable!"); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Tuple tuple = (Tuple) o; - if (!Objects.equals(left, tuple.left)) return false; - return Objects.equals(right, tuple.right); - } - - @Override - public int hashCode() { - int result = left != null ? left.hashCode() : 0; - result = 31 * result + (right != null ? right.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return String.format("(%s, %s)", left.toString(), right.toString()); - } - - public Tuple invert() { - return new Tuple<>(right, left); - } - - public static Tuple of(L left, R right) { - return new Tuple<>(left, right); - } -} - diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/util/TupleTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/util/TupleTest.java deleted file mode 100644 index c38d37e5..00000000 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/util/TupleTest.java +++ /dev/null @@ -1,14 +0,0 @@ -package usi.si.seart.analyzer.util; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -class TupleTest { - - @Test - void invertTest() { - Tuple tuple = Tuple.of(1, "hello!"); - Tuple elput = Tuple.of("hello!", 1); - Assertions.assertEquals(elput, tuple.invert()); - } -} \ No newline at end of file From a85a6c12f05d4810c8d79fbe16060bc0a2b65a7b Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 8 Sep 2023 10:29:42 +0200 Subject: [PATCH 0315/1089] Deleting invalid run configuration --- .idea/runConfigurations/Tests__dl4se_tree_sitter.xml | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 .idea/runConfigurations/Tests__dl4se_tree_sitter.xml diff --git a/.idea/runConfigurations/Tests__dl4se_tree_sitter.xml b/.idea/runConfigurations/Tests__dl4se_tree_sitter.xml deleted file mode 100644 index 30c44902..00000000 --- a/.idea/runConfigurations/Tests__dl4se_tree_sitter.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - \ No newline at end of file From 39551bd1db528798ba2dfbcc3d3e45c84273c989 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 8 Sep 2023 10:45:40 +0200 Subject: [PATCH 0316/1089] Each SQL migration now has a changeset author and ID --- liquibase/scripts/00_init.sql | 1 + liquibase/scripts/01_user.sql | 1 + liquibase/scripts/02_view.sql | 1 + 3 files changed, 3 insertions(+) diff --git a/liquibase/scripts/00_init.sql b/liquibase/scripts/00_init.sql index d096acdc..3f46faa6 100644 --- a/liquibase/scripts/00_init.sql +++ b/liquibase/scripts/00_init.sql @@ -1,4 +1,5 @@ -- liquibase formatted sql +-- changeset dabico:1 CREATE SEQUENCE hibernate_sequence START 1 INCREMENT 1; diff --git a/liquibase/scripts/01_user.sql b/liquibase/scripts/01_user.sql index 264d6d25..cf0b0559 100644 --- a/liquibase/scripts/01_user.sql +++ b/liquibase/scripts/01_user.sql @@ -1,4 +1,5 @@ -- liquibase formatted sql +-- changeset dabico:2 CREATE TABLE "configuration" ( "key" text PRIMARY KEY NOT NULL, diff --git a/liquibase/scripts/02_view.sql b/liquibase/scripts/02_view.sql index 5b1022fc..730cc79e 100644 --- a/liquibase/scripts/02_view.sql +++ b/liquibase/scripts/02_view.sql @@ -1,4 +1,5 @@ -- liquibase formatted sql +-- changeset dabico:3 CREATE MATERIALIZED VIEW table_counts AS SELECT 'user' AS "table", COUNT(id) FROM "user" From 5f6605af04f177812c248dbf531242f0cbca8229 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 8 Sep 2023 12:02:41 +0200 Subject: [PATCH 0317/1089] Added edge case to `JavaLineCounterTest` What if the acquired nodes are on the same line? For instance: a block comment preceding a method declaration, without any new lines in between. In this case, we can not count their line span individually and then add them together. What we must do instead is merge ranges whose end position row is equal to the start position row of its neighbor. --- .../seart/analyzer/count/JavaLineCounterTest.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaLineCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaLineCounterTest.java index e9230bcf..ed71363e 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaLineCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaLineCounterTest.java @@ -1,6 +1,8 @@ package usi.si.seart.analyzer.count; import ch.usi.si.seart.treesitter.Node; +import ch.usi.si.seart.treesitter.Tree; +import lombok.Cleanup; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import usi.si.seart.analyzer.test.JavaBaseTest; @@ -35,4 +37,16 @@ void countChildrenTest() { // Subtract one for the lost space between package and class Assertions.assertEquals(getInput().lines().count() - 1, actual, message); } + + @Test + void countChildrenOnSameLineTest() { + Counter counter = new LineCounter(); + String input = "/* */ class _ {\n}\n"; + @Cleanup Tree tree = parser.parse(input); + Node root = tree.getRootNode(); + Node comment = root.getChild(0); + Node class_declaration = root.getChild(1); + Long actual = counter.count(comment, class_declaration); + Assertions.assertEquals(input.lines().count(), actual); + } } \ No newline at end of file From 38dc7374ea151a4d20448c534e254c7b02cea070 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 8 Sep 2023 12:06:15 +0200 Subject: [PATCH 0318/1089] Fixed aforementioned issue of `LineCounter` --- .../si/seart/analyzer/count/LineCounter.java | 58 ++++++++++++++++++- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/LineCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/LineCounter.java index 2c2688f9..9965a926 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/LineCounter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/LineCounter.java @@ -3,14 +3,66 @@ import ch.usi.si.seart.treesitter.Node; import ch.usi.si.seart.treesitter.Point; import ch.usi.si.seart.treesitter.Range; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.experimental.FieldDefaults; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class LineCounter extends AbstractCounter { @Override public Long count(Node node) { Range range = node.getRange(); - Point startPoint = range.getStartPoint(); - Point endPoint = range.getEndPoint(); - return (long) (endPoint.getRow() - startPoint.getRow() + 1); + Span span = new Span(range); + return count(span); + } + + @Override + protected Long count(Stream nodes) { + List spans = nodes.map(Node::getRange) + .map(Span::new) + .collect(Collectors.toList()); + return merge(spans).stream() + .mapToLong(this::count) + .sum(); + } + + private Long count(Span span) { + Point startPoint = span.getStart(); + Point endPoint = span.getEnd(); + long startRow = startPoint.getRow(); + long endRow = endPoint.getRow(); + return endRow - startRow + 1; + } + + private static List merge(List spans) { + List result = new ArrayList<>(); + spans.stream().reduce((left, right) -> { + int leftRow = left.getEnd().getRow(); + int rightTow = right.getStart().getRow(); + if (leftRow == rightTow) + return new Span(left.getStart(), right.getEnd()); + result.add(left); + return right; + }).ifPresent(result::add); + return result; + } + + @Getter + @AllArgsConstructor + @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) + private static class Span { + + Point start; + Point end; + + public Span(Range range) { + this(range.getStartPoint(), range.getEndPoint()); + } } } From a5de5ddbeb96cfec0888edeac418cd68fb0c3c28 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 8 Sep 2023 14:24:27 +0200 Subject: [PATCH 0319/1089] The liquibase changelog now only includes the first file The rest will be included once they are ready --- liquibase/changelog.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/liquibase/changelog.xml b/liquibase/changelog.xml index 3bbb6614..ee4b05ea 100644 --- a/liquibase/changelog.xml +++ b/liquibase/changelog.xml @@ -4,5 +4,5 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.23.xsd"> - + From 470697986ad89ea010b1dbaa615bc9800301e559 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 8 Sep 2023 14:24:57 +0200 Subject: [PATCH 0320/1089] The Google HTTP client is now a top-level dependency --- dl4se-crawler/pom.xml | 1 - pom.xml | 8 ++++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/dl4se-crawler/pom.xml b/dl4se-crawler/pom.xml index 4f031618..5b85fdb2 100644 --- a/dl4se-crawler/pom.xml +++ b/dl4se-crawler/pom.xml @@ -63,7 +63,6 @@ com.google.http-client google-http-client - 1.42.2 diff --git a/pom.xml b/pom.xml index 8c420127..eb177631 100644 --- a/pom.xml +++ b/pom.xml @@ -38,6 +38,7 @@ 3.25.5 1.18.28 32.1.2-jre + 1.43.3 3.1.10 42.6.0 0.11.5 @@ -69,6 +70,13 @@ pom import
+ + com.google.http-client + google-http-client-bom + ${google.httpClient.version} + pom + import + org.springframework.boot spring-boot-dependencies From 13694fb0dd730655c86d255bdb72fad604ff5b20 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 8 Sep 2023 14:25:40 +0200 Subject: [PATCH 0321/1089] Renaming the Guava version property --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index eb177631..d90e3e9d 100644 --- a/pom.xml +++ b/pom.xml @@ -37,7 +37,7 @@ 5.10.0 3.25.5 1.18.28 - 32.1.2-jre + 32.1.2-jre 1.43.3 3.1.10 42.6.0 @@ -66,7 +66,7 @@ com.google.guava guava-bom - ${guava.version} + ${google.guava.version} pom import From 30771582540624329ea90a5017e48cd53ba016cd Mon Sep 17 00:00:00 2001 From: dabico Date: Sat, 16 Sep 2023 12:41:31 +0200 Subject: [PATCH 0322/1089] Bumping patch version of `java-tree-sitter` `1.4.0` -> `1.4.2` --- dl4se-analyzer/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dl4se-analyzer/pom.xml b/dl4se-analyzer/pom.xml index 9d6f6e5c..349686d5 100644 --- a/dl4se-analyzer/pom.xml +++ b/dl4se-analyzer/pom.xml @@ -25,7 +25,7 @@ ch.usi.si.seart java-tree-sitter - 1.4.0 + 1.4.2 org.apache.commons From ae5a372da3b2f3ed0d974cf0e9361dc0a778168e Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 18 Sep 2023 11:34:47 +0200 Subject: [PATCH 0323/1089] Removing private field in `MainConfig` --- .../src/main/java/usi/si/seart/config/MainConfig.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/config/MainConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/MainConfig.java index c4ba5bdb..cf511736 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/MainConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/MainConfig.java @@ -34,12 +34,9 @@ @Configuration public class MainConfig { - @Value("${java.io.tmpdir}") - private String tmpDir; - @Bean - public Path fileStorageDirPath() { - return Path.of(tmpDir, "dl4se_storage"); + public Path fileStorageDirPath(@Value("${java.io.tmpdir}") String value) { + return Path.of(value, "dl4se_storage"); } @Bean From f1f92028388b22cc8b76f557e93c715c44bad96c Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 18 Sep 2023 15:22:13 +0200 Subject: [PATCH 0324/1089] Specifying Postgres Dialect --- dl4se-server/src/main/resources/application.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/dl4se-server/src/main/resources/application.properties b/dl4se-server/src/main/resources/application.properties index 4bf35ada..741396f5 100644 --- a/dl4se-server/src/main/resources/application.properties +++ b/dl4se-server/src/main/resources/application.properties @@ -52,6 +52,7 @@ spring.jpa.open-in-view=false spring.jpa.hibernate.ddl-auto=none spring.jpa.properties.hibernate.types.print.banner=false spring.jpa.properties.hibernate.jdbc.fetch_size=500 +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL10Dialect # JPA Debugging Configuration spring.jpa.properties.hibernate.format_sql=false From 2da085036b256868037d2240bf9d268b2997f8c6 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 18 Sep 2023 15:37:56 +0200 Subject: [PATCH 0325/1089] `java-tree-sitter` is now a top-level dependency --- dl4se-analyzer/pom.xml | 5 ----- pom.xml | 6 ++++++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/dl4se-analyzer/pom.xml b/dl4se-analyzer/pom.xml index 349686d5..331a5d0e 100644 --- a/dl4se-analyzer/pom.xml +++ b/dl4se-analyzer/pom.xml @@ -22,11 +22,6 @@ dl4se-model ${project.version} - - ch.usi.si.seart - java-tree-sitter - 1.4.2 - org.apache.commons commons-lang3 diff --git a/pom.xml b/pom.xml index d90e3e9d..f393d823 100644 --- a/pom.xml +++ b/pom.xml @@ -36,6 +36,7 @@ UTF-8 5.10.0 3.25.5 + 1.4.2 1.18.28 32.1.2-jre 1.43.3 @@ -115,6 +116,11 @@ postgresql ${postgresql.version} + + ch.usi.si.seart + java-tree-sitter + ${treesitter.version} + From bac8d6c6a8b8664a7afeb4508e107caeab40cee7 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 22 Sep 2023 09:23:09 +0200 Subject: [PATCH 0326/1089] Bumping minor version of `java-tree-sitter` `1.4.2` -> `1.5.1` Since this is the version that allows direct access to content from nodes, a lot of the analysis stuff was simplified. As of this commit, the `NodeMapper` class has been rendered completely irrelevant. This has led to massive improvements in the overall construction of all the analyzer classes, as well as their inheritance hierarchy. --- .../java/usi/si/seart/analyzer/Analyzer.java | 16 ++++++------ .../usi/si/seart/analyzer/NodeMapper.java | 25 ------------------- .../analyzer/count/CharacterCounter.java | 11 ++------ .../count/ContentTraverseCounter.java | 12 --------- .../analyzer/count/JavaTokenCounter.java | 9 +------ .../analyzer/count/PythonTokenCounter.java | 9 +------ .../si/seart/analyzer/count/TokenCounter.java | 19 +++++--------- .../enumerator/BoilerplateEnumerator.java | 13 +++------- .../enumerator/JavaBoilerplateEnumerator.java | 9 +------ .../PythonBoilerplateEnumerator.java | 11 ++------ .../si/seart/analyzer/hash/ContentHasher.java | 16 ++++++------ .../node/ContainsNonAsciiPredicate.java | 17 ++----------- .../predicate/node/NodeContentPredicate.java | 12 --------- .../analyzer/printer/ContentPrinter.java | 12 --------- .../seart/analyzer/printer/NodePrinter.java | 11 ++------ .../query/multi/MultiCaptureQueries.java | 2 +- .../query/single/SingleCaptureQueries.java | 2 +- .../count/JavaCharacterCounterTest.java | 6 ++--- .../analyzer/count/JavaTokenCounterTest.java | 6 ++--- .../count/PythonTokenCounterTest.java | 6 ++--- .../JavaBoilerplateEnumeratorTest.java | 5 +--- .../PythonBoilerplateEnumeratorTest.java | 9 ++----- .../analyzer/hash/JavaContentHasherTest.java | 19 ++++++-------- .../node/ContainsNonAsciiPredicateTest.java | 10 +++----- .../analyzer/printer/NodePrinterTest.java | 8 +++--- .../usi/si/seart/analyzer/test/BaseTest.java | 12 ++------- pom.xml | 2 +- 27 files changed, 67 insertions(+), 222 deletions(-) delete mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/NodeMapper.java delete mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/ContentTraverseCounter.java delete mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/NodeContentPredicate.java delete mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/ContentPrinter.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java index 9fba6f88..723088aa 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java @@ -53,7 +53,6 @@ public class Analyzer implements AutoCloseable { LocalClone localClone; Path path; - String source; Counter lineCounter; Counter totalTokenCounter; @@ -85,23 +84,22 @@ public Analyzer(LocalClone localClone, Path path, Language language) throws IOEx this.parser = new Parser(language); this.localClone = localClone; this.path = path; - this.source = Files.readString(path); + String source = Files.readString(path); this.tree = parser.parse(source); - NodeMapper mapper = () -> source.getBytes(NodeMapper.DEFAULT_CHARSET); this.lineCounter = new LineCounter(); - this.totalTokenCounter = TokenCounter.getInstance(language, mapper); + this.totalTokenCounter = TokenCounter.getInstance(language); this.codeTokenCounter = CodeTokenCounter.getInstance(language); - this.characterCounter = new CharacterCounter(mapper); - this.contentHasher = new ContentHasher(mapper); + this.characterCounter = new CharacterCounter(); + this.contentHasher = new ContentHasher(); this.syntaxTreeHasher = new SyntaxTreeHasher(); this.containsError = new ContainsErrorPredicate(); - this.containsNonAscii = new ContainsNonAsciiPredicate(mapper); + this.containsNonAscii = new ContainsNonAsciiPredicate(); this.testFilePredicate = TestFilePredicate.getInstance(language); - this.nodePrinter = new NodePrinter(mapper); + this.nodePrinter = new NodePrinter(); this.syntaxTreePrinter = new SyntaxTreePrinter(); this.expressionPrinter = new SymbolicExpressionPrinter(); this.multiCaptureQueries = MultiCaptureQueries.getInstance(language); - this.boilerplateEnumerator = BoilerplateEnumerator.getInstance(language, mapper); + this.boilerplateEnumerator = BoilerplateEnumerator.getInstance(language); } @Override diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/NodeMapper.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/NodeMapper.java deleted file mode 100644 index b168cf88..00000000 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/NodeMapper.java +++ /dev/null @@ -1,25 +0,0 @@ -package usi.si.seart.analyzer; - -import ch.usi.si.seart.treesitter.Range; - -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; - -public interface NodeMapper { - - Charset DEFAULT_CHARSET = StandardCharsets.UTF_16LE; - - byte[] getBytes(); - - default byte[] getBytesForRange(Range range) { - int startByte = range.getStartByte() * 2; - int endByte = range.getEndByte() * 2; - return Arrays.copyOfRange(getBytes(), startByte, endByte); - } - - default String getContentForRange(Range range) { - byte[] bytes = getBytesForRange(range); - return new String(bytes, DEFAULT_CHARSET); - } -} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CharacterCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CharacterCounter.java index b829d798..66c3f4da 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CharacterCounter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CharacterCounter.java @@ -1,21 +1,14 @@ package usi.si.seart.analyzer.count; import ch.usi.si.seart.treesitter.Node; -import ch.usi.si.seart.treesitter.Range; -import usi.si.seart.analyzer.NodeMapper; -public class CharacterCounter extends ContentTraverseCounter { - - public CharacterCounter(NodeMapper mapper) { - super(mapper); - } +public class CharacterCounter extends TraverseCounter { @Override protected void nodeCallback(Node node) { boolean leafNode = node.getChildCount() == 0; if (leafNode) { - Range range = node.getRange(); - String content = mapper.getContentForRange(range); + String content = node.getContent(); String noSpace = content.replaceAll("\\s", ""); count.addAndGet(noSpace.length()); } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/ContentTraverseCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/ContentTraverseCounter.java deleted file mode 100644 index c5b154ee..00000000 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/ContentTraverseCounter.java +++ /dev/null @@ -1,12 +0,0 @@ -package usi.si.seart.analyzer.count; - -import usi.si.seart.analyzer.NodeMapper; - -public abstract class ContentTraverseCounter extends TraverseCounter { - - protected final NodeMapper mapper; - - protected ContentTraverseCounter(NodeMapper mapper) { - this.mapper = mapper; - } -} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/JavaTokenCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/JavaTokenCounter.java index da143bc2..894bc7a8 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/JavaTokenCounter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/JavaTokenCounter.java @@ -1,23 +1,16 @@ package usi.si.seart.analyzer.count; import ch.usi.si.seart.treesitter.Node; -import ch.usi.si.seart.treesitter.Range; import org.apache.commons.lang3.StringUtils; -import usi.si.seart.analyzer.NodeMapper; public class JavaTokenCounter extends TokenCounter { - public JavaTokenCounter(NodeMapper mapper) { - super(mapper); - } - @Override protected void nodeCallback(Node node) { boolean leafNode = node.getChildCount() == 0; if (leafNode) { String[] tokens; - Range range = node.getRange(); - String content = mapper.getContentForRange(range); + String content = node.getContent(); switch (node.getType()) { case "block_comment": content = StringUtils.substringBetween(content, "/*", "*/"); diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/PythonTokenCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/PythonTokenCounter.java index 2faf46cf..d6c4e244 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/PythonTokenCounter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/PythonTokenCounter.java @@ -1,16 +1,10 @@ package usi.si.seart.analyzer.count; import ch.usi.si.seart.treesitter.Node; -import ch.usi.si.seart.treesitter.Range; import org.apache.commons.lang3.StringUtils; -import usi.si.seart.analyzer.NodeMapper; public class PythonTokenCounter extends TokenCounter { - public PythonTokenCounter(NodeMapper mapper) { - super(mapper); - } - @Override protected void nodeCallback(Node node) { String type = node.getType(); @@ -18,8 +12,7 @@ protected void nodeCallback(Node node) { if (type.equals("string")) { count.addAndGet(1L); } else if (leafNode && type.equals("comment")) { - Range range = node.getRange(); - String content = mapper.getContentForRange(range); + String content = node.getContent(); content = StringUtils.substringAfter(content, "#"); String[] tokens = StringUtils.split(content); count.addAndGet(tokens.length + 1L); diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TokenCounter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TokenCounter.java index aa05aefa..ccee7b9d 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TokenCounter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TokenCounter.java @@ -2,14 +2,8 @@ import ch.usi.si.seart.treesitter.Language; import ch.usi.si.seart.treesitter.Node; -import ch.usi.si.seart.treesitter.Range; -import usi.si.seart.analyzer.NodeMapper; -public abstract class TokenCounter extends ContentTraverseCounter { - - public TokenCounter(NodeMapper mapper) { - super(mapper); - } +public abstract class TokenCounter extends TraverseCounter { @Override protected void nodeCallback(Node node) { @@ -17,8 +11,7 @@ protected void nodeCallback(Node node) { if (leafNode) { String type = node.getType(); if (type.equals("comment")) { - Range range = node.getRange(); - String content = mapper.getContentForRange(range); + String content = node.getContent(); String[] tokens = content.split("\\s+"); count.addAndGet(tokens.length); } else { @@ -27,14 +20,14 @@ protected void nodeCallback(Node node) { } } - public static TokenCounter getInstance(Language language, NodeMapper mapper) { + public static TokenCounter getInstance(Language language) { switch (language) { case JAVA: - return new JavaTokenCounter(mapper); + return new JavaTokenCounter(); case PYTHON: - return new PythonTokenCounter(mapper); + return new PythonTokenCounter(); default: - return new TokenCounter(mapper) {}; + return new TokenCounter() {}; } } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/BoilerplateEnumerator.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/BoilerplateEnumerator.java index c89bb31d..f9ab5bd6 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/BoilerplateEnumerator.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/BoilerplateEnumerator.java @@ -1,23 +1,16 @@ package usi.si.seart.analyzer.enumerator; import ch.usi.si.seart.treesitter.Language; -import usi.si.seart.analyzer.NodeMapper; import usi.si.seart.model.code.Boilerplate; public abstract class BoilerplateEnumerator implements Enumerator { - protected final NodeMapper mapper; - - protected BoilerplateEnumerator(NodeMapper mapper) { - this.mapper = mapper; - } - - public static Enumerator getInstance(Language language, NodeMapper mapper) { + public static Enumerator getInstance(Language language) { switch (language) { case JAVA: - return new JavaBoilerplateEnumerator(mapper); + return new JavaBoilerplateEnumerator(); case PYTHON: - return new PythonBoilerplateEnumerator(mapper); + return new PythonBoilerplateEnumerator(); default: return node -> null; } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumerator.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumerator.java index 4bf06228..76492f8f 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumerator.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumerator.java @@ -1,24 +1,17 @@ package usi.si.seart.analyzer.enumerator; import ch.usi.si.seart.treesitter.Node; -import ch.usi.si.seart.treesitter.Range; -import usi.si.seart.analyzer.NodeMapper; import usi.si.seart.model.code.Boilerplate; public class JavaBoilerplateEnumerator extends BoilerplateEnumerator { - public JavaBoilerplateEnumerator(NodeMapper mapper) { - super(mapper); - } - @Override public Boilerplate asEnum(Node node) { String type = node.getType(); if (type.equals("constructor_declaration")) return Boilerplate.CONSTRUCTOR; if (!type.equals("method_declaration")) return null; Node identifier = node.getChildByFieldName("name"); - Range range = identifier.getRange(); - String name = mapper.getContentForRange(range); + String name = identifier.getContent(); if (name.startsWith("set")) return Boilerplate.SETTER; if (name.startsWith("get")) return Boilerplate.GETTER; switch (name) { diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumerator.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumerator.java index 1a380753..8f218f9f 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumerator.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumerator.java @@ -1,16 +1,10 @@ package usi.si.seart.analyzer.enumerator; import ch.usi.si.seart.treesitter.Node; -import ch.usi.si.seart.treesitter.Range; -import usi.si.seart.analyzer.NodeMapper; import usi.si.seart.model.code.Boilerplate; public class PythonBoilerplateEnumerator extends BoilerplateEnumerator { - public PythonBoilerplateEnumerator(NodeMapper mapper) { - super(mapper); - } - @Override public Boilerplate asEnum(Node node) { if (!node.getType().equals("function_definition")) return null; @@ -18,7 +12,7 @@ public Boilerplate asEnum(Node node) { for (Node prev = node.getPrevSibling(); prev != null; prev = prev.getPrevSibling()) { switch (prev.getType()) { case "decorator": - String decorator = mapper.getContentForRange(prev.getRange()); + String decorator = prev.getContent(); if (decorator.equals("@property")) return Boilerplate.GETTER; else if (decorator.endsWith(".setter")) return Boilerplate.SETTER; case "comment": @@ -29,8 +23,7 @@ public Boilerplate asEnum(Node node) { } } Node identifier = node.getChildByFieldName("name"); - Range range = identifier.getRange(); - String name = mapper.getContentForRange(range); + String name = identifier.getContent(); switch (name) { case "__new__": return Boilerplate.CONSTRUCTOR; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java index 6e4772a6..299f3030 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java @@ -1,20 +1,18 @@ package usi.si.seart.analyzer.hash; import ch.usi.si.seart.treesitter.Node; -import ch.usi.si.seart.treesitter.Range; import ch.usi.si.seart.treesitter.TreeCursor; import lombok.Cleanup; import lombok.Getter; -import usi.si.seart.analyzer.NodeMapper; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; @Getter public class ContentHasher extends SHA256Hasher { - protected final NodeMapper mapper; - - public ContentHasher(NodeMapper mapper) { - this.mapper = mapper; - } + // FIXME: 21.09.23 This is so we retain consistency with the existing data + private static final Charset CHARSET = StandardCharsets.UTF_16LE; @Override protected void update(Node node) { @@ -23,8 +21,8 @@ protected void update(Node node) { boolean leafNode = current.getChildCount() == 0; boolean isComment = current.getType().contains("comment"); if (leafNode && !isComment) { - Range range = current.getRange(); - byte[] bytes = mapper.getBytesForRange(range); + String content = current.getContent(); + byte[] bytes = content.getBytes(CHARSET); md.update(bytes); } }); diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicate.java index 119525e0..436510af 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicate.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicate.java @@ -1,24 +1,11 @@ package usi.si.seart.analyzer.predicate.node; import ch.usi.si.seart.treesitter.Node; -import ch.usi.si.seart.treesitter.Range; -import usi.si.seart.analyzer.NodeMapper; -public class ContainsNonAsciiPredicate extends NodeContentPredicate { - - public ContainsNonAsciiPredicate(NodeMapper mapper) { - super(mapper); - } +public class ContainsNonAsciiPredicate extends NodePredicate { @Override public boolean test(Node node) { - Range range = node.getRange(); - byte[] bytes = mapper.getBytesForRange(range); - for (int i = 0; i < bytes.length; i += 2) { - if (bytes[i] < 0 || bytes[i + 1] != 0) { - return true; - } - } - return false; + return node.getContent().chars().anyMatch(c -> c > 127); } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/NodeContentPredicate.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/NodeContentPredicate.java deleted file mode 100644 index c9306685..00000000 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/NodeContentPredicate.java +++ /dev/null @@ -1,12 +0,0 @@ -package usi.si.seart.analyzer.predicate.node; - -import usi.si.seart.analyzer.NodeMapper; - -public abstract class NodeContentPredicate extends NodePredicate { - - protected final NodeMapper mapper; - - protected NodeContentPredicate(NodeMapper mapper) { - this.mapper = mapper; - } -} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/ContentPrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/ContentPrinter.java deleted file mode 100644 index 50b6611d..00000000 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/ContentPrinter.java +++ /dev/null @@ -1,12 +0,0 @@ -package usi.si.seart.analyzer.printer; - -import usi.si.seart.analyzer.NodeMapper; - -public abstract class ContentPrinter extends AbstractPrinter { - - protected final NodeMapper mapper; - - protected ContentPrinter(NodeMapper mapper) { - this.mapper = mapper; - } -} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java index bda4c9b9..014a8e20 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java @@ -1,23 +1,16 @@ package usi.si.seart.analyzer.printer; import ch.usi.si.seart.treesitter.Node; -import ch.usi.si.seart.treesitter.Range; -import usi.si.seart.analyzer.NodeMapper; import java.util.List; import java.util.stream.Collector; import java.util.stream.Collectors; -public class NodePrinter extends ContentPrinter { - - public NodePrinter(NodeMapper mapper) { - super(mapper); - } +public class NodePrinter extends AbstractPrinter { @Override public String print(Node node) { - Range range = node.getRange(); - String content = mapper.getContentForRange(range); + String content = node.getContent(); List lines = content.lines() .map(line -> line.replace("\t", " ")) .collect(Collectors.toList()); diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java index ecb88f8d..41791240 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java @@ -29,7 +29,7 @@ public abstract class MultiCaptureQueries implements Queries>> execute(Node node, String pattern) { @Cleanup Query query = new Query(language, pattern); verify(query); - @Cleanup QueryCursor cursor = new QueryCursor(node, query); + @Cleanup QueryCursor cursor = node.walk(query); Stream matches = StreamSupport.stream(cursor.spliterator(), false); return matches.map(match -> { QueryCapture[] captures = match.getCaptures(); diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/SingleCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/SingleCaptureQueries.java index 9bee21d0..bf0eeb4f 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/SingleCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/SingleCaptureQueries.java @@ -28,7 +28,7 @@ public abstract class SingleCaptureQueries implements Queries> { public List execute(Node node, String pattern) { @Cleanup Query query = new Query(language, pattern); verify(query); - @Cleanup QueryCursor cursor = new QueryCursor(node, query); + @Cleanup QueryCursor cursor = node.walk(query); Stream matches = StreamSupport.stream(cursor.spliterator(), false); return matches.map(QueryMatch::getCaptures) .flatMap(Arrays::stream) diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCharacterCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCharacterCounterTest.java index ec42335d..2e0e3b03 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCharacterCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCharacterCounterTest.java @@ -13,14 +13,14 @@ class JavaCharacterCounterTest extends JavaBaseTest { @Test void countEmptyTest() { - Counter counter = new CharacterCounter(getNodeMapper()); + Counter counter = new CharacterCounter(); Assertions.assertEquals(0, counter.count()); Assertions.assertEquals(0, counter.count(new HashSet<>())); } @Test void countRootTest(){ - Counter counter = new CharacterCounter(getNodeMapper()); + Counter counter = new CharacterCounter(); Long actual = counter.count(tree.getRootNode()); // Remove 2 for the space in string and comment Assertions.assertEquals(getJoinedTokens().length() - 2, actual, message); @@ -28,7 +28,7 @@ void countRootTest(){ @Test void countChildrenTest() { - Counter counter = new CharacterCounter(getNodeMapper()); + Counter counter = new CharacterCounter(); Node root = tree.getRootNode(); Node package_declaration = root.getChild(0); Node class_declaration = root.getChild(1); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaTokenCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaTokenCounterTest.java index ca5f38d3..28e77e5a 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaTokenCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaTokenCounterTest.java @@ -13,14 +13,14 @@ class JavaTokenCounterTest extends JavaBaseTest { @Test void countEmptyTest() { - Counter counter = new JavaTokenCounter(getNodeMapper()); + Counter counter = new JavaTokenCounter(); Assertions.assertEquals(0, counter.count()); Assertions.assertEquals(0, counter.count(new HashSet<>())); } @Test void countRootTest() { - Counter counter = new JavaTokenCounter(getNodeMapper()); + Counter counter = new JavaTokenCounter(); Long actual = counter.count(tree.getRootNode()); // Add 2 for the individual comment words Assertions.assertEquals(getNodes().size() + 2, actual, message); @@ -28,7 +28,7 @@ void countRootTest() { @Test void countChildrenTest() { - Counter counter = new JavaTokenCounter(getNodeMapper()); + Counter counter = new JavaTokenCounter(); Node root = tree.getRootNode(); Node package_declaration = root.getChild(0); Node class_declaration = root.getChild(1); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/PythonTokenCounterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/PythonTokenCounterTest.java index d17c0406..aec1ebbd 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/PythonTokenCounterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/PythonTokenCounterTest.java @@ -13,14 +13,14 @@ class PythonTokenCounterTest extends PythonBaseTest { @Test void countEmptyTest() { - Counter counter = new PythonTokenCounter(getNodeMapper()); + Counter counter = new PythonTokenCounter(); Assertions.assertEquals(0, counter.count()); Assertions.assertEquals(0, counter.count(new HashSet<>())); } @Test void countRootTest() { - Counter counter = new PythonTokenCounter(getNodeMapper()); + Counter counter = new PythonTokenCounter(); Long actual = counter.count(tree.getRootNode()); // Add 2 for the individual comment words Assertions.assertEquals(getNodes().size() + 2, actual, message); @@ -28,7 +28,7 @@ void countRootTest() { @Test void countChildrenTest() { - Counter counter = new PythonTokenCounter(getNodeMapper()); + Counter counter = new PythonTokenCounter(); Node module = tree.getRootNode(); Node function = module.getChild(0); Node[] children = function.getChildren().toArray(new Node[0]); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java index 728b943d..ac046bac 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java @@ -13,7 +13,6 @@ import org.junit.jupiter.params.provider.ArgumentsSource; import usi.si.seart.model.code.Boilerplate; -import java.nio.charset.StandardCharsets; import java.util.stream.Stream; class JavaBoilerplateEnumeratorTest { @@ -47,9 +46,7 @@ public Stream provideArguments(ExtensionContext context) { @ParameterizedTest(name = "[{index}] {1}") @ArgumentsSource(JavaCodeProvider.class) void asEnumTest(String source, Boilerplate expected) { - BoilerplateEnumerator enumerator = new JavaBoilerplateEnumerator( - () -> source.getBytes(StandardCharsets.UTF_16LE) - ); + BoilerplateEnumerator enumerator = new JavaBoilerplateEnumerator(); @Cleanup Parser parser = new Parser(Language.JAVA); @Cleanup Tree tree = parser.parse(source); Node root = tree.getRootNode(); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java index 1fc7a6ec..49b80a34 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java @@ -13,7 +13,6 @@ import org.junit.jupiter.params.provider.ArgumentsSource; import usi.si.seart.model.code.Boilerplate; -import java.nio.charset.StandardCharsets; import java.util.List; import java.util.stream.Stream; @@ -124,9 +123,7 @@ void asEnumTest(List sources, Boilerplate expected) { @Cleanup Tree tree = parser.parse(source); Node root = tree.getRootNode(); Node function_definition = root.getChild(0); - BoilerplateEnumerator enumerator = new PythonBoilerplateEnumerator( - () -> source.getBytes(StandardCharsets.UTF_16LE) - ); + BoilerplateEnumerator enumerator = new PythonBoilerplateEnumerator(); Boilerplate actual = enumerator.asEnum(function_definition); Assertions.assertEquals(expected, actual); } @@ -153,9 +150,7 @@ void asEnumTestSpecial(String source, Boilerplate expected) { Node root = tree.getRootNode(); Node decorated_definition = root.getChild(0); Node function_definition = decorated_definition.getChildByFieldName("definition"); - BoilerplateEnumerator enumerator = new PythonBoilerplateEnumerator( - () -> source.getBytes(StandardCharsets.UTF_16LE) - ); + BoilerplateEnumerator enumerator = new PythonBoilerplateEnumerator(); Boilerplate actual = enumerator.asEnum(function_definition); Assertions.assertEquals(expected, actual); } diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaContentHasherTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaContentHasherTest.java index f730ae5e..3d53d1cd 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaContentHasherTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaContentHasherTest.java @@ -4,21 +4,20 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import java.nio.charset.StandardCharsets; import java.util.HashSet; class JavaContentHasherTest extends JavaHasherTest { @Test void emptyTest() { - Hasher hasher = new ContentHasher(getNodeMapper()); + Hasher hasher = new ContentHasher(); Assertions.assertEquals(EMPTY, hasher.hash()); Assertions.assertEquals(EMPTY, hasher.hash(new HashSet<>())); } @Test void hashTest() { - Hasher hasher = new ContentHasher(getNodeMapper()); + Hasher hasher = new ContentHasher(); String actual = hasher.hash(tree.getRootNode()); String expected = sha256(getJoinedTokens()); Assertions.assertEquals(expected, actual, "Incrementally digested tree hash should be equal to the flat code manual digest!"); @@ -26,7 +25,7 @@ void hashTest() { @Test void idempotencyTest() { - Hasher hasher = new ContentHasher(getNodeMapper()); + Hasher hasher = new ContentHasher(); String first = hasher.hash(tree.getRootNode()); String second = hasher.hash(tree.getRootNode()); Assertions.assertEquals(first, second, "Same instance should be reusable for multiple invocations!"); @@ -46,13 +45,11 @@ void noCommentImpactTest() { " System.out.println(\"Hello, World!\");\n" + " }\n" + "}"; - - byte[] bytes_2 = input_2.getBytes(StandardCharsets.UTF_16LE); Tree other = parser.parse(input_2); - ContentHasher hasher_1 = new ContentHasher(getNodeMapper()); - ContentHasher hasher_2 = new ContentHasher(() -> bytes_2); - String first = hasher_1.hash(tree.getRootNode()); - String second = hasher_2.hash(other.getRootNode()); - Assertions.assertEquals(first, second, "Comments should not impact the hashing result!"); + ContentHasher hasher_1 = new ContentHasher(); + ContentHasher hasher_2 = new ContentHasher(); + String actual = hasher_1.hash(tree.getRootNode()); + String expected = hasher_2.hash(other.getRootNode()); + Assertions.assertEquals(expected, actual, "Comments should not impact the hashing result!"); } } \ No newline at end of file diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicateTest.java index 387cbe70..dd35e9ec 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicateTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicateTest.java @@ -5,14 +5,13 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import java.nio.charset.StandardCharsets; import java.util.HashSet; class ContainsNonAsciiPredicateTest extends PredicateTest { @Test void emptyInputTest() { - NodePredicate predicate = new ContainsNonAsciiPredicate(getNodeMapper()); + NodePredicate predicate = new ContainsNonAsciiPredicate(); Assertions.assertFalse(predicate.test()); Assertions.assertFalse(predicate.test(new HashSet<>())); } @@ -31,8 +30,7 @@ void containsOnlyAsciiTest() { " System.out.println(\"Hello, World!\");\n" + " }\n" + "}"; - byte[] bytes_2 = input_2.getBytes(StandardCharsets.UTF_16LE); - NodePredicate predicate = new ContainsNonAsciiPredicate(() -> bytes_2); + NodePredicate predicate = new ContainsNonAsciiPredicate(); Tree tree = parser.parse(input_2); boolean result = predicate.test(tree.getRootNode()); Assertions.assertFalse(result); @@ -40,14 +38,14 @@ void containsOnlyAsciiTest() { @Test void containsNonAsciiTest() { - NodePredicate predicate = new ContainsNonAsciiPredicate(getNodeMapper()); + NodePredicate predicate = new ContainsNonAsciiPredicate(); boolean result = predicate.test(tree.getRootNode()); Assertions.assertTrue(result); } @Test void anyContainsNonAscii() { - NodePredicate predicate = new ContainsNonAsciiPredicate(getNodeMapper()); + NodePredicate predicate = new ContainsNonAsciiPredicate(); Node root = tree.getRootNode(); Node package_declaration = root.getChild(0); Node class_declaration = root.getChild(1); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java index b9b77be3..7bb06338 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java @@ -11,14 +11,14 @@ class NodePrinterTest extends JavaBaseTest { @Test void printNothingTest() { - Printer printer = new NodePrinter(getNodeMapper()); + Printer printer = new NodePrinter(); Assertions.assertEquals("", printer.print()); Assertions.assertEquals("", printer.print(new HashSet<>())); } @Test void printRootTest() { - Printer printer = new NodePrinter(getNodeMapper()); + Printer printer = new NodePrinter(); Node root = tree.getRootNode(); String actual = printer.print(root); String expected = getInput(); @@ -27,7 +27,7 @@ void printRootTest() { @Test void printChildTest() { - Printer printer = new NodePrinter(getNodeMapper()); + Printer printer = new NodePrinter(); Node root = tree.getRootNode(); Node method = root.getChild(1).getChildByFieldName("body").getChild(1); String actual = printer.print(method); @@ -41,7 +41,7 @@ void printChildTest() { @Test void printMultipleTest() { - Printer printer = new NodePrinter(getNodeMapper()); + Printer printer = new NodePrinter(); Node root = tree.getRootNode(); Node package_declaration = root.getChild(0); Node class_declaration = root.getChild(1); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java index 6077af8f..11d8b160 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java @@ -6,9 +6,9 @@ import ch.usi.si.seart.treesitter.Tree; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; -import usi.si.seart.analyzer.NodeMapper; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.List; public abstract class BaseTest { @@ -44,16 +44,8 @@ void tearDown() { protected abstract String getInput(); - protected byte[] getBytes() { - return getInput().getBytes(getCharset()); - } - protected Charset getCharset() { - return NodeMapper.DEFAULT_CHARSET; - } - - protected NodeMapper getNodeMapper() { - return this::getBytes; + return StandardCharsets.UTF_16LE; } protected abstract List getTokens(); diff --git a/pom.xml b/pom.xml index f393d823..5c0b9b5d 100644 --- a/pom.xml +++ b/pom.xml @@ -36,7 +36,7 @@ UTF-8 5.10.0 3.25.5 - 1.4.2 + 1.5.1 1.18.28 32.1.2-jre 1.43.3 From 1587928bfc7f864ef28d3bf0a61969cfc047c80c Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 26 Sep 2023 10:45:56 +0200 Subject: [PATCH 0327/1089] Bumping minor version of `java-tree-sitter` `1.5.1` -> `1.6.0` --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5c0b9b5d..7d45203c 100644 --- a/pom.xml +++ b/pom.xml @@ -36,7 +36,7 @@ UTF-8 5.10.0 3.25.5 - 1.5.1 + 1.6.0 1.18.28 32.1.2-jre 1.43.3 From 1a894c47d2975d8d6ab32a444cf9bf9cd6a24534 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 2 Oct 2023 14:15:01 +0200 Subject: [PATCH 0328/1089] Bumping minor version of `java-tree-sitter` `1.6.0` -> `1.7.0` --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7d45203c..7543d47e 100644 --- a/pom.xml +++ b/pom.xml @@ -36,7 +36,7 @@ UTF-8 5.10.0 3.25.5 - 1.6.0 + 1.7.0 1.18.28 32.1.2-jre 1.43.3 From 957e033fb601b9c5fa15f3564b3c27de71714328 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 2 Oct 2023 14:18:30 +0200 Subject: [PATCH 0329/1089] Removing deprecated API usages in `BaseTest` --- .../src/test/java/usi/si/seart/analyzer/test/BaseTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java index 11d8b160..8db76888 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java @@ -27,7 +27,7 @@ protected void setUp() { } void setUpParser() { - parser = new Parser(getLanguage()); + parser = Parser.getFor(getLanguage()); } void setUpTree() { From e11e51fabbd4ac94b11e0792076f5ca15550d9c3 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 2 Oct 2023 14:27:50 +0200 Subject: [PATCH 0330/1089] Removing deprecated API usages in `SingleCaptureQueries` --- .../analyzer/query/single/SingleCaptureQueries.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/SingleCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/SingleCaptureQueries.java index bf0eeb4f..f8fa31ee 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/SingleCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/SingleCaptureQueries.java @@ -3,7 +3,6 @@ import ch.usi.si.seart.treesitter.Language; import ch.usi.si.seart.treesitter.Node; import ch.usi.si.seart.treesitter.Query; -import ch.usi.si.seart.treesitter.QueryCapture; import ch.usi.si.seart.treesitter.QueryCursor; import ch.usi.si.seart.treesitter.QueryMatch; import lombok.AccessLevel; @@ -11,7 +10,7 @@ import lombok.Cleanup; import usi.si.seart.analyzer.query.Queries; -import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; @@ -26,13 +25,12 @@ public abstract class SingleCaptureQueries implements Queries> { public abstract List getComments(Node node); public List execute(Node node, String pattern) { - @Cleanup Query query = new Query(language, pattern); + @Cleanup Query query = Query.getFor(language, pattern); verify(query); @Cleanup QueryCursor cursor = node.walk(query); Stream matches = StreamSupport.stream(cursor.spliterator(), false); - return matches.map(QueryMatch::getCaptures) - .flatMap(Arrays::stream) - .map(QueryCapture::getNode) + return matches.map(QueryMatch::getNodes) + .flatMap(Collection::stream) .collect(Collectors.toList()); } From 3b7eec4006bfb31480778df3cd40d1a8fef30e23 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 2 Oct 2023 14:28:30 +0200 Subject: [PATCH 0331/1089] Removing deprecated API usages in `MultiCaptureQueries` --- .../query/multi/MultiCaptureQueries.java | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java index 41791240..f75f27b6 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java @@ -1,9 +1,9 @@ package usi.si.seart.analyzer.query.multi; +import ch.usi.si.seart.treesitter.Capture; import ch.usi.si.seart.treesitter.Language; import ch.usi.si.seart.treesitter.Node; import ch.usi.si.seart.treesitter.Query; -import ch.usi.si.seart.treesitter.QueryCapture; import ch.usi.si.seart.treesitter.QueryCursor; import ch.usi.si.seart.treesitter.QueryMatch; import lombok.AccessLevel; @@ -13,8 +13,10 @@ import usi.si.seart.analyzer.query.Queries; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -27,18 +29,19 @@ public abstract class MultiCaptureQueries implements Queries>> getCallableDeclarations(Node node); public List>> execute(Node node, String pattern) { - @Cleanup Query query = new Query(language, pattern); + @Cleanup Query query = Query.getFor(language, pattern); verify(query); @Cleanup QueryCursor cursor = node.walk(query); Stream matches = StreamSupport.stream(cursor.spliterator(), false); return matches.map(match -> { - QueryCapture[] captures = match.getCaptures(); - List> tuples = new ArrayList<>(captures.length); - for (QueryCapture capture: captures) { - Node capturedNode = capture.getNode(); - String captureName = query.getCaptureName(capture); - Pair tuple = Pair.of(captureName, capturedNode); - tuples.add(tuple); + Map> captures = match.getCaptures(); + List> tuples = new ArrayList<>(captures.size()); + for (Map.Entry> entries: captures.entrySet()) { + String captureName = entries.getKey().getName(); + for (Node capturedNode: entries.getValue()) { + Pair tuple = Pair.of(captureName, capturedNode); + tuples.add(tuple); + } } return tuples; }).collect(Collectors.toList()); From 843e73b57eef652702c8a91ecb94ea7afa01b657 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 2 Oct 2023 14:28:41 +0200 Subject: [PATCH 0332/1089] Removing deprecated API usages in test files --- .../analyzer/enumerator/JavaBoilerplateEnumeratorTest.java | 2 +- .../analyzer/enumerator/PythonBoilerplateEnumeratorTest.java | 4 ++-- .../analyzer/predicate/node/ContainsErrorPredicateTest.java | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java index ac046bac..51a07a23 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java @@ -47,7 +47,7 @@ public Stream provideArguments(ExtensionContext context) { @ArgumentsSource(JavaCodeProvider.class) void asEnumTest(String source, Boilerplate expected) { BoilerplateEnumerator enumerator = new JavaBoilerplateEnumerator(); - @Cleanup Parser parser = new Parser(Language.JAVA); + @Cleanup Parser parser = Parser.getFor(Language.JAVA); @Cleanup Tree tree = parser.parse(source); Node root = tree.getRootNode(); Node class_declaration = root.getChild(0); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java index 49b80a34..d3155c97 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java @@ -118,7 +118,7 @@ public Stream provideArguments(ExtensionContext extensionCo @ParameterizedTest(name = "[{index}] {1}") @ArgumentsSource(PythonCodeProvider.class) void asEnumTest(List sources, Boilerplate expected) { - @Cleanup Parser parser = new Parser(Language.PYTHON); + @Cleanup Parser parser = Parser.getFor(Language.PYTHON); for (String source: sources) { @Cleanup Tree tree = parser.parse(source); Node root = tree.getRootNode(); @@ -145,7 +145,7 @@ public Stream provideArguments(ExtensionContext context) { @ParameterizedTest(name = "[{index}] {1}") @ArgumentsSource(PythonCodeProviderSpecial.class) void asEnumTestSpecial(String source, Boilerplate expected) { - @Cleanup Parser parser = new Parser(Language.PYTHON); + @Cleanup Parser parser = Parser.getFor(Language.PYTHON); @Cleanup Tree tree = parser.parse(source); Node root = tree.getRootNode(); Node decorated_definition = root.getChild(0); diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicateTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicateTest.java index 29b0e234..700b68e8 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicateTest.java +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicateTest.java @@ -28,7 +28,7 @@ void containsNoErrorTest() { @Test void containsErrorTest() { - @Cleanup Parser parser = new Parser(Language.C); + @Cleanup Parser parser = Parser.getFor(Language.C); Tree error = parser.parse(getInput()); Node root = error.getRootNode(); NodePredicate predicate = new ContainsErrorPredicate(); @@ -38,7 +38,7 @@ void containsErrorTest() { @Test void anyContainsErrorTest() { - @Cleanup Parser parser = new Parser(Language.C); + @Cleanup Parser parser = Parser.getFor(Language.C); Tree error = parser.parse(getInput()); Node root = error.getRootNode(); Node declaration = root.getChild(0); From 893addc6aba092d90f98c01089968237fdaef244 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 2 Oct 2023 14:28:57 +0200 Subject: [PATCH 0333/1089] Removing deprecated API usages in `Analyzer` --- .../src/main/java/usi/si/seart/analyzer/Analyzer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java index 723088aa..e105f24a 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java @@ -81,7 +81,7 @@ public Analyzer(LocalClone localClone, Path path, String languageName) throws IO public Analyzer(LocalClone localClone, Path path, Language language) throws IOException { this.language = language; - this.parser = new Parser(language); + this.parser = Parser.getFor(language); this.localClone = localClone; this.path = path; String source = Files.readString(path); From 61ee461eb0002a88bf4d45299bbab41290ec1fe8 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 2 Oct 2023 15:09:15 +0200 Subject: [PATCH 0334/1089] Simplified the constructor for `Analyzer` --- .../src/main/java/usi/si/seart/analyzer/Analyzer.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java index e105f24a..acaf92a6 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java @@ -75,8 +75,15 @@ public class Analyzer implements AutoCloseable { Enumerator boilerplateEnumerator; - public Analyzer(LocalClone localClone, Path path, String languageName) throws IOException { - this(localClone, path, Language.valueOf(languageName)); + public Analyzer(LocalClone localClone, Path path) throws IOException { + this( + localClone, + path, + Language.associatedWith(path) + .stream() + .findFirst() + .orElseThrow() + ); } public Analyzer(LocalClone localClone, Path path, Language language) throws IOException { From 79e2badd96cd97694ccbbd4b8724364c4ee3c016 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 2 Oct 2023 15:09:43 +0200 Subject: [PATCH 0335/1089] `CodeCrawler` uses new `Analyzer` constructor --- .../main/java/usi/si/seart/crawler/component/CodeCrawler.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java index 20361df6..7488afcc 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java @@ -290,8 +290,7 @@ private void analyzeAndStore(LocalClone localClone, Path path) { log.trace("Analyzing file: {}", localClone.relativePathOf(path)); String extension = com.google.common.io.Files.getFileExtension(path.toString()); Language language = extensionToLanguage.get(extension); - String name = language.getName().toUpperCase(); - try (Analyzer analyzer = new Analyzer(localClone, path, name)) { + try (Analyzer analyzer = new Analyzer(localClone, path)) { Analyzer.Result result = analyzer.analyze(); File file = result.getFile(); List functions = result.getFunctions(); From d38c5d2995e2b21dac84895d1319c190635ba10e Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 4 Oct 2023 14:58:40 +0200 Subject: [PATCH 0336/1089] `Analyzer` now has a method for setting `Parser` timeout --- .../src/main/java/usi/si/seart/analyzer/Analyzer.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java index acaf92a6..c2dcb6fa 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java @@ -38,6 +38,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.time.Duration; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -115,6 +116,10 @@ public void close() { parser.close(); } + public void setParserTimeout(Duration duration) { + parser.setTimeout(duration); + } + @Getter @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) @AllArgsConstructor From 6cdbd3c3ff7764319ee2f823ff03fcaeeb6adae4 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 4 Oct 2023 15:11:30 +0200 Subject: [PATCH 0337/1089] Added new file filtering options We now provide optional filtering parameters for files during crawling: - `max-size` - `max-lines` - `max-parse-time` - `glob-pattern` The last option will eventually replace `app.crawl-job.ignore.file-pattern` --- .../seart/crawler/config/CrawlerConfig.java | 78 ++++++++++++++++++- .../src/main/resources/application.properties | 4 + 2 files changed, 78 insertions(+), 4 deletions(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/CrawlerConfig.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/CrawlerConfig.java index cd830463..4f713824 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/CrawlerConfig.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/CrawlerConfig.java @@ -1,19 +1,33 @@ package usi.si.seart.crawler.config; import com.google.api.client.http.GenericUrl; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.experimental.FieldDefaults; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.ConfigurationPropertiesScan; +import org.springframework.boot.context.properties.ConstructorBinding; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.util.unit.DataSize; import usi.si.seart.model.job.Job; +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.io.UncheckedIOException; import java.nio.file.FileSystems; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.PathMatcher; import java.time.Duration; import java.time.LocalDateTime; +import java.util.Optional; import java.util.function.Predicate; @Configuration +@ConfigurationPropertiesScan public class CrawlerConfig { @Bean @@ -36,9 +50,65 @@ public LocalDateTime defaultStartDateTime(@Value("${app.crawl-job.start-date-tim return LocalDateTime.parse(value); } - @Bean - public Predicate analyzeFilePredicate(@Value("${app.crawl-job.ignore.file-pattern}") String value) { - PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher("glob:" + value); - return Predicate.not(pathMatcher::matches); + @Getter + @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) + @ConfigurationProperties(prefix = "app.crawl-job.ignore.repository.file") + public static class FileFilter implements Predicate { + + Predicate pathPredicate; + + Optional maxSize; + + Optional maxLines; + + Optional maxParseTime; + + @ConstructorBinding + public FileFilter(String globPattern, DataSize maxSize, Long maxLines, Duration maxParseTime) { + PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:" + globPattern); + this.pathPredicate = Predicate.not(matcher::matches); + this.maxSize = Optional.ofNullable(maxSize); + this.maxLines = Optional.ofNullable(maxLines); + this.maxParseTime = Optional.ofNullable(maxParseTime); + } + + private boolean testPath(Path path) { + return pathPredicate.test(path); + } + + private boolean testSize(Path path) { + return maxSize.map(maxSize -> { + try { + long bytes = Files.size(path); + DataSize size = DataSize.ofBytes(bytes); + return size.compareTo(maxSize) < 0; + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + }).orElse(true); + } + + private boolean testLine(Path path) { + return maxLines.map(maxLines -> { + try ( + FileReader fileReader = new FileReader(path.toFile()); + BufferedReader bufferedReader = new BufferedReader(fileReader) + ) { + int lines = 0; + while (bufferedReader.readLine() != null) { + lines++; + if (lines >= maxLines) return false; + } + return true; + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + }).orElse(true); + } + + @Override + public boolean test(Path path) { + return testPath(path) && testSize(path) && testLine(path); + } } } diff --git a/dl4se-crawler/src/main/resources/application.properties b/dl4se-crawler/src/main/resources/application.properties index 5ffddd6d..7405c628 100644 --- a/dl4se-crawler/src/main/resources/application.properties +++ b/dl4se-crawler/src/main/resources/application.properties @@ -43,3 +43,7 @@ app.crawl-job.start-date-time=2008-01-01T00:00:00 app.crawl-job.type=${CRAWLER_JOB:CODE} app.crawl-job.ignore.project-names= app.crawl-job.ignore.file-pattern= +app.crawl-job.ignore.repository.file.max-size=5MB +app.crawl-job.ignore.repository.file.max-lines=10000 +app.crawl-job.ignore.repository.file.max-parse-time=1000ms +app.crawl-job.ignore.repository.file.glob-pattern= From dffb9a49cebfde1d91f8ada868afbc727ce03e9b Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 4 Oct 2023 15:12:42 +0200 Subject: [PATCH 0338/1089] Integrating new filter changes into the crawler --- .../seart/crawler/component/CodeCrawler.java | 21 ++++++++++--------- .../src/main/resources/application.properties | 3 +-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java index 7488afcc..4ea0aebe 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java @@ -18,6 +18,7 @@ import org.springframework.stereotype.Component; import usi.si.seart.analyzer.Analyzer; import usi.si.seart.analyzer.LocalClone; +import usi.si.seart.crawler.config.CrawlerConfig; import usi.si.seart.crawler.dto.SearchResultDto; import usi.si.seart.crawler.git.Git; import usi.si.seart.crawler.git.GitException; @@ -49,7 +50,6 @@ import java.util.Optional; import java.util.Set; import java.util.function.BiConsumer; -import java.util.function.Predicate; import java.util.stream.Collectors; @Slf4j @@ -71,14 +71,14 @@ public class CodeCrawler implements Runnable { LanguageService languageService; ConversionService conversionService; - Predicate analyzeFilePredicate; + CrawlerConfig.FileFilter fileFilter; @NonFinal @Value("${app.general.tmp-dir-prefix}") String prefix; @NonFinal - @Value("${app.crawl-job.ignore.project-names}") + @Value("${app.crawl-job.ignore.repository.names}") List ignoreProjects; Set languageNames = new HashSet<>(); @@ -194,17 +194,17 @@ private void updateRepoData(GitRepo repo, Set repoLanguages) { if (!Strings.isNullOrEmpty(diff.toString())) log.debug("Diff since last update:\n{}", diff); diff.getAdded().stream() - .filter(analyzeFilePredicate) + .filter(fileFilter) .forEach(path -> addFile(localClone, path)); diff.getDeleted().forEach(path -> deleteFile(repo, path)); diff.getModified().forEach(path -> { deleteFile(repo, path); - if (analyzeFilePredicate.test(path)) + if (fileFilter.test(path)) addFile(localClone, path); }); diff.getRenamed().forEach((key, value) -> { - boolean validOld = analyzeFilePredicate.test(key); - boolean validNew = analyzeFilePredicate.test(value); + boolean validOld = fileFilter.test(key); + boolean validNew = fileFilter.test(value); if (validOld && validNew) renameFile(repo, key, value); else if (validOld) @@ -214,13 +214,13 @@ else if (validNew) }); diff.getEdited().forEach((key, value) -> { deleteFile(repo, key); - if (analyzeFilePredicate.test(value)) + if (fileFilter.test(value)) addFile(localClone, value); }); diff.getCopied() .values() .stream() - .filter(analyzeFilePredicate) + .filter(fileFilter) .forEach(value -> addFile(localClone, value)); gitRepoService.createOrUpdate(repo); @@ -281,7 +281,7 @@ private void mineRepoData(LocalClone localClone, Set languages) { .map(localDirectory::resolve) .collect(Collectors.toSet()); Set filtered = Sets.difference(candidates, analyzed).stream() - .filter(analyzeFilePredicate) + .filter(fileFilter) .collect(Collectors.toSet()); filtered.forEach(target -> analyzeAndStore(localClone, target)); } @@ -291,6 +291,7 @@ private void analyzeAndStore(LocalClone localClone, Path path) { String extension = com.google.common.io.Files.getFileExtension(path.toString()); Language language = extensionToLanguage.get(extension); try (Analyzer analyzer = new Analyzer(localClone, path)) { + fileFilter.getMaxParseTime().ifPresent(analyzer::setParserTimeout); Analyzer.Result result = analyzer.analyze(); File file = result.getFile(); List functions = result.getFunctions(); diff --git a/dl4se-crawler/src/main/resources/application.properties b/dl4se-crawler/src/main/resources/application.properties index 7405c628..39c36184 100644 --- a/dl4se-crawler/src/main/resources/application.properties +++ b/dl4se-crawler/src/main/resources/application.properties @@ -41,8 +41,7 @@ app.crawl-job.next-run-delay=PT6H app.crawl-job.url=${CRAWLER_URL:https://seart-ghs.si.usi.ch/api/r/search} app.crawl-job.start-date-time=2008-01-01T00:00:00 app.crawl-job.type=${CRAWLER_JOB:CODE} -app.crawl-job.ignore.project-names= -app.crawl-job.ignore.file-pattern= +app.crawl-job.ignore.repository.names= app.crawl-job.ignore.repository.file.max-size=5MB app.crawl-job.ignore.repository.file.max-lines=10000 app.crawl-job.ignore.repository.file.max-parse-time=1000ms From d4c8358a426cc285dcf499160ab6b00f4b707ad6 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 4 Oct 2023 16:09:21 +0200 Subject: [PATCH 0339/1089] Better exception-handling structure for `CodeCrawler` --- .../seart/crawler/component/CodeCrawler.java | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java index 4ea0aebe..cd1b332d 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java @@ -5,6 +5,7 @@ import com.google.common.base.Strings; import com.google.common.collect.Sets; import lombok.AccessLevel; +import lombok.Cleanup; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; @@ -112,7 +113,7 @@ public void run() { log.info("Finished! Next run scheduled for: {}", nextRun); } - @SneakyThrows + @SneakyThrows(IOException.class) private GenericUrl fetchSearchResults(GenericUrl url, LocalDate checkpoint) { GenericUrl requestUrl = url.set("committedMin", checkpoint.toString()) .set("sort", "lastCommit") @@ -169,16 +170,14 @@ private void inspectSearchResult(SearchResultDto item) { saveCrawlProgress(lastUpdateGhs); } - @SneakyThrows(IOException.class) private void updateRepoData(GitRepo repo, Set repoLanguages) { String name = repo.getName(); LocalDateTime lastCommit = repo.getLastCommit(); - log.info("Updating repository: {} [Last Commit: {}]", name, lastCommit); - Path localDirectory = Files.createTempDirectory(prefix); - LocalClone localClone = new LocalClone(repo, localDirectory); - try (Git git = new Git(name, localDirectory, lastCommit)) { - + try { + Path localDirectory = Files.createTempDirectory(prefix); + LocalClone localClone = new LocalClone(repo, localDirectory); + @Cleanup Git git = new Git(name, localDirectory, lastCommit); Set notMined = Sets.difference(repoLanguages, repo.getLanguages()); if (!notMined.isEmpty()) { mineRepoData(localClone, notMined); @@ -224,6 +223,8 @@ else if (validNew) .forEach(value -> addFile(localClone, value)); gitRepoService.createOrUpdate(repo); + } catch (IOException ex) { + log.error("Could not create temporary directory for: " + name, ex); } catch (GitException ex) { log.error("Git operation error for: " + name, ex); } @@ -241,24 +242,22 @@ private void renameFile(GitRepo repo, Path oldPath, Path newPath) { fileService.rename(repo, oldPath, newPath); } - @SneakyThrows(IOException.class) private void mineRepoData(GitRepo repo, Set languages) { String name = repo.getName(); LocalDateTime lastUpdateGhs = repo.getLastCommit(); - - Path localDirectory = Files.createTempDirectory(prefix); - LocalClone localClone = new LocalClone(repo, localDirectory); log.info("Mining repository: {} [Last Commit: {}]", name, lastUpdateGhs); - try (Git git = new Git(name, localDirectory, true)) { + try { + Path localDirectory = Files.createTempDirectory(prefix); + LocalClone localClone = new LocalClone(repo, localDirectory); + @Cleanup Git git = new Git(name, localDirectory, true); Git.Commit latest = git.getLastCommitInfo(); - mineRepoData(localClone, languages); - repo.setLanguages(languages); repo.setLastCommit(latest.getTimestamp()); repo.setLastCommitSHA(latest.getSha()); - gitRepoService.createOrUpdate(repo); + } catch (IOException ex) { + log.error("Could not create temporary directory for: " + name, ex); } catch (GitException ex) { log.error("Git operation error for: " + name, ex); } @@ -287,7 +286,8 @@ private void mineRepoData(LocalClone localClone, Set languages) { } private void analyzeAndStore(LocalClone localClone, Path path) { - log.trace("Analyzing file: {}", localClone.relativePathOf(path)); + Path relative = localClone.relativePathOf(path); + log.debug("Analyzing file: {}", relative); String extension = com.google.common.io.Files.getFileExtension(path.toString()); Language language = extensionToLanguage.get(extension); try (Analyzer analyzer = new Analyzer(localClone, path)) { @@ -299,7 +299,7 @@ private void analyzeAndStore(LocalClone localClone, Path path) { functions.forEach(function -> function.setLanguage(language)); fileService.create(file); } catch (Exception ex) { - log.error("", ex); + log.error("Exception occurred while analyzing: {}", relative, ex); } } } From de7c1a25b655a2cddd67de145a634191f3ed46fc Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 5 Oct 2023 11:26:49 +0200 Subject: [PATCH 0340/1089] Adding `guava` as a dependency to the `dl4se-analyzer` --- dl4se-analyzer/pom.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dl4se-analyzer/pom.xml b/dl4se-analyzer/pom.xml index 331a5d0e..159a5075 100644 --- a/dl4se-analyzer/pom.xml +++ b/dl4se-analyzer/pom.xml @@ -26,5 +26,9 @@ org.apache.commons commons-lang3 + + com.google.guava + guava + From e0a5c534ec584e1fc94e9b8fc9b5371086eb0bf3 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 5 Oct 2023 11:28:54 +0200 Subject: [PATCH 0341/1089] `Analyzer` now implicitly filters the "null" character (`0x00`) --- .../java/usi/si/seart/analyzer/Analyzer.java | 48 +++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java index c2dcb6fa..a80481cb 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java @@ -5,6 +5,7 @@ import ch.usi.si.seart.treesitter.Parser; import ch.usi.si.seart.treesitter.Point; import ch.usi.si.seart.treesitter.Tree; +import com.google.common.io.CharStreams; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Cleanup; @@ -35,8 +36,10 @@ import usi.si.seart.model.code.File; import usi.si.seart.model.code.Function; +import java.io.FileReader; +import java.io.FilterReader; import java.io.IOException; -import java.nio.file.Files; +import java.io.Reader; import java.nio.file.Path; import java.time.Duration; import java.util.ArrayList; @@ -92,8 +95,7 @@ public Analyzer(LocalClone localClone, Path path, Language language) throws IOEx this.parser = Parser.getFor(language); this.localClone = localClone; this.path = path; - String source = Files.readString(path); - this.tree = parser.parse(source); + this.tree = parser.parse(readFile(path)); this.lineCounter = new LineCounter(); this.totalTokenCounter = TokenCounter.getInstance(language); this.codeTokenCounter = CodeTokenCounter.getInstance(language); @@ -260,4 +262,44 @@ public String print(Collection nodes) { return astPrinter.print(targets); } } + + private static String readFile(Path path) throws IOException { + @Cleanup Reader fileReader = new FileReader(path.toFile()); + @Cleanup Reader filterReader = new NullFilteredReader(fileReader); + return CharStreams.toString(filterReader); + } + + private static class NullFilteredReader extends FilterReader { + + private NullFilteredReader(Reader in) { + super(in); + } + + @Override + public int read() throws IOException { + int current; + do current = super.read(); + while (current == 0); + return current; + } + + @Override + public int read(char[] cbuf, int off, int len) throws IOException { + int read = super.read(cbuf, off, len); + if (read == -1) return -1; + int pos = off - 1; + for (int readPos = off; readPos < off + read; readPos++) { + if (cbuf[readPos] == 0) { + continue; + } else { + pos++; + } + + if (pos < readPos) { + cbuf[pos] = cbuf[readPos]; + } + } + return pos - off + 1; + } + } } From 1b996611b627bca6b028209e9e9e4a4056aa4333 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 5 Oct 2023 11:30:18 +0200 Subject: [PATCH 0342/1089] Bumping `spring-boot-dependencies` patch version `2.7.15` -> `2.7.16` --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7543d47e..89390183 100644 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,7 @@ 42.6.0 0.11.5 2.15.2 - 2.7.15 + 2.7.16 2021.0.8 From 96d7aca1ebd45aa24ff04093212c60d9ac35b389 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 5 Oct 2023 11:31:32 +0200 Subject: [PATCH 0343/1089] Bumping `lombok` patch version `1.18.28` -> `1.18.30` --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 89390183..87fb0c3a 100644 --- a/pom.xml +++ b/pom.xml @@ -37,7 +37,7 @@ 5.10.0 3.25.5 1.7.0 - 1.18.28 + 1.18.30 32.1.2-jre 1.43.3 3.1.10 From f6c9bf91d5ef5d9e5cd7091f819fa2f575c97756 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 5 Oct 2023 11:39:10 +0200 Subject: [PATCH 0344/1089] Deleting the unused `Traverser` hierarchy --- .../traverser/PreviousCommentTraverser.java | 24 ------- .../seart/analyzer/traverser/Traverser.java | 9 --- .../PreviousCommentTraverserTest.java | 72 ------------------- 3 files changed, 105 deletions(-) delete mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/traverser/PreviousCommentTraverser.java delete mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/traverser/Traverser.java delete mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/traverser/PreviousCommentTraverserTest.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/traverser/PreviousCommentTraverser.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/traverser/PreviousCommentTraverser.java deleted file mode 100644 index ab5e75af..00000000 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/traverser/PreviousCommentTraverser.java +++ /dev/null @@ -1,24 +0,0 @@ -package usi.si.seart.analyzer.traverser; - -import ch.usi.si.seart.treesitter.Node; - -import java.util.ArrayList; -import java.util.List; - -public class PreviousCommentTraverser implements Traverser> { - - @Override - public List getNodes(Node node) { - List results = new ArrayList<>(); - Node current = node; - while (current != null) { - Node previous = current.getPrevSibling(); - if (previous == null) break; - String type = previous.getType(); - if (!type.contains("comment")) break; - results.add(previous); - current = previous; - } - return results; - } -} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/traverser/Traverser.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/traverser/Traverser.java deleted file mode 100644 index 77db5640..00000000 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/traverser/Traverser.java +++ /dev/null @@ -1,9 +0,0 @@ -package usi.si.seart.analyzer.traverser; - -import ch.usi.si.seart.treesitter.Node; - -import java.util.Collection; - -public interface Traverser> { - C getNodes(Node node); -} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/traverser/PreviousCommentTraverserTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/traverser/PreviousCommentTraverserTest.java deleted file mode 100644 index ddce7e42..00000000 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/traverser/PreviousCommentTraverserTest.java +++ /dev/null @@ -1,72 +0,0 @@ -package usi.si.seart.analyzer.traverser; - -import ch.usi.si.seart.treesitter.Node; -import lombok.SneakyThrows; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import usi.si.seart.analyzer.test.JavaBaseTest; - -import java.util.Collection; - -class PreviousCommentTraverserTest extends JavaBaseTest { - - @Override - protected String getInput() { - return - "/**\n" + - " * A simple example class that contains a single field and two methods\n" + - " */\n" + - "public class Example {\n" + - "\n" + - " private int value;\n" + - " \n" + - " /**\n" + - " * Constructor that initializes the value field\n" + - " * @param val the initial value\n" + - " */\n" + - " public Example(int val) {\n" + - " this.value = val;\n" + - " }\n" + - " \n" + - " /**\n" + - " * This method updates the value of the field with the new value\n" + - " * passed as an argument\n" + - " */\n" + - " // Returns the current value\n" + - " public int getValue() {\n" + - " return value;\n" + - " }\n" + - " \n" + - " /**\n" + - " * Method to update the value field\n" + - " */\n" + - " /*\n" + - " * This method updates the value of the field with the new value\n" + - " * passed as an argument\n" + - " */\n" + - " public void setValue(int newVal) {\n" + - " this.value = newVal;\n" + - " }\n" + - "}"; - } - - @Test - @SneakyThrows - void getNodesTest() { - Node root = tree.getRootNode(); - Node body = root.getChild(1).getChildByFieldName("body"); - Traverser traverser = new PreviousCommentTraverser(); - - Node target = body.getChild(3); // constructor - Collection actual = traverser.getNodes(target); - Assertions.assertEquals(1, actual.size()); - - target = body.getChild(6); // getter - actual = traverser.getNodes(target); - Assertions.assertEquals(2, actual.size()); - - target = body.getChild(9); // setter - actual = traverser.getNodes(target); - Assertions.assertEquals(2, actual.size()); - } -} \ No newline at end of file From f9453f9f634a5469f019ef3cc4c8b66f52343052 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 5 Oct 2023 14:16:05 +0200 Subject: [PATCH 0345/1089] Separating the new reader into public API --- .../java/usi/si/seart/analyzer/Analyzer.java | 36 +---------------- .../seart/analyzer/io/NullFilteredReader.java | 39 +++++++++++++++++++ 2 files changed, 40 insertions(+), 35 deletions(-) create mode 100644 dl4se-analyzer/src/main/java/usi/si/seart/analyzer/io/NullFilteredReader.java diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java index a80481cb..c7c1400a 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java @@ -22,6 +22,7 @@ import usi.si.seart.analyzer.hash.ContentHasher; import usi.si.seart.analyzer.hash.Hasher; import usi.si.seart.analyzer.hash.SyntaxTreeHasher; +import usi.si.seart.analyzer.io.NullFilteredReader; import usi.si.seart.analyzer.predicate.node.ContainsErrorPredicate; import usi.si.seart.analyzer.predicate.node.ContainsNonAsciiPredicate; import usi.si.seart.analyzer.predicate.node.NodePredicate; @@ -37,7 +38,6 @@ import usi.si.seart.model.code.Function; import java.io.FileReader; -import java.io.FilterReader; import java.io.IOException; import java.io.Reader; import java.nio.file.Path; @@ -268,38 +268,4 @@ private static String readFile(Path path) throws IOException { @Cleanup Reader filterReader = new NullFilteredReader(fileReader); return CharStreams.toString(filterReader); } - - private static class NullFilteredReader extends FilterReader { - - private NullFilteredReader(Reader in) { - super(in); - } - - @Override - public int read() throws IOException { - int current; - do current = super.read(); - while (current == 0); - return current; - } - - @Override - public int read(char[] cbuf, int off, int len) throws IOException { - int read = super.read(cbuf, off, len); - if (read == -1) return -1; - int pos = off - 1; - for (int readPos = off; readPos < off + read; readPos++) { - if (cbuf[readPos] == 0) { - continue; - } else { - pos++; - } - - if (pos < readPos) { - cbuf[pos] = cbuf[readPos]; - } - } - return pos - off + 1; - } - } } diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/io/NullFilteredReader.java b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/io/NullFilteredReader.java new file mode 100644 index 00000000..e5c5b8c4 --- /dev/null +++ b/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/io/NullFilteredReader.java @@ -0,0 +1,39 @@ +package usi.si.seart.analyzer.io; + +import java.io.FilterReader; +import java.io.IOException; +import java.io.Reader; + +public class NullFilteredReader extends FilterReader { + + public NullFilteredReader(Reader in) { + super(in); + } + + @Override + public int read() throws IOException { + int current; + do current = super.read(); + while (current == 0); + return current; + } + + @Override + public int read(char[] cbuf, int off, int len) throws IOException { + int read = super.read(cbuf, off, len); + if (read == -1) return -1; + int pos = off - 1; + for (int readPos = off; readPos < off + read; readPos++) { + if (cbuf[readPos] == 0) { + continue; + } else { + pos++; + } + + if (pos < readPos) { + cbuf[pos] = cbuf[readPos]; + } + } + return pos - off + 1; + } +} From b3fdd556f5ebb5feb1943d94612528ed9fd56762 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 5 Oct 2023 14:17:08 +0200 Subject: [PATCH 0346/1089] Adding test case for new reader I was feeling a bit paranoid about whether it worked but now I'm certain --- .../analyzer/io/NullFilteredReaderTest.java | 21 ++++++++++++++ .../usi/si/seart/analyzer/io/ReaderTest.java | 29 +++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/io/NullFilteredReaderTest.java create mode 100644 dl4se-analyzer/src/test/java/usi/si/seart/analyzer/io/ReaderTest.java diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/io/NullFilteredReaderTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/io/NullFilteredReaderTest.java new file mode 100644 index 00000000..06768896 --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/io/NullFilteredReaderTest.java @@ -0,0 +1,21 @@ +package usi.si.seart.analyzer.io; + +import java.io.Reader; + +class NullFilteredReaderTest extends ReaderTest { + + @Override + protected Reader getSubject(Reader initial) { + return new NullFilteredReader(initial); + } + + @Override + protected String getInput() { + return "This\0is\0a\0test!"; + } + + @Override + protected String getExpected() { + return "Thisisatest!"; + } +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/io/ReaderTest.java b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/io/ReaderTest.java new file mode 100644 index 00000000..0b91ca4f --- /dev/null +++ b/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/io/ReaderTest.java @@ -0,0 +1,29 @@ +package usi.si.seart.analyzer.io; + +import com.google.common.io.CharStreams; +import lombok.Cleanup; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; + +abstract class ReaderTest { + + protected abstract Reader getSubject(Reader initial); + + protected abstract String getInput(); + + protected abstract String getExpected(); + + @Test + void testRead() throws IOException { + String input = getInput(); + String expected = getExpected(); + @Cleanup Reader stringReader = new StringReader(input); + @Cleanup Reader testSubject = getSubject(stringReader); + String actual = CharStreams.toString(testSubject); + Assertions.assertEquals(expected, actual); + } +} From cbfbc17a1eb3c0996da22d59a2d8e8214d5a1e70 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 5 Oct 2023 17:19:37 +0200 Subject: [PATCH 0347/1089] Filters return false if the file can not be found --- .../java/usi/si/seart/crawler/config/CrawlerConfig.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/CrawlerConfig.java b/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/CrawlerConfig.java index 4f713824..58e09bad 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/CrawlerConfig.java +++ b/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/CrawlerConfig.java @@ -14,11 +14,13 @@ import usi.si.seart.model.job.Job; import java.io.BufferedReader; +import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.FileSystems; import java.nio.file.Files; +import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.PathMatcher; import java.time.Duration; @@ -82,6 +84,8 @@ private boolean testSize(Path path) { long bytes = Files.size(path); DataSize size = DataSize.ofBytes(bytes); return size.compareTo(maxSize) < 0; + } catch (NoSuchFileException ex) { + return false; } catch (IOException ex) { throw new UncheckedIOException(ex); } @@ -100,6 +104,8 @@ private boolean testLine(Path path) { if (lines >= maxLines) return false; } return true; + } catch (FileNotFoundException ex) { + return false; } catch (IOException ex) { throw new UncheckedIOException(ex); } From 673fed291a5134752d5b40370bc8897de5cac767 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 9 Oct 2023 10:19:49 +0200 Subject: [PATCH 0348/1089] Altering `task` schema to use JSON columns for `query` and `processing` --- .../POST__task__dataset__create.xml | 5 + .idea/runConfigurations/POST__task_create.xml | 5 - .../usi/si/seart/model/task/CodeTask.java | 20 --- .../java/usi/si/seart/model/task/Task.java | 44 +++--- .../model/task/processing/CodeProcessing.java | 96 ------------- .../model/task/processing/Processing.java | 60 --------- .../si/seart/model/task/query/CodeQuery.java | 115 ---------------- .../si/seart/model/task/query/FileQuery.java | 47 ------- .../seart/model/task/query/FunctionQuery.java | 47 ------- .../usi/si/seart/model/task/query/Query.java | 102 -------------- .../si/seart/controller/TaskController.java | 36 ++--- .../task/{CodeTaskDto.java => TaskDto.java} | 16 +-- .../task/processing/CodeProcessingDto.java | 63 --------- .../si/seart/dto/task/query/CodeQueryDto.java | 126 ------------------ .../si/seart/dto/task/query/FileQueryDto.java | 30 ----- .../dto/task/query/FunctionQueryDto.java | 30 ----- .../usi/si/seart/service/TaskService.java | 38 +++--- liquibase/changelog.xml | 1 + liquibase/scripts/01_user.sql | 47 +------ 19 files changed, 71 insertions(+), 857 deletions(-) create mode 100644 .idea/runConfigurations/POST__task__dataset__create.xml delete mode 100644 .idea/runConfigurations/POST__task_create.xml delete mode 100644 dl4se-model/src/main/java/usi/si/seart/model/task/CodeTask.java delete mode 100644 dl4se-model/src/main/java/usi/si/seart/model/task/processing/CodeProcessing.java delete mode 100644 dl4se-model/src/main/java/usi/si/seart/model/task/processing/Processing.java delete mode 100644 dl4se-model/src/main/java/usi/si/seart/model/task/query/CodeQuery.java delete mode 100644 dl4se-model/src/main/java/usi/si/seart/model/task/query/FileQuery.java delete mode 100644 dl4se-model/src/main/java/usi/si/seart/model/task/query/FunctionQuery.java delete mode 100644 dl4se-model/src/main/java/usi/si/seart/model/task/query/Query.java rename dl4se-server/src/main/java/usi/si/seart/dto/task/{CodeTaskDto.java => TaskDto.java} (63%) delete mode 100644 dl4se-server/src/main/java/usi/si/seart/dto/task/processing/CodeProcessingDto.java delete mode 100644 dl4se-server/src/main/java/usi/si/seart/dto/task/query/CodeQueryDto.java delete mode 100644 dl4se-server/src/main/java/usi/si/seart/dto/task/query/FileQueryDto.java delete mode 100644 dl4se-server/src/main/java/usi/si/seart/dto/task/query/FunctionQueryDto.java diff --git a/.idea/runConfigurations/POST__task__dataset__create.xml b/.idea/runConfigurations/POST__task__dataset__create.xml new file mode 100644 index 00000000..96a8fadf --- /dev/null +++ b/.idea/runConfigurations/POST__task__dataset__create.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/POST__task_create.xml b/.idea/runConfigurations/POST__task_create.xml deleted file mode 100644 index aed81efd..00000000 --- a/.idea/runConfigurations/POST__task_create.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/dl4se-model/src/main/java/usi/si/seart/model/task/CodeTask.java b/dl4se-model/src/main/java/usi/si/seart/model/task/CodeTask.java deleted file mode 100644 index cbf6ed25..00000000 --- a/dl4se-model/src/main/java/usi/si/seart/model/task/CodeTask.java +++ /dev/null @@ -1,20 +0,0 @@ -package usi.si.seart.model.task; - -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.experimental.FieldDefaults; -import lombok.experimental.SuperBuilder; - -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; - -@Entity -@DiscriminatorValue("CODE") -@Getter -@Setter -@SuperBuilder -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@FieldDefaults(level = AccessLevel.PRIVATE) -public class CodeTask extends Task {} diff --git a/dl4se-model/src/main/java/usi/si/seart/model/task/Task.java b/dl4se-model/src/main/java/usi/si/seart/model/task/Task.java index 63fc63bf..01a2828b 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/task/Task.java +++ b/dl4se-model/src/main/java/usi/si/seart/model/task/Task.java @@ -2,6 +2,9 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import io.hypersistence.utils.hibernate.type.json.JsonType; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; @@ -9,30 +12,23 @@ import lombok.NoArgsConstructor; import lombok.Setter; import lombok.experimental.FieldDefaults; -import lombok.experimental.SuperBuilder; import org.hibernate.Hibernate; import org.hibernate.annotations.Type; import org.hibernate.annotations.TypeDef; -import usi.si.seart.model.task.processing.Processing; -import usi.si.seart.model.task.query.Query; +import org.hibernate.annotations.TypeDefs; +import usi.si.seart.model.job.Job; import usi.si.seart.model.type.StringEnumType; import usi.si.seart.model.user.User; import javax.persistence.Basic; -import javax.persistence.CascadeType; import javax.persistence.Column; -import javax.persistence.DiscriminatorColumn; -import javax.persistence.DiscriminatorType; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; import javax.persistence.GeneratedValue; import javax.persistence.Id; -import javax.persistence.Inheritance; -import javax.persistence.InheritanceType; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; -import javax.persistence.OneToOne; import javax.persistence.Table; import javax.persistence.Version; import javax.validation.constraints.NotNull; @@ -44,16 +40,17 @@ @Entity @Table(name = "task") -@Inheritance(strategy = InheritanceType.SINGLE_TABLE) -@DiscriminatorColumn(name = "dataset", discriminatorType = DiscriminatorType.STRING) @Getter @Setter -@SuperBuilder +@Builder @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor(access = AccessLevel.PROTECTED) @FieldDefaults(level = AccessLevel.PROTECTED) -@TypeDef(name = "string-enum", typeClass = StringEnumType.class) -public abstract class Task { +@TypeDefs({ + @TypeDef(name = "string-enum", typeClass = StringEnumType.class), + @TypeDef(name = "json", typeClass = JsonType.class) +}) +public class Task { @Id @GeneratedValue @@ -70,11 +67,20 @@ public abstract class Task { @JoinColumn(name = "user_id") User user; - @OneToOne(mappedBy = "task", cascade = CascadeType.ALL, orphanRemoval = true, optional = false) - Query query; + @Basic(optional = false) + @Enumerated(EnumType.STRING) + @Type(type = "string-enum") + Job dataset; + + @NotNull + @Type(type = "json") + @Builder.Default + JsonNode query = JsonNodeFactory.instance.objectNode(); - @OneToOne(mappedBy = "task", cascade = CascadeType.ALL, orphanRemoval = true, optional = false) - Processing processing; + @NotNull + @Type(type = "json") + @Builder.Default + JsonNode processing = JsonNodeFactory.instance.objectNode(); @Basic(optional = false) @Enumerated(EnumType.STRING) @@ -130,6 +136,6 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(user, query, processing); + return Objects.hash(user, dataset, query, processing); } } diff --git a/dl4se-model/src/main/java/usi/si/seart/model/task/processing/CodeProcessing.java b/dl4se-model/src/main/java/usi/si/seart/model/task/processing/CodeProcessing.java deleted file mode 100644 index f5047e68..00000000 --- a/dl4se-model/src/main/java/usi/si/seart/model/task/processing/CodeProcessing.java +++ /dev/null @@ -1,96 +0,0 @@ -package usi.si.seart.model.task.processing; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.hypersistence.utils.hibernate.type.array.ListArrayType; -import lombok.AccessLevel; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.experimental.FieldDefaults; -import lombok.experimental.SuperBuilder; -import org.hibernate.Hibernate; -import org.hibernate.annotations.Type; -import org.hibernate.annotations.TypeDef; -import usi.si.seart.validation.constraints.AllNullOrNotNull; -import usi.si.seart.validation.constraints.NullOrNotBlank; -import usi.si.seart.validation.constraints.NullOrRange; - -import javax.persistence.Column; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.TreeSet; - -@Entity -@DiscriminatorValue("CODE") -@Getter -@Setter -@SuperBuilder -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@FieldDefaults(level = AccessLevel.PRIVATE) -@AllNullOrNotNull(fields = { "maskToken", "maskPercentage", "maskContiguousOnly" }) -@TypeDef(name = "list-array", typeClass = ListArrayType.class) -public class CodeProcessing extends Processing { - - @NotNull - @Column(name = "remove_docstring") - @JsonProperty(value = "remove_docstring") - Boolean removeDocstring; - - @NotNull - @Column(name = "remove_inner_comments") - @JsonProperty(value = "remove_inner_comments") - Boolean removeInnerComments; - - @NullOrNotBlank - @Column(name = "mask_token") - @JsonProperty(value = "mask_token") - String maskToken; - - @NullOrRange(min = 1, max = 100) - @Column(name = "mask_percentage") - @JsonProperty(value = "mask_percentage") - Integer maskPercentage; - - @Column(name = "mask_contiguous_only") - @JsonProperty(value = "mask_contiguous_only") - Boolean maskContiguousOnly; - - @NotNull - @Column(name = "abstract_code") - @JsonProperty(value = "abstract_code") - Boolean abstractCode; - - @NotNull - @Type(type = "list-array") - @Builder.Default - @Column(name = "abstract_idioms") - @JsonProperty(value = "abstract_idioms") - List<@NotBlank String> abstractIdioms = new ArrayList<>(); - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false; - CodeProcessing that = (CodeProcessing) o; - return id != null && Objects.equals(id, that.id); - } - - @Override - public int hashCode() { - return Objects.hash( - super.hashCode(), - removeDocstring, - removeInnerComments, - maskToken, - maskPercentage, - maskContiguousOnly, - new TreeSet<>(abstractIdioms) - ); - } -} diff --git a/dl4se-model/src/main/java/usi/si/seart/model/task/processing/Processing.java b/dl4se-model/src/main/java/usi/si/seart/model/task/processing/Processing.java deleted file mode 100644 index 68921c1e..00000000 --- a/dl4se-model/src/main/java/usi/si/seart/model/task/processing/Processing.java +++ /dev/null @@ -1,60 +0,0 @@ -package usi.si.seart.model.task.processing; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.experimental.FieldDefaults; -import lombok.experimental.SuperBuilder; -import org.hibernate.Hibernate; -import usi.si.seart.model.task.Task; - -import javax.persistence.DiscriminatorColumn; -import javax.persistence.DiscriminatorType; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; -import javax.persistence.Inheritance; -import javax.persistence.InheritanceType; -import javax.persistence.JoinColumn; -import javax.persistence.OneToOne; -import javax.persistence.Table; -import java.util.Objects; - -@Entity -@Table(name = "processing") -@Inheritance(strategy = InheritanceType.SINGLE_TABLE) -@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING) -@Getter -@Setter -@SuperBuilder -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@AllArgsConstructor(access = AccessLevel.PROTECTED) -@FieldDefaults(level = AccessLevel.PROTECTED) -public abstract class Processing { - - @Id - @GeneratedValue - @JsonIgnore - Long id; - - @OneToOne(optional = false) - @JoinColumn(name = "task_id") - @JsonIgnore - Task task; - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false; - Processing that = (Processing) o; - return id != null && Objects.equals(id, that.id); - } - - @Override - public int hashCode() { - return getClass().hashCode(); - } -} diff --git a/dl4se-model/src/main/java/usi/si/seart/model/task/query/CodeQuery.java b/dl4se-model/src/main/java/usi/si/seart/model/task/query/CodeQuery.java deleted file mode 100644 index 5395af3e..00000000 --- a/dl4se-model/src/main/java/usi/si/seart/model/task/query/CodeQuery.java +++ /dev/null @@ -1,115 +0,0 @@ -package usi.si.seart.model.task.query; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonUnwrapped; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.experimental.FieldDefaults; -import lombok.experimental.SuperBuilder; -import org.hibernate.Hibernate; -import usi.si.seart.model.Language; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.validation.constraints.NotNull; -import java.util.Objects; - -@Entity -@Getter -@Setter -@SuperBuilder -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@AllArgsConstructor(access = AccessLevel.PROTECTED) -@FieldDefaults(level = AccessLevel.PROTECTED) -public abstract class CodeQuery extends Query { - - @NotNull - @ManyToOne(optional = false) - @JoinColumn(name = "lang_id") - @JsonUnwrapped(prefix = "language_") - Language language; - - @NotNull - @Column(name = "include_ast") - @JsonProperty(value = "include_ast") - Boolean includeAst; - - @Column(name = "min_tokens") - @JsonProperty(value = "min_tokens") - Long minTokens; - - @Column(name = "max_tokens") - @JsonProperty(value = "max_tokens") - Long maxTokens; - - @Column(name = "min_lines") - @JsonProperty(value = "min_lines") - Long minLines; - - @Column(name = "max_lines") - @JsonProperty(value = "max_lines") - Long maxLines; - - @Column(name = "min_characters") - @JsonProperty(value = "min_characters") - Long minCharacters; - - @Column(name = "max_characters") - @JsonProperty(value = "max_characters") - Long maxCharacters; - - @NotNull - @Column(name = "exclude_duplicates") - @JsonProperty(value = "exclude_duplicates") - Boolean excludeDuplicates; - - @NotNull - @Column(name = "exclude_identical") - @JsonProperty(value = "exclude_identical") - Boolean excludeIdentical; - - @NotNull - @Column(name = "exclude_test") - @JsonProperty(value = "exclude_test") - Boolean excludeTest; - - @NotNull - @Column(name = "exclude_non_ascii") - @JsonProperty(value = "exclude_non_ascii") - Boolean excludeNonAscii; - - @JsonProperty("granularity") - public abstract String getGranularity(); - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false; - CodeQuery codeQuery = (CodeQuery) o; - return id != null && Objects.equals(id, codeQuery.id); - } - - @Override - public int hashCode() { - return Objects.hash( - super.hashCode(), - language, - includeAst, - minTokens, - maxTokens, - minLines, - maxLines, - minCharacters, - maxCharacters, - excludeDuplicates, - excludeIdentical, - excludeTest, - excludeNonAscii - ); - } -} diff --git a/dl4se-model/src/main/java/usi/si/seart/model/task/query/FileQuery.java b/dl4se-model/src/main/java/usi/si/seart/model/task/query/FileQuery.java deleted file mode 100644 index f2eb7a2c..00000000 --- a/dl4se-model/src/main/java/usi/si/seart/model/task/query/FileQuery.java +++ /dev/null @@ -1,47 +0,0 @@ -package usi.si.seart.model.task.query; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.experimental.FieldDefaults; -import lombok.experimental.SuperBuilder; -import org.hibernate.Hibernate; - -import javax.persistence.Column; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import java.util.Objects; - -@Entity -@DiscriminatorValue("CODE_FILE") -@Getter -@Setter -@SuperBuilder -@NoArgsConstructor -@FieldDefaults(level = AccessLevel.PRIVATE) -public class FileQuery extends CodeQuery { - - @Column(name = "exclude_unparsable") - @JsonProperty(value = "exclude_unparsable") - Boolean excludeUnparsable; - - @Override - public String getGranularity() { - return "file"; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false; - FileQuery fileQuery = (FileQuery) o; - return id != null && Objects.equals(id, fileQuery.id); - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), excludeUnparsable); - } -} diff --git a/dl4se-model/src/main/java/usi/si/seart/model/task/query/FunctionQuery.java b/dl4se-model/src/main/java/usi/si/seart/model/task/query/FunctionQuery.java deleted file mode 100644 index 960c3fa5..00000000 --- a/dl4se-model/src/main/java/usi/si/seart/model/task/query/FunctionQuery.java +++ /dev/null @@ -1,47 +0,0 @@ -package usi.si.seart.model.task.query; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.experimental.FieldDefaults; -import lombok.experimental.SuperBuilder; -import org.hibernate.Hibernate; - -import javax.persistence.Column; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import java.util.Objects; - -@Entity -@DiscriminatorValue("CODE_FUNCTION") -@Getter -@Setter -@SuperBuilder -@NoArgsConstructor -@FieldDefaults(level = AccessLevel.PRIVATE) -public class FunctionQuery extends CodeQuery { - - @Column(name = "exclude_boilerplate") - @JsonProperty(value = "exclude_boilerplate") - Boolean excludeBoilerplate; - - @Override - public String getGranularity() { - return "function"; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false; - FunctionQuery that = (FunctionQuery) o; - return id != null && Objects.equals(id, that.id); - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), excludeBoilerplate); - } -} diff --git a/dl4se-model/src/main/java/usi/si/seart/model/task/query/Query.java b/dl4se-model/src/main/java/usi/si/seart/model/task/query/Query.java deleted file mode 100644 index c35fd16d..00000000 --- a/dl4se-model/src/main/java/usi/si/seart/model/task/query/Query.java +++ /dev/null @@ -1,102 +0,0 @@ -package usi.si.seart.model.task.query; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.experimental.FieldDefaults; -import lombok.experimental.SuperBuilder; -import org.hibernate.Hibernate; -import usi.si.seart.model.task.Task; - -import javax.persistence.Column; -import javax.persistence.DiscriminatorColumn; -import javax.persistence.DiscriminatorType; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; -import javax.persistence.Inheritance; -import javax.persistence.InheritanceType; -import javax.persistence.JoinColumn; -import javax.persistence.OneToOne; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.PositiveOrZero; -import java.util.Objects; - -@Entity -@Table(name = "query") -@Inheritance(strategy = InheritanceType.SINGLE_TABLE) -@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING) -@Getter -@Setter -@SuperBuilder -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@AllArgsConstructor(access = AccessLevel.PROTECTED) -@FieldDefaults(level = AccessLevel.PROTECTED) -public abstract class Query { - - @Id - @GeneratedValue - @JsonIgnore - Long id; - - @OneToOne(optional = false) - @JoinColumn(name = "task_id") - @JsonIgnore - Task task; - - @NotNull - @Column(name = "has_license") - @JsonProperty(value = "has_license") - Boolean hasLicense; - - @NotNull - @Column(name = "exclude_forks") - @JsonProperty(value = "exclude_forks") - Boolean excludeForks; - - @PositiveOrZero - @Column(name = "min_commits") - @JsonProperty(value = "min_commits") - Long minCommits; - - @PositiveOrZero - @Column(name = "min_contributors") - @JsonProperty(value = "min_contributors") - Long minContributors; - - @PositiveOrZero - @Column(name = "min_issues") - @JsonProperty(value = "min_issues") - Long minIssues; - - @PositiveOrZero - @Column(name = "min_stars") - @JsonProperty(value = "min_stars") - Long minStars; - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false; - Query query = (Query) o; - return id != null && Objects.equals(id, query.id); - } - - @Override - public int hashCode() { - return Objects.hash( - getClass().hashCode(), - hasLicense, - excludeForks, - minCommits, - minContributors, - minIssues, - minStars - ); - } -} diff --git a/dl4se-server/src/main/java/usi/si/seart/controller/TaskController.java b/dl4se-server/src/main/java/usi/si/seart/controller/TaskController.java index 1704ba6f..979d1c32 100644 --- a/dl4se-server/src/main/java/usi/si/seart/controller/TaskController.java +++ b/dl4se-server/src/main/java/usi/si/seart/controller/TaskController.java @@ -1,5 +1,6 @@ package usi.si.seart.controller; +import com.fasterxml.jackson.databind.JsonNode; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.SneakyThrows; @@ -25,16 +26,12 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import usi.si.seart.dto.task.CodeTaskDto; +import usi.si.seart.dto.task.TaskDto; import usi.si.seart.dto.task.TaskSearchDto; -import usi.si.seart.dto.task.processing.CodeProcessingDto; -import usi.si.seart.dto.task.query.CodeQueryDto; -import usi.si.seart.model.Language; +import usi.si.seart.model.job.Job; import usi.si.seart.model.task.Status; import usi.si.seart.model.task.Task; import usi.si.seart.model.task.Task_; -import usi.si.seart.model.task.processing.CodeProcessing; -import usi.si.seart.model.task.query.CodeQuery; import usi.si.seart.model.user.Role; import usi.si.seart.model.user.User; import usi.si.seart.model.user.User_; @@ -43,7 +40,6 @@ import usi.si.seart.service.ConfigurationService; import usi.si.seart.service.DownloadService; import usi.si.seart.service.FileSystemService; -import usi.si.seart.service.LanguageService; import usi.si.seart.service.TaskService; import usi.si.seart.service.UserService; @@ -64,7 +60,6 @@ public class TaskController { TaskService taskService; UserService userService; - LanguageService languageService; DownloadService downloadService; FileSystemService fileSystemService; ConversionService conversionService; @@ -92,30 +87,27 @@ public ResponseEntity tasks( } @SuppressWarnings("ConstantConditions") - @PostMapping("/create") + @PostMapping("/{dataset}/create") public ResponseEntity create( - @Valid @RequestBody CodeTaskDto codeTaskDto, @AuthenticationPrincipal UserPrincipal principal + @PathVariable String dataset, + @Valid @RequestBody TaskDto taskDto, + @AuthenticationPrincipal UserPrincipal principal ) { - LocalDateTime requestedAt = LocalDateTime.now(ZoneOffset.UTC); User requester = userService.getWithEmail(principal.getEmail()); + return create(requester, Job.valueOf(dataset.toUpperCase()), taskDto.getQuery(), taskDto.getProcessing()); + } + + private ResponseEntity create(User requester, Job dataset, JsonNode query, JsonNode processing) { + LocalDateTime requestedAt = LocalDateTime.now(ZoneOffset.UTC); Integer taskLimit = configurationService.get("request_limit", Integer.class); if (!taskService.canCreateTask(requester, taskLimit)) return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).build(); - CodeQueryDto queryDto = codeTaskDto.getQuery(); - CodeQuery query = conversionService.convert(queryDto, CodeQuery.class); - - Language language = languageService.getWithName(queryDto.getLanguageName()); - query.setLanguage(language); - - CodeProcessingDto processingDto = codeTaskDto.getProcessing(); - CodeProcessing processing = conversionService.convert(processingDto, CodeProcessing.class); - - if (taskService.activeTaskExists(requester, query, processing)) + if (taskService.activeTaskExists(requester, dataset, query, processing)) return ResponseEntity.status(HttpStatus.CONFLICT).build(); - taskService.create(requester, requestedAt, query, processing); + taskService.create(requester, dataset, query, processing, requestedAt); return ResponseEntity.status(HttpStatus.ACCEPTED).build(); } diff --git a/dl4se-server/src/main/java/usi/si/seart/dto/task/CodeTaskDto.java b/dl4se-server/src/main/java/usi/si/seart/dto/task/TaskDto.java similarity index 63% rename from dl4se-server/src/main/java/usi/si/seart/dto/task/CodeTaskDto.java rename to dl4se-server/src/main/java/usi/si/seart/dto/task/TaskDto.java index 9e638be0..72dbe58f 100644 --- a/dl4se-server/src/main/java/usi/si/seart/dto/task/CodeTaskDto.java +++ b/dl4se-server/src/main/java/usi/si/seart/dto/task/TaskDto.java @@ -2,35 +2,31 @@ import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.experimental.FieldDefaults; -import usi.si.seart.dto.task.processing.CodeProcessingDto; -import usi.si.seart.dto.task.query.CodeQueryDto; -import usi.si.seart.dto.task.query.FileQueryDto; -import javax.validation.Valid; import javax.validation.constraints.NotNull; @Getter @Builder -@FieldDefaults(level = AccessLevel.PRIVATE) @NoArgsConstructor @AllArgsConstructor -public class CodeTaskDto { +@FieldDefaults(level = AccessLevel.PRIVATE) +public class TaskDto { - @Valid @NotNull @JsonSetter(nulls = Nulls.SKIP) @Builder.Default - CodeQueryDto query = new FileQueryDto(); + JsonNode query = JsonNodeFactory.instance.objectNode(); - @Valid @NotNull @JsonSetter(nulls = Nulls.SKIP) @Builder.Default - CodeProcessingDto processing = new CodeProcessingDto(); + JsonNode processing = JsonNodeFactory.instance.objectNode(); } diff --git a/dl4se-server/src/main/java/usi/si/seart/dto/task/processing/CodeProcessingDto.java b/dl4se-server/src/main/java/usi/si/seart/dto/task/processing/CodeProcessingDto.java deleted file mode 100644 index 9fbac6b7..00000000 --- a/dl4se-server/src/main/java/usi/si/seart/dto/task/processing/CodeProcessingDto.java +++ /dev/null @@ -1,63 +0,0 @@ -package usi.si.seart.dto.task.processing; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.experimental.FieldDefaults; -import usi.si.seart.validation.constraints.AllNullOrNotNull; -import usi.si.seart.validation.constraints.NullOrNotBlank; -import usi.si.seart.validation.constraints.NullOrRange; - -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - -@Getter -@Builder -@FieldDefaults(level = AccessLevel.PRIVATE) -@NoArgsConstructor -@AllArgsConstructor -@AllNullOrNotNull(fields = { "maskToken", "maskPercentage", "maskContiguousOnly" }) -public class CodeProcessingDto { - - @NotNull - @JsonProperty(value = "remove_docstring") - @JsonSetter(nulls = Nulls.SKIP) - @Builder.Default - Boolean removeDocstring = false; - - @NotNull - @JsonProperty(value = "remove_inner_comments") - @JsonSetter(nulls = Nulls.SKIP) - @Builder.Default - Boolean removeInnerComments = false; - - @NullOrNotBlank - @JsonProperty(value = "mask_token") - String maskToken; - - @NullOrRange(min = 1, max = 100) - @JsonProperty(value = "mask_percentage") - Integer maskPercentage; - - @JsonProperty(value = "mask_contiguous_only") - Boolean maskContiguousOnly; - - @NotNull - @JsonProperty(value = "abstract_code") - @JsonSetter(nulls = Nulls.SKIP) - @Builder.Default - Boolean abstractCode = false; - - @NotNull - @JsonProperty(value = "abstract_idioms") - @JsonSetter(nulls = Nulls.SKIP) - @Builder.Default - List<@NotBlank String> abstractIdioms = new ArrayList<>(); -} diff --git a/dl4se-server/src/main/java/usi/si/seart/dto/task/query/CodeQueryDto.java b/dl4se-server/src/main/java/usi/si/seart/dto/task/query/CodeQueryDto.java deleted file mode 100644 index 3f551640..00000000 --- a/dl4se-server/src/main/java/usi/si/seart/dto/task/query/CodeQueryDto.java +++ /dev/null @@ -1,126 +0,0 @@ -package usi.si.seart.dto.task.query; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.JsonSubTypes; -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import com.fasterxml.jackson.annotation.Nulls; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.experimental.FieldDefaults; -import lombok.experimental.SuperBuilder; - -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.PositiveOrZero; - -@Getter -@Setter -@SuperBuilder -@FieldDefaults(level = AccessLevel.PRIVATE) -@NoArgsConstructor -@AllArgsConstructor -@JsonTypeInfo( - use = JsonTypeInfo.Id.NAME, - property = "granularity" -) -@JsonSubTypes({ - @JsonSubTypes.Type(value = FileQueryDto.class, name = "file"), - @JsonSubTypes.Type(value = FunctionQueryDto.class, name = "function") -}) -@JsonIgnoreProperties(ignoreUnknown = true) -public abstract class CodeQueryDto { - - @NotBlank - @JsonProperty(value = "language_name") - String languageName; - - @NotNull - @JsonProperty(value = "has_license") - @JsonSetter(nulls = Nulls.SKIP) - @Builder.Default - Boolean hasLicense = false; - - @NotNull - @JsonProperty(value = "exclude_forks") - @JsonSetter(nulls = Nulls.SKIP) - @Builder.Default - Boolean excludeForks = false; - - @PositiveOrZero - @JsonProperty(value = "min_commits") - @JsonSetter(nulls = Nulls.SKIP) - @Builder.Default - Long minCommits = 0L; - - @PositiveOrZero - @JsonProperty(value = "min_contributors") - @JsonSetter(nulls = Nulls.SKIP) - @Builder.Default - Long minContributors = 0L; - - @PositiveOrZero - @JsonProperty(value = "min_issues") - @JsonSetter(nulls = Nulls.SKIP) - @Builder.Default - Long minIssues = 0L; - - @PositiveOrZero - @JsonProperty(value = "min_stars") - @JsonSetter(nulls = Nulls.SKIP) - @Builder.Default - Long minStars = 0L; - - @NotNull - @JsonProperty(value = "include_ast") - @JsonSetter(nulls = Nulls.SKIP) - @Builder.Default - Boolean includeAst = true; - - @JsonProperty(value = "min_tokens") - Long minTokens; - - @JsonProperty(value = "max_tokens") - Long maxTokens; - - @JsonProperty(value = "min_lines") - Long minLines; - - @JsonProperty(value = "max_lines") - Long maxLines; - - @JsonProperty(value = "min_characters") - Long minCharacters; - - @JsonProperty(value = "max_characters") - Long maxCharacters; - - @NotNull - @JsonProperty(value = "exclude_duplicates") - @JsonSetter(nulls = Nulls.SKIP) - @Builder.Default - Boolean excludeDuplicates = false; - - @NotNull - @JsonProperty(value = "exclude_identical") - @JsonSetter(nulls = Nulls.SKIP) - @Builder.Default - Boolean excludeIdentical = false; - - @NotNull - @JsonProperty(value = "exclude_test") - @JsonSetter(nulls = Nulls.SKIP) - @Builder.Default - Boolean excludeTest = false; - - @NotNull - @JsonProperty(value = "exclude_non_ascii") - @JsonSetter(nulls = Nulls.SKIP) - @Builder.Default - Boolean excludeNonAscii = false; -} diff --git a/dl4se-server/src/main/java/usi/si/seart/dto/task/query/FileQueryDto.java b/dl4se-server/src/main/java/usi/si/seart/dto/task/query/FileQueryDto.java deleted file mode 100644 index 23d4a30d..00000000 --- a/dl4se-server/src/main/java/usi/si/seart/dto/task/query/FileQueryDto.java +++ /dev/null @@ -1,30 +0,0 @@ -package usi.si.seart.dto.task.query; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.experimental.FieldDefaults; -import lombok.experimental.SuperBuilder; - -import javax.validation.constraints.NotNull; - -@Getter -@Setter -@SuperBuilder -@FieldDefaults(level = AccessLevel.PRIVATE) -@NoArgsConstructor -@AllArgsConstructor -public class FileQueryDto extends CodeQueryDto { - - @NotNull - @JsonProperty(value = "exclude_unparsable") - @JsonSetter(nulls = Nulls.SKIP) - @Builder.Default - Boolean excludeUnparsable = false; -} diff --git a/dl4se-server/src/main/java/usi/si/seart/dto/task/query/FunctionQueryDto.java b/dl4se-server/src/main/java/usi/si/seart/dto/task/query/FunctionQueryDto.java deleted file mode 100644 index 1e964f07..00000000 --- a/dl4se-server/src/main/java/usi/si/seart/dto/task/query/FunctionQueryDto.java +++ /dev/null @@ -1,30 +0,0 @@ -package usi.si.seart.dto.task.query; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.experimental.FieldDefaults; -import lombok.experimental.SuperBuilder; - -import javax.validation.constraints.NotNull; - -@Getter -@Setter -@SuperBuilder -@FieldDefaults(level = AccessLevel.PRIVATE) -@NoArgsConstructor -@AllArgsConstructor -public class FunctionQueryDto extends CodeQueryDto { - - @NotNull - @JsonProperty(value = "exclude_boilerplate") - @JsonSetter(nulls = Nulls.SKIP) - @Builder.Default - Boolean excludeBoilerplate = false; -} diff --git a/dl4se-server/src/main/java/usi/si/seart/service/TaskService.java b/dl4se-server/src/main/java/usi/si/seart/service/TaskService.java index 6172a1fc..147c12b3 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/TaskService.java +++ b/dl4se-server/src/main/java/usi/si/seart/service/TaskService.java @@ -1,5 +1,6 @@ package usi.si.seart.service; +import com.fasterxml.jackson.databind.JsonNode; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Cleanup; @@ -14,13 +15,9 @@ import org.springframework.util.ConcurrentReferenceHashMap; import usi.si.seart.exception.TaskFailedException; import usi.si.seart.exception.TaskNotFoundException; -import usi.si.seart.model.task.CodeTask; +import usi.si.seart.model.job.Job; import usi.si.seart.model.task.Status; import usi.si.seart.model.task.Task; -import usi.si.seart.model.task.processing.CodeProcessing; -import usi.si.seart.model.task.processing.Processing; -import usi.si.seart.model.task.query.CodeQuery; -import usi.si.seart.model.task.query.Query; import usi.si.seart.model.user.User; import usi.si.seart.repository.TaskRepository; @@ -39,8 +36,8 @@ public interface TaskService { boolean canCreateTask(User user, Integer limit); - boolean activeTaskExists(User user, Query query, Processing processing); - void create(User requester, LocalDateTime requestedAt, CodeQuery query, CodeProcessing processing); + boolean activeTaskExists(User user, Job dataset, JsonNode query, JsonNode processing); + void create(User requester, Job dataset, JsonNode query, JsonNode processing, LocalDateTime requestedAt); T update(T task); void cancel(T task); void registerException(TaskFailedException ex); @@ -75,8 +72,8 @@ public boolean canCreateTask(User user, Integer limit) { } @Override - public boolean activeTaskExists(User user, Query query, Processing processing) { - int taskHash = Objects.hash(user, query, processing); + public boolean activeTaskExists(User user, Job dataset, JsonNode query, JsonNode processing) { + int taskHash = Objects.hash(user, dataset, query, processing); return taskRepository.findAllByUserAndStatusIn(user, Status.Category.ACTIVE) .stream() .mapToInt(Task::hashCode) @@ -84,17 +81,18 @@ public boolean activeTaskExists(User user, Query query, Processing processing) { } @Override - public void create(User requester, LocalDateTime requestedAt, CodeQuery query, CodeProcessing processing) { - Task task = CodeTask.builder() - .user(requester) - .submitted(requestedAt) - .query(query) - .processing(processing) - .build(); - - query.setTask(task); - processing.setTask(task); - taskRepository.save(task); + public void create( + User requester, Job dataset, JsonNode query, JsonNode processing, LocalDateTime requestedAt + ) { + taskRepository.save( + Task.builder() + .user(requester) + .dataset(dataset) + .query(query) + .processing(processing) + .submitted(requestedAt) + .build() + ); } @Override diff --git a/liquibase/changelog.xml b/liquibase/changelog.xml index ee4b05ea..5b1f4084 100644 --- a/liquibase/changelog.xml +++ b/liquibase/changelog.xml @@ -5,4 +5,5 @@ xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.23.xsd"> + diff --git a/liquibase/scripts/01_user.sql b/liquibase/scripts/01_user.sql index cf0b0559..74e2fcc3 100644 --- a/liquibase/scripts/01_user.sql +++ b/liquibase/scripts/01_user.sql @@ -32,6 +32,8 @@ CREATE TABLE "task" ( "uuid" uuid UNIQUE NOT NULL, "dataset" text NOT NULL, "user_id" bigint NOT NULL, + "query" json NOT NULL, + "processing" json NOT NULL, "status" text NOT NULL, "version" bigint NOT NULL, "checkpoint_id" bigint, @@ -45,57 +47,12 @@ CREATE TABLE "task" ( "error_stack_trace" text ); -CREATE TABLE "query" ( - "id" bigint PRIMARY KEY NOT NULL, - "task_id" bigint NOT NULL, - "lang_id" bigint NOT NULL, - "type" text NOT NULL, - "has_license" boolean NOT NULL, - "exclude_forks" boolean NOT NULL, - "min_commits" bigint NOT NULL, - "min_contributors" bigint NOT NULL, - "min_issues" bigint NOT NULL, - "min_stars" bigint NOT NULL, - "include_ast" boolean NOT NULL, - "min_tokens" bigint, - "max_tokens" bigint, - "min_lines" bigint, - "max_lines" bigint, - "min_characters" bigint, - "max_characters" bigint, - "exclude_duplicates" boolean NOT NULL, - "exclude_identical" boolean NOT NULL, - "exclude_test" boolean NOT NULL, - "exclude_non_ascii" boolean NOT NULL, - "exclude_unparsable" boolean, - "exclude_boilerplate" boolean -); - -CREATE TABLE "processing" ( - "id" bigint PRIMARY KEY NOT NULL, - "task_id" bigint NOT NULL, - "type" text NOT NULL, - "remove_docstring" boolean NOT NULL, - "remove_inner_comments" boolean NOT NULL, - "mask_token" text, - "mask_percentage" integer, - "mask_contiguous_only" boolean, - "abstract_code" boolean NOT NULL, - "abstract_idioms" text[] NOT NULL -); - ALTER TABLE "token" ADD FOREIGN KEY ("user_id") REFERENCES "user" ("id") ON DELETE CASCADE; ALTER TABLE "task" ADD FOREIGN KEY ("user_id") REFERENCES "user" ("id"); -ALTER TABLE "query" ADD FOREIGN KEY ("task_id") REFERENCES "task" ("id") ON DELETE CASCADE; -ALTER TABLE "query" ADD FOREIGN KEY ("lang_id") REFERENCES "language" ("id"); -ALTER TABLE "processing" ADD FOREIGN KEY ("task_id") REFERENCES "task" ("id") ON DELETE CASCADE; CREATE INDEX "token_user_id_idx" ON "token" (user_id); CREATE INDEX "task_user_id_idx" ON "task" (user_id); CREATE INDEX "task_expired_idx" ON "task" (finished, expired) WHERE finished IS NOT NULL AND expired = false; -CREATE INDEX "query_task_id_idx" ON "query" (task_id); -CREATE INDEX "query_lang_id_idx" ON "query" (lang_id); -CREATE INDEX "processing_task_id_idx" ON "processing" (task_id); CREATE INDEX "file_content_hash_idx" ON "file" (content_hash); CREATE INDEX "function_content_hash_idx" ON "function" (content_hash); CREATE INDEX "file_ast_hash_idx" ON "file" (ast_hash); From 7bb1ceb02c0ab95f3493638f868a32be223dbbb8 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 9 Oct 2023 10:24:44 +0200 Subject: [PATCH 0349/1089] Added new converter from `query` JSON to `Code` specification Compared to the old converter which returned jOOQ queries, specifications can be used for paginated queries, counts and even streams. The latter of the three will only work if we include the custom repository files that we use in GHS. --- .../TaskToCodeSpecificationConverter.java | 289 ++++++++++++++++++ http/TaskController.http | 8 +- 2 files changed, 293 insertions(+), 4 deletions(-) create mode 100644 dl4se-server/src/main/java/usi/si/seart/converter/TaskToCodeSpecificationConverter.java diff --git a/dl4se-server/src/main/java/usi/si/seart/converter/TaskToCodeSpecificationConverter.java b/dl4se-server/src/main/java/usi/si/seart/converter/TaskToCodeSpecificationConverter.java new file mode 100644 index 00000000..0f5c119b --- /dev/null +++ b/dl4se-server/src/main/java/usi/si/seart/converter/TaskToCodeSpecificationConverter.java @@ -0,0 +1,289 @@ +package usi.si.seart.converter; + +import com.fasterxml.jackson.databind.JsonNode; +import org.springframework.core.convert.converter.Converter; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.lang.NonNull; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; +import usi.si.seart.model.GitRepo_; +import usi.si.seart.model.Language_; +import usi.si.seart.model.code.Boilerplate; +import usi.si.seart.model.code.Code; +import usi.si.seart.model.code.Code_; +import usi.si.seart.model.code.File; +import usi.si.seart.model.code.Function; +import usi.si.seart.model.code.Function_; +import usi.si.seart.model.job.Job; +import usi.si.seart.model.task.Task; + +import javax.persistence.criteria.Expression; +import javax.persistence.criteria.Path; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; +import javax.persistence.criteria.Subquery; +import javax.persistence.metamodel.SingularAttribute; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +@Component +public class TaskToCodeSpecificationConverter implements Converter> { + + protected static final java.util.function.Predicate isPositive = value -> value > 0; + + @Override + @NonNull + public Specification convert(@NonNull Task source) { + Job dataset = source.getDataset(); + JsonNode query = source.getQuery(); + JsonNode processing = source.getProcessing(); + Assert.isTrue(Job.CODE.equals(dataset), "Can not convert this type of dataset: " + dataset); + Assert.isTrue(query.isObject(), "Query must be a JSON object!"); + Assert.isTrue(processing.isObject(), "Processing must be a JSON object!"); + Assert.isTrue(query.has("granularity"), "Query must have 'granularity' defined!"); + String granularity = query.get("granularity").asText(); + return convert(query, processing, granularity); + } + + private Specification convert( + @NonNull JsonNode query, @NonNull JsonNode processing, @NonNull String granularity + ) { + switch (granularity) { + case "file": + return convert(query, processing, File.class); + case "function": + return convert(query, processing, Function.class); + default: + throw new IllegalArgumentException("Converter not implemented for granularity: " + granularity); + } + } + + private Specification convert( + @NonNull JsonNode query, @NonNull JsonNode processing, Class granularity + ) { + return (supertypeRoot, criteriaQuery, criteriaBuilder) -> { + List predicates = new ArrayList<>(); + Root root = criteriaBuilder.treat(supertypeRoot, granularity); + + // Entity type predicate + Predicate entityType = criteriaBuilder.equal(root.type(), criteriaBuilder.literal(granularity)); + predicates.add(entityType); + + // Language predicate + Optional.ofNullable(query.get("language_name")) + .map(JsonNode::asText) + .filter(StringUtils::hasText) + .ifPresent(value -> { + Path path = root.join(Code_.language).get(Language_.name); + Predicate predicate = criteriaBuilder.equal(path, value); + predicates.add(predicate); + }); + + // Has license check + Optional.ofNullable(query.get("has_license")) + .map(JsonNode::asBoolean) + .filter(Boolean::booleanValue) + .ifPresent(ignored -> { + Path path = root.join(Code_.repo).get(GitRepo_.license); + Predicate predicate = criteriaBuilder.isNotNull(path); + predicates.add(predicate); + }); + + // Exclude fork predicate + Optional.ofNullable(query.get("exclude_forks")) + .map(JsonNode::asBoolean) + .filter(Boolean::booleanValue) + .ifPresent(ignored -> { + Path path = root.join(Code_.repo).get(GitRepo_.isFork); + Predicate predicate = criteriaBuilder.isFalse(path); + predicates.add(predicate); + }); + + // Minimum commits predicate + Optional.ofNullable(query.get("min_commits")) + .map(JsonNode::numberValue) + .map(Number::longValue) + .filter(isPositive) + .ifPresent(value -> { + Path path = root.join(Code_.repo).get(GitRepo_.commits); + Predicate predicate = criteriaBuilder.greaterThanOrEqualTo(path, value); + predicates.add(predicate); + }); + + // Minimum contributors predicate + Optional.ofNullable(query.get("min_contributors")) + .map(JsonNode::numberValue) + .map(Number::longValue) + .filter(isPositive) + .ifPresent(value -> { + Path path = root.join(Code_.repo).get(GitRepo_.contributors); + Predicate predicate = criteriaBuilder.greaterThanOrEqualTo(path, value); + predicates.add(predicate); + }); + + // Minimum issues predicate + Optional.ofNullable(query.get("min_issues")) + .map(JsonNode::numberValue) + .map(Number::longValue) + .filter(isPositive) + .ifPresent(value -> { + Path path = root.join(Code_.repo).get(GitRepo_.issues); + Predicate predicate = criteriaBuilder.greaterThanOrEqualTo(path, value); + predicates.add(predicate); + }); + + // Minimum stars predicate + Optional.ofNullable(query.get("min_stars")) + .map(JsonNode::numberValue) + .map(Number::longValue) + .filter(isPositive) + .ifPresent(value -> { + Path path = root.join(Code_.repo).get(GitRepo_.stars); + Predicate predicate = criteriaBuilder.greaterThanOrEqualTo(path, value); + predicates.add(predicate); + }); + + // Minimum characters predicate + Optional.ofNullable(query.get("min_characters")) + .map(JsonNode::numberValue) + .map(Number::longValue) + .filter(isPositive) + .ifPresent(value -> { + Path path = root.get(Code_.characters); + Predicate predicate = criteriaBuilder.greaterThanOrEqualTo(path, value); + predicates.add(predicate); + }); + + // Maximum characters predicate + Optional.ofNullable(query.get("max_characters")) + .map(JsonNode::numberValue) + .map(Number::longValue) + .filter(isPositive) + .ifPresent(value -> { + Path path = root.get(Code_.characters); + Predicate predicate = criteriaBuilder.lessThanOrEqualTo(path, value); + predicates.add(predicate); + }); + + boolean removeInnerComments = Optional.ofNullable(processing.get("remove_inner_comments")) + .map(JsonNode::asBoolean) + .orElse(false); + boolean removeDocstrings = Optional.ofNullable(processing.get("remove_docstring")) + .map(JsonNode::asBoolean) + .orElse(false); + SingularAttribute attribute = removeInnerComments && removeDocstrings + ? Code_.codeTokens + : Code_.totalTokens; + + // Minimum tokens predicate + Optional.ofNullable(query.get("min_tokens")) + .map(JsonNode::numberValue) + .map(Number::longValue) + .filter(isPositive) + .ifPresent(value -> { + Path path = root.get(attribute); + Predicate predicate = criteriaBuilder.greaterThanOrEqualTo(path, value); + predicates.add(predicate); + }); + + // Maximum tokens predicate + Optional.ofNullable(query.get("max_tokens")) + .map(JsonNode::numberValue) + .map(Number::longValue) + .filter(isPositive) + .ifPresent(value -> { + Path path = root.get(attribute); + Predicate predicate = criteriaBuilder.lessThanOrEqualTo(path, value); + predicates.add(predicate); + }); + + // Minimum lines predicate + Optional.ofNullable(query.get("min_lines")) + .map(JsonNode::numberValue) + .map(Number::longValue) + .filter(isPositive) + .ifPresent(value -> { + Path path = root.get(Code_.lines); + Predicate predicate = criteriaBuilder.greaterThanOrEqualTo(path, value); + predicates.add(predicate); + }); + + // Maximum lines predicate + Optional.ofNullable(query.get("max_lines")) + .map(JsonNode::numberValue) + .map(Number::longValue) + .filter(isPositive) + .ifPresent(value -> { + Path path = root.get(Code_.lines); + Predicate predicate = criteriaBuilder.lessThanOrEqualTo(path, value); + predicates.add(predicate); + }); + + // Duplicates predicate + boolean excludeIdentical = Optional.ofNullable(query.get("exclude_identical")) + .map(JsonNode::asBoolean) + .orElse(false); + boolean excludeDuplicates = Optional.ofNullable(query.get("exclude_duplicates")) + .map(JsonNode::asBoolean) + .orElse(false); + if (excludeIdentical || excludeDuplicates) { + Path path = root.get(Code_.id); + SingularAttribute distinct = excludeIdentical + ? Code_.astHash + : Code_.contentHash; + Subquery subselect = criteriaQuery.subquery(Long.class); + Root subselectRoot = subselect.from(granularity); + subselect.select(criteriaBuilder.min(subselectRoot.get(Code_.id))); + subselect.groupBy(subselectRoot.get(distinct)); + Expression expression = subselect.getSelection(); + Predicate predicate = path.in(expression); + predicates.add(predicate); + } + + // Exclude test instances + Optional.ofNullable(query.get("exclude_test")) + .map(JsonNode::asBoolean) + .filter(Boolean::booleanValue) + .ifPresent(ignored -> { + Path path = root.get(Code_.isTest); + Predicate predicate = criteriaBuilder.isFalse(path); + predicates.add(predicate); + }); + + // Exclude instances containing non-ASCII characters + Optional.ofNullable(query.get("exclude_non_ascii")) + .map(JsonNode::asBoolean) + .filter(Boolean::booleanValue) + .ifPresent(ignored -> { + Path path = root.get(Code_.containsNonAscii); + Predicate predicate = criteriaBuilder.isFalse(path); + predicates.add(predicate); + }); + + // Exclude instances containing errors + Optional.ofNullable(query.get("exclude_errors")) + .map(JsonNode::asBoolean) + .filter(Boolean::booleanValue) + .ifPresent(ignored -> { + Path path = root.get(Code_.containsError); + Predicate predicate = criteriaBuilder.isFalse(path); + predicates.add(predicate); + }); + + // Exclude boilerplate instances + Optional.ofNullable(query.get("exclude_boilerplate")) + .map(JsonNode::asBoolean) + .filter(value -> value && Function.class.equals(granularity)) + .ifPresent(ignored -> { + Path path = root.get(Function_.BOILERPLATE_TYPE); + Predicate predicate = criteriaBuilder.isNull(path); + predicates.add(predicate); + }); + + criteriaQuery.distinct(true); + return criteriaBuilder.and(predicates.toArray(Predicate[]::new)); + }; + } +} diff --git a/http/TaskController.http b/http/TaskController.http index bed0e26d..22b69ce3 100644 --- a/http/TaskController.http +++ b/http/TaskController.http @@ -1,5 +1,5 @@ -### POST /task/create -POST https://localhost:8080/api/task/create +### POST /task/{dataset}/create +POST https://localhost:8080/api/task/code/create Authorization: Bearer {{token}} Content-Type: application/json @@ -13,7 +13,6 @@ Content-Type: application/json "min_contributors" : 10, "min_issues" : 5, "min_stars" : 20, - "include_ast" : true, "min_tokens" : 10, "max_tokens" : 5000, "min_lines" : 3, @@ -24,6 +23,7 @@ Content-Type: application/json "exclude_identical" : true, "exclude_test" : false, "exclude_non_ascii" : true, + "exclude_errors": true, "exclude_boilerplate" : true }, "processing" : { @@ -63,4 +63,4 @@ Authorization: Bearer {{token}} ### GET /task/download GET https://localhost:8080/api/task/download/{{uuid}}?token={{task_token}} -Content-Type: application/gzip \ No newline at end of file +Content-Type: application/gzip From 8620ef090f34c5c523cfb792182f5495b350d947 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 9 Oct 2023 10:25:17 +0200 Subject: [PATCH 0350/1089] Inclusion of AST and s-expression is now moved to the `processing` part --- http/TaskController.http | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/http/TaskController.http b/http/TaskController.http index 22b69ce3..0a042446 100644 --- a/http/TaskController.http +++ b/http/TaskController.http @@ -27,17 +27,10 @@ Content-Type: application/json "exclude_boilerplate" : true }, "processing" : { + "include_ast" : false, + "include_symbolic_expression": false, "remove_docstring" : true, - "remove_inner_comments" : false, - "mask_token" : "", - "mask_percentage" : 50, - "mask_contiguous_only" : true, - "abstract_code": true, - "abstract_idioms" : [ - "App", - "main", - "String" - ] + "remove_inner_comments" : true } } From 5a7a05ecf84328fb13bea11ba9c8f380f237dc28 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 9 Oct 2023 10:26:28 +0200 Subject: [PATCH 0351/1089] Adding custom repository files from GHS We should make this into an extension some day --- .../JpaStreamableSpecificationRepository.java | 12 ++++ ...StreamableSpecificationRepositoryImpl.java | 57 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 dl4se-server/src/main/java/usi/si/seart/repository/specification/JpaStreamableSpecificationRepository.java create mode 100644 dl4se-server/src/main/java/usi/si/seart/repository/specification/JpaStreamableSpecificationRepositoryImpl.java diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/specification/JpaStreamableSpecificationRepository.java b/dl4se-server/src/main/java/usi/si/seart/repository/specification/JpaStreamableSpecificationRepository.java new file mode 100644 index 00000000..cf69f3d8 --- /dev/null +++ b/dl4se-server/src/main/java/usi/si/seart/repository/specification/JpaStreamableSpecificationRepository.java @@ -0,0 +1,12 @@ +package usi.si.seart.repository.specification; + +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; + +import java.util.stream.Stream; + +public interface JpaStreamableSpecificationRepository { + + Stream stream(Specification specification, Class domainClass); + Stream stream(Specification specification, Class domainClass, Sort sort); +} diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/specification/JpaStreamableSpecificationRepositoryImpl.java b/dl4se-server/src/main/java/usi/si/seart/repository/specification/JpaStreamableSpecificationRepositoryImpl.java new file mode 100644 index 00000000..8678a3c5 --- /dev/null +++ b/dl4se-server/src/main/java/usi/si/seart/repository/specification/JpaStreamableSpecificationRepositoryImpl.java @@ -0,0 +1,57 @@ +package usi.si.seart.repository.specification; + +import lombok.AllArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.query.QueryUtils; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; + +import javax.persistence.EntityManager; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; +import java.util.stream.Stream; + +@Repository +@Transactional(readOnly = true) +@AllArgsConstructor(onConstructor_ = @Autowired) +public class JpaStreamableSpecificationRepositoryImpl implements JpaStreamableSpecificationRepository { + + private final EntityManager em; + + @Override + public Stream stream(Specification specification, Class domainClass) { + return stream(specification, domainClass, Sort.unsorted()); + } + + @Override + public Stream stream(Specification specification, Class domainClass, Sort sort) { + Assert.notNull(domainClass, "Domain class must not be null!"); + Assert.notNull(sort, "Sort must not be null!"); + + CriteriaBuilder builder = em.getCriteriaBuilder(); + CriteriaQuery query = builder.createQuery(domainClass); + Root root = query.from(domainClass); + + if (specification != null) { + Predicate predicate = specification.toPredicate(root, query, builder); + if (predicate != null) { + query.where(predicate); + } + } + + query.select(root); + + if (sort.isSorted()) { + query.orderBy(QueryUtils.toOrders(sort, root, builder)); + } + + query.select(root); + + return em.createQuery(query).getResultStream(); + } +} From 9dfd6352accab7b9e1b44f3f96727c3e771eba5a Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 9 Oct 2023 10:32:13 +0200 Subject: [PATCH 0352/1089] Complete rework of `TaskRunner`, `CodeService` and `FileSystemService` The entire dataset construction system has been changed: - The `query` JSON is now converted to a specification prior to running - The `CodeRepository` now implements the newly introduced custom ones - Code relying on Hibernate native queries has been shafted completely - Query results are now streamed directly into a GZ archive - The `FileSystemService` now only deals in GZ archives - The `TaskRunner` dynamically removes `ast` and `symbolicExpression` columns based on what the user specified in the processing part --- .../si/seart/repository/CodeRepository.java | 53 ++----- .../usi/si/seart/scheduling/TaskRunner.java | 148 ++++++++---------- .../usi/si/seart/service/CodeService.java | 46 +----- .../si/seart/service/FileSystemService.java | 66 +++----- 4 files changed, 105 insertions(+), 208 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/CodeRepository.java b/dl4se-server/src/main/java/usi/si/seart/repository/CodeRepository.java index f151adaa..672bafcb 100644 --- a/dl4se-server/src/main/java/usi/si/seart/repository/CodeRepository.java +++ b/dl4se-server/src/main/java/usi/si/seart/repository/CodeRepository.java @@ -1,47 +1,16 @@ package usi.si.seart.repository; -import org.springframework.stereotype.Repository; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; import usi.si.seart.model.code.Code; - -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; -import javax.persistence.Query; -import java.util.Map; -import java.util.stream.Stream; - -public interface CodeRepository { - +import usi.si.seart.repository.specification.JpaStreamableSpecificationRepository; + +public interface CodeRepository extends + JpaRepository, + JpaSpecificationExecutor, + JpaStreamableSpecificationRepository +{ + @Query(value = "SELECT size FROM code_size_in_bytes", nativeQuery = true) Long size(); - Long count(String queryString, Map parameters); - Stream stream(String queryString, Map parameters, Class codeClass); - - @Repository - class CodeRepositoryImpl implements CodeRepository { - - @PersistenceContext - EntityManager entityManager; - - @Override - public Long size() { - Query query = entityManager.createNativeQuery("SELECT size FROM code_size_in_bytes"); - return ((Number) query.getSingleResult()).longValue(); - } - - @Override - public Long count(String queryString, Map parameters) { - Query query = entityManager.createNativeQuery(queryString); - parameters.forEach(query::setParameter); - return ((Number) query.getSingleResult()).longValue(); - } - - @Override - @SuppressWarnings("unchecked") - public Stream stream( - String queryString, Map parameters, Class codeClass - ) { - Query query = entityManager.createNativeQuery(queryString, codeClass); - parameters.forEach(query::setParameter); - return query.getResultStream(); - } - } } diff --git a/dl4se-server/src/main/java/usi/si/seart/scheduling/TaskRunner.java b/dl4se-server/src/main/java/usi/si/seart/scheduling/TaskRunner.java index 7a70e29c..c5bd8278 100644 --- a/dl4se-server/src/main/java/usi/si/seart/scheduling/TaskRunner.java +++ b/dl4se-server/src/main/java/usi/si/seart/scheduling/TaskRunner.java @@ -1,30 +1,25 @@ package usi.si.seart.scheduling; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.json.JsonMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.AccessLevel; import lombok.AllArgsConstructor; -import lombok.Cleanup; import lombok.experimental.FieldDefaults; -import lombok.experimental.NonFinal; import lombok.extern.slf4j.Slf4j; -import org.jooq.Queries; +import org.bouncycastle.util.Iterable; import org.springframework.core.convert.ConversionService; import org.springframework.dao.OptimisticLockingFailureException; +import org.springframework.data.jpa.domain.Specification; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; import usi.si.seart.exception.TaskFailedException; -import usi.si.seart.function.CodeProcessingPipeline; import usi.si.seart.model.code.Code; -import usi.si.seart.model.code.File; -import usi.si.seart.model.code.Function; -import usi.si.seart.model.task.CodeTask; +import usi.si.seart.model.job.Job; import usi.si.seart.model.task.Status; import usi.si.seart.model.task.Task; -import usi.si.seart.model.task.query.FileQuery; -import usi.si.seart.model.task.query.FunctionQuery; -import usi.si.seart.model.task.query.Query; import usi.si.seart.service.CodeService; import usi.si.seart.service.EmailService; import usi.si.seart.service.FileSystemService; @@ -34,13 +29,12 @@ import java.io.BufferedWriter; import java.io.FileOutputStream; import java.io.OutputStreamWriter; -import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.time.LocalDateTime; import java.time.ZoneOffset; -import java.util.Map; import java.util.Optional; import java.util.stream.Stream; +import java.util.zip.GZIPOutputStream; @Slf4j @AllArgsConstructor @@ -71,93 +65,75 @@ public void run() { next.ifPresentOrElse(this::run, () -> log.debug("No tasks to execute!")); } + @SuppressWarnings("unchecked") private void run(Task task) { log.info("Executing task: [{}]", task.getUuid()); - if (task instanceof CodeTask) { - run((CodeTask) task); - } else { - String message = "Unsupported task type: " + task.getClass().getName(); + Job dataset = task.getDataset(); + // FIXME: 06.10.2023 This will need to be changed later for other dataset types + if (!Job.CODE.equals(dataset)) { + String message = "Unsupported task type: " + dataset; UnsupportedOperationException cause = new UnsupportedOperationException(message); throw new TaskFailedException(task, cause); } - } - - private void run(CodeTask task) { - @SuppressWarnings("ConstantConditions") - org.jooq.Query[] queries = conversionService.convert(task, Queries.class).queries(); - CodeProcessingPipeline pipeline = conversionService.convert(task, CodeProcessingPipeline.class); - - Class codeClass; - Query codeQuery = task.getQuery(); - if (codeQuery instanceof FileQuery) { - codeClass = File.class; - } else if (codeQuery instanceof FunctionQuery) { - codeClass = Function.class; - } else { - String message = "Unsupported code granularity level: " + codeQuery.getClass().getName(); - UnsupportedOperationException cause = new UnsupportedOperationException(message); - throw new TaskFailedException(task, cause); - } - + Specification specification = conversionService.convert(task, Specification.class); TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager); transactionTemplate.setReadOnly(true); - transactionTemplate.execute( - new TaskRunnerTransactionCallbackWithoutResult(task, codeClass, queries[0], queries[1], pipeline) - ); + transactionTemplate.execute(new TransactionCallback(task, specification)); } + @FieldDefaults(level = AccessLevel.PRIVATE) + @AllArgsConstructor(access = AccessLevel.PRIVATE) + private class TransactionCallback extends TransactionCallbackWithoutResult { - @AllArgsConstructor - @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) - private class TaskRunnerTransactionCallbackWithoutResult extends TransactionCallbackWithoutResult { - - @NonFinal Task task; - - Class codeClass; - - org.jooq.Query resultQuery; - org.jooq.Query countQuery; + Task task; - java.util.function.Function> pipeline; + Specification specification; @Override protected void doInTransactionWithoutResult(TransactionStatus status) { try { - Path exportPath = fileSystemService.createTaskFile(task); - { - @Cleanup BufferedWriter writer = new BufferedWriter( - new OutputStreamWriter( - new FileOutputStream(exportPath.toFile(), true), - StandardCharsets.UTF_8 - ) - ); - - Long totalResults = codeService.countTotalResults(countQuery); - task.setTotalResults(totalResults); - task = taskService.update(task); - - @Cleanup Stream> stream = codeService.streamAndProcess( - resultQuery, pipeline, codeClass - ); - Iterable> iterable = stream::iterator; + JsonNode processing = task.getProcessing(); + Long totalResults = codeService.count(specification); + task.setTotalResults(totalResults); + task = taskService.update(task); + Path exportPath = fileSystemService.createTaskArchive(task); + try ( + Stream stream = codeService.streamAllDynamically(specification); + FileOutputStream fileOutputStream = new FileOutputStream(exportPath.toFile(), true); + GZIPOutputStream gzipOutputStream = new GZIPOutputStream(fileOutputStream); + OutputStreamWriter outputStreamWriter = new OutputStreamWriter(gzipOutputStream); + BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter) + ) { + Iterable iterable = stream::iterator; long count = task.getProcessedResults(); - for (Map code : iterable) { + for (Code code: iterable) { count += 1; - - long id = (long) code.get("id"); + Long id = code.getId(); task.setCheckpointId(id); task.setProcessedResults(count); - code.remove("id"); - String serialized = jsonMapper.writeValueAsString(code); - writer.write(serialized); - writer.newLine(); + // TODO: 06.10.2023 Apply transformations here + + ObjectNode json = jsonMapper.valueToTree(code); + json.remove("id"); + Optional.ofNullable(processing.get("include_ast")) + .map(JsonNode::asBoolean) + .filter(Boolean::booleanValue) + .ifPresentOrElse(value -> {}, () -> json.remove("ast")); + Optional.ofNullable(processing.get("include_symbolic_expression")) + .map(JsonNode::asBoolean) + .filter(Boolean::booleanValue) + .ifPresentOrElse(value -> {}, () -> json.remove("symbolic_expression")); + + String serialized = jsonMapper.writeValueAsString(json); + bufferedWriter.write(serialized); + bufferedWriter.newLine(); if (count % fetchSize == 0) { Long fileSize = fileSystemService.getFileSize(task); task.setSize(fileSize); task = taskService.update(task); - writer.flush(); + bufferedWriter.flush(); entityManager.clear(); } } @@ -165,22 +141,25 @@ protected void doInTransactionWithoutResult(TransactionStatus status) { Long fileSize = fileSystemService.getFileSize(task); task.setSize(fileSize); - task = taskService.update(task); - - fileSystemService.compressTaskFile(task); - task.setStatus(Status.FINISHED); task.setFinished(LocalDateTime.now(ZoneOffset.UTC)); task = taskService.update(task); log.info("Finished task: [{}]", task.getUuid()); emailService.sendTaskNotificationEmail(task); } catch (OptimisticLockingFailureException ex) { - // Only two threads can modify a single task: - // 1) The task executor - // 2) The /cancel route - // That means if the locking failure occurs here, the task has been marked as cancelled, and we should - // move on to executing the next task. Still, this exception should be logged at the debug level, just - // in case we run into other locking issues when we introduce new features... + /* + * Only two threads can modify a single task: + * + * 1) The task executor + * 2) The /cancel route + * + * That means if the locking failure occurs here, + * the task has been marked as cancelled, + * and we should move on to executing the next task. + * Still, this exception should be logged at the debug level, + * just in case we run into other locking + * issues when we introduce new features... + */ fileSystemService.cleanTaskFiles(task); log.info("Cancelled task: [{}]", task.getUuid()); log.debug("", ex); @@ -188,6 +167,5 @@ protected void doInTransactionWithoutResult(TransactionStatus status) { throw new TaskFailedException(task, thr); } } - } } diff --git a/dl4se-server/src/main/java/usi/si/seart/service/CodeService.java b/dl4se-server/src/main/java/usi/si/seart/service/CodeService.java index e2b00d1e..c1df4ab9 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/CodeService.java +++ b/dl4se-server/src/main/java/usi/si/seart/service/CodeService.java @@ -3,65 +3,35 @@ import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.experimental.FieldDefaults; -import org.jooq.DSLContext; -import org.jooq.Query; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; import usi.si.seart.model.code.Code; import usi.si.seart.repository.CodeRepository; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; import java.util.stream.Stream; public interface CodeService { - Long countTotalResults(Query query); - Stream> streamAndProcess( - Query query, Function> pipeline, Class codeClass - ); + Long count(Specification specification); + + Stream streamAllDynamically(Specification specification); @Service @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) @AllArgsConstructor(onConstructor_ = @Autowired) class CodeServiceImpl implements CodeService { - DSLContext dslContext; CodeRepository codeRepository; - @PersistenceContext - EntityManager entityManager; - @Override - public Long countTotalResults(Query query) { - String sql = dslContext.renderNamedParams(query); - Map parameters = getQueryParameters(query); - return codeRepository.count(sql, parameters); + public Long count(Specification specification) { + return codeRepository.count(specification); } @Override - public Stream> streamAndProcess( - Query query, Function> processing, Class codeClass - ) { - String sql = dslContext.renderNamedParams(query); - Map parameters = getQueryParameters(query); - return codeRepository.stream(sql, parameters, codeClass) - .map(code -> { - entityManager.detach(code); - return processing.apply(code); - }); - } - - @SuppressWarnings("ConstantConditions") - private Map getQueryParameters(Query query) { - return query.getParams() - .entrySet() - .stream() - .map(entry -> Map.entry(entry.getKey(), entry.getValue().getValue())) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + public Stream streamAllDynamically(Specification specification) { + return codeRepository.stream(specification, Code.class); } } } diff --git a/dl4se-server/src/main/java/usi/si/seart/service/FileSystemService.java b/dl4se-server/src/main/java/usi/si/seart/service/FileSystemService.java index c75e6e6b..a42bab8a 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/FileSystemService.java +++ b/dl4se-server/src/main/java/usi/si/seart/service/FileSystemService.java @@ -2,26 +2,22 @@ import lombok.AccessLevel; import lombok.AllArgsConstructor; -import lombok.Cleanup; -import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import usi.si.seart.model.task.Task; -import java.io.FileInputStream; -import java.io.FileOutputStream; +import java.io.File; import java.io.IOException; +import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.zip.GZIPOutputStream; public interface FileSystemService { Path getTaskArchive(Task task); - Path createTaskFile(Task task) throws IOException; - void compressTaskFile(Task task); + Path createTaskArchive(Task task); void cleanTaskFiles(Task task); Long getFileSize(Task task); @@ -35,57 +31,41 @@ class FileSystemServiceImpl implements FileSystemService { @Override public Path getTaskArchive(Task task) { - return getArchiveFilePath(task); + return getPath(task); } @Override - public Path createTaskFile(Task task) throws IOException { - Path tmpFilePath = getRegularFilePath(task); - if (Files.notExists(tmpFilePath)) Files.createFile(tmpFilePath); - return tmpFilePath; - } - - @Override - @SneakyThrows - public void compressTaskFile(Task task) { - Path regularFilePath = getRegularFilePath(task); - Path archiveFilePath = getArchiveFilePath(task); - @Cleanup GZIPOutputStream outputStream = new GZIPOutputStream(new FileOutputStream(archiveFilePath.toFile())); - @Cleanup FileInputStream inputStream = new FileInputStream(regularFilePath.toFile()); - byte[] buffer = new byte[1024]; - int len; - while ((len = inputStream.read(buffer)) > 0) { - outputStream.write(buffer, 0, len); + public Path createTaskArchive(Task task) { + Path path = getPath(task); + if (Files.exists(path)) return path; + try { + return Files.createFile(path); + } catch (IOException ex) { + throw new UncheckedIOException(ex); } - Files.delete(regularFilePath); } @Override - @SneakyThrows public void cleanTaskFiles(Task task) { - Path regularFilePath = getRegularFilePath(task); - Path archiveFilePath = getArchiveFilePath(task); - if (Files.exists(regularFilePath)) Files.delete(regularFilePath); - if (Files.exists(archiveFilePath)) Files.delete(archiveFilePath); + Path path = getPath(task); + if (Files.notExists(path)) return; + try { + Files.delete(path); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } } @Override public Long getFileSize(Task task) { - Path tmpFilePath = getRegularFilePath(task); - return tmpFilePath.toFile().length(); - } - - private Path getRegularFilePath(Task task) { - return getPath(task, "jsonl"); - } - - private Path getArchiveFilePath(Task task) { - return getPath(task, "jsonl.gz"); + Path path = getPath(task); + File file = path.toFile(); + return file.length(); } - private Path getPath(Task task, String extension) { + private Path getPath(Task task) { String name = task.getUuid().toString(); - return Path.of(fileStorageDirPath.toString(), name+"."+extension); + return Path.of(fileStorageDirPath.toString(), name + ".jsonl.gz"); } } } From 48b6b2b378023f96c2fe3fcef162ae6549d639f5 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 9 Oct 2023 10:34:02 +0200 Subject: [PATCH 0353/1089] Removing all the unnecessary crap --- .../java/usi/si/seart/config/MainConfig.java | 16 - .../DtoToCodeProcessingConverter.java | 23 -- .../converter/GenericCodeQueryConverter.java | 65 ---- .../TaskToProcessingPipelineConverter.java | 315 ------------------ .../converter/TaskToQueriesConverter.java | 274 --------------- .../function/CodeProcessingPipeline.java | 35 -- 6 files changed, 728 deletions(-) delete mode 100644 dl4se-server/src/main/java/usi/si/seart/converter/DtoToCodeProcessingConverter.java delete mode 100644 dl4se-server/src/main/java/usi/si/seart/converter/GenericCodeQueryConverter.java delete mode 100644 dl4se-server/src/main/java/usi/si/seart/converter/TaskToProcessingPipelineConverter.java delete mode 100644 dl4se-server/src/main/java/usi/si/seart/converter/TaskToQueriesConverter.java delete mode 100644 dl4se-server/src/main/java/usi/si/seart/function/CodeProcessingPipeline.java diff --git a/dl4se-server/src/main/java/usi/si/seart/config/MainConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/MainConfig.java index cf511736..cb96ef04 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/MainConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/MainConfig.java @@ -4,9 +4,6 @@ import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import org.jooq.DSLContext; -import org.jooq.SQLDialect; -import org.jooq.impl.DSL; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -16,13 +13,9 @@ import org.springframework.lang.NonNull; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import usi.si.seart.converter.DtoToCodeProcessingConverter; import usi.si.seart.converter.DtoToConfigurationConverter; import usi.si.seart.converter.DtoToUserConverter; -import usi.si.seart.converter.GenericCodeQueryConverter; import usi.si.seart.converter.TaskSearchDtoToSpecificationConverter; -import usi.si.seart.converter.TaskToProcessingPipelineConverter; -import usi.si.seart.converter.TaskToQueriesConverter; import usi.si.seart.converter.UserSearchDtoToSpecificationConverter; import usi.si.seart.jackson.PageSerializer; import usi.si.seart.jackson.SortSerializer; @@ -39,11 +32,6 @@ public Path fileStorageDirPath(@Value("${java.io.tmpdir}") String value) { return Path.of(value, "dl4se_storage"); } - @Bean - public DSLContext dslContext() { - return DSL.using(SQLDialect.POSTGRES); - } - @Bean public JsonMapper jsonMapper() { JsonMapper jsonMapper = new JsonMapper(); @@ -77,10 +65,6 @@ public void addCorsMappings(@NonNull final CorsRegistry registry) { public void addFormatters(@NonNull final FormatterRegistry registry) { registry.addConverter(new DtoToUserConverter()); registry.addConverter(new DtoToConfigurationConverter()); - registry.addConverter(new GenericCodeQueryConverter()); - registry.addConverter(new DtoToCodeProcessingConverter()); - registry.addConverter(new TaskToProcessingPipelineConverter()); - registry.addConverter(new TaskToQueriesConverter(dslContext())); registry.addConverter(new TaskSearchDtoToSpecificationConverter()); registry.addConverter(new UserSearchDtoToSpecificationConverter()); } diff --git a/dl4se-server/src/main/java/usi/si/seart/converter/DtoToCodeProcessingConverter.java b/dl4se-server/src/main/java/usi/si/seart/converter/DtoToCodeProcessingConverter.java deleted file mode 100644 index 522b343c..00000000 --- a/dl4se-server/src/main/java/usi/si/seart/converter/DtoToCodeProcessingConverter.java +++ /dev/null @@ -1,23 +0,0 @@ -package usi.si.seart.converter; - -import org.springframework.core.convert.converter.Converter; -import org.springframework.lang.NonNull; -import usi.si.seart.dto.task.processing.CodeProcessingDto; -import usi.si.seart.model.task.processing.CodeProcessing; - -public class DtoToCodeProcessingConverter implements Converter { - - @Override - @NonNull - public CodeProcessing convert(@NonNull CodeProcessingDto source) { - return CodeProcessing.builder() - .removeDocstring(source.getRemoveDocstring()) - .removeInnerComments(source.getRemoveInnerComments()) - .maskToken(source.getMaskToken()) - .maskPercentage(source.getMaskPercentage()) - .maskContiguousOnly(source.getMaskContiguousOnly()) - .abstractCode(source.getAbstractCode()) - .abstractIdioms(source.getAbstractIdioms()) - .build(); - } -} diff --git a/dl4se-server/src/main/java/usi/si/seart/converter/GenericCodeQueryConverter.java b/dl4se-server/src/main/java/usi/si/seart/converter/GenericCodeQueryConverter.java deleted file mode 100644 index bd4dba7a..00000000 --- a/dl4se-server/src/main/java/usi/si/seart/converter/GenericCodeQueryConverter.java +++ /dev/null @@ -1,65 +0,0 @@ -package usi.si.seart.converter; - -import org.springframework.core.convert.TypeDescriptor; -import org.springframework.core.convert.converter.GenericConverter; -import usi.si.seart.dto.task.query.CodeQueryDto; -import usi.si.seart.dto.task.query.FileQueryDto; -import usi.si.seart.dto.task.query.FunctionQueryDto; -import usi.si.seart.model.task.query.CodeQuery; -import usi.si.seart.model.task.query.FileQuery; -import usi.si.seart.model.task.query.FunctionQuery; - -import java.util.Set; - -public class GenericCodeQueryConverter implements GenericConverter { - - @Override - public Set getConvertibleTypes() { - return Set.of( - new ConvertiblePair(FileQueryDto.class, CodeQuery.class), - new ConvertiblePair(FunctionQueryDto.class, CodeQuery.class) - ); - } - - @Override - public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { - Class sourceClass = sourceType.getType(); - if (sourceClass == FileQueryDto.class) { - FileQueryDto dto = (FileQueryDto) source; - FileQuery.FileQueryBuilder builder = FileQuery.builder(); - copyToBuilder(builder, dto); - return builder - .excludeUnparsable(dto.getExcludeUnparsable()) - .build(); - } else if (sourceClass == FunctionQueryDto.class) { - FunctionQueryDto dto = (FunctionQueryDto) source; - FunctionQuery.FunctionQueryBuilder builder = FunctionQuery.builder(); - copyToBuilder(builder, dto); - return builder - .excludeBoilerplate(dto.getExcludeBoilerplate()) - .build(); - } else { - throw new IllegalStateException(); - } - } - - private static void copyToBuilder(CodeQuery.CodeQueryBuilder builder, CodeQueryDto source) { - builder.hasLicense(source.getHasLicense()) - .excludeForks(source.getExcludeForks()) - .minCommits(source.getMinCommits()) - .minContributors(source.getMinContributors()) - .minIssues(source.getMinIssues()) - .minStars(source.getMinStars()) - .includeAst(source.getIncludeAst()) - .minTokens(source.getMinTokens()) - .maxTokens(source.getMaxTokens()) - .minLines(source.getMinLines()) - .maxLines(source.getMaxLines()) - .minCharacters(source.getMinCharacters()) - .maxCharacters(source.getMaxCharacters()) - .excludeDuplicates(source.getExcludeDuplicates()) - .excludeIdentical(source.getExcludeIdentical()) - .excludeTest(source.getExcludeTest()) - .excludeNonAscii(source.getExcludeNonAscii()); - } -} diff --git a/dl4se-server/src/main/java/usi/si/seart/converter/TaskToProcessingPipelineConverter.java b/dl4se-server/src/main/java/usi/si/seart/converter/TaskToProcessingPipelineConverter.java deleted file mode 100644 index 11d34a9b..00000000 --- a/dl4se-server/src/main/java/usi/si/seart/converter/TaskToProcessingPipelineConverter.java +++ /dev/null @@ -1,315 +0,0 @@ -package usi.si.seart.converter; - -import com.github.javaparser.ParseProblemException; -import com.github.javaparser.StaticJavaParser; -import com.github.javaparser.ast.Node; -import com.github.javaparser.ast.comments.Comment; -import com.github.javaparser.printer.XmlPrinter; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import lombok.Setter; -import lombok.experimental.FieldDefaults; -import lombok.experimental.NonFinal; -import org.antlr.v4.runtime.Token; -import org.springframework.core.convert.converter.Converter; -import org.springframework.lang.NonNull; -import usi.si.seart.function.CodeProcessingPipeline; -import usi.si.seart.model.code.Boilerplate; -import usi.si.seart.model.code.Code; -import usi.si.seart.model.code.File; -import usi.si.seart.model.code.Function; -import usi.si.seart.model.task.CodeTask; -import usi.si.seart.model.task.Task; -import usi.si.seart.model.task.processing.CodeProcessing; -import usi.si.seart.model.task.processing.Processing; -import usi.si.seart.model.task.query.CodeQuery; -import usi.si.seart.model.task.query.FileQuery; -import usi.si.seart.model.task.query.FunctionQuery; -import usi.si.seart.model.task.query.Query; -import usi.si.seart.src2abs.Abstractor; -import usi.si.seart.src2abs.Parser; -import usi.si.seart.src2abs.Tokenizer; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; -import java.util.TreeSet; -import java.util.concurrent.ThreadLocalRandom; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -public class TaskToProcessingPipelineConverter implements Converter { - - private static final XmlPrinter astPrinter = new XmlPrinter(true); - - @Override - @NonNull - public CodeProcessingPipeline convert(@NonNull Task source) { - if (source instanceof CodeTask) { - return convert((CodeTask) source); - } else { - throw new UnsupportedOperationException( - "Converter not implemented for task type: " + source.getClass().getName() - ); - } - } - - private CodeProcessingPipeline convert(CodeTask source) { - Query query = source.getQuery(); - Processing processing = source.getProcessing(); - if (query instanceof CodeQuery && processing instanceof CodeProcessing) { - return convert((CodeQuery) query, (CodeProcessing) processing); - } else { - throw new IllegalArgumentException(String.format( - "No processing mapping for (query, processing) tuple types: (%s, %s)", - query.getClass().getName(), - processing.getClass().getName() - )); - } - } - - private CodeProcessingPipeline convert(CodeQuery codeQuery, CodeProcessing codeProcessing) { - boolean includeAst = codeQuery.getIncludeAst(); - if (codeQuery instanceof FileQuery) { - return convert(codeProcessing, includeAst, File.class); - } else if (codeQuery instanceof FunctionQuery) { - return convert(codeProcessing, includeAst, Function.class); - } else { - throw new UnsupportedOperationException( - "Converter not implemented for code granularity: " + codeProcessing.getClass().getName() - ); - } - } - - // TODO 06.10.22: Extract each of the added pipeline functions into its own separate class - private CodeProcessingPipeline convert( - CodeProcessing codeProcessing, boolean includeAst, Class granularity - ) { - CodeProcessingPipeline pipeline = new CodeProcessingPipeline(); - - if (!includeAst) { - pipeline.add(map -> { - map.remove("ast"); - return map; - }); - } - - boolean removeDocstring = codeProcessing.getRemoveDocstring(); - boolean removeInnerComments = codeProcessing.getRemoveInnerComments(); - boolean abstractCode = codeProcessing.getAbstractCode(); - boolean maskCode = codeProcessing.getMaskPercentage() != null; - - if (removeDocstring || removeInnerComments) { - pipeline.add(map -> { - try { - String content = (String) map.get("content"); - Boilerplate boilerplate = Boilerplate.valueOfNullable(map.get("boilerplate_type")); - java.util.function.Function parser = getParser(granularity, boilerplate); - Node node = parser.apply(content); - Predicate predicate = generateCommentPredicate(removeDocstring, removeInnerComments); - List comments = node.getAllContainedComments(); - node.getComment().ifPresent(comments::add); - comments.stream().filter(predicate).forEach(Comment::remove); - map.put("content", node.toString()); - if (includeAst) { - map.put("ast", astPrinter.output(node)); - } - } catch (ParseProblemException | StackOverflowError ignore) {} - return map; - }); - } - - if (abstractCode) { - pipeline.add(map -> { - try { - String sourceCode = (String) map.get("content"); - Boilerplate boilerplate = Boilerplate.valueOfNullable(map.get("boilerplate_type")); - java.util.function.Function parser = getParser(granularity, boilerplate); - String cleanedCode = Abstractor.cleanCode(sourceCode); - Set idioms = new TreeSet<>(codeProcessing.getAbstractIdioms()); - Parser absParser = new Parser(); - absParser.parse(cleanedCode, parser); - Tokenizer tokenizer = new Tokenizer(absParser, idioms); - Node node = parser.apply(tokenizer.tokenize(sourceCode)); - map.put("content", node.toString()); - if (includeAst) { - map.put("ast", astPrinter.output(node)); - } - map.put("abstractions", tokenizer.export()); - } catch (ParseProblemException | StackOverflowError ignore) {} - return map; - }); - } - - // TODO 29.07.22: Use alternative method that does not remove comments - if (maskCode) { - pipeline.add(map -> { - try { - String sourceCode = (String) map.get("content"); - // TODO 12.10.22: Use a utility for this instead - sourceCode = sourceCode.replaceAll("\\s+", " "); - int percentage = codeProcessing.getMaskPercentage(); - boolean contiguous = codeProcessing.getMaskContiguousOnly(); - String maskToken = codeProcessing.getMaskToken(); - List tokens = Tokenizer.readTokens(sourceCode); - List wrapped = generateSelector(percentage, contiguous).apply(tokens); - LinkedList> groupedWrapped = wrapped.stream().collect( - LinkedList::new, - (lists, wrapper) -> { - if (lists.isEmpty()) { - withNewList(lists, wrapper); - } else { - withNewString(lists, wrapper); - } - }, - LinkedList::addAll - ); - - map.put("content", mask(groupedWrapped, maskToken)); - map.put("oracle", oracle(groupedWrapped, maskToken)); - map.remove("ast"); - } catch (StackOverflowError ignore) {} - return map; - }); - } - - return pipeline; - } - - // TODO 19.10.22: Move this to the `Code` class hierarchy - private static final java.util.function.Function fileParser = StaticJavaParser::parse; - private static final java.util.function.Function functionParser = StaticJavaParser::parseMethodDeclaration; - private static final java.util.function.Function constructorParser = StaticJavaParser::parseBodyDeclaration; - private static java.util.function.Function getParser( - Class granularity, Boilerplate boilerplate - ) { - if (granularity == File.class) { - return fileParser; - } else if (granularity == Function.class) { - if (Boilerplate.CONSTRUCTOR == boilerplate) { - return constructorParser; - } else { - return functionParser; - } - } else { - throw new IllegalArgumentException( - "Parser not mapped for code granularity: " + granularity.getName() - ); - } - } - - private static final Predicate IS_ANY_COMMENT = comment -> true; - private static final Predicate IS_LINE_COMMENT = Comment::isLineComment; - private static final Predicate IS_BLOCK_COMMENT = Comment::isBlockComment; - private static final Predicate IS_JAVADOC_COMMENT = Comment::isJavadocComment; - private static Predicate generateCommentPredicate(boolean removeDocstring, boolean removeInnerComments) { - Predicate predicate; - if (removeInnerComments && removeDocstring) { - predicate = IS_ANY_COMMENT; - } else if (removeDocstring) { - predicate = IS_JAVADOC_COMMENT; - } else { - predicate = IS_LINE_COMMENT.or(IS_BLOCK_COMMENT); - } - return predicate; - } - - @Getter - @Setter - @RequiredArgsConstructor - @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) - private static class TokenWrapper { - - Token token; - int ordinal; - @NonFinal - boolean selected = false; - - public void select() { - selected = true; - } - } - - private java.util.function.Function, List> generateSelector( - int percentage, boolean contiguous - ) { - return tokens -> { - List wrapped = new ArrayList<>(tokens.size()); - for (int i = 0; i < tokens.size(); i++) { - wrapped.add(new TokenWrapper(tokens.get(i), i)); - } - if (!contiguous) Collections.shuffle(wrapped); - int startMax = wrapped.size() * (100 - percentage) / 100; - for ( - int i = ThreadLocalRandom.current().nextInt(startMax + 1), selected = 0; - (i < wrapped.size()) && (selected < (wrapped.size() * percentage / 100)); - i++, selected++ - ) { - wrapped.get(i).select(); - } - if (!contiguous) wrapped.sort(Comparator.comparingInt(TokenWrapper::getOrdinal)); - return wrapped; - }; - } - - private void withNewList(LinkedList> groups, TokenWrapper token) { - LinkedList group = new LinkedList<>(); - group.add(token); - groups.add(group); - } - - private void withNewString(LinkedList> groups, TokenWrapper token) { - LinkedList prevGroup = groups.getLast(); - if (prevGroup.getLast().isSelected() == token.isSelected()) { - prevGroup.add(token); - } else { - withNewList(groups, token); - } - } - - private String mask(LinkedList> groups, String maskToken) { - return applyMasking(groups, (group) -> group.getFirst().isSelected(), maskToken); - } - - private String oracle(LinkedList> groups, String maskToken) { - return applyMasking(groups, (group) -> !group.getFirst().isSelected(), maskToken); - } - - private String applyMasking( - LinkedList> groups, Predicate> predicate, String maskToken - ) { - StringBuilder stringBuilder = new StringBuilder(); - int count = 1; - for (LinkedList group : groups) { - if (predicate.test(group)) { - stringBuilder.append("<").append(maskToken).append("_").append(count).append("> "); - count += 1; - } else { - List tokens = group.stream() - .map(TokenWrapper::getToken) - .collect(Collectors.toList()); - String joined = joinTokens(tokens); - stringBuilder.append(joined).append(" "); - } - } - return stringBuilder.toString().stripTrailing(); - } - - private String joinTokens(List tokens) { - StringBuilder stringBuilder = new StringBuilder(); - Token prev = tokens.get(0); - stringBuilder.append(prev.getText()); - for (int i = 1; i < tokens.size(); i++) { - Token curr = tokens.get(i); - if (curr.getStartIndex() - prev.getStopIndex() > 1) - stringBuilder.append(" "); - stringBuilder.append(curr.getText()); - prev = curr; - } - return stringBuilder.toString(); - } -} diff --git a/dl4se-server/src/main/java/usi/si/seart/converter/TaskToQueriesConverter.java b/dl4se-server/src/main/java/usi/si/seart/converter/TaskToQueriesConverter.java deleted file mode 100644 index f7cf5e82..00000000 --- a/dl4se-server/src/main/java/usi/si/seart/converter/TaskToQueriesConverter.java +++ /dev/null @@ -1,274 +0,0 @@ -package usi.si.seart.converter; - -import lombok.AllArgsConstructor; -import org.jooq.Condition; -import org.jooq.DSLContext; -import org.jooq.Field; -import org.jooq.Param; -import org.jooq.Queries; -import org.jooq.SelectFieldOrAsterisk; -import org.jooq.Table; -import org.jooq.impl.DSL; -import org.springframework.core.convert.converter.Converter; -import org.springframework.lang.NonNull; -import usi.si.seart.model.task.CodeTask; -import usi.si.seart.model.task.Task; -import usi.si.seart.model.task.processing.CodeProcessing; -import usi.si.seart.model.task.processing.Processing; -import usi.si.seart.model.task.query.CodeQuery; -import usi.si.seart.model.task.query.FileQuery; -import usi.si.seart.model.task.query.FunctionQuery; -import usi.si.seart.model.task.query.Query; - -import java.util.ArrayList; -import java.util.List; - -@AllArgsConstructor -public class TaskToQueriesConverter implements Converter { - - private final DSLContext dslCtx; - - @Override - @NonNull - public Queries convert(@NonNull Task source) { - if (source instanceof CodeTask) { - return convert((CodeTask) source); - } else { - throw new UnsupportedOperationException( - "Converter not implemented for task type: " + source.getClass().getName() - ); - } - } - - private Queries convert(CodeTask source) { - Query query = source.getQuery(); - Processing processing = source.getProcessing(); - Long checkpointId = source.getCheckpointId(); - if (query instanceof CodeQuery && processing instanceof CodeProcessing) { - return convert((CodeQuery) query, (CodeProcessing) processing, checkpointId); - } else { - throw new IllegalArgumentException(String.format( - "No SQL mapping for (query, processing) tuple types: (%s, %s)", - query.getClass().getName(), - processing.getClass().getName() - )); - } - } - - private Queries convert(CodeQuery codeQuery, CodeProcessing codeProcessing, Long checkpointId) { - org.jooq.Query resultQuery = getResultQuery(codeQuery, codeProcessing, checkpointId); - org.jooq.Query countQuery = getCountQuery(codeQuery, codeProcessing); - return DSL.queries(resultQuery, countQuery); - } - - @SuppressWarnings("ConstantConditions") - private org.jooq.Query getResultQuery(CodeQuery codeQuery, CodeProcessing codeProcessing, Long checkpointId) { - Table codeTable = getDerivedCodeTable(codeQuery, codeProcessing, checkpointId); - Table langTable = getDerivedLangTable(codeQuery); - Table repoTable = getDerivedRepoTable(codeQuery); - - Field codeTableId = codeTable.field("id", Long.class); - Field langTableId = langTable.field("id", Long.class); - Field repoTableId = repoTable.field("id", Long.class); - Field codeTableLangId = codeTable.field("lang_id", Long.class); - Field codeTableRepoId = codeTable.field("repo_id", Long.class); - - return DSL.select(codeTable.fields()) - .from(codeTable) - .innerJoin(langTable) - .on(codeTableLangId.equal(langTableId)) - .innerJoin(repoTable) - .on(codeTableRepoId.equal(repoTableId)) - .orderBy(codeTableId) - .getQuery(); - } - - @SuppressWarnings("ConstantConditions") - private org.jooq.Query getCountQuery(CodeQuery codeQuery, CodeProcessing codeProcessing) { - Table codeTable = getDerivedCodeTable(codeQuery, codeProcessing, null); - Table langTable = getDerivedLangTable(codeQuery); - Table repoTable = getDerivedRepoTable(codeQuery); - - Field codeTableId = codeTable.field("id", Long.class); - Field langTableId = langTable.field("id", Long.class); - Field repoTableId = repoTable.field("id", Long.class); - Field codeTableLangId = codeTable.field("lang_id", Long.class); - Field codeTableRepoId = codeTable.field("repo_id", Long.class); - - return DSL.select(DSL.count(codeTableId)) - .from(codeTable) - .innerJoin(langTable) - .on(codeTableLangId.equal(langTableId)) - .innerJoin(repoTable) - .on(codeTableRepoId.equal(repoTableId)) - .getQuery(); - } - - private Table getDerivedCodeTable(CodeQuery codeQuery, CodeProcessing codeProcessing, Long checkpointId) { - Field id = DSL.field("id", Long.class); - Field repoId = DSL.field("repo_id", Long.class); - Field langId = DSL.field("lang_id", Long.class); - Field path = DSL.field("path", String.class); - Field fileId = DSL.field("file_id", Long.class); - Field content = DSL.field("content", String.class); - Field contentHash = DSL.field("content_hash", String.class); - Field ast = DSL.field("ast", String.class); - Field astHash = DSL.field("ast_hash", String.class); - Field totalTokens = DSL.field("total_tokens", Long.class); - Field codeTokens = DSL.field("code_tokens", Long.class); - Field lines = DSL.field("lines", Long.class); - Field characters = DSL.field("characters", Long.class); - Field isTest = DSL.field("is_test", Boolean.class); - Field containsNonAscii = DSL.field("contains_non_ascii", Boolean.class); - Field isParsed = DSL.field("is_parsed", Boolean.class); - Field boilerplateType = DSL.field("boilerplate_type", String.class); - - List> fields = new ArrayList<>(); - fields.add(id); - fields.add(repoId); - fields.add(langId); - if (codeQuery instanceof FileQuery) { - fields.add(path); - fields.add(isParsed); - } - if (codeQuery instanceof FunctionQuery) fields.add(fileId); - fields.add(content); - fields.add(contentHash); - fields.add(ast); - fields.add(astHash); - fields.add(totalTokens); - fields.add(codeTokens); - fields.add(lines); - fields.add(characters); - fields.add(isTest); - fields.add(containsNonAscii); - if (codeQuery instanceof FunctionQuery) fields.add(boilerplateType); - - boolean excludeDuplicates = codeQuery.getExcludeDuplicates(); - boolean excludeIdentical = codeQuery.getExcludeIdentical(); - List distinctColumn; - if (excludeIdentical) { - distinctColumn = List.of(astHash); - } else if (excludeDuplicates) { - distinctColumn = List.of(contentHash); - } else { - distinctColumn = List.of(); - } - - String tableName; - boolean excludeUnparsable = false; - boolean excludeBoilerplate = false; - if (codeQuery instanceof FileQuery) { - tableName = "file"; - excludeUnparsable = ((FileQuery) codeQuery).getExcludeUnparsable(); - } else if (codeQuery instanceof FunctionQuery) { - tableName = "function"; - excludeBoilerplate = ((FunctionQuery) codeQuery).getExcludeBoilerplate(); - } else { - throw new IllegalArgumentException( - "No SQL mapping for query type: ["+codeQuery.getClass().getName()+"]" - ); - } - - boolean excludeTest = codeQuery.getExcludeTest(); - boolean excludeNonAscii = codeQuery.getExcludeNonAscii(); - Long minLines = codeQuery.getMinLines(); - Long maxLines = codeQuery.getMaxLines(); - Long minTokens = codeQuery.getMinTokens(); - Long maxTokens = codeQuery.getMaxTokens(); - Long minChars = codeQuery.getMinCharacters(); - Long maxChars = codeQuery.getMaxCharacters(); - - boolean removeDocstring = codeProcessing.getRemoveDocstring(); - boolean removeInnerComments = codeProcessing.getRemoveInnerComments(); - Field tokens; - if (removeDocstring && removeInnerComments) { - tokens = codeTokens; - } else { - tokens = totalTokens; - } - - Param minId = DSL.param("checkpoint_id", checkpointId); - Param notTest = DSL.param("is_test", false); - Param ascii = DSL.param("non_ascii", false); - Param parsed = DSL.param("is_parsed", true); - - List conditions = new ArrayList<>(); - conditions.add(getRangeCondition(lines, minLines, maxLines)); - conditions.add(getRangeCondition(characters, minChars, maxChars)); - conditions.add(getRangeCondition(tokens, minTokens, maxTokens)); - if (excludeTest) conditions.add(isTest.equal(notTest)); - if (excludeNonAscii) conditions.add(containsNonAscii.equal(ascii)); - if (excludeUnparsable) conditions.add(isParsed.equal(parsed)); - if (excludeBoilerplate) conditions.add(boilerplateType.isNull()); - if (minId.getValue() != null) conditions.add(id.greaterThan(minId)); - - return dslCtx.select(fields) - .distinctOn(distinctColumn) - .from(tableName) - .where(conditions) - .asTable("f"); - } - - private Table getDerivedLangTable(CodeQuery codeQuery) { - Field id = DSL.field("id", Long.class); - Param idParam = DSL.param("lang_id", codeQuery.getLanguage().getId()); - return dslCtx.select(id) - .from("language") - .where(id.equal(idParam)) - .asTable("l"); - } - - private Table getDerivedRepoTable(Query query) { - boolean hasLicense = query.getHasLicense(); - boolean excludeForks = query.getExcludeForks(); - - Param minCommits = DSL.param("commits_min", query.getMinCommits()); - Param minContributors = DSL.param("contributors_min", query.getMinContributors()); - Param minIssues = DSL.param("issues_min", query.getMinIssues()); - Param minStars = DSL.param("stars_min", query.getMinStars()); - Param notFork = DSL.param("fork", false); - - Field id = DSL.field("id", Long.class); - Field license = DSL.field("license", String.class); - Field isFork = DSL.field("is_fork", Boolean.class); - Field commits = DSL.field("commits", Long.class); - Field contributors = DSL.field("contributors", Long.class); - Field issues = DSL.field("issues", Long.class); - Field stars = DSL.field("stars", Long.class); - - List conditions = new ArrayList<>(); - conditions.add(commits.greaterOrEqual(minCommits)); - conditions.add(contributors.greaterOrEqual(minContributors)); - conditions.add(issues.greaterOrEqual(minIssues)); - conditions.add(stars.greaterOrEqual(minStars)); - if (excludeForks) conditions.add(isFork.equal(notFork)); - if (hasLicense) conditions.add(license.isNotNull()); - - return dslCtx.select(id) - .from("git_repo") - .where(conditions) - .asTable("gr"); - } - - private static Condition getRangeCondition(Field field, T lower, T upper) { - Param lowerParam; - Param upperParam; - if (lower != null) { - lowerParam = DSL.param(field.getName()+"_min", lower); - if (upper != null) { - upperParam = DSL.param(field.getName()+"_max", upper); - return field.between(lowerParam, upperParam); - } else { - return field.greaterOrEqual(lowerParam); - } - } else { - if (upper != null) { - upperParam = DSL.param(field.getName()+"_max", upper); - return field.lessOrEqual(upperParam); - } else { - return DSL.noCondition(); - } - } - } -} diff --git a/dl4se-server/src/main/java/usi/si/seart/function/CodeProcessingPipeline.java b/dl4se-server/src/main/java/usi/si/seart/function/CodeProcessingPipeline.java deleted file mode 100644 index d5e23182..00000000 --- a/dl4se-server/src/main/java/usi/si/seart/function/CodeProcessingPipeline.java +++ /dev/null @@ -1,35 +0,0 @@ -package usi.si.seart.function; - -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import lombok.NoArgsConstructor; -import usi.si.seart.model.code.Code; - -import java.text.SimpleDateFormat; -import java.util.Map; -import java.util.function.Function; -import java.util.function.UnaryOperator; - -@NoArgsConstructor -public class CodeProcessingPipeline implements Function> { - - private static final ObjectMapper objectMapper; - static { - objectMapper = new ObjectMapper(); - objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss")); - objectMapper.registerModule(new JavaTimeModule()); - } - - private Function, Map> pipeline = Function.identity(); - - public void add(UnaryOperator> operation) { - pipeline = pipeline.andThen(operation); - } - - @Override - public Map apply(Code code) { - Map map = objectMapper.convertValue(code, new TypeReference<>() {}); - return pipeline.apply(map); - } -} From a738fa92f8c5e11d7aa1c32d02ccc65a7323eace Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 9 Oct 2023 12:17:38 +0200 Subject: [PATCH 0354/1089] Distinct content and ast hashes are now stored in dedicated views --- .../seart/views/code/FileAstHashDistinct.java | 9 ++++ .../views/code/FileContentHashDistinct.java | 9 ++++ .../views/code/FunctionAstHashDistinct.java | 9 ++++ .../code/FunctionContentHashDistinct.java | 9 ++++ .../usi/si/seart/views/code/HashDistinct.java | 44 +++++++++++++++++++ liquibase/scripts/02_view.sql | 28 ++++++++++++ 6 files changed, 108 insertions(+) create mode 100644 dl4se-model/src/main/java/usi/si/seart/views/code/FileAstHashDistinct.java create mode 100644 dl4se-model/src/main/java/usi/si/seart/views/code/FileContentHashDistinct.java create mode 100644 dl4se-model/src/main/java/usi/si/seart/views/code/FunctionAstHashDistinct.java create mode 100644 dl4se-model/src/main/java/usi/si/seart/views/code/FunctionContentHashDistinct.java create mode 100644 dl4se-model/src/main/java/usi/si/seart/views/code/HashDistinct.java diff --git a/dl4se-model/src/main/java/usi/si/seart/views/code/FileAstHashDistinct.java b/dl4se-model/src/main/java/usi/si/seart/views/code/FileAstHashDistinct.java new file mode 100644 index 00000000..ed2b23cf --- /dev/null +++ b/dl4se-model/src/main/java/usi/si/seart/views/code/FileAstHashDistinct.java @@ -0,0 +1,9 @@ +package usi.si.seart.views.code; + +import javax.persistence.Entity; +import javax.persistence.Table; + +@Entity +@Table(name = "file_ast_hash_distinct") +public class FileAstHashDistinct extends HashDistinct { +} diff --git a/dl4se-model/src/main/java/usi/si/seart/views/code/FileContentHashDistinct.java b/dl4se-model/src/main/java/usi/si/seart/views/code/FileContentHashDistinct.java new file mode 100644 index 00000000..88316356 --- /dev/null +++ b/dl4se-model/src/main/java/usi/si/seart/views/code/FileContentHashDistinct.java @@ -0,0 +1,9 @@ +package usi.si.seart.views.code; + +import javax.persistence.Entity; +import javax.persistence.Table; + +@Entity +@Table(name = "file_content_hash_distinct") +public class FileContentHashDistinct extends HashDistinct { +} diff --git a/dl4se-model/src/main/java/usi/si/seart/views/code/FunctionAstHashDistinct.java b/dl4se-model/src/main/java/usi/si/seart/views/code/FunctionAstHashDistinct.java new file mode 100644 index 00000000..5cb70c69 --- /dev/null +++ b/dl4se-model/src/main/java/usi/si/seart/views/code/FunctionAstHashDistinct.java @@ -0,0 +1,9 @@ +package usi.si.seart.views.code; + +import javax.persistence.Entity; +import javax.persistence.Table; + +@Entity +@Table(name = "function_ast_hash_distinct") +public class FunctionAstHashDistinct extends HashDistinct { +} diff --git a/dl4se-model/src/main/java/usi/si/seart/views/code/FunctionContentHashDistinct.java b/dl4se-model/src/main/java/usi/si/seart/views/code/FunctionContentHashDistinct.java new file mode 100644 index 00000000..18e452cd --- /dev/null +++ b/dl4se-model/src/main/java/usi/si/seart/views/code/FunctionContentHashDistinct.java @@ -0,0 +1,9 @@ +package usi.si.seart.views.code; + +import javax.persistence.Entity; +import javax.persistence.Table; + +@Entity +@Table(name = "function_content_hash_distinct") +public class FunctionContentHashDistinct extends HashDistinct { +} diff --git a/dl4se-model/src/main/java/usi/si/seart/views/code/HashDistinct.java b/dl4se-model/src/main/java/usi/si/seart/views/code/HashDistinct.java new file mode 100644 index 00000000..72688b48 --- /dev/null +++ b/dl4se-model/src/main/java/usi/si/seart/views/code/HashDistinct.java @@ -0,0 +1,44 @@ +package usi.si.seart.views.code; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.experimental.FieldDefaults; +import org.hibernate.annotations.Immutable; +import usi.si.seart.validation.constraints.Hash; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; +import java.util.Objects; + +@Entity +@Getter +@Immutable +@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PROTECTED) +@FieldDefaults(level = AccessLevel.PROTECTED) +public abstract class HashDistinct { + + @Id + Long id; + + @Hash + String hash; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + HashDistinct that = (HashDistinct) o; + return Objects.equals(id, that.id); + } + + @Override + public int hashCode() { + return Objects.hash(id, hash); + } +} diff --git a/liquibase/scripts/02_view.sql b/liquibase/scripts/02_view.sql index 730cc79e..054c065c 100644 --- a/liquibase/scripts/02_view.sql +++ b/liquibase/scripts/02_view.sql @@ -1,6 +1,34 @@ -- liquibase formatted sql -- changeset dabico:3 +CREATE OR REPLACE VIEW file_content_hash_distinct AS +SELECT + MIN(id) AS id, + content_hash AS hash +FROM file +GROUP BY content_hash; + +CREATE OR REPLACE VIEW file_ast_hash_distinct AS +SELECT + MIN(id) AS id, + ast_hash AS hash +FROM file +GROUP BY ast_hash; + +CREATE OR REPLACE VIEW function_content_hash_distinct AS +SELECT + MIN(id) AS id, + content_hash AS hash +FROM function +GROUP BY content_hash; + +CREATE OR REPLACE VIEW function_ast_hash_distinct AS +SELECT + MIN(id) AS id, + ast_hash AS hash +FROM function +GROUP BY ast_hash; + CREATE MATERIALIZED VIEW table_counts AS SELECT 'user' AS "table", COUNT(id) FROM "user" UNION From eec929402df93405bf2471a85fb9d5f69ca0075b Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 9 Oct 2023 12:18:55 +0200 Subject: [PATCH 0355/1089] `Code` specification now makes use of the newly introduced views The reason this was also done was to better optimize the query plan. This should lead to better performance in the long term. --- .../TaskToCodeSpecificationConverter.java | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/converter/TaskToCodeSpecificationConverter.java b/dl4se-server/src/main/java/usi/si/seart/converter/TaskToCodeSpecificationConverter.java index 0f5c119b..39c19849 100644 --- a/dl4se-server/src/main/java/usi/si/seart/converter/TaskToCodeSpecificationConverter.java +++ b/dl4se-server/src/main/java/usi/si/seart/converter/TaskToCodeSpecificationConverter.java @@ -17,6 +17,8 @@ import usi.si.seart.model.code.Function_; import usi.si.seart.model.job.Job; import usi.si.seart.model.task.Task; +import usi.si.seart.views.code.HashDistinct; +import usi.si.seart.views.code.HashDistinct_; import javax.persistence.criteria.Expression; import javax.persistence.criteria.Path; @@ -229,16 +231,15 @@ private Specification convert( .map(JsonNode::asBoolean) .orElse(false); if (excludeIdentical || excludeDuplicates) { - Path path = root.get(Code_.id); - SingularAttribute distinct = excludeIdentical - ? Code_.astHash - : Code_.contentHash; - Subquery subselect = criteriaQuery.subquery(Long.class); - Root subselectRoot = subselect.from(granularity); - subselect.select(criteriaBuilder.min(subselectRoot.get(Code_.id))); - subselect.groupBy(subselectRoot.get(distinct)); - Expression expression = subselect.getSelection(); - Predicate predicate = path.in(expression); + Class distinct = getViewClass(granularity.getSimpleName(), excludeIdentical); + Subquery subquery = criteriaQuery.subquery(Boolean.class); + Root subroot = subquery.from(distinct); + Path codePath = root.get(Code_.id); + Path hashPath = subroot.get(HashDistinct_.id); + Expression ignored = criteriaBuilder.literal(true); + Predicate equal = criteriaBuilder.equal(codePath, hashPath); + subquery.select(ignored).where(equal); + Predicate predicate = criteriaBuilder.exists(subquery); predicates.add(predicate); } @@ -286,4 +287,16 @@ private Specification convert( return criteriaBuilder.and(predicates.toArray(Predicate[]::new)); }; } + + @SuppressWarnings("unchecked") + private static Class getViewClass(String granularity, boolean identical) { + try { + String pkg = HashDistinct.class.getPackageName(); + String category = identical ? "Ast" : "Content"; + String name = String.format("%s.%s%sHashDistinct", pkg, granularity, category); + return (Class) Class.forName(name); + } catch (ClassNotFoundException ignored) { + throw new IllegalArgumentException("No hash view for granularity: " + granularity); + } + } } From f7e98095287e497512d478b2602c632d3506082c Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 9 Oct 2023 12:24:16 +0200 Subject: [PATCH 0356/1089] Segregating regular from materialized views --- liquibase/changelog.xml | 1 + liquibase/scripts/02_view.sql | 34 ------------------------- liquibase/scripts/03_materialize.sql | 38 ++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 34 deletions(-) create mode 100644 liquibase/scripts/03_materialize.sql diff --git a/liquibase/changelog.xml b/liquibase/changelog.xml index 5b1f4084..1ac69dac 100644 --- a/liquibase/changelog.xml +++ b/liquibase/changelog.xml @@ -6,4 +6,5 @@ http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.23.xsd"> + diff --git a/liquibase/scripts/02_view.sql b/liquibase/scripts/02_view.sql index 054c065c..6c252f36 100644 --- a/liquibase/scripts/02_view.sql +++ b/liquibase/scripts/02_view.sql @@ -28,37 +28,3 @@ SELECT ast_hash AS hash FROM function GROUP BY ast_hash; - -CREATE MATERIALIZED VIEW table_counts AS -SELECT 'user' AS "table", COUNT(id) FROM "user" -UNION -SELECT 'task' AS "table", COUNT(id) FROM task -UNION -SELECT 'git_repo' AS "table", COUNT(id) FROM git_repo -UNION -SELECT 'file' AS "table", COUNT(id) FROM file -UNION -SELECT 'function' AS "table", COUNT(id) FROM function; - -CREATE MATERIALIZED VIEW git_repos_by_language AS -SELECT l.id AS lang_id, COUNT(l.id) FROM git_repo gr -INNER JOIN git_repo_language grl ON gr.id = grl.repo_id -INNER JOIN language l on l.id = grl.lang_id -GROUP BY l.id; - -CREATE MATERIALIZED VIEW files_by_language AS -SELECT l.id AS lang_id, COUNT(l.id) FROM file f -INNER JOIN language l ON f.lang_id = l.id GROUP BY l.id; - -CREATE MATERIALIZED VIEW functions_by_language AS -SELECT l.id AS lang_id, COUNT(l.id) FROM function f -INNER JOIN language l ON f.lang_id = l.id GROUP BY l.id; - -CREATE MATERIALIZED VIEW code_size_in_bytes AS -SELECT SUM(characters) AS size FROM file; - -CREATE UNIQUE INDEX ON table_counts("table"); -CREATE UNIQUE INDEX ON git_repos_by_language(lang_id); -CREATE UNIQUE INDEX ON files_by_language(lang_id); -CREATE UNIQUE INDEX ON functions_by_language(lang_id); -CREATE UNIQUE INDEX ON code_size_in_bytes(size); diff --git a/liquibase/scripts/03_materialize.sql b/liquibase/scripts/03_materialize.sql new file mode 100644 index 00000000..1d80212b --- /dev/null +++ b/liquibase/scripts/03_materialize.sql @@ -0,0 +1,38 @@ +-- liquibase formatted sql +-- changeset dabico:4 + +CREATE MATERIALIZED VIEW table_counts AS +SELECT 'user' AS "table", COUNT(id) FROM "user" +UNION +SELECT 'task' AS "table", COUNT(id) FROM task +UNION +SELECT 'git_repo' AS "table", COUNT(id) FROM git_repo +UNION +SELECT 'file' AS "table", COUNT(id) FROM file +UNION +SELECT 'function' AS "table", COUNT(id) FROM function; + +CREATE MATERIALIZED VIEW git_repos_by_language AS +SELECT l.id AS lang_id, COUNT(l.id) FROM git_repo gr +INNER JOIN git_repo_language grl ON gr.id = grl.repo_id +INNER JOIN language l on l.id = grl.lang_id +GROUP BY l.id; + +CREATE MATERIALIZED VIEW files_by_language AS +SELECT l.id AS lang_id, COUNT(l.id) FROM file f +INNER JOIN language l ON f.lang_id = l.id +GROUP BY l.id; + +CREATE MATERIALIZED VIEW functions_by_language AS +SELECT l.id AS lang_id, COUNT(l.id) FROM function f +INNER JOIN language l ON f.lang_id = l.id +GROUP BY l.id; + +CREATE MATERIALIZED VIEW code_size_in_bytes AS +SELECT SUM(characters) AS size FROM file; + +CREATE UNIQUE INDEX ON table_counts("table"); +CREATE UNIQUE INDEX ON git_repos_by_language(lang_id); +CREATE UNIQUE INDEX ON files_by_language(lang_id); +CREATE UNIQUE INDEX ON functions_by_language(lang_id); +CREATE UNIQUE INDEX ON code_size_in_bytes(size); From 865eac4bdc513d20288d64c9f55cc07b03f588bd Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 9 Oct 2023 14:53:00 +0200 Subject: [PATCH 0357/1089] The `Page` and `Sort` serializers now both implement `StdSerializer` This is the recommended approach compared to the one we were using. --- .../main/java/usi/si/seart/config/MainConfig.java | 6 ++---- .../java/usi/si/seart/jackson/PageSerializer.java | 12 ++++++++---- .../java/usi/si/seart/jackson/SortSerializer.java | 8 ++++++-- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/config/MainConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/MainConfig.java index cb96ef04..4fbdbe9f 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/MainConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/MainConfig.java @@ -7,8 +7,6 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.Sort; import org.springframework.format.FormatterRegistry; import org.springframework.lang.NonNull; import org.springframework.web.servlet.config.annotation.CorsRegistry; @@ -39,8 +37,8 @@ public JsonMapper jsonMapper() { jsonMapper.registerModules( new JavaTimeModule(), new SimpleModule("dl4se-spring-data-custom", Version.unknownVersion()) - .addSerializer(Sort.class, SortSerializer.INSTANCE) - .addSerializer(PageImpl.class, PageSerializer.INSTANCE) + .addSerializer(SortSerializer.INSTANCE) + .addSerializer(PageSerializer.INSTANCE) ); return jsonMapper; } diff --git a/dl4se-server/src/main/java/usi/si/seart/jackson/PageSerializer.java b/dl4se-server/src/main/java/usi/si/seart/jackson/PageSerializer.java index f9ea2366..ec289a90 100644 --- a/dl4se-server/src/main/java/usi/si/seart/jackson/PageSerializer.java +++ b/dl4se-server/src/main/java/usi/si/seart/jackson/PageSerializer.java @@ -1,18 +1,22 @@ package usi.si.seart.jackson; import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; -import org.springframework.data.domain.PageImpl; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import org.springframework.data.domain.Page; import java.io.IOException; -public class PageSerializer extends JsonSerializer { +public class PageSerializer extends StdSerializer> { + + public PageSerializer() { + super(Page.class, false); + } public static final PageSerializer INSTANCE = new PageSerializer(); @Override - public void serialize(PageImpl value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + public void serialize(Page value, JsonGenerator gen, SerializerProvider serializers) throws IOException { gen.writeStartObject(); gen.writeNumberField("page", value.getNumber() + 1); diff --git a/dl4se-server/src/main/java/usi/si/seart/jackson/SortSerializer.java b/dl4se-server/src/main/java/usi/si/seart/jackson/SortSerializer.java index a762550e..73ec52f8 100644 --- a/dl4se-server/src/main/java/usi/si/seart/jackson/SortSerializer.java +++ b/dl4se-server/src/main/java/usi/si/seart/jackson/SortSerializer.java @@ -1,16 +1,20 @@ package usi.si.seart.jackson; import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; import org.springframework.data.domain.Sort; import java.io.IOException; -public class SortSerializer extends JsonSerializer { +public class SortSerializer extends StdSerializer { public static final SortSerializer INSTANCE = new SortSerializer(); + public SortSerializer() { + super(Sort.class); + } + @Override public void serialize(Sort value, JsonGenerator gen, SerializerProvider serializers) throws IOException { gen.writeStartArray(); From a8295368ddb515e6d043987acd8f79caf1c0764d Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 9 Oct 2023 15:04:27 +0200 Subject: [PATCH 0358/1089] Web-related configurations are now separated into a dedicated class --- .../java/usi/si/seart/config/MainConfig.java | 29 ------------------ .../java/usi/si/seart/config/WebConfig.java | 30 +++++++++++++++++++ 2 files changed, 30 insertions(+), 29 deletions(-) create mode 100644 dl4se-server/src/main/java/usi/si/seart/config/WebConfig.java diff --git a/dl4se-server/src/main/java/usi/si/seart/config/MainConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/MainConfig.java index 4fbdbe9f..5a63985d 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/MainConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/MainConfig.java @@ -7,14 +7,6 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.format.FormatterRegistry; -import org.springframework.lang.NonNull; -import org.springframework.web.servlet.config.annotation.CorsRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import usi.si.seart.converter.DtoToConfigurationConverter; -import usi.si.seart.converter.DtoToUserConverter; -import usi.si.seart.converter.TaskSearchDtoToSpecificationConverter; -import usi.si.seart.converter.UserSearchDtoToSpecificationConverter; import usi.si.seart.jackson.PageSerializer; import usi.si.seart.jackson.SortSerializer; @@ -47,25 +39,4 @@ public JsonMapper jsonMapper() { public DateFormat dateFormat() { return new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss"); } - - @Bean - public WebMvcConfigurer webConfigurer() { - return new WebMvcConfigurer() { - @Override - public void addCorsMappings(@NonNull final CorsRegistry registry) { - registry.addMapping("/**") - .allowedMethods("*") - .allowedOrigins("*") - .exposedHeaders("Content-Type", "Content-Disposition", "Content-Length", "Date"); - } - - @Override - public void addFormatters(@NonNull final FormatterRegistry registry) { - registry.addConverter(new DtoToUserConverter()); - registry.addConverter(new DtoToConfigurationConverter()); - registry.addConverter(new TaskSearchDtoToSpecificationConverter()); - registry.addConverter(new UserSearchDtoToSpecificationConverter()); - } - }; - } } diff --git a/dl4se-server/src/main/java/usi/si/seart/config/WebConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/WebConfig.java new file mode 100644 index 00000000..27d261d8 --- /dev/null +++ b/dl4se-server/src/main/java/usi/si/seart/config/WebConfig.java @@ -0,0 +1,30 @@ +package usi.si.seart.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.format.FormatterRegistry; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import usi.si.seart.converter.DtoToConfigurationConverter; +import usi.si.seart.converter.DtoToUserConverter; +import usi.si.seart.converter.TaskSearchDtoToSpecificationConverter; +import usi.si.seart.converter.UserSearchDtoToSpecificationConverter; + +@Configuration +public class WebConfig implements WebMvcConfigurer { + + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedMethods("*") + .allowedOrigins("*") + .exposedHeaders("Content-Type", "Content-Disposition", "Content-Length", "Date"); + } + + @Override + public void addFormatters(FormatterRegistry registry) { + registry.addConverter(new DtoToUserConverter()); + registry.addConverter(new DtoToConfigurationConverter()); + registry.addConverter(new TaskSearchDtoToSpecificationConverter()); + registry.addConverter(new UserSearchDtoToSpecificationConverter()); + } +} From a8b1857392bf9cdedcb68fa29a1b68a3fa117cb1 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 9 Oct 2023 15:06:21 +0200 Subject: [PATCH 0359/1089] Both custom serializer constructors now have private access --- .../src/main/java/usi/si/seart/jackson/PageSerializer.java | 6 +++--- .../src/main/java/usi/si/seart/jackson/SortSerializer.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/jackson/PageSerializer.java b/dl4se-server/src/main/java/usi/si/seart/jackson/PageSerializer.java index ec289a90..de4dc47d 100644 --- a/dl4se-server/src/main/java/usi/si/seart/jackson/PageSerializer.java +++ b/dl4se-server/src/main/java/usi/si/seart/jackson/PageSerializer.java @@ -9,12 +9,12 @@ public class PageSerializer extends StdSerializer> { - public PageSerializer() { + public static final PageSerializer INSTANCE = new PageSerializer(); + + private PageSerializer() { super(Page.class, false); } - public static final PageSerializer INSTANCE = new PageSerializer(); - @Override public void serialize(Page value, JsonGenerator gen, SerializerProvider serializers) throws IOException { gen.writeStartObject(); diff --git a/dl4se-server/src/main/java/usi/si/seart/jackson/SortSerializer.java b/dl4se-server/src/main/java/usi/si/seart/jackson/SortSerializer.java index 73ec52f8..10d71dd4 100644 --- a/dl4se-server/src/main/java/usi/si/seart/jackson/SortSerializer.java +++ b/dl4se-server/src/main/java/usi/si/seart/jackson/SortSerializer.java @@ -11,7 +11,7 @@ public class SortSerializer extends StdSerializer { public static final SortSerializer INSTANCE = new SortSerializer(); - public SortSerializer() { + private SortSerializer() { super(Sort.class); } From 5b06d1ae2b28bb923668d4f44c37f97bb8b8d314 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 9 Oct 2023 16:42:08 +0200 Subject: [PATCH 0360/1089] Added converter from `User` to `UserPrincipal` --- .../java/usi/si/seart/config/WebConfig.java | 2 ++ .../UserToUserPrincipalConverter.java | 21 +++++++++++++++++++ .../usi/si/seart/security/UserPrincipal.java | 2 +- 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 dl4se-server/src/main/java/usi/si/seart/converter/UserToUserPrincipalConverter.java diff --git a/dl4se-server/src/main/java/usi/si/seart/config/WebConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/WebConfig.java index 27d261d8..5605a794 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/WebConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/WebConfig.java @@ -8,6 +8,7 @@ import usi.si.seart.converter.DtoToUserConverter; import usi.si.seart.converter.TaskSearchDtoToSpecificationConverter; import usi.si.seart.converter.UserSearchDtoToSpecificationConverter; +import usi.si.seart.converter.UserToUserPrincipalConverter; @Configuration public class WebConfig implements WebMvcConfigurer { @@ -26,5 +27,6 @@ public void addFormatters(FormatterRegistry registry) { registry.addConverter(new DtoToConfigurationConverter()); registry.addConverter(new TaskSearchDtoToSpecificationConverter()); registry.addConverter(new UserSearchDtoToSpecificationConverter()); + registry.addConverter(new UserToUserPrincipalConverter()); } } diff --git a/dl4se-server/src/main/java/usi/si/seart/converter/UserToUserPrincipalConverter.java b/dl4se-server/src/main/java/usi/si/seart/converter/UserToUserPrincipalConverter.java new file mode 100644 index 00000000..ea5173cc --- /dev/null +++ b/dl4se-server/src/main/java/usi/si/seart/converter/UserToUserPrincipalConverter.java @@ -0,0 +1,21 @@ +package usi.si.seart.converter; + +import org.springframework.core.convert.converter.Converter; +import usi.si.seart.model.user.User; +import usi.si.seart.security.UserPrincipal; + +public class UserToUserPrincipalConverter implements Converter { + + @Override + public UserPrincipal convert(User source) { + return UserPrincipal.builder() + .id(source.getId()) + .uid(source.getUid()) + .username(source.getEmail()) + .password(source.getPassword()) + .verified(source.getVerified()) + .enabled(source.getEnabled()) + .role(source.getRole()) + .build(); + } +} diff --git a/dl4se-server/src/main/java/usi/si/seart/security/UserPrincipal.java b/dl4se-server/src/main/java/usi/si/seart/security/UserPrincipal.java index e8712fcb..f9fb1aa4 100644 --- a/dl4se-server/src/main/java/usi/si/seart/security/UserPrincipal.java +++ b/dl4se-server/src/main/java/usi/si/seart/security/UserPrincipal.java @@ -14,7 +14,7 @@ import java.util.Collection; import java.util.List; -@Builder(access = AccessLevel.PRIVATE) +@Builder @AllArgsConstructor(access = AccessLevel.PRIVATE) @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class UserPrincipal implements UserDetails { From 16de6459b6a44b1466637cc33b6c81346937b167 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 9 Oct 2023 16:47:40 +0200 Subject: [PATCH 0361/1089] Moved `AuthenticationEntrypoint` to `SecurityConfig` --- .../usi/si/seart/config/SecurityConfig.java | 14 +++++++----- .../jwt/JwtAuthenticationEntryPoint.java | 22 ------------------- 2 files changed, 9 insertions(+), 27 deletions(-) delete mode 100644 dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtAuthenticationEntryPoint.java diff --git a/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java index 67247a78..c38cc11e 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java @@ -22,12 +22,12 @@ import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import usi.si.seart.security.CustomUserDetailsService; -import usi.si.seart.security.jwt.JwtAuthenticationEntryPoint; import usi.si.seart.security.jwt.JwtRequestFilter; -import java.security.Key; +import javax.servlet.http.HttpServletResponse; @EnableWebSecurity @EnableGlobalMethodSecurity( @@ -41,8 +41,6 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { CustomUserDetailsService userDetailsService; - JwtAuthenticationEntryPoint entryPoint; - @NonFinal @Value("${jwt.secret}") String secret; @@ -59,7 +57,7 @@ protected void configure(HttpSecurity http) throws Exception { .csrf() .disable() .exceptionHandling() - .authenticationEntryPoint(entryPoint) + .authenticationEntryPoint(authenticationEntryPoint()) .and() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) @@ -119,6 +117,12 @@ public JwtParser jwtParser() { return Jwts.parserBuilder() .setSigningKey(secretKey()) .build(); + public AuthenticationEntryPoint authenticationEntryPoint() { + return (request, response, authException) -> { + int code = HttpServletResponse.SC_UNAUTHORIZED; + String message = Encode.forHtml(authException.getMessage()); + response.sendError(code, message); + }; } @Override diff --git a/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtAuthenticationEntryPoint.java b/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtAuthenticationEntryPoint.java deleted file mode 100644 index d55355bd..00000000 --- a/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtAuthenticationEntryPoint.java +++ /dev/null @@ -1,22 +0,0 @@ -package usi.si.seart.security.jwt; - -import org.owasp.encoder.Encode; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.web.AuthenticationEntryPoint; -import org.springframework.stereotype.Component; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; - -@Component -public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { - - @Override - public void commence( - HttpServletRequest request, HttpServletResponse response, AuthenticationException authException - ) throws IOException, ServletException { - response.sendError(HttpServletResponse.SC_UNAUTHORIZED, Encode.forHtml(authException.getMessage())); - } -} From 9ed6b185d82c0f87fadd42d399816207e2ab842a Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 9 Oct 2023 18:14:24 +0200 Subject: [PATCH 0362/1089] Extracting JWT-adjacent settings into dedicated `@Configuration` class --- .../java/usi/si/seart/config/JwtConfig.java | 44 +++++++++++++++ .../usi/si/seart/config/SecurityConfig.java | 33 ++---------- .../seart/security/jwt/JwtRequestFilter.java | 54 +++++++++---------- .../seart/security/jwt/JwtTokenProvider.java | 5 +- 4 files changed, 73 insertions(+), 63 deletions(-) create mode 100644 dl4se-server/src/main/java/usi/si/seart/config/JwtConfig.java diff --git a/dl4se-server/src/main/java/usi/si/seart/config/JwtConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/JwtConfig.java new file mode 100644 index 00000000..42fa3053 --- /dev/null +++ b/dl4se-server/src/main/java/usi/si/seart/config/JwtConfig.java @@ -0,0 +1,44 @@ +package usi.si.seart.config; + +import io.jsonwebtoken.JwtBuilder; +import io.jsonwebtoken.JwtParser; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.security.Keys; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import usi.si.seart.repository.UserRepository; +import usi.si.seart.security.jwt.JwtRequestFilter; +import usi.si.seart.security.jwt.JwtTokenProvider; + +import java.security.Key; + +@Configuration +public class JwtConfig { + + @Bean + public Key secretKey(@Value("${jwt.secret}") String value) { + return Keys.hmacShaKeyFor(value.getBytes()); + } + + @Bean + public JwtBuilder jwtBuilder(Key secretKey) { + return Jwts.builder().signWith(secretKey, SignatureAlgorithm.HS512); + } + + @Bean + public JwtParser jwtParser(Key secretKey) { + return Jwts.parserBuilder().setSigningKey(secretKey).build(); + } + + @Bean + public JwtTokenProvider jwtTokenProvider(JwtBuilder builder, JwtParser parser) { + return new JwtTokenProvider(builder, parser); + } + + @Bean + public JwtRequestFilter jwtRequestFilter(JwtTokenProvider jwtTokenProvider, UserRepository userRepository) { + return new JwtRequestFilter(jwtTokenProvider, userRepository); + } +} diff --git a/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java index c38cc11e..dde5c951 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java @@ -1,16 +1,10 @@ package usi.si.seart.config; -import io.jsonwebtoken.JwtBuilder; -import io.jsonwebtoken.JwtParser; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.SignatureAlgorithm; -import io.jsonwebtoken.security.Keys; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import lombok.experimental.FieldDefaults; -import lombok.experimental.NonFinal; +import org.owasp.encoder.Encode; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.BeanIds; @@ -41,9 +35,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { CustomUserDetailsService userDetailsService; - @NonFinal - @Value("${jwt.secret}") - String secret; + JwtRequestFilter jwtRequestFilter; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { @@ -89,7 +81,7 @@ protected void configure(HttpSecurity http) throws Exception { .anyRequest() .authenticated(); - http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); + http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class); } @Bean @@ -98,25 +90,6 @@ public PasswordEncoder passwordEncoder() { } @Bean - public JwtRequestFilter jwtAuthenticationFilter() { - return new JwtRequestFilter(); - } - - @Bean - public Key secretKey() { - return Keys.hmacShaKeyFor(secret.getBytes()); - } - - @Bean - public JwtBuilder jwtBuilder() { - return Jwts.builder().signWith(secretKey(), SignatureAlgorithm.HS512); - } - - @Bean - public JwtParser jwtParser() { - return Jwts.parserBuilder() - .setSigningKey(secretKey()) - .build(); public AuthenticationEntryPoint authenticationEntryPoint() { return (request, response, authException) -> { int code = HttpServletResponse.SC_UNAUTHORIZED; diff --git a/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtRequestFilter.java b/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtRequestFilter.java index 78eead19..225c977b 100644 --- a/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtRequestFilter.java +++ b/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtRequestFilter.java @@ -1,13 +1,14 @@ package usi.si.seart.security.jwt; import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.experimental.FieldDefaults; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.lang.NonNull; +import org.springframework.http.HttpHeaders; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.web.authentication.WebAuthenticationDetails; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.web.filter.OncePerRequestFilter; import usi.si.seart.exception.UserNotFoundException; @@ -19,43 +20,38 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +import java.util.Collection; import java.util.Optional; -@Slf4j -@FieldDefaults(level = AccessLevel.PRIVATE) +@AllArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class JwtRequestFilter extends OncePerRequestFilter { - @Autowired JwtTokenProvider tokenProvider; - - @Autowired UserRepository userRepository; @Override protected void doFilterInternal( - @NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain + HttpServletRequest request, HttpServletResponse response, FilterChain filterChain ) throws ServletException, IOException { - Optional jwt = getJwtFromRequest(request); - jwt.ifPresent(token -> { - if (tokenProvider.validateToken(token)) { - Long id = tokenProvider.getUserIdFromJWT(token); - UserDetails userDetails = userRepository.findById(id) - .map(UserPrincipal::of) - .orElseThrow(() -> new UserNotFoundException("id", id)); - UsernamePasswordAuthenticationToken authentication = - new UsernamePasswordAuthenticationToken( - userDetails, null, userDetails.getAuthorities() - ); - authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); - SecurityContextHolder.getContext().setAuthentication(authentication); - } + String token = request.getHeader(HttpHeaders.AUTHORIZATION); + Optional optional = Optional.ofNullable(token) + .filter(value -> value.startsWith("Bearer ")) + .map(value -> value.substring(7)) + .filter(tokenProvider::validateToken) + .map(tokenProvider::getUserIdFromJWT); + optional.ifPresent(id -> { + UserDetails userDetails = userRepository.findById(id) + .map(UserPrincipal::of) + .orElseThrow(() -> new UserNotFoundException("id", id)); + Collection authorities = userDetails.getAuthorities(); + WebAuthenticationDetails details = new WebAuthenticationDetailsSource().buildDetails(request); + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( + userDetails, null, authorities + ); + authentication.setDetails(details); + SecurityContextHolder.getContext().setAuthentication(authentication); }); filterChain.doFilter(request, response); } - - private Optional getJwtFromRequest(HttpServletRequest request) { - return Optional.ofNullable(request.getHeader("Authorization")) - .filter(value -> value.startsWith("Bearer ")) - .map(value -> value.substring(7)); - } } diff --git a/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtTokenProvider.java b/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtTokenProvider.java index f6a39e68..9d0f5e46 100644 --- a/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtTokenProvider.java +++ b/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtTokenProvider.java @@ -6,9 +6,7 @@ import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.experimental.FieldDefaults; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; -import org.springframework.stereotype.Component; import usi.si.seart.security.UserPrincipal; import java.time.ZoneOffset; @@ -16,8 +14,7 @@ import java.util.Date; -@Component -@AllArgsConstructor(onConstructor_ = @Autowired) +@AllArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class JwtTokenProvider { From 64951c84e64d3e3a1acddcc362e588844097a1ba Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 9 Oct 2023 18:17:18 +0200 Subject: [PATCH 0363/1089] Simplifying `SimpleModule` constructor usage --- dl4se-server/src/main/java/usi/si/seart/config/MainConfig.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/config/MainConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/MainConfig.java index 5a63985d..80ecd05b 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/MainConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/MainConfig.java @@ -1,6 +1,5 @@ package usi.si.seart.config; -import com.fasterxml.jackson.core.Version; import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; @@ -28,7 +27,7 @@ public JsonMapper jsonMapper() { jsonMapper.setDateFormat(dateFormat()); jsonMapper.registerModules( new JavaTimeModule(), - new SimpleModule("dl4se-spring-data-custom", Version.unknownVersion()) + new SimpleModule("dl4se-spring-data-custom") .addSerializer(SortSerializer.INSTANCE) .addSerializer(PageSerializer.INSTANCE) ); From 113e9e4fd1195e0547590414b241232e3725b882 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 9 Oct 2023 18:44:20 +0200 Subject: [PATCH 0364/1089] `CustomUserDetailsService` now uses the `ConversionService` --- .../si/seart/security/CustomUserDetailsService.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/security/CustomUserDetailsService.java b/dl4se-server/src/main/java/usi/si/seart/security/CustomUserDetailsService.java index e6cac319..33e9143e 100644 --- a/dl4se-server/src/main/java/usi/si/seart/security/CustomUserDetailsService.java +++ b/dl4se-server/src/main/java/usi/si/seart/security/CustomUserDetailsService.java @@ -1,7 +1,10 @@ package usi.si.seart.security; +import lombok.AccessLevel; import lombok.AllArgsConstructor; +import lombok.experimental.FieldDefaults; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.convert.ConversionService; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; @@ -10,16 +13,16 @@ @Service @AllArgsConstructor(onConstructor_ = @Autowired) +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class CustomUserDetailsService implements UserDetailsService { - private final UserRepository userRepository; + UserRepository userRepository; + ConversionService conversionService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { return userRepository.findByEmail(username) - .map(UserPrincipal::of) - .orElseThrow(() -> - new UsernameNotFoundException("No user registered with the email: " + username) - ); + .map(user -> conversionService.convert(user, UserPrincipal.class)) + .orElseThrow(() -> new UsernameNotFoundException("No user registered with the email: " + username)); } } From 7012ad0ae32c5eea9e10c81696bab7533b631b4f Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 9 Oct 2023 18:51:53 +0200 Subject: [PATCH 0365/1089] `JwtRequestFilter` is now abstract --- .../java/usi/si/seart/config/JwtConfig.java | 17 +++++++++++++++-- .../si/seart/security/jwt/JwtRequestFilter.java | 14 +++++--------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/config/JwtConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/JwtConfig.java index 42fa3053..182e288f 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/JwtConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/JwtConfig.java @@ -8,7 +8,11 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.convert.ConversionService; +import org.springframework.security.core.userdetails.UserDetails; +import usi.si.seart.exception.UserNotFoundException; import usi.si.seart.repository.UserRepository; +import usi.si.seart.security.UserPrincipal; import usi.si.seart.security.jwt.JwtRequestFilter; import usi.si.seart.security.jwt.JwtTokenProvider; @@ -38,7 +42,16 @@ public JwtTokenProvider jwtTokenProvider(JwtBuilder builder, JwtParser parser) { } @Bean - public JwtRequestFilter jwtRequestFilter(JwtTokenProvider jwtTokenProvider, UserRepository userRepository) { - return new JwtRequestFilter(jwtTokenProvider, userRepository); + public JwtRequestFilter jwtRequestFilter( + JwtTokenProvider jwtTokenProvider, UserRepository userRepository, ConversionService conversionService + ) { + return new JwtRequestFilter(jwtTokenProvider) { + @Override + protected UserDetails getUserDetails(Long id) { + return userRepository.findById(id) + .map(user -> conversionService.convert(user, UserPrincipal.class)) + .orElseThrow(() -> new UserNotFoundException("id", id)); + } + }; } } diff --git a/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtRequestFilter.java b/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtRequestFilter.java index 225c977b..35b3627f 100644 --- a/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtRequestFilter.java +++ b/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtRequestFilter.java @@ -11,9 +11,6 @@ import org.springframework.security.web.authentication.WebAuthenticationDetails; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.web.filter.OncePerRequestFilter; -import usi.si.seart.exception.UserNotFoundException; -import usi.si.seart.repository.UserRepository; -import usi.si.seart.security.UserPrincipal; import javax.servlet.FilterChain; import javax.servlet.ServletException; @@ -23,12 +20,13 @@ import java.util.Collection; import java.util.Optional; -@AllArgsConstructor +@AllArgsConstructor(access = AccessLevel.PROTECTED) @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) -public class JwtRequestFilter extends OncePerRequestFilter { +public abstract class JwtRequestFilter extends OncePerRequestFilter { JwtTokenProvider tokenProvider; - UserRepository userRepository; + + protected abstract UserDetails getUserDetails(Long id); @Override protected void doFilterInternal( @@ -41,9 +39,7 @@ protected void doFilterInternal( .filter(tokenProvider::validateToken) .map(tokenProvider::getUserIdFromJWT); optional.ifPresent(id -> { - UserDetails userDetails = userRepository.findById(id) - .map(UserPrincipal::of) - .orElseThrow(() -> new UserNotFoundException("id", id)); + UserDetails userDetails = getUserDetails(id); Collection authorities = userDetails.getAuthorities(); WebAuthenticationDetails details = new WebAuthenticationDetailsSource().buildDetails(request); UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( From 72122040b174bf990468bb5190d7910e01e70479 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 9 Oct 2023 23:29:01 +0200 Subject: [PATCH 0366/1089] EntityNotFoundException now uses a dedicated `lombok` annotation --- .../usi/si/seart/exception/EntityNotFoundException.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/exception/EntityNotFoundException.java b/dl4se-server/src/main/java/usi/si/seart/exception/EntityNotFoundException.java index f55f18e6..8f587c85 100644 --- a/dl4se-server/src/main/java/usi/si/seart/exception/EntityNotFoundException.java +++ b/dl4se-server/src/main/java/usi/si/seart/exception/EntityNotFoundException.java @@ -1,8 +1,8 @@ package usi.si.seart.exception; -public abstract class EntityNotFoundException extends RuntimeException { +import lombok.AccessLevel; +import lombok.experimental.StandardException; - public EntityNotFoundException(String message) { - super(message); - } +@StandardException(access = AccessLevel.PROTECTED) +public abstract class EntityNotFoundException extends RuntimeException { } From bb5a31ae62641257a863e20229b2f6aeec13629d Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 10 Oct 2023 00:10:38 +0200 Subject: [PATCH 0367/1089] Refactoring `EntityNotFoundException` The logic for constructing individual exception messages has been extracted to the abstract class. Furthermore, all implementing instances are associated with a specific entity type. This allows exceptions to only be constructed with `Attribute` instances associated with the same class. Furthermore, the value for which the entity was not found must coincide with the value of the attribute. As a result there can no longer be instances of type `TaskNotFoundException` that refer to a `Language` column with a completely different type value. Things are much more restricted now. --- .../main/java/usi/si/seart/config/JwtConfig.java | 3 ++- .../usi/si/seart/controller/AdminController.java | 3 ++- .../exception/ConfigurationNotFoundException.java | 10 ++++++---- .../seart/exception/EntityNotFoundException.java | 14 +++++++++++++- .../seart/exception/LanguageNotFoundException.java | 10 ++++++---- .../si/seart/exception/TaskNotFoundException.java | 10 ++++++---- .../si/seart/exception/TokenNotFoundException.java | 10 ++++++---- .../si/seart/exception/UserNotFoundException.java | 10 ++++++---- .../java/usi/si/seart/service/DownloadService.java | 3 ++- .../java/usi/si/seart/service/LanguageService.java | 3 ++- .../usi/si/seart/service/PasswordResetService.java | 3 ++- .../java/usi/si/seart/service/TaskService.java | 3 ++- .../java/usi/si/seart/service/UserService.java | 7 ++++--- .../usi/si/seart/service/VerificationService.java | 5 +++-- 14 files changed, 62 insertions(+), 32 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/config/JwtConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/JwtConfig.java index 182e288f..91fdb157 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/JwtConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/JwtConfig.java @@ -11,6 +11,7 @@ import org.springframework.core.convert.ConversionService; import org.springframework.security.core.userdetails.UserDetails; import usi.si.seart.exception.UserNotFoundException; +import usi.si.seart.model.user.User_; import usi.si.seart.repository.UserRepository; import usi.si.seart.security.UserPrincipal; import usi.si.seart.security.jwt.JwtRequestFilter; @@ -50,7 +51,7 @@ public JwtRequestFilter jwtRequestFilter( protected UserDetails getUserDetails(Long id) { return userRepository.findById(id) .map(user -> conversionService.convert(user, UserPrincipal.class)) - .orElseThrow(() -> new UserNotFoundException("id", id)); + .orElseThrow(() -> new UserNotFoundException(User_.id, id)); } }; } diff --git a/dl4se-server/src/main/java/usi/si/seart/controller/AdminController.java b/dl4se-server/src/main/java/usi/si/seart/controller/AdminController.java index 125b5c39..ca3b6760 100644 --- a/dl4se-server/src/main/java/usi/si/seart/controller/AdminController.java +++ b/dl4se-server/src/main/java/usi/si/seart/controller/AdminController.java @@ -20,6 +20,7 @@ import usi.si.seart.dto.user.UserSearchDto; import usi.si.seart.exception.ConfigurationNotFoundException; import usi.si.seart.model.Configuration; +import usi.si.seart.model.Configuration_; import usi.si.seart.model.task.Task; import usi.si.seart.model.task.Task_; import usi.si.seart.model.user.Role; @@ -126,7 +127,7 @@ public ResponseEntity updateConfiguration(@RequestBody Map<@NotBlank String, for (Configuration configuration: configurations) { boolean exists = configurationService.exists(configuration); - if (!exists) throw new ConfigurationNotFoundException(configuration.getKey()); + if (!exists) throw new ConfigurationNotFoundException(Configuration_.key, configuration.getKey()); } return ResponseEntity.ok(configurationService.update(configurations)); diff --git a/dl4se-server/src/main/java/usi/si/seart/exception/ConfigurationNotFoundException.java b/dl4se-server/src/main/java/usi/si/seart/exception/ConfigurationNotFoundException.java index b0900aa2..5cd475de 100644 --- a/dl4se-server/src/main/java/usi/si/seart/exception/ConfigurationNotFoundException.java +++ b/dl4se-server/src/main/java/usi/si/seart/exception/ConfigurationNotFoundException.java @@ -1,10 +1,12 @@ package usi.si.seart.exception; -public class ConfigurationNotFoundException extends EntityNotFoundException { +import usi.si.seart.model.Configuration; + +import javax.persistence.metamodel.Attribute; - private static final String format = "Could not find Configuration with key: %s"; +public class ConfigurationNotFoundException extends EntityNotFoundException { - public ConfigurationNotFoundException(String key) { - super(String.format(format, key)); + public ConfigurationNotFoundException(Attribute attribute, T value) { + super(Configuration.class, attribute, value); } } diff --git a/dl4se-server/src/main/java/usi/si/seart/exception/EntityNotFoundException.java b/dl4se-server/src/main/java/usi/si/seart/exception/EntityNotFoundException.java index 8f587c85..82d17f6d 100644 --- a/dl4se-server/src/main/java/usi/si/seart/exception/EntityNotFoundException.java +++ b/dl4se-server/src/main/java/usi/si/seart/exception/EntityNotFoundException.java @@ -3,6 +3,18 @@ import lombok.AccessLevel; import lombok.experimental.StandardException; -@StandardException(access = AccessLevel.PROTECTED) +import javax.persistence.metamodel.Attribute; + +@StandardException(access = AccessLevel.PRIVATE) public abstract class EntityNotFoundException extends RuntimeException { + + private static final String TEMPLATE = "Could not find %s with: [%s = %s]"; + + private static String formatMessage(String entity, String field, Object value) { + return String.format(TEMPLATE, entity, field, value); + } + + protected EntityNotFoundException(Class entity, Attribute attribute, T value) { + super(formatMessage(entity.getSimpleName(), attribute.getName(), value)); + } } diff --git a/dl4se-server/src/main/java/usi/si/seart/exception/LanguageNotFoundException.java b/dl4se-server/src/main/java/usi/si/seart/exception/LanguageNotFoundException.java index 5ca537ab..3c1507d3 100644 --- a/dl4se-server/src/main/java/usi/si/seart/exception/LanguageNotFoundException.java +++ b/dl4se-server/src/main/java/usi/si/seart/exception/LanguageNotFoundException.java @@ -1,10 +1,12 @@ package usi.si.seart.exception; -public class LanguageNotFoundException extends EntityNotFoundException { +import usi.si.seart.model.Language; + +import javax.persistence.metamodel.Attribute; - private static final String format = "Could not find Language with: [%s = %s]"; +public class LanguageNotFoundException extends EntityNotFoundException { - public LanguageNotFoundException(String field, Object value) { - super(String.format(format, field, value.toString())); + public LanguageNotFoundException(Attribute attribute, T value) { + super(Language.class, attribute, value); } } diff --git a/dl4se-server/src/main/java/usi/si/seart/exception/TaskNotFoundException.java b/dl4se-server/src/main/java/usi/si/seart/exception/TaskNotFoundException.java index 983c2394..e1a85cb5 100644 --- a/dl4se-server/src/main/java/usi/si/seart/exception/TaskNotFoundException.java +++ b/dl4se-server/src/main/java/usi/si/seart/exception/TaskNotFoundException.java @@ -1,10 +1,12 @@ package usi.si.seart.exception; -public class TaskNotFoundException extends EntityNotFoundException { +import usi.si.seart.model.task.Task; + +import javax.persistence.metamodel.Attribute; - private static final String format = "Could not find Task with: [%s = %s]"; +public class TaskNotFoundException extends EntityNotFoundException { - public TaskNotFoundException(String field, Object value) { - super(String.format(format, field, value.toString())); + public TaskNotFoundException(Attribute attribute, T value) { + super(Task.class, attribute, value); } } diff --git a/dl4se-server/src/main/java/usi/si/seart/exception/TokenNotFoundException.java b/dl4se-server/src/main/java/usi/si/seart/exception/TokenNotFoundException.java index 0e42b911..f0696992 100644 --- a/dl4se-server/src/main/java/usi/si/seart/exception/TokenNotFoundException.java +++ b/dl4se-server/src/main/java/usi/si/seart/exception/TokenNotFoundException.java @@ -1,10 +1,12 @@ package usi.si.seart.exception; -public class TokenNotFoundException extends EntityNotFoundException { +import usi.si.seart.model.user.token.Token; + +import javax.persistence.metamodel.Attribute; - private static final String format = "Could not find Token with: [%s = %s]"; +public class TokenNotFoundException extends EntityNotFoundException { - public TokenNotFoundException(String field, Object value) { - super(String.format(format, field, value.toString())); + public TokenNotFoundException(Attribute attribute, T value) { + super(Token.class, attribute, value); } } diff --git a/dl4se-server/src/main/java/usi/si/seart/exception/UserNotFoundException.java b/dl4se-server/src/main/java/usi/si/seart/exception/UserNotFoundException.java index 9c445f7d..56cec153 100644 --- a/dl4se-server/src/main/java/usi/si/seart/exception/UserNotFoundException.java +++ b/dl4se-server/src/main/java/usi/si/seart/exception/UserNotFoundException.java @@ -1,10 +1,12 @@ package usi.si.seart.exception; -public class UserNotFoundException extends EntityNotFoundException { +import usi.si.seart.model.user.User; + +import javax.persistence.metamodel.Attribute; - private static final String format = "Could not find User with: [%s = %s]"; +public class UserNotFoundException extends EntityNotFoundException { - public UserNotFoundException(String field, Object value) { - super(String.format(format, field, value.toString())); + public UserNotFoundException(Attribute attribute, T value) { + super(User.class, attribute, value); } } diff --git a/dl4se-server/src/main/java/usi/si/seart/service/DownloadService.java b/dl4se-server/src/main/java/usi/si/seart/service/DownloadService.java index f4d63268..f612626d 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/DownloadService.java +++ b/dl4se-server/src/main/java/usi/si/seart/service/DownloadService.java @@ -10,6 +10,7 @@ import usi.si.seart.model.user.User; import usi.si.seart.model.user.token.DownloadToken; import usi.si.seart.model.user.token.Token; +import usi.si.seart.model.user.token.Token_; import usi.si.seart.repository.TokenRepository; import java.util.UUID; @@ -46,7 +47,7 @@ public void consume(String value) { throw new TokenExpiredException(token); return token; - }).orElseThrow(() -> new TokenNotFoundException("value", value)); + }).orElseThrow(() -> new TokenNotFoundException(Token_.value, value)); } } } diff --git a/dl4se-server/src/main/java/usi/si/seart/service/LanguageService.java b/dl4se-server/src/main/java/usi/si/seart/service/LanguageService.java index d5df4bd4..18ecde59 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/LanguageService.java +++ b/dl4se-server/src/main/java/usi/si/seart/service/LanguageService.java @@ -7,6 +7,7 @@ import org.springframework.stereotype.Service; import usi.si.seart.exception.LanguageNotFoundException; import usi.si.seart.model.Language; +import usi.si.seart.model.Language_; import usi.si.seart.repository.LanguageRepository; import java.util.List; @@ -26,7 +27,7 @@ class LanguageServiceImpl implements LanguageService { @Override public Language getWithName(String name) { return languageRepository.findByName(name) - .orElseThrow(() -> new LanguageNotFoundException("name", name)); + .orElseThrow(() -> new LanguageNotFoundException(Language_.name, name)); } @Override diff --git a/dl4se-server/src/main/java/usi/si/seart/service/PasswordResetService.java b/dl4se-server/src/main/java/usi/si/seart/service/PasswordResetService.java index 93f2c36c..ba60e675 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/PasswordResetService.java +++ b/dl4se-server/src/main/java/usi/si/seart/service/PasswordResetService.java @@ -11,6 +11,7 @@ import usi.si.seart.model.user.User; import usi.si.seart.model.user.token.PasswordResetToken; import usi.si.seart.model.user.token.Token; +import usi.si.seart.model.user.token.Token_; import usi.si.seart.repository.TokenRepository; import usi.si.seart.repository.UserRepository; @@ -62,7 +63,7 @@ public void verify(String value, String newPass) { user.setPassword(passwordEncoder.encode(newPass)); tokenRepository.delete(token); return userRepository.save(user); - }).orElseThrow(() -> new TokenNotFoundException("value", value)); + }).orElseThrow(() -> new TokenNotFoundException(Token_.value, value)); } } } diff --git a/dl4se-server/src/main/java/usi/si/seart/service/TaskService.java b/dl4se-server/src/main/java/usi/si/seart/service/TaskService.java index 147c12b3..c6613695 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/TaskService.java +++ b/dl4se-server/src/main/java/usi/si/seart/service/TaskService.java @@ -18,6 +18,7 @@ import usi.si.seart.model.job.Job; import usi.si.seart.model.task.Status; import usi.si.seart.model.task.Task; +import usi.si.seart.model.task.Task_; import usi.si.seart.model.user.User; import usi.si.seart.repository.TaskRepository; @@ -171,7 +172,7 @@ public Page getAll(Specification specification, Pageable pageable) { @Override public Task getWithUUID(UUID uuid) { return taskRepository.findByUuid(uuid) - .orElseThrow(() -> new TaskNotFoundException("uuid", uuid)); + .orElseThrow(() -> new TaskNotFoundException(Task_.uuid, uuid)); } } } diff --git a/dl4se-server/src/main/java/usi/si/seart/service/UserService.java b/dl4se-server/src/main/java/usi/si/seart/service/UserService.java index a566bc9b..71aeae2b 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/UserService.java +++ b/dl4se-server/src/main/java/usi/si/seart/service/UserService.java @@ -12,6 +12,7 @@ import usi.si.seart.exception.UserNotFoundException; import usi.si.seart.model.user.Role; import usi.si.seart.model.user.User; +import usi.si.seart.model.user.User_; import usi.si.seart.repository.UserRepository; public interface UserService { @@ -51,19 +52,19 @@ public Page getAll(Specification specification, Pageable pageable) { @Override public User getWithId(Long id) { return userRepository.findById(id) - .orElseThrow(() -> new UserNotFoundException("id", id)); + .orElseThrow(() -> new UserNotFoundException(User_.id, id)); } @Override public User getWithUid(String uid) { return userRepository.findByUid(uid) - .orElseThrow(() -> new UserNotFoundException("uid", uid)); + .orElseThrow(() -> new UserNotFoundException(User_.uid, uid)); } @Override public User getWithEmail(String email) { return userRepository.findByEmail(email) - .orElseThrow(() -> new UserNotFoundException("email", email)); + .orElseThrow(() -> new UserNotFoundException(User_.email, email)); } } } diff --git a/dl4se-server/src/main/java/usi/si/seart/service/VerificationService.java b/dl4se-server/src/main/java/usi/si/seart/service/VerificationService.java index d3687953..7d6c6457 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/VerificationService.java +++ b/dl4se-server/src/main/java/usi/si/seart/service/VerificationService.java @@ -9,6 +9,7 @@ import usi.si.seart.exception.TokenNotFoundException; import usi.si.seart.model.user.User; import usi.si.seart.model.user.token.Token; +import usi.si.seart.model.user.token.Token_; import usi.si.seart.model.user.token.VerificationToken; import usi.si.seart.repository.TokenRepository; import usi.si.seart.repository.UserRepository; @@ -50,7 +51,7 @@ public void verify(String value) { user.setVerified(true); tokenRepository.delete(token); return userRepository.save(user); - }).orElseThrow(() -> new TokenNotFoundException("value", value)); + }).orElseThrow(() -> new TokenNotFoundException(Token_.value, value)); } @Override @@ -58,7 +59,7 @@ public Token refresh(String value) { return tokenRepository.findByValue(value).map(token -> { token.setValue(UUID.randomUUID().toString()); return tokenRepository.save(token); - }).orElseThrow(() -> new TokenNotFoundException("value", value)); + }).orElseThrow(() -> new TokenNotFoundException(Token_.value, value)); } } } From f34b106c5028bfeb1a107298f88ebfb1e4081561 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 10 Oct 2023 08:34:38 +0200 Subject: [PATCH 0368/1089] Custom bean definition for `AuthenticationManager` --- .../usi/si/seart/config/SecurityConfig.java | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java index dde5c951..3e9793f4 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java @@ -7,13 +7,16 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.config.BeanIds; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.AuthenticationEntryPoint; @@ -98,9 +101,19 @@ public AuthenticationEntryPoint authenticationEntryPoint() { }; } - @Override - @Bean(BeanIds.AUTHENTICATION_MANAGER) - public AuthenticationManager authenticationManagerBean() throws Exception { - return super.authenticationManagerBean(); + @Bean + public AuthenticationManager authenticationManager( + PasswordEncoder passwordEncoder, UserDetailsService userDetailsService + ) { + return authentication -> { + String username = authentication.getName(); + String password = authentication.getCredentials().toString(); + UserDetails userDetails = userDetailsService.loadUserByUsername(username); + if (passwordEncoder.matches(password, userDetails.getPassword())) { + return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + } else { + throw new BadCredentialsException("Incorrect password!"); + } + }; } } From e8d5d53f06457a53740329b1e6ae8f4797dcaa1f Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 10 Oct 2023 08:46:47 +0200 Subject: [PATCH 0369/1089] Completely eliminating reliance on `WebSecurityConfigurerAdapter` The current version of Spring Boot we use marks it as deprecated. Moving away from code like this will help us when migrating to the newer version of the framework. --- .../usi/si/seart/config/SecurityConfig.java | 30 ++++++++----------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java index 3e9793f4..76934a32 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java @@ -9,19 +9,17 @@ import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -import usi.si.seart.security.CustomUserDetailsService; import usi.si.seart.security.jwt.JwtRequestFilter; import javax.servlet.http.HttpServletResponse; @@ -34,25 +32,20 @@ ) @RequiredArgsConstructor(onConstructor_ = @Autowired) @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) -public class SecurityConfig extends WebSecurityConfigurerAdapter { +public class SecurityConfig { - CustomUserDetailsService userDetailsService; - - JwtRequestFilter jwtRequestFilter; - - @Override - protected void configure(AuthenticationManagerBuilder auth) throws Exception { - auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); - } - - @Override - protected void configure(HttpSecurity http) throws Exception { - http.cors() + @Bean + public SecurityFilterChain securityFilterChain( + HttpSecurity httpSecurity, + AuthenticationEntryPoint authenticationEntryPoint, + JwtRequestFilter jwtRequestFilter + ) throws Exception { + httpSecurity.cors() .and() .csrf() .disable() .exceptionHandling() - .authenticationEntryPoint(authenticationEntryPoint()) + .authenticationEntryPoint(authenticationEntryPoint) .and() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) @@ -84,7 +77,8 @@ protected void configure(HttpSecurity http) throws Exception { .anyRequest() .authenticated(); - http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class); + httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class); + return httpSecurity.build(); } @Bean From 4cdc90fdad7db150ddb4f38f8ba47684ae170ba5 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 10 Oct 2023 08:56:29 +0200 Subject: [PATCH 0370/1089] Moved `CustomUserDetailsService` code to `SecurityConfig` --- .../usi/si/seart/config/SecurityConfig.java | 11 ++++++++ .../security/CustomUserDetailsService.java | 28 ------------------- 2 files changed, 11 insertions(+), 28 deletions(-) delete mode 100644 dl4se-server/src/main/java/usi/si/seart/security/CustomUserDetailsService.java diff --git a/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java index 76934a32..2f120283 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java @@ -6,6 +6,7 @@ import org.owasp.encoder.Encode; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; +import org.springframework.core.convert.ConversionService; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; @@ -15,11 +16,14 @@ import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import usi.si.seart.repository.UserRepository; +import usi.si.seart.security.UserPrincipal; import usi.si.seart.security.jwt.JwtRequestFilter; import javax.servlet.http.HttpServletResponse; @@ -95,6 +99,13 @@ public AuthenticationEntryPoint authenticationEntryPoint() { }; } + @Bean + public UserDetailsService userDetailsService(UserRepository userRepository, ConversionService conversionService) { + return username -> userRepository.findByEmail(username) + .map(user -> conversionService.convert(user, UserPrincipal.class)) + .orElseThrow(() -> new UsernameNotFoundException("No user registered with the email: " + username)); + } + @Bean public AuthenticationManager authenticationManager( PasswordEncoder passwordEncoder, UserDetailsService userDetailsService diff --git a/dl4se-server/src/main/java/usi/si/seart/security/CustomUserDetailsService.java b/dl4se-server/src/main/java/usi/si/seart/security/CustomUserDetailsService.java deleted file mode 100644 index 33e9143e..00000000 --- a/dl4se-server/src/main/java/usi/si/seart/security/CustomUserDetailsService.java +++ /dev/null @@ -1,28 +0,0 @@ -package usi.si.seart.security; - -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.experimental.FieldDefaults; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.convert.ConversionService; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.stereotype.Service; -import usi.si.seart.repository.UserRepository; - -@Service -@AllArgsConstructor(onConstructor_ = @Autowired) -@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) -public class CustomUserDetailsService implements UserDetailsService { - - UserRepository userRepository; - ConversionService conversionService; - - @Override - public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { - return userRepository.findByEmail(username) - .map(user -> conversionService.convert(user, UserPrincipal.class)) - .orElseThrow(() -> new UsernameNotFoundException("No user registered with the email: " + username)); - } -} From 4db509d7cf05f910bf721f2324438803017bff19 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 10 Oct 2023 09:31:41 +0200 Subject: [PATCH 0371/1089] UserDetailsService now decorates `UserService` and `ConversionService` --- .../usi/si/seart/config/SecurityConfig.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java index 2f120283..3eb889de 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java @@ -22,9 +22,11 @@ import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -import usi.si.seart.repository.UserRepository; +import usi.si.seart.exception.UserNotFoundException; +import usi.si.seart.model.user.User; import usi.si.seart.security.UserPrincipal; import usi.si.seart.security.jwt.JwtRequestFilter; +import usi.si.seart.service.UserService; import javax.servlet.http.HttpServletResponse; @@ -100,10 +102,15 @@ public AuthenticationEntryPoint authenticationEntryPoint() { } @Bean - public UserDetailsService userDetailsService(UserRepository userRepository, ConversionService conversionService) { - return username -> userRepository.findByEmail(username) - .map(user -> conversionService.convert(user, UserPrincipal.class)) - .orElseThrow(() -> new UsernameNotFoundException("No user registered with the email: " + username)); + public UserDetailsService userDetailsService(UserService userService, ConversionService conversionService) { + return username -> { + try { + User user = userService.getWithEmail(username); + return conversionService.convert(user, UserPrincipal.class); + } catch (UserNotFoundException ex) { + throw new UsernameNotFoundException(ex.getMessage()); + } + }; } @Bean From cca671666dcd0ebfc211a8e98d4d72a84358beae Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 10 Oct 2023 10:08:45 +0200 Subject: [PATCH 0372/1089] `AuthenticationManager` now takes enabled status into account --- .../main/java/usi/si/seart/config/SecurityConfig.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java index 3eb889de..0373f0ab 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java @@ -9,6 +9,7 @@ import org.springframework.core.convert.ConversionService; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.DisabledException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -121,11 +122,13 @@ public AuthenticationManager authenticationManager( String username = authentication.getName(); String password = authentication.getCredentials().toString(); UserDetails userDetails = userDetailsService.loadUserByUsername(username); - if (passwordEncoder.matches(password, userDetails.getPassword())) { + boolean enabled = userDetails.isEnabled(); + if (!enabled) + throw new DisabledException("User is currently disabled!"); + if (passwordEncoder.matches(password, userDetails.getPassword())) return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); - } else { + else throw new BadCredentialsException("Incorrect password!"); - } }; } } From c26c1f83044e1c3df5c45218e2a741907bdb1087 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 10 Oct 2023 10:09:19 +0200 Subject: [PATCH 0373/1089] `JwtRequestFilter` now also uses `UserService` instead of the repository --- .../main/java/usi/si/seart/config/JwtConfig.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/config/JwtConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/JwtConfig.java index 91fdb157..7074d52b 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/JwtConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/JwtConfig.java @@ -10,12 +10,13 @@ import org.springframework.context.annotation.Configuration; import org.springframework.core.convert.ConversionService; import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UsernameNotFoundException; import usi.si.seart.exception.UserNotFoundException; -import usi.si.seart.model.user.User_; -import usi.si.seart.repository.UserRepository; +import usi.si.seart.model.user.User; import usi.si.seart.security.UserPrincipal; import usi.si.seart.security.jwt.JwtRequestFilter; import usi.si.seart.security.jwt.JwtTokenProvider; +import usi.si.seart.service.UserService; import java.security.Key; @@ -44,14 +45,17 @@ public JwtTokenProvider jwtTokenProvider(JwtBuilder builder, JwtParser parser) { @Bean public JwtRequestFilter jwtRequestFilter( - JwtTokenProvider jwtTokenProvider, UserRepository userRepository, ConversionService conversionService + JwtTokenProvider jwtTokenProvider, UserService userService, ConversionService conversionService ) { return new JwtRequestFilter(jwtTokenProvider) { @Override protected UserDetails getUserDetails(Long id) { - return userRepository.findById(id) - .map(user -> conversionService.convert(user, UserPrincipal.class)) - .orElseThrow(() -> new UserNotFoundException(User_.id, id)); + try { + User user = userService.getWithId(id); + return conversionService.convert(user, UserPrincipal.class); + } catch (UserNotFoundException ex) { + throw new UsernameNotFoundException(ex.getMessage()); + } } }; } From 5848ca18609d6c04ce4b1defd785e31215d87710 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 10 Oct 2023 10:10:30 +0200 Subject: [PATCH 0374/1089] Removed unused factory method from `UserPrincipal` --- .../java/usi/si/seart/security/UserPrincipal.java | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/security/UserPrincipal.java b/dl4se-server/src/main/java/usi/si/seart/security/UserPrincipal.java index f9fb1aa4..10e74247 100644 --- a/dl4se-server/src/main/java/usi/si/seart/security/UserPrincipal.java +++ b/dl4se-server/src/main/java/usi/si/seart/security/UserPrincipal.java @@ -9,7 +9,6 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import usi.si.seart.model.user.Role; -import usi.si.seart.model.user.User; import java.util.Collection; import java.util.List; @@ -37,18 +36,6 @@ public class UserPrincipal implements UserDetails { Role role; - public static UserPrincipal of(User user) { - return UserPrincipal.builder() - .id(user.getId()) - .uid(user.getUid()) - .username(user.getEmail()) - .password(user.getPassword()) - .verified(user.getVerified()) - .enabled(user.getEnabled()) - .role(user.getRole()) - .build(); - } - @Override public Collection getAuthorities() { return List.of(new SimpleGrantedAuthority("ROLE_" + role.name())); From b13aee2da432594f64174f2d61391137885b5e07 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 10 Oct 2023 10:56:10 +0200 Subject: [PATCH 0375/1089] Pagination configuration is now completely static --- .../usi/si/seart/config/PaginationConfig.java | 26 ------------------- .../src/main/resources/application.properties | 7 +++++ 2 files changed, 7 insertions(+), 26 deletions(-) delete mode 100644 dl4se-server/src/main/java/usi/si/seart/config/PaginationConfig.java diff --git a/dl4se-server/src/main/java/usi/si/seart/config/PaginationConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/PaginationConfig.java deleted file mode 100644 index 729acc18..00000000 --- a/dl4se-server/src/main/java/usi/si/seart/config/PaginationConfig.java +++ /dev/null @@ -1,26 +0,0 @@ -package usi.si.seart.config; - -import lombok.AllArgsConstructor; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.web.config.EnableSpringDataWebSupport; -import org.springframework.data.web.config.PageableHandlerMethodArgumentResolverCustomizer; -import usi.si.seart.service.ConfigurationService; - -@Configuration -@EnableSpringDataWebSupport -@AllArgsConstructor(onConstructor_ = @Autowired) -public class PaginationConfig { - - ConfigurationService configurationService; - - @Bean - PageableHandlerMethodArgumentResolverCustomizer pageableResolverCustomizer() { - Integer maxPageSize = configurationService.get("max_page_size", Integer.class); - return pageableResolver -> { - pageableResolver.setMaxPageSize(maxPageSize); - pageableResolver.setOneIndexedParameters(true); - }; - } -} diff --git a/dl4se-server/src/main/resources/application.properties b/dl4se-server/src/main/resources/application.properties index 741396f5..aec3fa6a 100644 --- a/dl4se-server/src/main/resources/application.properties +++ b/dl4se-server/src/main/resources/application.properties @@ -42,6 +42,13 @@ spring.security.user.name=${SERVER_SECURITY_USER} spring.security.user.password=${SERVER_SECURITY_PASS} spring.security.user.roles=admin +# Pagination Configuration +spring.data.web.pageable.size-parameter=size +spring.data.web.pageable.page-parameter=page +spring.data.web.pageable.default-page-size=20 +spring.data.web.pageable.max-page-size=100 +spring.data.web.pageable.one-indexed-parameters=true + # Logging Configuration logging.level.usi.si.seart=INFO logging.level.org.jooq.Constants=WARN From 1ce1efa2e803bd7869e4c4369993b36e25724638 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 10 Oct 2023 11:09:25 +0200 Subject: [PATCH 0376/1089] Re-enabling Spring Data Web support --- dl4se-server/src/main/java/usi/si/seart/config/WebConfig.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dl4se-server/src/main/java/usi/si/seart/config/WebConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/WebConfig.java index 5605a794..7217c291 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/WebConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/WebConfig.java @@ -1,6 +1,7 @@ package usi.si.seart.config; import org.springframework.context.annotation.Configuration; +import org.springframework.data.web.config.EnableSpringDataWebSupport; import org.springframework.format.FormatterRegistry; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @@ -11,6 +12,7 @@ import usi.si.seart.converter.UserToUserPrincipalConverter; @Configuration +@EnableSpringDataWebSupport public class WebConfig implements WebMvcConfigurer { @Override From 9bb8fb3a0b1581f5cb611554445d4016beb4b71e Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 10 Oct 2023 11:12:17 +0200 Subject: [PATCH 0377/1089] Removing unneeded annotations --- .../src/main/java/usi/si/seart/config/SecurityConfig.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java index 0373f0ab..4272e3d9 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java @@ -1,10 +1,6 @@ package usi.si.seart.config; -import lombok.AccessLevel; -import lombok.RequiredArgsConstructor; -import lombok.experimental.FieldDefaults; import org.owasp.encoder.Encode; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.core.convert.ConversionService; import org.springframework.security.authentication.AuthenticationManager; @@ -37,8 +33,6 @@ jsr250Enabled = true, prePostEnabled = true ) -@RequiredArgsConstructor(onConstructor_ = @Autowired) -@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class SecurityConfig { @Bean From 6d1b92cdda603f3fde4f858cc1d7b3c9f70e2807 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 10 Oct 2023 11:39:49 +0200 Subject: [PATCH 0378/1089] Adding a dedicated submodule for the serializers --- .../java/usi/si/seart/jackson/PaginationModule.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 dl4se-server/src/main/java/usi/si/seart/jackson/PaginationModule.java diff --git a/dl4se-server/src/main/java/usi/si/seart/jackson/PaginationModule.java b/dl4se-server/src/main/java/usi/si/seart/jackson/PaginationModule.java new file mode 100644 index 00000000..56e47942 --- /dev/null +++ b/dl4se-server/src/main/java/usi/si/seart/jackson/PaginationModule.java @@ -0,0 +1,12 @@ +package usi.si.seart.jackson; + +import com.fasterxml.jackson.databind.module.SimpleModule; + +public class PaginationModule extends SimpleModule { + + public PaginationModule() { + super(PaginationModule.class.getName()); + addSerializer(SortSerializer.INSTANCE); + addSerializer(PageSerializer.INSTANCE); + } +} From 9bf2c3ef018e4e8f6f65a411d6fc7d5b143b43d9 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 10 Oct 2023 11:40:17 +0200 Subject: [PATCH 0379/1089] Changing bean definition for `JsonMapper` --- .../java/usi/si/seart/config/MainConfig.java | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/config/MainConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/MainConfig.java index 80ecd05b..e235752f 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/MainConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/MainConfig.java @@ -1,13 +1,11 @@ package usi.si.seart.config; import com.fasterxml.jackson.databind.json.JsonMapper; -import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import usi.si.seart.jackson.PageSerializer; -import usi.si.seart.jackson.SortSerializer; +import usi.si.seart.jackson.PaginationModule; import java.nio.file.Path; import java.text.DateFormat; @@ -22,16 +20,14 @@ public Path fileStorageDirPath(@Value("${java.io.tmpdir}") String value) { } @Bean - public JsonMapper jsonMapper() { - JsonMapper jsonMapper = new JsonMapper(); - jsonMapper.setDateFormat(dateFormat()); - jsonMapper.registerModules( - new JavaTimeModule(), - new SimpleModule("dl4se-spring-data-custom") - .addSerializer(SortSerializer.INSTANCE) - .addSerializer(PageSerializer.INSTANCE) - ); - return jsonMapper; + public JsonMapper jsonMapper(DateFormat dateFormat) { + return JsonMapper.builder() + .defaultDateFormat(dateFormat) + .addModules( + new JavaTimeModule(), + new PaginationModule() + ) + .build(); } @Bean From ec8c6bae982e634af7ca45f7dceba771ebd0a952 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 10 Oct 2023 11:46:05 +0200 Subject: [PATCH 0380/1089] `update` and `cancel` methods of `TaskService` no longer generic --- .../src/main/java/usi/si/seart/service/TaskService.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/service/TaskService.java b/dl4se-server/src/main/java/usi/si/seart/service/TaskService.java index c6613695..6196f94a 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/TaskService.java +++ b/dl4se-server/src/main/java/usi/si/seart/service/TaskService.java @@ -39,8 +39,8 @@ public interface TaskService { boolean canCreateTask(User user, Integer limit); boolean activeTaskExists(User user, Job dataset, JsonNode query, JsonNode processing); void create(User requester, Job dataset, JsonNode query, JsonNode processing, LocalDateTime requestedAt); - T update(T task); - void cancel(T task); + Task update(Task task); + void cancel(Task task); void registerException(TaskFailedException ex); void forEachNonExpired(Consumer consumer); void forEachExecuting(Consumer consumer); @@ -98,7 +98,7 @@ public void create( @Override @Transactional(propagation = Propagation.REQUIRES_NEW) - public T update(T task) { + public Task update(Task task) { Lock taskLock = taskLockMap.getLock(task); try { taskLock.lock(); @@ -110,7 +110,7 @@ public T update(T task) { @Override @Transactional(propagation = Propagation.REQUIRES_NEW) - public void cancel(T task) { + public void cancel(Task task) { Lock taskLock = taskLockMap.getLock(task); try { taskLock.lock(); From 6503774d33c8650f81ff98f1be86348ff45b884c Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 10 Oct 2023 11:59:06 +0200 Subject: [PATCH 0381/1089] Removing jOOQ from dependency list --- dl4se-server/pom.xml | 4 ---- dl4se-server/src/main/resources/application.properties | 1 - 2 files changed, 5 deletions(-) diff --git a/dl4se-server/pom.xml b/dl4se-server/pom.xml index 190d7b79..adc2d0a7 100644 --- a/dl4se-server/pom.xml +++ b/dl4se-server/pom.xml @@ -90,10 +90,6 @@ org.springframework.boot spring-boot-starter-validation
- - org.springframework.boot - spring-boot-starter-jooq - org.springframework.boot spring-boot-starter-mail diff --git a/dl4se-server/src/main/resources/application.properties b/dl4se-server/src/main/resources/application.properties index aec3fa6a..fe55d42e 100644 --- a/dl4se-server/src/main/resources/application.properties +++ b/dl4se-server/src/main/resources/application.properties @@ -51,7 +51,6 @@ spring.data.web.pageable.one-indexed-parameters=true # Logging Configuration logging.level.usi.si.seart=INFO -logging.level.org.jooq.Constants=WARN # JPA Configuration spring.jpa.database=postgresql From e3a389efb746fcf542e89063a3b91531afc2fd0c Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 11 Oct 2023 11:17:36 +0200 Subject: [PATCH 0382/1089] Removed the `last_update` column from `configuration` --- .../main/java/usi/si/seart/model/Configuration.java | 13 ------------- liquibase/scripts/01_user.sql | 3 +-- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/dl4se-model/src/main/java/usi/si/seart/model/Configuration.java b/dl4se-model/src/main/java/usi/si/seart/model/Configuration.java index c8c79d52..95eb5240 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/Configuration.java +++ b/dl4se-model/src/main/java/usi/si/seart/model/Configuration.java @@ -9,15 +9,11 @@ import lombok.ToString; import lombok.experimental.FieldDefaults; -import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; -import javax.persistence.PreUpdate; import javax.persistence.Table; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; -import java.time.LocalDateTime; -import java.time.ZoneOffset; @Entity @Table(name = "configuration") @@ -36,13 +32,4 @@ public class Configuration { @NotNull String value; - - @NotNull - @Column(name = "last_update") - LocalDateTime lastUpdate; - - @PreUpdate - private void preUpdate() { - lastUpdate = LocalDateTime.now(ZoneOffset.UTC); - } } diff --git a/liquibase/scripts/01_user.sql b/liquibase/scripts/01_user.sql index 74e2fcc3..702068db 100644 --- a/liquibase/scripts/01_user.sql +++ b/liquibase/scripts/01_user.sql @@ -3,8 +3,7 @@ CREATE TABLE "configuration" ( "key" text PRIMARY KEY NOT NULL, - "value" text NOT NULL, - "last_update" timestamp NOT NULL + "value" text NOT NULL ); CREATE TABLE "user" ( From ebb257aee22f65798af5b54e327b142fdb814a54 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 11 Oct 2023 11:21:32 +0200 Subject: [PATCH 0383/1089] `Configuration` initialization is now handled by an `InitializingBean` This is similar to how languages are initialized in the crawler. It also makes more sense to do it this way, since the migrations should not be used to insert data into tables. That being said, the configurations will only configure the number of running tasks and maximum number of user requests for the time being. I believe that the CRON expressions are not helpful enough to be configurable. --- .../beans/ConfigurationInitializingBean.java | 40 +++++++++++++++++++ .../src/main/resources/configurations.yaml | 2 + liquibase/scripts/01_user.sql | 9 ----- 3 files changed, 42 insertions(+), 9 deletions(-) create mode 100644 dl4se-server/src/main/java/usi/si/seart/beans/ConfigurationInitializingBean.java create mode 100644 dl4se-server/src/main/resources/configurations.yaml diff --git a/dl4se-server/src/main/java/usi/si/seart/beans/ConfigurationInitializingBean.java b/dl4se-server/src/main/java/usi/si/seart/beans/ConfigurationInitializingBean.java new file mode 100644 index 00000000..cc8706e3 --- /dev/null +++ b/dl4se-server/src/main/java/usi/si/seart/beans/ConfigurationInitializingBean.java @@ -0,0 +1,40 @@ +package usi.si.seart.beans; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.experimental.FieldDefaults; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.stereotype.Component; +import org.yaml.snakeyaml.Yaml; +import usi.si.seart.model.Configuration; +import usi.si.seart.repository.ConfigurationRepository; + +import java.io.InputStream; +import java.util.Map; +import java.util.Optional; +import java.util.function.Supplier; + +@Component("ConfigurationInitializingBean") +@AllArgsConstructor(onConstructor_ = @Autowired) +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +public class ConfigurationInitializingBean implements InitializingBean { + + ConfigurationRepository configurationRepository; + + @Override + public void afterPropertiesSet() throws Exception { + Resource resource = new ClassPathResource("configurations.yaml"); + InputStream inputStream = resource.getInputStream(); + Map map = new Yaml().load(inputStream); + map.forEach((key, value) -> { + Optional optional = configurationRepository.findById(key); + Supplier supplier = () -> new Configuration(key, value); + Configuration configuration = optional.orElseGet(supplier); + configuration.setValue(value); + configurationRepository.save(configuration); + }); + } +} diff --git a/dl4se-server/src/main/resources/configurations.yaml b/dl4se-server/src/main/resources/configurations.yaml new file mode 100644 index 00000000..09c66fac --- /dev/null +++ b/dl4se-server/src/main/resources/configurations.yaml @@ -0,0 +1,2 @@ +request_limit: "3" +task_runner_count: "2" diff --git a/liquibase/scripts/01_user.sql b/liquibase/scripts/01_user.sql index 702068db..01edf426 100644 --- a/liquibase/scripts/01_user.sql +++ b/liquibase/scripts/01_user.sql @@ -57,12 +57,3 @@ CREATE INDEX "function_content_hash_idx" ON "function" (content_hash); CREATE INDEX "file_ast_hash_idx" ON "file" (ast_hash); CREATE INDEX "function_ast_hash_idx" ON "function" (ast_hash); CREATE INDEX "git_repo_stats_idx" ON "git_repo" (commits, contributors, issues, stars) INCLUDE (is_fork, license); - -INSERT INTO configuration(key, value, last_update) -VALUES - ('request_limit', '3', now()), - ('max_page_size', '100', now()), - ('task_runner_count', '2', now()), - ('task_cleaner_cron', '0 */15 * * * *', now()), - ('repo_maintainer_cron', '0 0 0 * * SUN', now()), - ('view_maintainer_cron', '0 0 0 * * *', now()); From a50a3f487cc847e95044b04c52ff9dc36a29829e Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 11 Oct 2023 11:46:48 +0200 Subject: [PATCH 0384/1089] `SchedulerConfig` now depends on the new `InitializingBean` --- .../src/main/java/usi/si/seart/config/SchedulerConfig.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java index 708f4bc8..3325fc46 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java @@ -14,6 +14,7 @@ import org.springframework.context.annotation.DependsOn; import org.springframework.core.convert.ConversionService; import org.springframework.scheduling.Trigger; +import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.scheduling.support.CronTrigger; import org.springframework.transaction.PlatformTransactionManager; @@ -39,7 +40,11 @@ import java.util.concurrent.ScheduledFuture; @Configuration -@DependsOn({"TaskRunnerRecoveryBean", "DirectoryInitializationBean"}) +@DependsOn({ + "ConfigurationInitializingBean", + "DirectoryInitializationBean", + "TaskRunnerRecoveryBean", +}) @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) @RequiredArgsConstructor(onConstructor_ = @Autowired) public class SchedulerConfig { From eddbbe2818ddec29749991addcd802566b9d25aa Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 11 Oct 2023 11:47:14 +0200 Subject: [PATCH 0385/1089] Removed the custom scheduler name --- .../src/main/java/usi/si/seart/config/SchedulerConfig.java | 1 - 1 file changed, 1 deletion(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java index 3325fc46..4d3393ff 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java @@ -101,7 +101,6 @@ public void shutdown() { threadPoolTaskScheduler.setDaemon(true); threadPoolTaskScheduler.setClock(Clock.systemUTC()); threadPoolTaskScheduler.setPoolSize(3 + runners); - threadPoolTaskScheduler.setThreadNamePrefix("DL4SEScheduler"); threadPoolTaskScheduler.setErrorHandler(new SchedulerErrorHandler()); threadPoolTaskScheduler.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); threadPoolTaskScheduler.initialize(); From f3695605770c1c69f902fa1b69ea81d09aae58c4 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 11 Oct 2023 11:47:36 +0200 Subject: [PATCH 0386/1089] Added missing annotation to the `@Configuration` class --- .../src/main/java/usi/si/seart/config/SchedulerConfig.java | 1 + 1 file changed, 1 insertion(+) diff --git a/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java index 4d3393ff..b49fe7c8 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java @@ -40,6 +40,7 @@ import java.util.concurrent.ScheduledFuture; @Configuration +@EnableScheduling @DependsOn({ "ConfigurationInitializingBean", "DirectoryInitializationBean", From f541b53480091c3ea0c90492e649e30d76a65dd6 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 11 Oct 2023 11:53:40 +0200 Subject: [PATCH 0387/1089] Improving `ViewMaintainer` scheduled job --- .../si/seart/scheduling/ViewMaintainer.java | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/scheduling/ViewMaintainer.java b/dl4se-server/src/main/java/usi/si/seart/scheduling/ViewMaintainer.java index 5601533d..1e62265a 100644 --- a/dl4se-server/src/main/java/usi/si/seart/scheduling/ViewMaintainer.java +++ b/dl4se-server/src/main/java/usi/si/seart/scheduling/ViewMaintainer.java @@ -5,9 +5,12 @@ import lombok.experimental.FieldDefaults; import lombok.extern.slf4j.Slf4j; import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; import java.util.List; import java.util.stream.Collectors; @@ -16,6 +19,11 @@ @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class ViewMaintainer implements Runnable { + private static final String SELECT = "SELECT matviewname AS material_view_name FROM pg_matviews;"; + + private static final String TEMPLATE = "REFRESH MATERIALIZED VIEW CONCURRENTLY %s;"; + + @PersistenceContext EntityManager entityManager; PlatformTransactionManager transactionManager; @@ -23,14 +31,25 @@ public class ViewMaintainer implements Runnable { @Override @SuppressWarnings("unchecked") public void run() { - String selectMaterialViews = "SELECT matviewname AS material_view_name FROM pg_matviews;"; - List views = entityManager.createNativeQuery(selectMaterialViews).getResultList(); + log.info("Recomputing statistics..."); + List views = entityManager.createNativeQuery(SELECT).getResultList(); String statements = views.stream() - .map(view -> String.format("REFRESH MATERIALIZED VIEW CONCURRENTLY %s;", view)) + .map(view -> String.format(TEMPLATE, view)) .collect(Collectors.joining()); - log.debug("Refreshing materialized views..."); TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager); - transactionTemplate.executeWithoutResult(status -> entityManager.createNativeQuery(statements).executeUpdate()); - log.debug("Finished refreshing materialized views."); + transactionTemplate.execute(new TransactionCallback(statements)); + log.info("Finished updating statistics."); + } + + @AllArgsConstructor(access = AccessLevel.PRIVATE) + @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) + private class TransactionCallback extends TransactionCallbackWithoutResult { + + String statements; + + @Override + protected void doInTransactionWithoutResult(TransactionStatus status) { + entityManager.createNativeQuery(statements).executeUpdate(); + } } } From 91c5acf90e756d8268676d67374e61616c1819bc Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 11 Oct 2023 11:54:16 +0200 Subject: [PATCH 0388/1089] Logging level changes to `TaskCleaner` scheduled job --- .../main/java/usi/si/seart/scheduling/TaskCleaner.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/scheduling/TaskCleaner.java b/dl4se-server/src/main/java/usi/si/seart/scheduling/TaskCleaner.java index 22a24256..90a2f638 100644 --- a/dl4se-server/src/main/java/usi/si/seart/scheduling/TaskCleaner.java +++ b/dl4se-server/src/main/java/usi/si/seart/scheduling/TaskCleaner.java @@ -18,13 +18,13 @@ public class TaskCleaner implements Runnable { @Override public void run() { - log.debug("Cleaning up expired task files..."); - taskService.forEachNonExpired(this::cleanAndFlag); - log.debug("Task cleaning complete!"); + log.info("Cleaning up expired task files..."); + taskService.forEachNonExpired(this::run); + log.info("Task cleaning complete!"); } - private void cleanAndFlag(Task task) { - log.trace("Deleting export file for task: [{}]", task.getUuid()); + private void run(Task task) { + log.debug("Deleting export file for task: [{}]", task.getUuid()); task.setExpired(true); fileSystemService.cleanTaskFiles(task); } From e9e6cd6b8caabd2db7cf574418c79b2fdb8b348c Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 11 Oct 2023 11:54:32 +0200 Subject: [PATCH 0389/1089] Logging level changes to `RepoMaintainer` scheduled job --- .../usi/si/seart/scheduling/RepoMaintainer.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/scheduling/RepoMaintainer.java b/dl4se-server/src/main/java/usi/si/seart/scheduling/RepoMaintainer.java index e58724fa..24ee6b42 100644 --- a/dl4se-server/src/main/java/usi/si/seart/scheduling/RepoMaintainer.java +++ b/dl4se-server/src/main/java/usi/si/seart/scheduling/RepoMaintainer.java @@ -20,17 +20,17 @@ public class RepoMaintainer implements Runnable { @Override public void run() { - log.debug("Running repository maintenance..."); - gitRepoService.forEach(this::checkExists); - log.debug("Repository maintenance complete!"); + log.info("Running repository maintenance..."); + gitRepoService.forEach(this::run); + log.info("Repository maintenance complete!"); } @SneakyThrows({IOException.class, InterruptedException.class}) - private void checkExists(GitRepo gitRepo) { + private void run(GitRepo gitRepo) { String name = gitRepo.getName(); String url = String.format("https://github.com/%s", name); - log.trace("Checking if Git repository exists: [{}]", name); + log.debug("Checking if Git repository exists: [{}]", name); ProcessBuilder pb = new ProcessBuilder("git", "ls-remote", url); pb.environment().put("GIT_TERMINAL_PROMPT", "0"); @@ -42,9 +42,9 @@ private void checkExists(GitRepo gitRepo) { if (exited) { isUnavailable = process.exitValue() != 0; } else { - log.trace("Attempting to terminate timed-out process: [{}]", pid); + log.debug("Attempting to terminate timed-out process: [{}]", pid); while (process.isAlive()) process.destroyForcibly(); - log.trace("Terminated timed-out process: [{}]", pid); + log.debug("Terminated timed-out process: [{}]", pid); } gitRepo.setIsUnavailable(isUnavailable); From 99f46fcbb790b51e5808b278b56184c2349ad104 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 11 Oct 2023 12:05:28 +0200 Subject: [PATCH 0390/1089] Triggers for CRON-scheduled tasks now reside in `application.properties` --- .../usi/si/seart/config/SchedulerConfig.java | 17 +++++++++-------- .../src/main/resources/application.properties | 4 ++++ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java index b49fe7c8..9c7fe57f 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java @@ -70,13 +70,14 @@ public class SchedulerConfig { Integer fetchSize; @Bean(destroyMethod="shutdown") - public ThreadPoolTaskScheduler taskScheduler() { + public ThreadPoolTaskScheduler taskScheduler( + @Value("${scheduling.task.task-cleaner.cron}") CronTrigger taskCleanerTrigger, + @Value("${scheduling.task.repo-maintainer.cron}") CronTrigger repoMaintainerTrigger, + @Value("${scheduling.task.view-maintainer.cron}") CronTrigger viewMaintainerTrigger + ) { Integer runners = configurationService.get("task_runner_count", Integer.class); - String taskCleanerCron = configurationService.get("task_cleaner_cron", String.class); - String repoMaintainerCron = configurationService.get("repo_maintainer_cron", String.class); - String viewMaintainerCron = configurationService.get("view_maintainer_cron", String.class); - ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler() { + private final Set> futures = new HashSet<>(); @Override @@ -106,9 +107,9 @@ public void shutdown() { threadPoolTaskScheduler.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); threadPoolTaskScheduler.initialize(); - threadPoolTaskScheduler.schedule(getRepoMaintainer(), new CronTrigger(repoMaintainerCron)); - threadPoolTaskScheduler.schedule(getTaskCleaner(), new CronTrigger(taskCleanerCron)); - threadPoolTaskScheduler.schedule(getViewMaintainer(), new CronTrigger(viewMaintainerCron)); + threadPoolTaskScheduler.schedule(getTaskCleaner(), taskCleanerTrigger); + threadPoolTaskScheduler.schedule(getRepoMaintainer(), repoMaintainerTrigger); + threadPoolTaskScheduler.schedule(getViewMaintainer(), viewMaintainerTrigger); for (int i = 0; i < runners; i++) threadPoolTaskScheduler.scheduleWithFixedDelay(getTaskRunner(), 500); diff --git a/dl4se-server/src/main/resources/application.properties b/dl4se-server/src/main/resources/application.properties index fe55d42e..01a0c0ea 100644 --- a/dl4se-server/src/main/resources/application.properties +++ b/dl4se-server/src/main/resources/application.properties @@ -80,3 +80,7 @@ website.url=${WEBSITE_URL:http://${website.host}:${website.port}} # JWT Configuration jwt.secret=${SERVER_JWT_SECRET} + +scheduling.task.task-cleaner.cron=0 */15 * * * * +scheduling.task.repo-maintainer.cron=0 0 0 * * SUN +scheduling.task.view-maintainer.cron=0 0 0 * * * From 4d93df3e0f42b66300395efc57f8b8edab33827f Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 11 Oct 2023 12:14:06 +0200 Subject: [PATCH 0391/1089] CRON-triggered jobs are now all components --- .../usi/si/seart/config/SchedulerConfig.java | 23 +++++-------------- .../si/seart/scheduling/RepoMaintainer.java | 5 +++- .../usi/si/seart/scheduling/TaskCleaner.java | 5 +++- .../si/seart/scheduling/ViewMaintainer.java | 5 +++- 4 files changed, 18 insertions(+), 20 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java index 9c7fe57f..54c1d898 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java @@ -29,7 +29,6 @@ import usi.si.seart.service.ConfigurationService; import usi.si.seart.service.EmailService; import usi.si.seart.service.FileSystemService; -import usi.si.seart.service.GitRepoService; import usi.si.seart.service.TaskService; import javax.persistence.EntityManager; @@ -54,7 +53,6 @@ public class SchedulerConfig { CodeService codeService; TaskService taskService; - GitRepoService gitRepoService; EmailService emailService; FileSystemService fileSystemService; ConversionService conversionService; @@ -71,6 +69,9 @@ public class SchedulerConfig { @Bean(destroyMethod="shutdown") public ThreadPoolTaskScheduler taskScheduler( + TaskCleaner taskCleaner, + RepoMaintainer repoMaintainer, + ViewMaintainer viewMaintainer, @Value("${scheduling.task.task-cleaner.cron}") CronTrigger taskCleanerTrigger, @Value("${scheduling.task.repo-maintainer.cron}") CronTrigger repoMaintainerTrigger, @Value("${scheduling.task.view-maintainer.cron}") CronTrigger viewMaintainerTrigger @@ -107,27 +108,15 @@ public void shutdown() { threadPoolTaskScheduler.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); threadPoolTaskScheduler.initialize(); - threadPoolTaskScheduler.schedule(getTaskCleaner(), taskCleanerTrigger); - threadPoolTaskScheduler.schedule(getRepoMaintainer(), repoMaintainerTrigger); - threadPoolTaskScheduler.schedule(getViewMaintainer(), viewMaintainerTrigger); + threadPoolTaskScheduler.schedule(taskCleaner, taskCleanerTrigger); + threadPoolTaskScheduler.schedule(repoMaintainer, repoMaintainerTrigger); + threadPoolTaskScheduler.schedule(viewMaintainer, viewMaintainerTrigger); for (int i = 0; i < runners; i++) threadPoolTaskScheduler.scheduleWithFixedDelay(getTaskRunner(), 500); return threadPoolTaskScheduler; } - private Runnable getRepoMaintainer() { - return new RepoMaintainer(gitRepoService); - } - - private Runnable getTaskCleaner() { - return new TaskCleaner(taskService, fileSystemService); - } - - private Runnable getViewMaintainer() { - return new ViewMaintainer(entityManager, transactionManager); - } - private Runnable getTaskRunner() { return new TaskRunner( jsonMapper, diff --git a/dl4se-server/src/main/java/usi/si/seart/scheduling/RepoMaintainer.java b/dl4se-server/src/main/java/usi/si/seart/scheduling/RepoMaintainer.java index 24ee6b42..906a8348 100644 --- a/dl4se-server/src/main/java/usi/si/seart/scheduling/RepoMaintainer.java +++ b/dl4se-server/src/main/java/usi/si/seart/scheduling/RepoMaintainer.java @@ -5,6 +5,8 @@ import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; import usi.si.seart.model.GitRepo; import usi.si.seart.service.GitRepoService; @@ -12,7 +14,8 @@ import java.util.concurrent.TimeUnit; @Slf4j -@AllArgsConstructor +@Component +@AllArgsConstructor(onConstructor_ = @Autowired) @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class RepoMaintainer implements Runnable { diff --git a/dl4se-server/src/main/java/usi/si/seart/scheduling/TaskCleaner.java b/dl4se-server/src/main/java/usi/si/seart/scheduling/TaskCleaner.java index 90a2f638..959c7d92 100644 --- a/dl4se-server/src/main/java/usi/si/seart/scheduling/TaskCleaner.java +++ b/dl4se-server/src/main/java/usi/si/seart/scheduling/TaskCleaner.java @@ -4,12 +4,15 @@ import lombok.AllArgsConstructor; import lombok.experimental.FieldDefaults; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; import usi.si.seart.model.task.Task; import usi.si.seart.service.FileSystemService; import usi.si.seart.service.TaskService; @Slf4j -@AllArgsConstructor +@Component +@AllArgsConstructor(onConstructor_ = @Autowired) @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class TaskCleaner implements Runnable { diff --git a/dl4se-server/src/main/java/usi/si/seart/scheduling/ViewMaintainer.java b/dl4se-server/src/main/java/usi/si/seart/scheduling/ViewMaintainer.java index 1e62265a..d0135ab4 100644 --- a/dl4se-server/src/main/java/usi/si/seart/scheduling/ViewMaintainer.java +++ b/dl4se-server/src/main/java/usi/si/seart/scheduling/ViewMaintainer.java @@ -4,6 +4,8 @@ import lombok.AllArgsConstructor; import lombok.experimental.FieldDefaults; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallbackWithoutResult; @@ -15,7 +17,8 @@ import java.util.stream.Collectors; @Slf4j -@AllArgsConstructor +@Component +@AllArgsConstructor(onConstructor_ = @Autowired) @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class ViewMaintainer implements Runnable { From f04bc34af9a5e65c345f217f8de57c2ba57a398d Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 11 Oct 2023 12:19:06 +0200 Subject: [PATCH 0392/1089] Revert "Removed the custom scheduler name" This commit reverts eddbbe2818ddec29749991addcd802566b9d25aa. --- .../src/main/java/usi/si/seart/config/SchedulerConfig.java | 1 + 1 file changed, 1 insertion(+) diff --git a/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java index 54c1d898..e46c8383 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java @@ -104,6 +104,7 @@ public void shutdown() { threadPoolTaskScheduler.setDaemon(true); threadPoolTaskScheduler.setClock(Clock.systemUTC()); threadPoolTaskScheduler.setPoolSize(3 + runners); + threadPoolTaskScheduler.setThreadNamePrefix("scheduling-"); threadPoolTaskScheduler.setErrorHandler(new SchedulerErrorHandler()); threadPoolTaskScheduler.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); threadPoolTaskScheduler.initialize(); From 7e7ecd46e5f45033a5493c7fcf19f18081def1c7 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 11 Oct 2023 14:19:53 +0200 Subject: [PATCH 0393/1089] `ErrorHandler` in `SchedulerConfig` is now created as a Bean --- .../usi/si/seart/config/SchedulerConfig.java | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java index e46c8383..16cecfbd 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java @@ -69,6 +69,7 @@ public class SchedulerConfig { @Bean(destroyMethod="shutdown") public ThreadPoolTaskScheduler taskScheduler( + ErrorHandler errorHandler, TaskCleaner taskCleaner, RepoMaintainer repoMaintainer, ViewMaintainer viewMaintainer, @@ -105,7 +106,7 @@ public void shutdown() { threadPoolTaskScheduler.setClock(Clock.systemUTC()); threadPoolTaskScheduler.setPoolSize(3 + runners); threadPoolTaskScheduler.setThreadNamePrefix("scheduling-"); - threadPoolTaskScheduler.setErrorHandler(new SchedulerErrorHandler()); + threadPoolTaskScheduler.setErrorHandler(errorHandler); threadPoolTaskScheduler.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); threadPoolTaskScheduler.initialize(); @@ -132,25 +133,30 @@ private Runnable getTaskRunner() { ); } - private class SchedulerErrorHandler implements ErrorHandler { + @Bean + public ErrorHandler errorHandler( + TaskService taskService, EmailService emailService, FileSystemService fileSystemService + ) { + return new ErrorHandler() { - private final Logger log = LoggerFactory.getLogger(this.getClass()); + private final Logger log = LoggerFactory.getLogger("usi.si.seart.config.SchedulerConfig$ErrorHandler"); - @Override - public void handleError(Throwable t) { - if (t instanceof TaskFailedException) { - handleError((TaskFailedException) t); - } else { - log.error("Unhandled exception occurred while performing a scheduled job.", t); + @Override + public void handleError(Throwable t) { + if (t instanceof TaskFailedException) { + handleError((TaskFailedException) t); + } else { + log.error("Unhandled exception occurred while performing a scheduled job.", t); + } } - } - - private void handleError(TaskFailedException ex) { - log.warn(ex.getMessage()); - taskService.registerException(ex); - Task task = ex.getTask(); - fileSystemService.cleanTaskFiles(task); - emailService.sendTaskNotificationEmail(task); - } + + private void handleError(TaskFailedException ex) { + log.warn(ex.getMessage()); + taskService.registerException(ex); + Task task = ex.getTask(); + fileSystemService.cleanTaskFiles(task); + emailService.sendTaskNotificationEmail(task); + } + }; } } From 8217f9cff3cc35b132f8d4b8046056413188e72d Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 11 Oct 2023 14:43:09 +0200 Subject: [PATCH 0394/1089] `TaskRunner` is now a prototype-scope component This implies that a new instance is created every time on dependency- injection. This may not seem desirable, until you realize that only the `SchedulerConfig` is the only class that creates its instances. This is a far superior solution as opposed to the non-component one. --- .../usi/si/seart/config/SchedulerConfig.java | 53 ++++--------------- .../usi/si/seart/scheduling/TaskRunner.java | 33 +++++++++++- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java index 16cecfbd..a2f13563 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java @@ -1,23 +1,21 @@ package usi.si.seart.config; -import com.fasterxml.jackson.databind.json.JsonMapper; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import lombok.experimental.FieldDefaults; -import lombok.experimental.NonFinal; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.beans.factory.config.AutowireCapableBeanFactory; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; -import org.springframework.core.convert.ConversionService; import org.springframework.scheduling.Trigger; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.scheduling.support.CronTrigger; -import org.springframework.transaction.PlatformTransactionManager; import org.springframework.util.ErrorHandler; import usi.si.seart.exception.TaskFailedException; import usi.si.seart.model.task.Task; @@ -25,14 +23,11 @@ import usi.si.seart.scheduling.TaskCleaner; import usi.si.seart.scheduling.TaskRunner; import usi.si.seart.scheduling.ViewMaintainer; -import usi.si.seart.service.CodeService; import usi.si.seart.service.ConfigurationService; import usi.si.seart.service.EmailService; import usi.si.seart.service.FileSystemService; import usi.si.seart.service.TaskService; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; import java.time.Clock; import java.util.HashSet; import java.util.Set; @@ -49,34 +44,19 @@ @RequiredArgsConstructor(onConstructor_ = @Autowired) public class SchedulerConfig { - JsonMapper jsonMapper; - - CodeService codeService; - TaskService taskService; - EmailService emailService; - FileSystemService fileSystemService; - ConversionService conversionService; - ConfigurationService configurationService; - - PlatformTransactionManager transactionManager; - - @PersistenceContext - EntityManager entityManager; - - @NonFinal - @Value("${spring.jpa.properties.hibernate.jdbc.fetch_size}") - Integer fetchSize; - @Bean(destroyMethod="shutdown") public ThreadPoolTaskScheduler taskScheduler( + ApplicationContext applicationContext, ErrorHandler errorHandler, TaskCleaner taskCleaner, RepoMaintainer repoMaintainer, ViewMaintainer viewMaintainer, @Value("${scheduling.task.task-cleaner.cron}") CronTrigger taskCleanerTrigger, @Value("${scheduling.task.repo-maintainer.cron}") CronTrigger repoMaintainerTrigger, - @Value("${scheduling.task.view-maintainer.cron}") CronTrigger viewMaintainerTrigger + @Value("${scheduling.task.view-maintainer.cron}") CronTrigger viewMaintainerTrigger, + ConfigurationService configurationService ) { + AutowireCapableBeanFactory autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory(); Integer runners = configurationService.get("task_runner_count", Integer.class); ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler() { @@ -113,24 +93,13 @@ public void shutdown() { threadPoolTaskScheduler.schedule(taskCleaner, taskCleanerTrigger); threadPoolTaskScheduler.schedule(repoMaintainer, repoMaintainerTrigger); threadPoolTaskScheduler.schedule(viewMaintainer, viewMaintainerTrigger); - for (int i = 0; i < runners; i++) - threadPoolTaskScheduler.scheduleWithFixedDelay(getTaskRunner(), 500); - return threadPoolTaskScheduler; - } + for (int i = 0; i < runners; i++) { + TaskRunner taskRunner = autowireCapableBeanFactory.createBean(TaskRunner.class); + threadPoolTaskScheduler.scheduleWithFixedDelay(taskRunner, 500); + } - private Runnable getTaskRunner() { - return new TaskRunner( - jsonMapper, - codeService, - taskService, - emailService, - fileSystemService, - conversionService, - transactionManager, - entityManager, - fetchSize - ); + return threadPoolTaskScheduler; } @Bean diff --git a/dl4se-server/src/main/java/usi/si/seart/scheduling/TaskRunner.java b/dl4se-server/src/main/java/usi/si/seart/scheduling/TaskRunner.java index c5bd8278..804d3b7e 100644 --- a/dl4se-server/src/main/java/usi/si/seart/scheduling/TaskRunner.java +++ b/dl4se-server/src/main/java/usi/si/seart/scheduling/TaskRunner.java @@ -8,9 +8,14 @@ import lombok.experimental.FieldDefaults; import lombok.extern.slf4j.Slf4j; import org.bouncycastle.util.Iterable; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; import org.springframework.core.convert.ConversionService; import org.springframework.dao.OptimisticLockingFailureException; import org.springframework.data.jpa.domain.Specification; +import org.springframework.stereotype.Component; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallbackWithoutResult; @@ -26,6 +31,7 @@ import usi.si.seart.service.TaskService; import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; import java.io.BufferedWriter; import java.io.FileOutputStream; import java.io.OutputStreamWriter; @@ -37,7 +43,8 @@ import java.util.zip.GZIPOutputStream; @Slf4j -@AllArgsConstructor +@Component +@Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE) @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class TaskRunner implements Runnable { @@ -51,10 +58,34 @@ public class TaskRunner implements Runnable { PlatformTransactionManager transactionManager; + @PersistenceContext EntityManager entityManager; Integer fetchSize; + @Autowired + public TaskRunner( + JsonMapper jsonMapper, + CodeService codeService, + TaskService taskService, + EmailService emailService, + FileSystemService fileSystemService, + ConversionService conversionService, + PlatformTransactionManager transactionManager, + EntityManager entityManager, + @Value("${spring.jpa.properties.hibernate.jdbc.fetch_size}") Integer fetchSize + ) { + this.jsonMapper = jsonMapper; + this.codeService = codeService; + this.taskService = taskService; + this.emailService = emailService; + this.fileSystemService = fileSystemService; + this.conversionService = conversionService; + this.transactionManager = transactionManager; + this.entityManager = entityManager; + this.fetchSize = fetchSize; + } + @Override public void run() { log.debug("Fetching next task to execute..."); From 3c208444c975adfeea9175d3acd203bebc543b80 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 11 Oct 2023 15:01:44 +0200 Subject: [PATCH 0395/1089] Renaming package `beans` -> `bean` --- .../si/seart/{beans => bean}/ConfigurationInitializingBean.java | 2 +- .../si/seart/{beans => bean}/DirectoryInitializationBean.java | 2 +- .../usi/si/seart/{beans => bean}/TaskRunnerRecoveryBean.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename dl4se-server/src/main/java/usi/si/seart/{beans => bean}/ConfigurationInitializingBean.java (98%) rename dl4se-server/src/main/java/usi/si/seart/{beans => bean}/DirectoryInitializationBean.java (96%) rename dl4se-server/src/main/java/usi/si/seart/{beans => bean}/TaskRunnerRecoveryBean.java (97%) diff --git a/dl4se-server/src/main/java/usi/si/seart/beans/ConfigurationInitializingBean.java b/dl4se-server/src/main/java/usi/si/seart/bean/ConfigurationInitializingBean.java similarity index 98% rename from dl4se-server/src/main/java/usi/si/seart/beans/ConfigurationInitializingBean.java rename to dl4se-server/src/main/java/usi/si/seart/bean/ConfigurationInitializingBean.java index cc8706e3..07d8215a 100644 --- a/dl4se-server/src/main/java/usi/si/seart/beans/ConfigurationInitializingBean.java +++ b/dl4se-server/src/main/java/usi/si/seart/bean/ConfigurationInitializingBean.java @@ -1,4 +1,4 @@ -package usi.si.seart.beans; +package usi.si.seart.bean; import lombok.AccessLevel; import lombok.AllArgsConstructor; diff --git a/dl4se-server/src/main/java/usi/si/seart/beans/DirectoryInitializationBean.java b/dl4se-server/src/main/java/usi/si/seart/bean/DirectoryInitializationBean.java similarity index 96% rename from dl4se-server/src/main/java/usi/si/seart/beans/DirectoryInitializationBean.java rename to dl4se-server/src/main/java/usi/si/seart/bean/DirectoryInitializationBean.java index 48270a67..4be5dd79 100644 --- a/dl4se-server/src/main/java/usi/si/seart/beans/DirectoryInitializationBean.java +++ b/dl4se-server/src/main/java/usi/si/seart/bean/DirectoryInitializationBean.java @@ -1,4 +1,4 @@ -package usi.si.seart.beans; +package usi.si.seart.bean; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; diff --git a/dl4se-server/src/main/java/usi/si/seart/beans/TaskRunnerRecoveryBean.java b/dl4se-server/src/main/java/usi/si/seart/bean/TaskRunnerRecoveryBean.java similarity index 97% rename from dl4se-server/src/main/java/usi/si/seart/beans/TaskRunnerRecoveryBean.java rename to dl4se-server/src/main/java/usi/si/seart/bean/TaskRunnerRecoveryBean.java index 36c00acf..63f4737f 100644 --- a/dl4se-server/src/main/java/usi/si/seart/beans/TaskRunnerRecoveryBean.java +++ b/dl4se-server/src/main/java/usi/si/seart/bean/TaskRunnerRecoveryBean.java @@ -1,4 +1,4 @@ -package usi.si.seart.beans; +package usi.si.seart.bean; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; From 606948b8d46b4a2993197870fe84d948693c8845 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 11 Oct 2023 15:13:37 +0200 Subject: [PATCH 0396/1089] Removing redundant annotations --- .../src/main/java/usi/si/seart/config/SchedulerConfig.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java index a2f13563..6f8d06ba 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java @@ -1,11 +1,7 @@ package usi.si.seart.config; -import lombok.AccessLevel; -import lombok.RequiredArgsConstructor; -import lombok.experimental.FieldDefaults; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.context.ApplicationContext; @@ -40,8 +36,6 @@ "DirectoryInitializationBean", "TaskRunnerRecoveryBean", }) -@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) -@RequiredArgsConstructor(onConstructor_ = @Autowired) public class SchedulerConfig { @Bean(destroyMethod="shutdown") From 6b1ff30cad3e1aa8e6386f5cb1309375905ec423 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 11 Oct 2023 16:31:49 +0200 Subject: [PATCH 0397/1089] Introducing `ReadableFileSize` utility class --- .../usi/si/seart/service/EmailService.java | 31 ++--------------- .../si/seart/util/unit/ReadableFileSize.java | 34 +++++++++++++++++++ 2 files changed, 36 insertions(+), 29 deletions(-) create mode 100644 dl4se-server/src/main/java/usi/si/seart/util/unit/ReadableFileSize.java diff --git a/dl4se-server/src/main/java/usi/si/seart/service/EmailService.java b/dl4se-server/src/main/java/usi/si/seart/service/EmailService.java index 6baf4bb7..d6c909ef 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/EmailService.java +++ b/dl4se-server/src/main/java/usi/si/seart/service/EmailService.java @@ -1,7 +1,6 @@ package usi.si.seart.service; import lombok.AccessLevel; -import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; @@ -15,12 +14,11 @@ import org.thymeleaf.context.Context; import org.thymeleaf.spring5.SpringTemplateEngine; import usi.si.seart.model.task.Task; +import usi.si.seart.util.unit.ReadableFileSize; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; import java.nio.charset.StandardCharsets; -import java.text.CharacterIterator; -import java.text.StringCharacterIterator; import java.util.HashMap; import java.util.Map; @@ -66,7 +64,7 @@ public void sendTaskNotificationEmail(Task task) { String uuidString = task.getUuid().toString(); String statusName = task.getStatus().name(); String subject = String.format("Task [%s]: %s", uuidString, statusName); - FileSize exportSize = new FileSize(task.getSize()); + ReadableFileSize exportSize = new ReadableFileSize(task.getSize()); Map variables = new HashMap<>(); variables.put("uuid", uuidString); @@ -118,30 +116,5 @@ private MimeMessage createMessage( helper.setText(html, true); return message; } - - // TODO 03.11.22: We may want to move this somewhere else later - @AllArgsConstructor - private static class FileSize { - - private final long bytes; - - private static final double UNIT = 1024.0; - - @Override - public String toString() { - // https://stackoverflow.com/a/3758880/17173324 - long absolute = bytes == Long.MIN_VALUE ? Long.MAX_VALUE : Math.abs(bytes); - if (absolute < UNIT) - return bytes + " B"; - long value = absolute; - CharacterIterator ci = new StringCharacterIterator("KMGTPE"); - for (int i = 40; i >= 0 && absolute > 0xfffccccccccccccL >> i; i -= 10) { - value >>= 10; - ci.next(); - } - value *= Long.signum(bytes); - return String.format("%.2f %cB", value / UNIT, ci.current()); - } - } } } diff --git a/dl4se-server/src/main/java/usi/si/seart/util/unit/ReadableFileSize.java b/dl4se-server/src/main/java/usi/si/seart/util/unit/ReadableFileSize.java new file mode 100644 index 00000000..897ef2fc --- /dev/null +++ b/dl4se-server/src/main/java/usi/si/seart/util/unit/ReadableFileSize.java @@ -0,0 +1,34 @@ +package usi.si.seart.util.unit; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.experimental.FieldDefaults; + +import java.text.CharacterIterator; +import java.text.StringCharacterIterator; + +@Getter +@AllArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +public final class ReadableFileSize { + + private static final double UNIT = 1024.0; + + long bytes; + + @Override + public String toString() { + // https://stackoverflow.com/a/3758880/17173324 + long absolute = bytes == Long.MIN_VALUE ? Long.MAX_VALUE : Math.abs(bytes); + if (absolute < UNIT) return bytes + " B"; + long value = absolute; + CharacterIterator ci = new StringCharacterIterator("KMGTPE"); + for (int i = 40; i >= 0 && absolute > 0xfffccccccccccccL >> i; i -= 10) { + value >>= 10; + ci.next(); + } + value *= Long.signum(bytes); + return String.format("%.2f %cB", value / UNIT, ci.current()); + } +} From 0dfac06adf0151792671b03a3dd04368e896be83 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 11 Oct 2023 16:44:05 +0200 Subject: [PATCH 0398/1089] Simplified a statement when creating mail message context --- .../src/main/java/usi/si/seart/service/EmailService.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/service/EmailService.java b/dl4se-server/src/main/java/usi/si/seart/service/EmailService.java index d6c909ef..dc25437b 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/EmailService.java +++ b/dl4se-server/src/main/java/usi/si/seart/service/EmailService.java @@ -106,9 +106,7 @@ private MimeMessage createMessage( StandardCharsets.UTF_8.name() ); - Context context = new Context(); - context.setVariables(variables); - + Context context = new Context(null, variables); String html = templateEngine.process(template, context); helper.setFrom(sender); helper.setTo(recipient); From 3d4763bc86fb74235b938b19f068af0963b3a6d9 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 11 Oct 2023 16:53:01 +0200 Subject: [PATCH 0399/1089] `sendTaskNotificationEmail` now also uses immutable maps --- .../usi/si/seart/service/EmailService.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/service/EmailService.java b/dl4se-server/src/main/java/usi/si/seart/service/EmailService.java index dc25437b..f2369a8f 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/EmailService.java +++ b/dl4se-server/src/main/java/usi/si/seart/service/EmailService.java @@ -19,7 +19,6 @@ import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; import java.nio.charset.StandardCharsets; -import java.util.HashMap; import java.util.Map; public interface EmailService { @@ -65,15 +64,15 @@ public void sendTaskNotificationEmail(Task task) { String statusName = task.getStatus().name(); String subject = String.format("Task [%s]: %s", uuidString, statusName); ReadableFileSize exportSize = new ReadableFileSize(task.getSize()); - - Map variables = new HashMap<>(); - variables.put("uuid", uuidString); - variables.put("status", statusName); - variables.put("submitted", task.getSubmitted()); - variables.put("started", task.getStarted()); - variables.put("finished", task.getFinished()); - variables.put("results", task.getProcessedResults()); - variables.put("size", exportSize.toString()); + Map variables = Map.ofEntries( + Map.entry("uuid", uuidString), + Map.entry("status", statusName), + Map.entry("submitted", task.getSubmitted()), + Map.entry("started", task.getStarted()), + Map.entry("finished", task.getFinished()), + Map.entry("results", task.getProcessedResults()), + Map.entry("size", exportSize.toString()) + ); MimeMessage message = createMessage("task_notification", recipient, subject, variables); mailSender.send(message); From e7d65275a87bf26ad8c840b00600a91fc6c95d74 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 11 Oct 2023 17:03:41 +0200 Subject: [PATCH 0400/1089] `Configuration` instances are now only initialized if they are missing This prevents instances of overwriting configurations with file settings once they are changed. Although now that I think about it, it might be better to migrate these to a properties file. --- .../bean/ConfigurationInitializingBean.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/bean/ConfigurationInitializingBean.java b/dl4se-server/src/main/java/usi/si/seart/bean/ConfigurationInitializingBean.java index 07d8215a..092d1e19 100644 --- a/dl4se-server/src/main/java/usi/si/seart/bean/ConfigurationInitializingBean.java +++ b/dl4se-server/src/main/java/usi/si/seart/bean/ConfigurationInitializingBean.java @@ -14,8 +14,6 @@ import java.io.InputStream; import java.util.Map; -import java.util.Optional; -import java.util.function.Supplier; @Component("ConfigurationInitializingBean") @AllArgsConstructor(onConstructor_ = @Autowired) @@ -29,12 +27,16 @@ public void afterPropertiesSet() throws Exception { Resource resource = new ClassPathResource("configurations.yaml"); InputStream inputStream = resource.getInputStream(); Map map = new Yaml().load(inputStream); - map.forEach((key, value) -> { - Optional optional = configurationRepository.findById(key); - Supplier supplier = () -> new Configuration(key, value); - Configuration configuration = optional.orElseGet(supplier); - configuration.setValue(value); - configurationRepository.save(configuration); - }); + map.entrySet().stream() + .filter(entry -> { + String key = entry.getKey(); + return !configurationRepository.existsById(key); + }) + .forEach(entry -> { + String key = entry.getKey(); + String value = entry.getValue(); + Configuration configuration = new Configuration(key, value); + configurationRepository.save(configuration); + }); } } From bfab96b96b221fea48ecd7bb8319b76c0f57782e Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 11 Oct 2023 17:41:43 +0200 Subject: [PATCH 0401/1089] `Configuration` instances created directly from properties file --- .../bean/ConfigurationInitializingBean.java | 33 ++++++++++--------- .../src/main/resources/application.properties | 3 ++ .../src/main/resources/configurations.yaml | 2 -- 3 files changed, 20 insertions(+), 18 deletions(-) delete mode 100644 dl4se-server/src/main/resources/configurations.yaml diff --git a/dl4se-server/src/main/java/usi/si/seart/bean/ConfigurationInitializingBean.java b/dl4se-server/src/main/java/usi/si/seart/bean/ConfigurationInitializingBean.java index 092d1e19..3c2fc110 100644 --- a/dl4se-server/src/main/java/usi/si/seart/bean/ConfigurationInitializingBean.java +++ b/dl4se-server/src/main/java/usi/si/seart/bean/ConfigurationInitializingBean.java @@ -7,13 +7,13 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PropertiesLoaderUtils; import org.springframework.stereotype.Component; -import org.yaml.snakeyaml.Yaml; import usi.si.seart.model.Configuration; import usi.si.seart.repository.ConfigurationRepository; -import java.io.InputStream; import java.util.Map; +import java.util.Properties; @Component("ConfigurationInitializingBean") @AllArgsConstructor(onConstructor_ = @Autowired) @@ -24,19 +24,20 @@ public class ConfigurationInitializingBean implements InitializingBean { @Override public void afterPropertiesSet() throws Exception { - Resource resource = new ClassPathResource("configurations.yaml"); - InputStream inputStream = resource.getInputStream(); - Map map = new Yaml().load(inputStream); - map.entrySet().stream() - .filter(entry -> { - String key = entry.getKey(); - return !configurationRepository.existsById(key); - }) - .forEach(entry -> { - String key = entry.getKey(); - String value = entry.getValue(); - Configuration configuration = new Configuration(key, value); - configurationRepository.save(configuration); - }); + Resource resource = new ClassPathResource("application.properties"); + Properties properties = PropertiesLoaderUtils.loadProperties(resource); + properties.entrySet().stream() + .map(entry -> Map.entry( + entry.getKey().toString(), + entry.getValue().toString() + )) + .filter(entry -> entry.getKey().startsWith("configuration")) + .map(entry -> Map.entry( + entry.getKey().substring(14), + entry.getValue() + )) + .filter(entry -> !configurationRepository.existsById(entry.getKey())) + .map(entry -> new Configuration(entry.getKey(), entry.getValue())) + .forEach(configurationRepository::save); } } diff --git a/dl4se-server/src/main/resources/application.properties b/dl4se-server/src/main/resources/application.properties index 01a0c0ea..ef354cff 100644 --- a/dl4se-server/src/main/resources/application.properties +++ b/dl4se-server/src/main/resources/application.properties @@ -84,3 +84,6 @@ jwt.secret=${SERVER_JWT_SECRET} scheduling.task.task-cleaner.cron=0 */15 * * * * scheduling.task.repo-maintainer.cron=0 0 0 * * SUN scheduling.task.view-maintainer.cron=0 0 0 * * * + +configuration.request_limit=3 +configuration.task_runner_count=2 diff --git a/dl4se-server/src/main/resources/configurations.yaml b/dl4se-server/src/main/resources/configurations.yaml deleted file mode 100644 index 09c66fac..00000000 --- a/dl4se-server/src/main/resources/configurations.yaml +++ /dev/null @@ -1,2 +0,0 @@ -request_limit: "3" -task_runner_count: "2" From 2afda139ced7c36e6cf6228c82e0caf8f6c4e214 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 12 Oct 2023 10:05:08 +0200 Subject: [PATCH 0402/1089] Logger name no longer hard-coded --- .../src/main/java/usi/si/seart/config/SchedulerConfig.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java index 6f8d06ba..4f4cee7d 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java @@ -102,7 +102,9 @@ public ErrorHandler errorHandler( ) { return new ErrorHandler() { - private final Logger log = LoggerFactory.getLogger("usi.si.seart.config.SchedulerConfig$ErrorHandler"); + private final Logger log = LoggerFactory.getLogger( + SchedulerConfig.class.getCanonicalName() + "$" + ErrorHandler.class.getSimpleName() + ); @Override public void handleError(Throwable t) { From efaea15a44a3a3b6df1fed6cf9e265116260b325 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 12 Oct 2023 10:23:00 +0200 Subject: [PATCH 0403/1089] Moving locks of `ConfigurationService` to outside the try block --- .../java/usi/si/seart/service/ConfigurationService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/service/ConfigurationService.java b/dl4se-server/src/main/java/usi/si/seart/service/ConfigurationService.java index 28675d88..8f3d9604 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/ConfigurationService.java +++ b/dl4se-server/src/main/java/usi/si/seart/service/ConfigurationService.java @@ -50,8 +50,8 @@ public PropertySource getPropertySource() { @Override public T get(String key, Class type) { + readLock.lock(); try { - readLock.lock(); return configurableEnvironment.getRequiredProperty(key, type); } finally { readLock.unlock(); @@ -60,8 +60,8 @@ public T get(String key, Class type) { @Override public Map get() { + readLock.lock(); try { - readLock.lock(); return configurationRepository.findAll().stream() .collect(Collectors.toMap( Configuration::getKey, @@ -76,8 +76,8 @@ public Map get() { @Override public Map update(Collection configurations) { + writeLock.lock(); try { - writeLock.lock(); configurationRepository.saveAll(configurations); Map configurationMap = configurationRepository.findAll().stream() .collect(Collectors.toMap(Configuration::getKey, Configuration::getValue)); From e9a13814ecc22a0890a055b54222ad1b8a60efec Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 12 Oct 2023 10:32:11 +0200 Subject: [PATCH 0404/1089] Improved `ConfigurationService` construction --- .../seart/service/ConfigurationService.java | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/service/ConfigurationService.java b/dl4se-server/src/main/java/usi/si/seart/service/ConfigurationService.java index 8f3d9604..dddd0dc0 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/ConfigurationService.java +++ b/dl4se-server/src/main/java/usi/si/seart/service/ConfigurationService.java @@ -1,7 +1,6 @@ package usi.si.seart.service; import lombok.AccessLevel; -import lombok.RequiredArgsConstructor; import lombok.experimental.FieldDefaults; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.ConfigurableEnvironment; @@ -29,17 +28,33 @@ public interface ConfigurationService { @Service @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) - @RequiredArgsConstructor(onConstructor_ = @Autowired) class ConfigurationServiceImpl implements ConfigurationService { + private static final String environmentName = "configurationEnvironment"; + ConfigurationRepository configurationRepository; ConfigurableEnvironment configurableEnvironment; - String environmentName = "dl4seEnvironment"; + Lock readLock; + Lock writeLock; + + @Autowired + public ConfigurationServiceImpl( + ConfigurationRepository configurationRepository, ConfigurableEnvironment configurableEnvironment + ) { + this(configurationRepository, configurableEnvironment, new ReentrantReadWriteLock()); + } - ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); - Lock readLock = readWriteLock.readLock(); - Lock writeLock = readWriteLock.writeLock(); + private ConfigurationServiceImpl( + ConfigurationRepository configurationRepository, + ConfigurableEnvironment configurableEnvironment, + ReadWriteLock readWriteLock + ) { + this.configurationRepository = configurationRepository; + this.configurableEnvironment = configurableEnvironment; + this.readLock = readWriteLock.readLock(); + this.writeLock = readWriteLock.writeLock(); + } @Override public PropertySource getPropertySource() { From 083e9a4763078384d3f0df55a4cdbdfec1e142b0 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 12 Oct 2023 11:59:07 +0200 Subject: [PATCH 0405/1089] Added special entity mapping for PostgreSQL materialized views --- .../seart/meta/PostgresMaterializedView.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 dl4se-model/src/main/java/usi/si/seart/meta/PostgresMaterializedView.java diff --git a/dl4se-model/src/main/java/usi/si/seart/meta/PostgresMaterializedView.java b/dl4se-model/src/main/java/usi/si/seart/meta/PostgresMaterializedView.java new file mode 100644 index 00000000..f1f2a6ea --- /dev/null +++ b/dl4se-model/src/main/java/usi/si/seart/meta/PostgresMaterializedView.java @@ -0,0 +1,45 @@ +package usi.si.seart.meta; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.experimental.FieldDefaults; +import org.hibernate.annotations.Immutable; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +@Entity +@Immutable +@Table(name = "pg_matviews") +@Getter +@NoArgsConstructor +@AllArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE) +public class PostgresMaterializedView { + + @Id + @Column(name = "matviewname") + String name; + + @NotBlank + @Column(name = "schemaname") + String schema; + + @NotBlank + @Column(name = "matviewowner") + String owner; + + @NotNull + @Column(name = "hasindexes") + Boolean indexed; + + @NotNull + @Column(name = "ispopulated") + Boolean populated; +} From afe6784cafacfa50e79625ba0a720c66a80b0d5b Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 12 Oct 2023 14:28:21 +0200 Subject: [PATCH 0406/1089] Refactoring `ViewMaintainer` to pass through a service layer --- .../si/seart/scheduling/ViewMaintainer.java | 39 ++----------------- .../usi/si/seart/service/MetaService.java | 18 +++++++++ 2 files changed, 21 insertions(+), 36 deletions(-) create mode 100644 dl4se-server/src/main/java/usi/si/seart/service/MetaService.java diff --git a/dl4se-server/src/main/java/usi/si/seart/scheduling/ViewMaintainer.java b/dl4se-server/src/main/java/usi/si/seart/scheduling/ViewMaintainer.java index d0135ab4..b2eca8f9 100644 --- a/dl4se-server/src/main/java/usi/si/seart/scheduling/ViewMaintainer.java +++ b/dl4se-server/src/main/java/usi/si/seart/scheduling/ViewMaintainer.java @@ -6,15 +6,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import org.springframework.transaction.PlatformTransactionManager; -import org.springframework.transaction.TransactionStatus; -import org.springframework.transaction.support.TransactionCallbackWithoutResult; -import org.springframework.transaction.support.TransactionTemplate; - -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; -import java.util.List; -import java.util.stream.Collectors; +import usi.si.seart.service.MetaService; @Slf4j @Component @@ -22,37 +14,12 @@ @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class ViewMaintainer implements Runnable { - private static final String SELECT = "SELECT matviewname AS material_view_name FROM pg_matviews;"; - - private static final String TEMPLATE = "REFRESH MATERIALIZED VIEW CONCURRENTLY %s;"; - - @PersistenceContext - EntityManager entityManager; - - PlatformTransactionManager transactionManager; + MetaService metaService; @Override - @SuppressWarnings("unchecked") public void run() { log.info("Recomputing statistics..."); - List views = entityManager.createNativeQuery(SELECT).getResultList(); - String statements = views.stream() - .map(view -> String.format(TEMPLATE, view)) - .collect(Collectors.joining()); - TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager); - transactionTemplate.execute(new TransactionCallback(statements)); + metaService.refreshMaterializedViews(); log.info("Finished updating statistics."); } - - @AllArgsConstructor(access = AccessLevel.PRIVATE) - @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) - private class TransactionCallback extends TransactionCallbackWithoutResult { - - String statements; - - @Override - protected void doInTransactionWithoutResult(TransactionStatus status) { - entityManager.createNativeQuery(statements).executeUpdate(); - } - } } diff --git a/dl4se-server/src/main/java/usi/si/seart/service/MetaService.java b/dl4se-server/src/main/java/usi/si/seart/service/MetaService.java new file mode 100644 index 00000000..cb68940a --- /dev/null +++ b/dl4se-server/src/main/java/usi/si/seart/service/MetaService.java @@ -0,0 +1,18 @@ +package usi.si.seart.service; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.stereotype.Service; + +public interface MetaService { + + void refreshMaterializedViews(); + + @Service + @ConditionalOnMissingBean(MetaService.class) + class MetaServiceStub implements MetaService { + + @Override + public void refreshMaterializedViews() { + } + } +} From c72dc94124498f88dc522a1a60bf344ac5c21015 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 12 Oct 2023 16:31:31 +0200 Subject: [PATCH 0407/1089] Removing `owner` column binding `PostgresMaterializedView` --- .../main/java/usi/si/seart/meta/PostgresMaterializedView.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dl4se-model/src/main/java/usi/si/seart/meta/PostgresMaterializedView.java b/dl4se-model/src/main/java/usi/si/seart/meta/PostgresMaterializedView.java index f1f2a6ea..c1cb3bf9 100644 --- a/dl4se-model/src/main/java/usi/si/seart/meta/PostgresMaterializedView.java +++ b/dl4se-model/src/main/java/usi/si/seart/meta/PostgresMaterializedView.java @@ -31,10 +31,6 @@ public class PostgresMaterializedView { @Column(name = "schemaname") String schema; - @NotBlank - @Column(name = "matviewowner") - String owner; - @NotNull @Column(name = "hasindexes") Boolean indexed; From 38fe64c82777944dd2324f2fb6af5449da966c6c Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 12 Oct 2023 16:55:16 +0200 Subject: [PATCH 0408/1089] Added helper procedure for refreshing materialized views Since it's not convenient to execute native `DO` statements in the `@Query` annotation, I had to introduce a helper procedure that will refresh materialized views. It does this by the name of the view itself, while applying concurrency if it contains a unique index. --- liquibase/scripts/04_procedure.sql | 41 ++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 liquibase/scripts/04_procedure.sql diff --git a/liquibase/scripts/04_procedure.sql b/liquibase/scripts/04_procedure.sql new file mode 100644 index 00000000..4347de9b --- /dev/null +++ b/liquibase/scripts/04_procedure.sql @@ -0,0 +1,41 @@ +-- liquibase formatted sql +-- changeset dabico:5 + +CREATE OR REPLACE PROCEDURE + "refresh_materialized_view"(name text) +AS $$ +DECLARE + _name text; + _oid oid; + _has_unique_index boolean; +BEGIN + -- Parameter Preconditions + IF name IS NULL + THEN RAISE EXCEPTION SQLSTATE 'C0001' + USING MESSAGE = 'name parameter is required'; + END IF; + -- Check Exists + _name := refresh_materialized_view.name; + IF NOT EXISTS( + SELECT FROM pg_matviews + WHERE pg_matviews.matviewname = _name + ) + THEN RAISE no_data_found; + END IF; + -- Retrieve OID + SELECT pg_class.oid INTO _oid + FROM pg_class + JOIN pg_matviews ON pg_matviews.matviewname = pg_class.relname + WHERE pg_matviews.matviewname = _name; + -- Examine Indexes + SELECT EXISTS( + SELECT FROM pg_index + WHERE pg_index.indisunique = true + AND pg_index.indrelid = _oid + ) INTO _has_unique_index; + -- Execute Refresh + EXECUTE 'REFRESH MATERIALIZED VIEW ' + || CASE WHEN _has_unique_index THEN 'CONCURRENTLY ' ELSE '' END + || _name; +END; +$$ LANGUAGE PLpgSQL; From 223c1e16f1895e58fdf17b3772b3434b4436237d Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 12 Oct 2023 17:00:32 +0200 Subject: [PATCH 0409/1089] Added dedicated repository that will invoke the custom refresh procedure --- .../PostgresMaterializedViewRepository.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 dl4se-server/src/main/java/usi/si/seart/repository/PostgresMaterializedViewRepository.java diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/PostgresMaterializedViewRepository.java b/dl4se-server/src/main/java/usi/si/seart/repository/PostgresMaterializedViewRepository.java new file mode 100644 index 00000000..ed2ee4ae --- /dev/null +++ b/dl4se-server/src/main/java/usi/si/seart/repository/PostgresMaterializedViewRepository.java @@ -0,0 +1,15 @@ +package usi.si.seart.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import usi.si.seart.meta.PostgresMaterializedView; + +import javax.validation.constraints.NotBlank; + +public interface PostgresMaterializedViewRepository extends JpaRepository { + + @Modifying + @Query(value = "CALL refresh_materialized_view(?1)", nativeQuery = true) + void refreshByName(@NotBlank String name); +} From 25d3b91ff7d73cfdd017b578120ad1b0bd04663f Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 12 Oct 2023 17:01:12 +0200 Subject: [PATCH 0410/1089] Added `MetaService` implementation dedicated to PostgreSQL --- .../usi/si/seart/service/MetaService.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/dl4se-server/src/main/java/usi/si/seart/service/MetaService.java b/dl4se-server/src/main/java/usi/si/seart/service/MetaService.java index cb68940a..c3d9091c 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/MetaService.java +++ b/dl4se-server/src/main/java/usi/si/seart/service/MetaService.java @@ -1,7 +1,15 @@ package usi.si.seart.service; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.experimental.FieldDefaults; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import usi.si.seart.meta.PostgresMaterializedView; +import usi.si.seart.repository.PostgresMaterializedViewRepository; public interface MetaService { @@ -15,4 +23,21 @@ class MetaServiceStub implements MetaService { public void refreshMaterializedViews() { } } + + @Service + @ConditionalOnProperty(value = "spring.jpa.database", havingValue = "postgresql") + @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) + @AllArgsConstructor(onConstructor_ = @Autowired) + class PostgresMetaService implements MetaService { + + PostgresMaterializedViewRepository materializedViewRepository; + + @Override + @Transactional + public void refreshMaterializedViews() { + materializedViewRepository.findAll().stream() + .map(PostgresMaterializedView::getName) + .forEach(materializedViewRepository::refreshByName); + } + } } From fd8fc7617e9b4b69f4c87ac89a36d463a88c3cb3 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 13 Oct 2023 10:22:37 +0200 Subject: [PATCH 0411/1089] Complete refactoring of materialized views and associated entities They no longer use subselects, and are immutable. Also, the entities themselves, their repositories, and the materialized views they map to are given more descriptive names. --- .../views/{TableCount.java => TableRows.java} | 14 ++-- ...anguageCount.java => CountByLanguage.java} | 10 +-- .../views/language/FileCountByLanguage.java | 9 +++ .../views/language/FileLanguageCount.java | 21 ----- .../language/FunctionCountByLanguage.java | 9 +++ .../views/language/FunctionLanguageCount.java | 21 ----- .../language/GitRepoCountByLanguage.java | 9 +++ .../views/language/GitRepoLanguageCount.java | 21 ----- .../si/seart/repository/CodeRepository.java | 2 +- .../FileCountByLanguageRepository.java | 8 ++ .../FileLanguageCountRepository.java | 8 -- .../FunctionCountByLanguageRepository.java | 8 ++ .../FunctionLanguageCountRepository.java | 8 -- .../GitRepoCountByLanguageRepository.java | 8 ++ .../GitRepoLanguageCountRepository.java | 8 -- .../repository/TableCountsRepository.java | 7 -- .../seart/repository/TableRowsRepository.java | 7 ++ .../si/seart/service/StatisticsService.java | 44 +++++------ liquibase/scripts/03_materialize.sql | 78 +++++++++++++------ 19 files changed, 143 insertions(+), 157 deletions(-) rename dl4se-model/src/main/java/usi/si/seart/views/{TableCount.java => TableRows.java} (68%) rename dl4se-model/src/main/java/usi/si/seart/views/language/{LanguageCount.java => CountByLanguage.java} (88%) create mode 100644 dl4se-model/src/main/java/usi/si/seart/views/language/FileCountByLanguage.java delete mode 100644 dl4se-model/src/main/java/usi/si/seart/views/language/FileLanguageCount.java create mode 100644 dl4se-model/src/main/java/usi/si/seart/views/language/FunctionCountByLanguage.java delete mode 100644 dl4se-model/src/main/java/usi/si/seart/views/language/FunctionLanguageCount.java create mode 100644 dl4se-model/src/main/java/usi/si/seart/views/language/GitRepoCountByLanguage.java delete mode 100644 dl4se-model/src/main/java/usi/si/seart/views/language/GitRepoLanguageCount.java create mode 100644 dl4se-server/src/main/java/usi/si/seart/repository/FileCountByLanguageRepository.java delete mode 100644 dl4se-server/src/main/java/usi/si/seart/repository/FileLanguageCountRepository.java create mode 100644 dl4se-server/src/main/java/usi/si/seart/repository/FunctionCountByLanguageRepository.java delete mode 100644 dl4se-server/src/main/java/usi/si/seart/repository/FunctionLanguageCountRepository.java create mode 100644 dl4se-server/src/main/java/usi/si/seart/repository/GitRepoCountByLanguageRepository.java delete mode 100644 dl4se-server/src/main/java/usi/si/seart/repository/GitRepoLanguageCountRepository.java delete mode 100644 dl4se-server/src/main/java/usi/si/seart/repository/TableCountsRepository.java create mode 100644 dl4se-server/src/main/java/usi/si/seart/repository/TableRowsRepository.java diff --git a/dl4se-model/src/main/java/usi/si/seart/views/TableCount.java b/dl4se-model/src/main/java/usi/si/seart/views/TableRows.java similarity index 68% rename from dl4se-model/src/main/java/usi/si/seart/views/TableCount.java rename to dl4se-model/src/main/java/usi/si/seart/views/TableRows.java index 1b899d55..65b45844 100644 --- a/dl4se-model/src/main/java/usi/si/seart/views/TableCount.java +++ b/dl4se-model/src/main/java/usi/si/seart/views/TableRows.java @@ -2,28 +2,24 @@ import lombok.AccessLevel; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.ToString; import lombok.experimental.FieldDefaults; -import org.hibernate.annotations.Subselect; +import org.hibernate.annotations.Immutable; import javax.persistence.Entity; import javax.persistence.Id; +import javax.persistence.Table; import javax.validation.constraints.NotNull; @Entity -@Subselect("SELECT * FROM table_counts") +@Immutable +@Table(name = "table_rows") @Getter -@Setter -@ToString -@Builder @NoArgsConstructor @AllArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE) -public class TableCount { +public class TableRows { @Id String table; diff --git a/dl4se-model/src/main/java/usi/si/seart/views/language/LanguageCount.java b/dl4se-model/src/main/java/usi/si/seart/views/language/CountByLanguage.java similarity index 88% rename from dl4se-model/src/main/java/usi/si/seart/views/language/LanguageCount.java rename to dl4se-model/src/main/java/usi/si/seart/views/language/CountByLanguage.java index 24713d7b..ccbb6cdc 100644 --- a/dl4se-model/src/main/java/usi/si/seart/views/language/LanguageCount.java +++ b/dl4se-model/src/main/java/usi/si/seart/views/language/CountByLanguage.java @@ -4,9 +4,8 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; -import lombok.Setter; import lombok.experimental.FieldDefaults; -import lombok.experimental.SuperBuilder; +import org.hibernate.annotations.Immutable; import usi.si.seart.model.Language; import javax.persistence.Column; @@ -19,14 +18,13 @@ import javax.validation.constraints.NotNull; @Entity -@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) @Getter -@Setter -@SuperBuilder +@Immutable +@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor(access = AccessLevel.PROTECTED) @FieldDefaults(level = AccessLevel.PROTECTED) -public abstract class LanguageCount { +public abstract class CountByLanguage { @Id @Column(name = "lang_id") diff --git a/dl4se-model/src/main/java/usi/si/seart/views/language/FileCountByLanguage.java b/dl4se-model/src/main/java/usi/si/seart/views/language/FileCountByLanguage.java new file mode 100644 index 00000000..341e0c8a --- /dev/null +++ b/dl4se-model/src/main/java/usi/si/seart/views/language/FileCountByLanguage.java @@ -0,0 +1,9 @@ +package usi.si.seart.views.language; + +import javax.persistence.Entity; +import javax.persistence.Table; + +@Entity +@Table(name = "file_count_by_language") +public class FileCountByLanguage extends CountByLanguage { +} diff --git a/dl4se-model/src/main/java/usi/si/seart/views/language/FileLanguageCount.java b/dl4se-model/src/main/java/usi/si/seart/views/language/FileLanguageCount.java deleted file mode 100644 index 4149bc0d..00000000 --- a/dl4se-model/src/main/java/usi/si/seart/views/language/FileLanguageCount.java +++ /dev/null @@ -1,21 +0,0 @@ -package usi.si.seart.views.language; - -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.experimental.FieldDefaults; -import lombok.experimental.SuperBuilder; -import org.hibernate.annotations.Subselect; - -import javax.persistence.Entity; - -@Entity -@Subselect("SELECT * FROM files_by_language") -@Getter -@Setter -@SuperBuilder -@NoArgsConstructor -@FieldDefaults(level = AccessLevel.PRIVATE) -public class FileLanguageCount extends LanguageCount { -} diff --git a/dl4se-model/src/main/java/usi/si/seart/views/language/FunctionCountByLanguage.java b/dl4se-model/src/main/java/usi/si/seart/views/language/FunctionCountByLanguage.java new file mode 100644 index 00000000..6afead33 --- /dev/null +++ b/dl4se-model/src/main/java/usi/si/seart/views/language/FunctionCountByLanguage.java @@ -0,0 +1,9 @@ +package usi.si.seart.views.language; + +import javax.persistence.Entity; +import javax.persistence.Table; + +@Entity +@Table(name = "function_count_by_language") +public class FunctionCountByLanguage extends CountByLanguage { +} diff --git a/dl4se-model/src/main/java/usi/si/seart/views/language/FunctionLanguageCount.java b/dl4se-model/src/main/java/usi/si/seart/views/language/FunctionLanguageCount.java deleted file mode 100644 index 19b5b792..00000000 --- a/dl4se-model/src/main/java/usi/si/seart/views/language/FunctionLanguageCount.java +++ /dev/null @@ -1,21 +0,0 @@ -package usi.si.seart.views.language; - -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.experimental.FieldDefaults; -import lombok.experimental.SuperBuilder; -import org.hibernate.annotations.Subselect; - -import javax.persistence.Entity; - -@Entity -@Subselect("SELECT * FROM functions_by_language") -@Getter -@Setter -@SuperBuilder -@NoArgsConstructor -@FieldDefaults(level = AccessLevel.PRIVATE) -public class FunctionLanguageCount extends LanguageCount { -} diff --git a/dl4se-model/src/main/java/usi/si/seart/views/language/GitRepoCountByLanguage.java b/dl4se-model/src/main/java/usi/si/seart/views/language/GitRepoCountByLanguage.java new file mode 100644 index 00000000..4970674f --- /dev/null +++ b/dl4se-model/src/main/java/usi/si/seart/views/language/GitRepoCountByLanguage.java @@ -0,0 +1,9 @@ +package usi.si.seart.views.language; + +import javax.persistence.Entity; +import javax.persistence.Table; + +@Entity +@Table(name = "git_repo_count_by_language") +public class GitRepoCountByLanguage extends CountByLanguage { +} diff --git a/dl4se-model/src/main/java/usi/si/seart/views/language/GitRepoLanguageCount.java b/dl4se-model/src/main/java/usi/si/seart/views/language/GitRepoLanguageCount.java deleted file mode 100644 index 6051764a..00000000 --- a/dl4se-model/src/main/java/usi/si/seart/views/language/GitRepoLanguageCount.java +++ /dev/null @@ -1,21 +0,0 @@ -package usi.si.seart.views.language; - -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.experimental.FieldDefaults; -import lombok.experimental.SuperBuilder; -import org.hibernate.annotations.Subselect; - -import javax.persistence.Entity; - -@Entity -@Subselect("SELECT * FROM git_repos_by_language") -@Getter -@Setter -@SuperBuilder -@NoArgsConstructor -@FieldDefaults(level = AccessLevel.PRIVATE) -public class GitRepoLanguageCount extends LanguageCount { -} diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/CodeRepository.java b/dl4se-server/src/main/java/usi/si/seart/repository/CodeRepository.java index 672bafcb..3630b2bb 100644 --- a/dl4se-server/src/main/java/usi/si/seart/repository/CodeRepository.java +++ b/dl4se-server/src/main/java/usi/si/seart/repository/CodeRepository.java @@ -11,6 +11,6 @@ public interface CodeRepository extends JpaSpecificationExecutor, JpaStreamableSpecificationRepository { - @Query(value = "SELECT size FROM code_size_in_bytes", nativeQuery = true) + @Query(value = "SELECT size FROM total_code_size_in_bytes", nativeQuery = true) Long size(); } diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/FileCountByLanguageRepository.java b/dl4se-server/src/main/java/usi/si/seart/repository/FileCountByLanguageRepository.java new file mode 100644 index 00000000..64a46be2 --- /dev/null +++ b/dl4se-server/src/main/java/usi/si/seart/repository/FileCountByLanguageRepository.java @@ -0,0 +1,8 @@ +package usi.si.seart.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import usi.si.seart.model.Language; +import usi.si.seart.views.language.FileCountByLanguage; + +public interface FileCountByLanguageRepository extends JpaRepository { +} diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/FileLanguageCountRepository.java b/dl4se-server/src/main/java/usi/si/seart/repository/FileLanguageCountRepository.java deleted file mode 100644 index c2d7fc1d..00000000 --- a/dl4se-server/src/main/java/usi/si/seart/repository/FileLanguageCountRepository.java +++ /dev/null @@ -1,8 +0,0 @@ -package usi.si.seart.repository; - -import org.springframework.data.jpa.repository.JpaRepository; -import usi.si.seart.model.Language; -import usi.si.seart.views.language.FileLanguageCount; - -public interface FileLanguageCountRepository extends JpaRepository { -} diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/FunctionCountByLanguageRepository.java b/dl4se-server/src/main/java/usi/si/seart/repository/FunctionCountByLanguageRepository.java new file mode 100644 index 00000000..0e88895e --- /dev/null +++ b/dl4se-server/src/main/java/usi/si/seart/repository/FunctionCountByLanguageRepository.java @@ -0,0 +1,8 @@ +package usi.si.seart.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import usi.si.seart.model.Language; +import usi.si.seart.views.language.FunctionCountByLanguage; + +public interface FunctionCountByLanguageRepository extends JpaRepository { +} diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/FunctionLanguageCountRepository.java b/dl4se-server/src/main/java/usi/si/seart/repository/FunctionLanguageCountRepository.java deleted file mode 100644 index 6901ad75..00000000 --- a/dl4se-server/src/main/java/usi/si/seart/repository/FunctionLanguageCountRepository.java +++ /dev/null @@ -1,8 +0,0 @@ -package usi.si.seart.repository; - -import org.springframework.data.jpa.repository.JpaRepository; -import usi.si.seart.model.Language; -import usi.si.seart.views.language.FunctionLanguageCount; - -public interface FunctionLanguageCountRepository extends JpaRepository { -} diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/GitRepoCountByLanguageRepository.java b/dl4se-server/src/main/java/usi/si/seart/repository/GitRepoCountByLanguageRepository.java new file mode 100644 index 00000000..7b076463 --- /dev/null +++ b/dl4se-server/src/main/java/usi/si/seart/repository/GitRepoCountByLanguageRepository.java @@ -0,0 +1,8 @@ +package usi.si.seart.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import usi.si.seart.model.Language; +import usi.si.seart.views.language.GitRepoCountByLanguage; + +public interface GitRepoCountByLanguageRepository extends JpaRepository { +} diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/GitRepoLanguageCountRepository.java b/dl4se-server/src/main/java/usi/si/seart/repository/GitRepoLanguageCountRepository.java deleted file mode 100644 index df429222..00000000 --- a/dl4se-server/src/main/java/usi/si/seart/repository/GitRepoLanguageCountRepository.java +++ /dev/null @@ -1,8 +0,0 @@ -package usi.si.seart.repository; - -import org.springframework.data.jpa.repository.JpaRepository; -import usi.si.seart.model.Language; -import usi.si.seart.views.language.GitRepoLanguageCount; - -public interface GitRepoLanguageCountRepository extends JpaRepository { -} diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/TableCountsRepository.java b/dl4se-server/src/main/java/usi/si/seart/repository/TableCountsRepository.java deleted file mode 100644 index 31a3b767..00000000 --- a/dl4se-server/src/main/java/usi/si/seart/repository/TableCountsRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package usi.si.seart.repository; - -import org.springframework.data.jpa.repository.JpaRepository; -import usi.si.seart.views.TableCount; - -public interface TableCountsRepository extends JpaRepository { -} diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/TableRowsRepository.java b/dl4se-server/src/main/java/usi/si/seart/repository/TableRowsRepository.java new file mode 100644 index 00000000..e56002a5 --- /dev/null +++ b/dl4se-server/src/main/java/usi/si/seart/repository/TableRowsRepository.java @@ -0,0 +1,7 @@ +package usi.si.seart.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import usi.si.seart.views.TableRows; + +public interface TableRowsRepository extends JpaRepository { +} diff --git a/dl4se-server/src/main/java/usi/si/seart/service/StatisticsService.java b/dl4se-server/src/main/java/usi/si/seart/service/StatisticsService.java index bcbd9757..523a3678 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/StatisticsService.java +++ b/dl4se-server/src/main/java/usi/si/seart/service/StatisticsService.java @@ -9,14 +9,14 @@ import usi.si.seart.model.task.Status; import usi.si.seart.model.user.User; import usi.si.seart.repository.CodeRepository; -import usi.si.seart.repository.FileLanguageCountRepository; -import usi.si.seart.repository.FunctionLanguageCountRepository; -import usi.si.seart.repository.GitRepoLanguageCountRepository; +import usi.si.seart.repository.FileCountByLanguageRepository; +import usi.si.seart.repository.FunctionCountByLanguageRepository; +import usi.si.seart.repository.GitRepoCountByLanguageRepository; import usi.si.seart.repository.LanguageRepository; -import usi.si.seart.repository.TableCountsRepository; +import usi.si.seart.repository.TableRowsRepository; import usi.si.seart.repository.TaskRepository; -import usi.si.seart.views.TableCount; -import usi.si.seart.views.language.LanguageCount; +import usi.si.seart.views.TableRows; +import usi.si.seart.views.language.CountByLanguage; import javax.persistence.Tuple; import java.util.List; @@ -47,11 +47,11 @@ public interface StatisticsService { @AllArgsConstructor(onConstructor_ = @Autowired) class StatisticsServiceImpl implements StatisticsService { - TableCountsRepository tableCountsRepository; + TableRowsRepository tableRowsRepository; - GitRepoLanguageCountRepository gitRepoLanguageCountRepository; - FileLanguageCountRepository fileLanguageCountRepository; - FunctionLanguageCountRepository functionLanguageCountRepository; + GitRepoCountByLanguageRepository gitRepoCountByLanguageRepository; + FileCountByLanguageRepository fileCountByLanguageRepository; + FunctionCountByLanguageRepository functionCountByLanguageRepository; CodeRepository codeRepository; LanguageRepository languageRepository; @@ -64,48 +64,48 @@ public Long codeSize() { @Override public Long countUsers() { - return tableCountsRepository.findById("user") - .map(TableCount::getCount) + return tableRowsRepository.findById("user") + .map(TableRows::getCount) .orElse(0L); } @Override public Long countGitRepos() { - return tableCountsRepository.findById("git_repo") - .map(TableCount::getCount) + return tableRowsRepository.findById("git_repo") + .map(TableRows::getCount) .orElse(0L); } @Override public Long countFiles() { - return tableCountsRepository.findById("file") - .map(TableCount::getCount) + return tableRowsRepository.findById("file") + .map(TableRows::getCount) .orElse(0L); } @Override public Long countFunctions() { - return tableCountsRepository.findById("function") - .map(TableCount::getCount) + return tableRowsRepository.findById("function") + .map(TableRows::getCount) .orElse(0L); } @Override public Map countGitReposByLanguage() { - return getLanguageCount(gitRepoLanguageCountRepository::findAll); + return getLanguageCount(gitRepoCountByLanguageRepository::findAll); } @Override public Map countFilesByLanguage() { - return getLanguageCount(fileLanguageCountRepository::findAll); + return getLanguageCount(fileCountByLanguageRepository::findAll); } @Override public Map countFunctionsByLanguage() { - return getLanguageCount(functionLanguageCountRepository::findAll); + return getLanguageCount(functionCountByLanguageRepository::findAll); } - private Map getLanguageCount(Supplier> supplier) { + private Map getLanguageCount(Supplier> supplier) { Stream> languagesEmpty = languageRepository.findAll().stream() .map(language -> Map.entry(language, 0L)); Stream> languagesData = supplier.get().stream() diff --git a/liquibase/scripts/03_materialize.sql b/liquibase/scripts/03_materialize.sql index 1d80212b..4b03b687 100644 --- a/liquibase/scripts/03_materialize.sql +++ b/liquibase/scripts/03_materialize.sql @@ -1,38 +1,66 @@ -- liquibase formatted sql -- changeset dabico:4 -CREATE MATERIALIZED VIEW table_counts AS -SELECT 'user' AS "table", COUNT(id) FROM "user" +CREATE MATERIALIZED VIEW table_rows AS +SELECT + 'user' AS "table", + COUNT(id) AS "count" +FROM "user" UNION -SELECT 'task' AS "table", COUNT(id) FROM task +SELECT + 'task' AS "table", + COUNT(id) AS "count" +FROM task UNION -SELECT 'git_repo' AS "table", COUNT(id) FROM git_repo +SELECT + 'git_repo' AS "table", + COUNT(id) AS "count" +FROM git_repo UNION -SELECT 'file' AS "table", COUNT(id) FROM file +SELECT + 'file' AS "table", + COUNT(id) AS "count" +FROM file UNION -SELECT 'function' AS "table", COUNT(id) FROM function; +SELECT + 'function' AS "table", + COUNT(id) AS "count" +FROM function; -CREATE MATERIALIZED VIEW git_repos_by_language AS -SELECT l.id AS lang_id, COUNT(l.id) FROM git_repo gr -INNER JOIN git_repo_language grl ON gr.id = grl.repo_id -INNER JOIN language l on l.id = grl.lang_id -GROUP BY l.id; +CREATE MATERIALIZED VIEW git_repo_count_by_language AS +SELECT + language.id AS lang_id, + COUNT(language.id) AS count +FROM git_repo +INNER JOIN git_repo_language + ON git_repo.id = git_repo_language.repo_id +INNER JOIN language + ON language.id = git_repo_language.lang_id +GROUP BY language.id; -CREATE MATERIALIZED VIEW files_by_language AS -SELECT l.id AS lang_id, COUNT(l.id) FROM file f -INNER JOIN language l ON f.lang_id = l.id -GROUP BY l.id; +CREATE MATERIALIZED VIEW file_count_by_language AS +SELECT + language.id AS lang_id, + COUNT(language.id) AS count +FROM file +INNER JOIN language + ON file.lang_id = language.id +GROUP BY language.id; -CREATE MATERIALIZED VIEW functions_by_language AS -SELECT l.id AS lang_id, COUNT(l.id) FROM function f -INNER JOIN language l ON f.lang_id = l.id -GROUP BY l.id; +CREATE MATERIALIZED VIEW function_count_by_language AS +SELECT + language.id AS lang_id, + COUNT(language.id) AS count +FROM function +INNER JOIN language + ON function.lang_id = language.id +GROUP BY language.id; -CREATE MATERIALIZED VIEW code_size_in_bytes AS +CREATE MATERIALIZED VIEW total_code_size_in_bytes AS SELECT SUM(characters) AS size FROM file; -CREATE UNIQUE INDEX ON table_counts("table"); -CREATE UNIQUE INDEX ON git_repos_by_language(lang_id); -CREATE UNIQUE INDEX ON files_by_language(lang_id); -CREATE UNIQUE INDEX ON functions_by_language(lang_id); -CREATE UNIQUE INDEX ON code_size_in_bytes(size); +CREATE UNIQUE INDEX ON table_rows("table"); +CREATE UNIQUE INDEX ON git_repo_count_by_language(lang_id); +CREATE UNIQUE INDEX ON file_count_by_language(lang_id); +CREATE UNIQUE INDEX ON function_count_by_language(lang_id); +CREATE UNIQUE INDEX ON total_code_size_in_bytes(size); From 9bbf1511d9dec859597ae09fc82a82ad4d9a7402 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 13 Oct 2023 10:24:15 +0200 Subject: [PATCH 0412/1089] Dead code removal --- .../main/java/usi/si/seart/repository/FileRepository.java | 7 ------- .../java/usi/si/seart/repository/FunctionRepository.java | 7 ------- .../java/usi/si/seart/repository/GitRepoRepository.java | 6 ------ 3 files changed, 20 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/FileRepository.java b/dl4se-server/src/main/java/usi/si/seart/repository/FileRepository.java index 8a3c6717..78462181 100644 --- a/dl4se-server/src/main/java/usi/si/seart/repository/FileRepository.java +++ b/dl4se-server/src/main/java/usi/si/seart/repository/FileRepository.java @@ -1,14 +1,7 @@ package usi.si.seart.repository; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; import usi.si.seart.model.code.File; -import javax.persistence.Tuple; -import java.util.List; - public interface FileRepository extends JpaRepository { - - @Query("SELECT l, COUNT(l) FROM File f JOIN f.language l GROUP BY l") - List countAllGroupByLanguage(); } diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/FunctionRepository.java b/dl4se-server/src/main/java/usi/si/seart/repository/FunctionRepository.java index 312270d4..fa5a5275 100644 --- a/dl4se-server/src/main/java/usi/si/seart/repository/FunctionRepository.java +++ b/dl4se-server/src/main/java/usi/si/seart/repository/FunctionRepository.java @@ -1,14 +1,7 @@ package usi.si.seart.repository; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; import usi.si.seart.model.code.Function; -import javax.persistence.Tuple; -import java.util.List; - public interface FunctionRepository extends JpaRepository { - - @Query("SELECT l, COUNT(l) FROM Function f JOIN f.language l GROUP BY l") - List countAllGroupByLanguage(); } diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/GitRepoRepository.java b/dl4se-server/src/main/java/usi/si/seart/repository/GitRepoRepository.java index f9554c71..93eb3116 100644 --- a/dl4se-server/src/main/java/usi/si/seart/repository/GitRepoRepository.java +++ b/dl4se-server/src/main/java/usi/si/seart/repository/GitRepoRepository.java @@ -1,17 +1,11 @@ package usi.si.seart.repository; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; import usi.si.seart.model.GitRepo; -import javax.persistence.Tuple; -import java.util.List; import java.util.stream.Stream; public interface GitRepoRepository extends JpaRepository { Stream streamAllBy(); - - @Query("SELECT l, COUNT(r) FROM GitRepo r JOIN r.languages l GROUP BY l") - List countAllGroupByLanguage(); } From 6a3d492604478ad84d371209a0ec5fcf96a03e0b Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 13 Oct 2023 10:47:49 +0200 Subject: [PATCH 0413/1089] Adding `equals` and `hashCode` to `CountByLanguage` and `TableRows` --- .../main/java/usi/si/seart/views/TableRows.java | 14 ++++++++++++++ .../si/seart/views/language/CountByLanguage.java | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/dl4se-model/src/main/java/usi/si/seart/views/TableRows.java b/dl4se-model/src/main/java/usi/si/seart/views/TableRows.java index 65b45844..6eb384cb 100644 --- a/dl4se-model/src/main/java/usi/si/seart/views/TableRows.java +++ b/dl4se-model/src/main/java/usi/si/seart/views/TableRows.java @@ -11,6 +11,7 @@ import javax.persistence.Id; import javax.persistence.Table; import javax.validation.constraints.NotNull; +import java.util.Objects; @Entity @Immutable @@ -26,4 +27,17 @@ public class TableRows { @NotNull Long count; + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + TableRows other = (TableRows) obj; + return Objects.equals(table, other.table); + } + + @Override + public int hashCode() { + return Objects.hash(table); + } } diff --git a/dl4se-model/src/main/java/usi/si/seart/views/language/CountByLanguage.java b/dl4se-model/src/main/java/usi/si/seart/views/language/CountByLanguage.java index ccbb6cdc..10e86d1c 100644 --- a/dl4se-model/src/main/java/usi/si/seart/views/language/CountByLanguage.java +++ b/dl4se-model/src/main/java/usi/si/seart/views/language/CountByLanguage.java @@ -16,6 +16,7 @@ import javax.persistence.OneToOne; import javax.persistence.PrimaryKeyJoinColumn; import javax.validation.constraints.NotNull; +import java.util.Objects; @Entity @Getter @@ -36,4 +37,17 @@ public abstract class CountByLanguage { @NotNull Long count; + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + CountByLanguage other = (CountByLanguage) obj; + return Objects.equals(language, other.language); + } + + @Override + public int hashCode() { + return Objects.hash(language); + } } From 01aa812401e1436b25dc5acc55e1d5ced8c99bcc Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 13 Oct 2023 11:57:24 +0200 Subject: [PATCH 0414/1089] `TableRows` -> `TableRowCount` --- .../{TableRows.java => TableRowCount.java} | 6 ++--- .../repository/TableRowCountRepository.java | 7 ++++++ .../seart/repository/TableRowsRepository.java | 7 ------ .../si/seart/service/StatisticsService.java | 22 +++++++++---------- liquibase/scripts/03_materialize.sql | 4 ++-- 5 files changed, 23 insertions(+), 23 deletions(-) rename dl4se-model/src/main/java/usi/si/seart/views/{TableRows.java => TableRowCount.java} (88%) create mode 100644 dl4se-server/src/main/java/usi/si/seart/repository/TableRowCountRepository.java delete mode 100644 dl4se-server/src/main/java/usi/si/seart/repository/TableRowsRepository.java diff --git a/dl4se-model/src/main/java/usi/si/seart/views/TableRows.java b/dl4se-model/src/main/java/usi/si/seart/views/TableRowCount.java similarity index 88% rename from dl4se-model/src/main/java/usi/si/seart/views/TableRows.java rename to dl4se-model/src/main/java/usi/si/seart/views/TableRowCount.java index 6eb384cb..e3a271dc 100644 --- a/dl4se-model/src/main/java/usi/si/seart/views/TableRows.java +++ b/dl4se-model/src/main/java/usi/si/seart/views/TableRowCount.java @@ -15,12 +15,12 @@ @Entity @Immutable -@Table(name = "table_rows") +@Table(name = "table_row_count") @Getter @NoArgsConstructor @AllArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE) -public class TableRows { +public class TableRowCount { @Id String table; @@ -32,7 +32,7 @@ public class TableRows { public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; - TableRows other = (TableRows) obj; + TableRowCount other = (TableRowCount) obj; return Objects.equals(table, other.table); } diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/TableRowCountRepository.java b/dl4se-server/src/main/java/usi/si/seart/repository/TableRowCountRepository.java new file mode 100644 index 00000000..c4c05fe0 --- /dev/null +++ b/dl4se-server/src/main/java/usi/si/seart/repository/TableRowCountRepository.java @@ -0,0 +1,7 @@ +package usi.si.seart.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import usi.si.seart.views.TableRowCount; + +public interface TableRowCountRepository extends JpaRepository { +} diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/TableRowsRepository.java b/dl4se-server/src/main/java/usi/si/seart/repository/TableRowsRepository.java deleted file mode 100644 index e56002a5..00000000 --- a/dl4se-server/src/main/java/usi/si/seart/repository/TableRowsRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package usi.si.seart.repository; - -import org.springframework.data.jpa.repository.JpaRepository; -import usi.si.seart.views.TableRows; - -public interface TableRowsRepository extends JpaRepository { -} diff --git a/dl4se-server/src/main/java/usi/si/seart/service/StatisticsService.java b/dl4se-server/src/main/java/usi/si/seart/service/StatisticsService.java index 523a3678..098c776d 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/StatisticsService.java +++ b/dl4se-server/src/main/java/usi/si/seart/service/StatisticsService.java @@ -13,9 +13,9 @@ import usi.si.seart.repository.FunctionCountByLanguageRepository; import usi.si.seart.repository.GitRepoCountByLanguageRepository; import usi.si.seart.repository.LanguageRepository; -import usi.si.seart.repository.TableRowsRepository; +import usi.si.seart.repository.TableRowCountRepository; import usi.si.seart.repository.TaskRepository; -import usi.si.seart.views.TableRows; +import usi.si.seart.views.TableRowCount; import usi.si.seart.views.language.CountByLanguage; import javax.persistence.Tuple; @@ -47,7 +47,7 @@ public interface StatisticsService { @AllArgsConstructor(onConstructor_ = @Autowired) class StatisticsServiceImpl implements StatisticsService { - TableRowsRepository tableRowsRepository; + TableRowCountRepository tableRowCountRepository; GitRepoCountByLanguageRepository gitRepoCountByLanguageRepository; FileCountByLanguageRepository fileCountByLanguageRepository; @@ -64,29 +64,29 @@ public Long codeSize() { @Override public Long countUsers() { - return tableRowsRepository.findById("user") - .map(TableRows::getCount) + return tableRowCountRepository.findById("user") + .map(TableRowCount::getCount) .orElse(0L); } @Override public Long countGitRepos() { - return tableRowsRepository.findById("git_repo") - .map(TableRows::getCount) + return tableRowCountRepository.findById("git_repo") + .map(TableRowCount::getCount) .orElse(0L); } @Override public Long countFiles() { - return tableRowsRepository.findById("file") - .map(TableRows::getCount) + return tableRowCountRepository.findById("file") + .map(TableRowCount::getCount) .orElse(0L); } @Override public Long countFunctions() { - return tableRowsRepository.findById("function") - .map(TableRows::getCount) + return tableRowCountRepository.findById("function") + .map(TableRowCount::getCount) .orElse(0L); } diff --git a/liquibase/scripts/03_materialize.sql b/liquibase/scripts/03_materialize.sql index 4b03b687..bdd5b4f9 100644 --- a/liquibase/scripts/03_materialize.sql +++ b/liquibase/scripts/03_materialize.sql @@ -1,7 +1,7 @@ -- liquibase formatted sql -- changeset dabico:4 -CREATE MATERIALIZED VIEW table_rows AS +CREATE MATERIALIZED VIEW table_row_count AS SELECT 'user' AS "table", COUNT(id) AS "count" @@ -59,7 +59,7 @@ GROUP BY language.id; CREATE MATERIALIZED VIEW total_code_size_in_bytes AS SELECT SUM(characters) AS size FROM file; -CREATE UNIQUE INDEX ON table_rows("table"); +CREATE UNIQUE INDEX ON table_row_count("table"); CREATE UNIQUE INDEX ON git_repo_count_by_language(lang_id); CREATE UNIQUE INDEX ON file_count_by_language(lang_id); CREATE UNIQUE INDEX ON function_count_by_language(lang_id); From e6c795a918ca2b76efbc9d043929ccfecf1cb526 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 13 Oct 2023 14:10:32 +0200 Subject: [PATCH 0415/1089] Programmatic access to `table_row_count` in `StatisticsService` --- .../si/seart/service/StatisticsService.java | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/service/StatisticsService.java b/dl4se-server/src/main/java/usi/si/seart/service/StatisticsService.java index 098c776d..24404ab8 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/StatisticsService.java +++ b/dl4se-server/src/main/java/usi/si/seart/service/StatisticsService.java @@ -5,7 +5,10 @@ import lombok.experimental.FieldDefaults; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import usi.si.seart.model.GitRepo; import usi.si.seart.model.Language; +import usi.si.seart.model.code.File; +import usi.si.seart.model.code.Function; import usi.si.seart.model.task.Status; import usi.si.seart.model.user.User; import usi.si.seart.repository.CodeRepository; @@ -18,6 +21,7 @@ import usi.si.seart.views.TableRowCount; import usi.si.seart.views.language.CountByLanguage; +import javax.persistence.Table; import javax.persistence.Tuple; import java.util.List; import java.util.Map; @@ -64,30 +68,31 @@ public Long codeSize() { @Override public Long countUsers() { - return tableRowCountRepository.findById("user") - .map(TableRowCount::getCount) - .orElse(0L); + return count(User.class); } @Override public Long countGitRepos() { - return tableRowCountRepository.findById("git_repo") - .map(TableRowCount::getCount) - .orElse(0L); + return count(GitRepo.class); } @Override public Long countFiles() { - return tableRowCountRepository.findById("file") - .map(TableRowCount::getCount) - .orElse(0L); + return count(File.class); } @Override public Long countFunctions() { - return tableRowCountRepository.findById("function") + return count(Function.class); + } + + private Long count(Class type) { + Table table = type.getAnnotation(Table.class); + if (table == null) throw new IllegalArgumentException("Not an entity: " + type.getSimpleName()); + String name = table.name().replaceAll("\"", ""); + return tableRowCountRepository.findById(name) .map(TableRowCount::getCount) - .orElse(0L); + .orElse(null); } @Override From cb1143748458373035c87a7a67e3b38267c5eb81 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 13 Oct 2023 15:18:48 +0200 Subject: [PATCH 0416/1089] Added `GroupedCount` generic interface Meant to encompass all types of count queries that are grouped by a single value. Currently, only `TableRowCount` and `CountByLanguage` implement it. --- .../java/usi/si/seart/views/GroupedCount.java | 19 +++++++++++++++++++ .../usi/si/seart/views/TableRowCount.java | 10 ++++++++-- .../seart/views/language/CountByLanguage.java | 11 +++++++++-- 3 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 dl4se-model/src/main/java/usi/si/seart/views/GroupedCount.java diff --git a/dl4se-model/src/main/java/usi/si/seart/views/GroupedCount.java b/dl4se-model/src/main/java/usi/si/seart/views/GroupedCount.java new file mode 100644 index 00000000..3d942d72 --- /dev/null +++ b/dl4se-model/src/main/java/usi/si/seart/views/GroupedCount.java @@ -0,0 +1,19 @@ +package usi.si.seart.views; + +import java.util.Map; + +public interface GroupedCount extends Map.Entry { + + K getKey(); + Long getCount(); + + @Override + default Long getValue() { + return getCount(); + } + + @Override + default Long setValue(Long value) { + throw new UnsupportedOperationException(); + } +} diff --git a/dl4se-model/src/main/java/usi/si/seart/views/TableRowCount.java b/dl4se-model/src/main/java/usi/si/seart/views/TableRowCount.java index e3a271dc..d58b3adf 100644 --- a/dl4se-model/src/main/java/usi/si/seart/views/TableRowCount.java +++ b/dl4se-model/src/main/java/usi/si/seart/views/TableRowCount.java @@ -16,18 +16,24 @@ @Entity @Immutable @Table(name = "table_row_count") -@Getter @NoArgsConstructor @AllArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE) -public class TableRowCount { +public class TableRowCount implements GroupedCount { @Id + @Getter String table; @NotNull + @Getter(onMethod_ = @Override) Long count; + @Override + public String getKey() { + return table; + } + @Override public boolean equals(Object obj) { if (this == obj) return true; diff --git a/dl4se-model/src/main/java/usi/si/seart/views/language/CountByLanguage.java b/dl4se-model/src/main/java/usi/si/seart/views/language/CountByLanguage.java index 10e86d1c..cb9baf50 100644 --- a/dl4se-model/src/main/java/usi/si/seart/views/language/CountByLanguage.java +++ b/dl4se-model/src/main/java/usi/si/seart/views/language/CountByLanguage.java @@ -7,6 +7,7 @@ import lombok.experimental.FieldDefaults; import org.hibernate.annotations.Immutable; import usi.si.seart.model.Language; +import usi.si.seart.views.GroupedCount; import javax.persistence.Column; import javax.persistence.Entity; @@ -19,25 +20,31 @@ import java.util.Objects; @Entity -@Getter @Immutable @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor(access = AccessLevel.PROTECTED) @FieldDefaults(level = AccessLevel.PROTECTED) -public abstract class CountByLanguage { +public abstract class CountByLanguage implements GroupedCount { @Id @Column(name = "lang_id") Long id; + @Getter @OneToOne(optional = false) @PrimaryKeyJoinColumn(name = "lang_id", referencedColumnName = "id") Language language; @NotNull + @Getter(onMethod_ = @Override) Long count; + @Override + public Language getKey() { + return language; + } + @Override public boolean equals(Object obj) { if (this == obj) return true; From 0757cc772a851ec5e2c759736c67336c5049c092 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 13 Oct 2023 15:39:08 +0200 Subject: [PATCH 0417/1089] Improved `by_language` materialized views to take 0 sums into account --- liquibase/scripts/03_materialize.sql | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/liquibase/scripts/03_materialize.sql b/liquibase/scripts/03_materialize.sql index bdd5b4f9..542b1c09 100644 --- a/liquibase/scripts/03_materialize.sql +++ b/liquibase/scripts/03_materialize.sql @@ -30,29 +30,29 @@ FROM function; CREATE MATERIALIZED VIEW git_repo_count_by_language AS SELECT language.id AS lang_id, - COUNT(language.id) AS count -FROM git_repo -INNER JOIN git_repo_language + COUNT(git_repo.id) AS count +FROM language +LEFT JOIN git_repo_language + ON git_repo_language.lang_id = language.id +LEFT JOIN git_repo ON git_repo.id = git_repo_language.repo_id -INNER JOIN language - ON language.id = git_repo_language.lang_id GROUP BY language.id; CREATE MATERIALIZED VIEW file_count_by_language AS SELECT language.id AS lang_id, - COUNT(language.id) AS count -FROM file -INNER JOIN language + COUNT(file.id) AS count +FROM language +LEFT JOIN file ON file.lang_id = language.id GROUP BY language.id; CREATE MATERIALIZED VIEW function_count_by_language AS SELECT language.id AS lang_id, - COUNT(language.id) AS count -FROM function -INNER JOIN language + COUNT(function.id) AS count +FROM language +LEFT JOIN function ON function.lang_id = language.id GROUP BY language.id; From b54da43a952022a089a5d4bc8e867190ce433c65 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 13 Oct 2023 15:48:26 +0200 Subject: [PATCH 0418/1089] Improving materialized view access The access responsibility is shifted to the entity class repository, while each accessor method returns a collection of `GroupedCount`. --- .../FileCountByLanguageRepository.java | 8 ---- .../si/seart/repository/FileRepository.java | 8 ++++ .../FunctionCountByLanguageRepository.java | 8 ---- .../seart/repository/FunctionRepository.java | 8 ++++ .../GitRepoCountByLanguageRepository.java | 8 ---- .../seart/repository/GitRepoRepository.java | 7 ++++ .../si/seart/service/StatisticsService.java | 37 ++++++++----------- 7 files changed, 39 insertions(+), 45 deletions(-) delete mode 100644 dl4se-server/src/main/java/usi/si/seart/repository/FileCountByLanguageRepository.java delete mode 100644 dl4se-server/src/main/java/usi/si/seart/repository/FunctionCountByLanguageRepository.java delete mode 100644 dl4se-server/src/main/java/usi/si/seart/repository/GitRepoCountByLanguageRepository.java diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/FileCountByLanguageRepository.java b/dl4se-server/src/main/java/usi/si/seart/repository/FileCountByLanguageRepository.java deleted file mode 100644 index 64a46be2..00000000 --- a/dl4se-server/src/main/java/usi/si/seart/repository/FileCountByLanguageRepository.java +++ /dev/null @@ -1,8 +0,0 @@ -package usi.si.seart.repository; - -import org.springframework.data.jpa.repository.JpaRepository; -import usi.si.seart.model.Language; -import usi.si.seart.views.language.FileCountByLanguage; - -public interface FileCountByLanguageRepository extends JpaRepository { -} diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/FileRepository.java b/dl4se-server/src/main/java/usi/si/seart/repository/FileRepository.java index 78462181..72cfe9a9 100644 --- a/dl4se-server/src/main/java/usi/si/seart/repository/FileRepository.java +++ b/dl4se-server/src/main/java/usi/si/seart/repository/FileRepository.java @@ -1,7 +1,15 @@ package usi.si.seart.repository; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import usi.si.seart.model.Language; import usi.si.seart.model.code.File; +import usi.si.seart.views.GroupedCount; + +import java.util.Collection; public interface FileRepository extends JpaRepository { + + @Query("SELECT _ FROM FileCountByLanguage _") + Collection> countByLanguage(); } diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/FunctionCountByLanguageRepository.java b/dl4se-server/src/main/java/usi/si/seart/repository/FunctionCountByLanguageRepository.java deleted file mode 100644 index 0e88895e..00000000 --- a/dl4se-server/src/main/java/usi/si/seart/repository/FunctionCountByLanguageRepository.java +++ /dev/null @@ -1,8 +0,0 @@ -package usi.si.seart.repository; - -import org.springframework.data.jpa.repository.JpaRepository; -import usi.si.seart.model.Language; -import usi.si.seart.views.language.FunctionCountByLanguage; - -public interface FunctionCountByLanguageRepository extends JpaRepository { -} diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/FunctionRepository.java b/dl4se-server/src/main/java/usi/si/seart/repository/FunctionRepository.java index fa5a5275..6c65c176 100644 --- a/dl4se-server/src/main/java/usi/si/seart/repository/FunctionRepository.java +++ b/dl4se-server/src/main/java/usi/si/seart/repository/FunctionRepository.java @@ -1,7 +1,15 @@ package usi.si.seart.repository; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import usi.si.seart.model.Language; import usi.si.seart.model.code.Function; +import usi.si.seart.views.GroupedCount; + +import java.util.Collection; public interface FunctionRepository extends JpaRepository { + + @Query("SELECT _ FROM FunctionCountByLanguage _") + Collection> countByLanguage(); } diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/GitRepoCountByLanguageRepository.java b/dl4se-server/src/main/java/usi/si/seart/repository/GitRepoCountByLanguageRepository.java deleted file mode 100644 index 7b076463..00000000 --- a/dl4se-server/src/main/java/usi/si/seart/repository/GitRepoCountByLanguageRepository.java +++ /dev/null @@ -1,8 +0,0 @@ -package usi.si.seart.repository; - -import org.springframework.data.jpa.repository.JpaRepository; -import usi.si.seart.model.Language; -import usi.si.seart.views.language.GitRepoCountByLanguage; - -public interface GitRepoCountByLanguageRepository extends JpaRepository { -} diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/GitRepoRepository.java b/dl4se-server/src/main/java/usi/si/seart/repository/GitRepoRepository.java index 93eb3116..da0feebf 100644 --- a/dl4se-server/src/main/java/usi/si/seart/repository/GitRepoRepository.java +++ b/dl4se-server/src/main/java/usi/si/seart/repository/GitRepoRepository.java @@ -1,11 +1,18 @@ package usi.si.seart.repository; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import usi.si.seart.model.GitRepo; +import usi.si.seart.model.Language; +import usi.si.seart.views.GroupedCount; +import java.util.Collection; import java.util.stream.Stream; public interface GitRepoRepository extends JpaRepository { Stream streamAllBy(); + + @Query("SELECT _ FROM GitRepoCountByLanguage _") + Collection> countByLanguage(); } diff --git a/dl4se-server/src/main/java/usi/si/seart/service/StatisticsService.java b/dl4se-server/src/main/java/usi/si/seart/service/StatisticsService.java index 24404ab8..2f9b12a0 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/StatisticsService.java +++ b/dl4se-server/src/main/java/usi/si/seart/service/StatisticsService.java @@ -12,17 +12,17 @@ import usi.si.seart.model.task.Status; import usi.si.seart.model.user.User; import usi.si.seart.repository.CodeRepository; -import usi.si.seart.repository.FileCountByLanguageRepository; -import usi.si.seart.repository.FunctionCountByLanguageRepository; -import usi.si.seart.repository.GitRepoCountByLanguageRepository; -import usi.si.seart.repository.LanguageRepository; +import usi.si.seart.repository.FileRepository; +import usi.si.seart.repository.FunctionRepository; +import usi.si.seart.repository.GitRepoRepository; import usi.si.seart.repository.TableRowCountRepository; import usi.si.seart.repository.TaskRepository; +import usi.si.seart.views.GroupedCount; import usi.si.seart.views.TableRowCount; -import usi.si.seart.views.language.CountByLanguage; import javax.persistence.Table; import javax.persistence.Tuple; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.function.Supplier; @@ -53,12 +53,10 @@ class StatisticsServiceImpl implements StatisticsService { TableRowCountRepository tableRowCountRepository; - GitRepoCountByLanguageRepository gitRepoCountByLanguageRepository; - FileCountByLanguageRepository fileCountByLanguageRepository; - FunctionCountByLanguageRepository functionCountByLanguageRepository; - + GitRepoRepository gitRepoRepository; + FileRepository fileRepository; + FunctionRepository functionRepository; CodeRepository codeRepository; - LanguageRepository languageRepository; TaskRepository taskRepository; @Override @@ -97,27 +95,24 @@ private Long count(Class type) { @Override public Map countGitReposByLanguage() { - return getLanguageCount(gitRepoCountByLanguageRepository::findAll); + return countByLanguage(gitRepoRepository::countByLanguage); } @Override public Map countFilesByLanguage() { - return getLanguageCount(fileCountByLanguageRepository::findAll); + return countByLanguage(fileRepository::countByLanguage); } @Override public Map countFunctionsByLanguage() { - return getLanguageCount(functionCountByLanguageRepository::findAll); + return countByLanguage(functionRepository::countByLanguage); } - private Map getLanguageCount(Supplier> supplier) { - Stream> languagesEmpty = languageRepository.findAll().stream() - .map(language -> Map.entry(language, 0L)); - Stream> languagesData = supplier.get().stream() - .map(entity -> Map.entry(entity.getLanguage(), entity.getCount())); - return Stream.concat(languagesEmpty, languagesData).collect( - Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> v2) - ); + private Map countByLanguage(Supplier>> supplier) { + return supplier.get().stream().collect(Collectors.toUnmodifiableMap( + Map.Entry::getKey, + Map.Entry::getValue + )); } @Override From c888e4893a27b6364516f83055e8a38ec8a87496 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 13 Oct 2023 16:09:24 +0200 Subject: [PATCH 0419/1089] `Task` lock acquisitions are now outside the try block --- .../src/main/java/usi/si/seart/service/TaskService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/service/TaskService.java b/dl4se-server/src/main/java/usi/si/seart/service/TaskService.java index 6196f94a..4fb915f6 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/TaskService.java +++ b/dl4se-server/src/main/java/usi/si/seart/service/TaskService.java @@ -100,8 +100,8 @@ public void create( @Transactional(propagation = Propagation.REQUIRES_NEW) public Task update(Task task) { Lock taskLock = taskLockMap.getLock(task); + taskLock.lock(); try { - taskLock.lock(); return taskRepository.saveAndFlush(task); } finally { taskLock.unlock(); @@ -112,8 +112,8 @@ public Task update(Task task) { @Transactional(propagation = Propagation.REQUIRES_NEW) public void cancel(Task task) { Lock taskLock = taskLockMap.getLock(task); + taskLock.lock(); try { - taskLock.lock(); taskRepository.markForCancellation(task.getId()); } finally { taskLock.unlock(); From 12e5ab9b3388ae10af695f3d046ad227fd1fe094 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 13 Oct 2023 17:50:19 +0200 Subject: [PATCH 0420/1089] Replacing `MetaService` with more descriptive `DatabaseService` This service also executes native queries directly through the `EntityManager`. This also marks the removal of the meta entities and repositories. --- .../seart/meta/PostgresMaterializedView.java | 41 ------------ .../PostgresMaterializedViewRepository.java | 15 ----- .../si/seart/scheduling/ViewMaintainer.java | 10 +-- .../usi/si/seart/service/DatabaseService.java | 66 +++++++++++++++++++ .../usi/si/seart/service/MetaService.java | 43 ------------ liquibase/scripts/04_procedure.sql | 41 ------------ 6 files changed, 71 insertions(+), 145 deletions(-) delete mode 100644 dl4se-model/src/main/java/usi/si/seart/meta/PostgresMaterializedView.java delete mode 100644 dl4se-server/src/main/java/usi/si/seart/repository/PostgresMaterializedViewRepository.java create mode 100644 dl4se-server/src/main/java/usi/si/seart/service/DatabaseService.java delete mode 100644 dl4se-server/src/main/java/usi/si/seart/service/MetaService.java delete mode 100644 liquibase/scripts/04_procedure.sql diff --git a/dl4se-model/src/main/java/usi/si/seart/meta/PostgresMaterializedView.java b/dl4se-model/src/main/java/usi/si/seart/meta/PostgresMaterializedView.java deleted file mode 100644 index c1cb3bf9..00000000 --- a/dl4se-model/src/main/java/usi/si/seart/meta/PostgresMaterializedView.java +++ /dev/null @@ -1,41 +0,0 @@ -package usi.si.seart.meta; - -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.experimental.FieldDefaults; -import org.hibernate.annotations.Immutable; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; - -@Entity -@Immutable -@Table(name = "pg_matviews") -@Getter -@NoArgsConstructor -@AllArgsConstructor -@FieldDefaults(level = AccessLevel.PRIVATE) -public class PostgresMaterializedView { - - @Id - @Column(name = "matviewname") - String name; - - @NotBlank - @Column(name = "schemaname") - String schema; - - @NotNull - @Column(name = "hasindexes") - Boolean indexed; - - @NotNull - @Column(name = "ispopulated") - Boolean populated; -} diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/PostgresMaterializedViewRepository.java b/dl4se-server/src/main/java/usi/si/seart/repository/PostgresMaterializedViewRepository.java deleted file mode 100644 index ed2ee4ae..00000000 --- a/dl4se-server/src/main/java/usi/si/seart/repository/PostgresMaterializedViewRepository.java +++ /dev/null @@ -1,15 +0,0 @@ -package usi.si.seart.repository; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Modifying; -import org.springframework.data.jpa.repository.Query; -import usi.si.seart.meta.PostgresMaterializedView; - -import javax.validation.constraints.NotBlank; - -public interface PostgresMaterializedViewRepository extends JpaRepository { - - @Modifying - @Query(value = "CALL refresh_materialized_view(?1)", nativeQuery = true) - void refreshByName(@NotBlank String name); -} diff --git a/dl4se-server/src/main/java/usi/si/seart/scheduling/ViewMaintainer.java b/dl4se-server/src/main/java/usi/si/seart/scheduling/ViewMaintainer.java index b2eca8f9..857bf226 100644 --- a/dl4se-server/src/main/java/usi/si/seart/scheduling/ViewMaintainer.java +++ b/dl4se-server/src/main/java/usi/si/seart/scheduling/ViewMaintainer.java @@ -6,7 +6,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import usi.si.seart.service.MetaService; +import usi.si.seart.service.DatabaseService; @Slf4j @Component @@ -14,12 +14,12 @@ @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class ViewMaintainer implements Runnable { - MetaService metaService; + DatabaseService databaseService; @Override public void run() { - log.info("Recomputing statistics..."); - metaService.refreshMaterializedViews(); - log.info("Finished updating statistics."); + log.info("Refreshing materialized views..."); + databaseService.refreshMaterializedViews(); + log.info("Finished refreshing views."); } } diff --git a/dl4se-server/src/main/java/usi/si/seart/service/DatabaseService.java b/dl4se-server/src/main/java/usi/si/seart/service/DatabaseService.java new file mode 100644 index 00000000..0e2509b7 --- /dev/null +++ b/dl4se-server/src/main/java/usi/si/seart/service/DatabaseService.java @@ -0,0 +1,66 @@ +package usi.si.seart.service; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.experimental.FieldDefaults; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; + +public interface DatabaseService { + + void refreshMaterializedViews(); + + @Service + @ConditionalOnMissingBean(DatabaseService.class) + class StubDatabaseService implements DatabaseService { + + @Override + public void refreshMaterializedViews() { + } + } + + @Service + @ConditionalOnProperty(value = "spring.jpa.database", havingValue = "postgresql") + @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) + @AllArgsConstructor(onConstructor_ = @Autowired) + class PostgresDatabaseService implements DatabaseService { + + @PersistenceContext + EntityManager entityManager; + + @Override + @Transactional + public void refreshMaterializedViews() { + entityManager.createNativeQuery( + "DO $$ " + + "DECLARE " + + "_materialized_view_name text; " + + "_has_unique_index boolean; " + + "BEGIN " + + "FOR _materialized_view_name, _has_unique_index IN (" + + "SELECT relname, indisunique " + + "FROM pg_class " + + "INNER JOIN pg_index " + + "ON pg_index.indrelid = pg_class.oid " + + "WHERE relkind = 'm' " + + "AND relnamespace IN (" + + "SELECT oid FROM pg_namespace " + + "WHERE nspname NOT LIKE 'pg_%' " + + "AND nspname != 'information_schema'" + + ")" + + ") " + + "LOOP EXECUTE 'REFRESH MATERIALIZED VIEW ' " + + "|| CASE WHEN _has_unique_index THEN 'CONCURRENTLY ' ELSE '' END " + + "|| _materialized_view_name; " + + "END LOOP; " + + "END $$;" + ).executeUpdate(); + } + } +} diff --git a/dl4se-server/src/main/java/usi/si/seart/service/MetaService.java b/dl4se-server/src/main/java/usi/si/seart/service/MetaService.java deleted file mode 100644 index c3d9091c..00000000 --- a/dl4se-server/src/main/java/usi/si/seart/service/MetaService.java +++ /dev/null @@ -1,43 +0,0 @@ -package usi.si.seart.service; - -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.experimental.FieldDefaults; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import usi.si.seart.meta.PostgresMaterializedView; -import usi.si.seart.repository.PostgresMaterializedViewRepository; - -public interface MetaService { - - void refreshMaterializedViews(); - - @Service - @ConditionalOnMissingBean(MetaService.class) - class MetaServiceStub implements MetaService { - - @Override - public void refreshMaterializedViews() { - } - } - - @Service - @ConditionalOnProperty(value = "spring.jpa.database", havingValue = "postgresql") - @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) - @AllArgsConstructor(onConstructor_ = @Autowired) - class PostgresMetaService implements MetaService { - - PostgresMaterializedViewRepository materializedViewRepository; - - @Override - @Transactional - public void refreshMaterializedViews() { - materializedViewRepository.findAll().stream() - .map(PostgresMaterializedView::getName) - .forEach(materializedViewRepository::refreshByName); - } - } -} diff --git a/liquibase/scripts/04_procedure.sql b/liquibase/scripts/04_procedure.sql deleted file mode 100644 index 4347de9b..00000000 --- a/liquibase/scripts/04_procedure.sql +++ /dev/null @@ -1,41 +0,0 @@ --- liquibase formatted sql --- changeset dabico:5 - -CREATE OR REPLACE PROCEDURE - "refresh_materialized_view"(name text) -AS $$ -DECLARE - _name text; - _oid oid; - _has_unique_index boolean; -BEGIN - -- Parameter Preconditions - IF name IS NULL - THEN RAISE EXCEPTION SQLSTATE 'C0001' - USING MESSAGE = 'name parameter is required'; - END IF; - -- Check Exists - _name := refresh_materialized_view.name; - IF NOT EXISTS( - SELECT FROM pg_matviews - WHERE pg_matviews.matviewname = _name - ) - THEN RAISE no_data_found; - END IF; - -- Retrieve OID - SELECT pg_class.oid INTO _oid - FROM pg_class - JOIN pg_matviews ON pg_matviews.matviewname = pg_class.relname - WHERE pg_matviews.matviewname = _name; - -- Examine Indexes - SELECT EXISTS( - SELECT FROM pg_index - WHERE pg_index.indisunique = true - AND pg_index.indrelid = _oid - ) INTO _has_unique_index; - -- Execute Refresh - EXECUTE 'REFRESH MATERIALIZED VIEW ' - || CASE WHEN _has_unique_index THEN 'CONCURRENTLY ' ELSE '' END - || _name; -END; -$$ LANGUAGE PLpgSQL; From 01a57026d5c03b6442d0d38ea96133f49843a972 Mon Sep 17 00:00:00 2001 From: dabico Date: Mon, 16 Oct 2023 12:10:09 +0200 Subject: [PATCH 0421/1089] Removing validation annotations that are no longer needed --- .../constraints/AllNullOrNotNull.java | 35 --------- .../AllNullOrNotNullValidator.java | 38 ---------- .../validation/constraints/NullOrRange.java | 43 ----------- .../resources/ValidationMessages.properties | 2 - .../constraints/AllNullOrNotNullTest.java | 54 -------------- .../constraints/NullOrRangeTest.java | 72 ------------------- 6 files changed, 244 deletions(-) delete mode 100644 dl4se-model/src/main/java/usi/si/seart/validation/constraints/AllNullOrNotNull.java delete mode 100644 dl4se-model/src/main/java/usi/si/seart/validation/constraints/AllNullOrNotNullValidator.java delete mode 100644 dl4se-model/src/main/java/usi/si/seart/validation/constraints/NullOrRange.java delete mode 100644 dl4se-model/src/test/java/usi/si/seart/validation/constraints/AllNullOrNotNullTest.java delete mode 100644 dl4se-model/src/test/java/usi/si/seart/validation/constraints/NullOrRangeTest.java diff --git a/dl4se-model/src/main/java/usi/si/seart/validation/constraints/AllNullOrNotNull.java b/dl4se-model/src/main/java/usi/si/seart/validation/constraints/AllNullOrNotNull.java deleted file mode 100644 index 60cefcb2..00000000 --- a/dl4se-model/src/main/java/usi/si/seart/validation/constraints/AllNullOrNotNull.java +++ /dev/null @@ -1,35 +0,0 @@ -package usi.si.seart.validation.constraints; - -import javax.validation.Constraint; -import javax.validation.Payload; -import java.lang.annotation.Documented; -import java.lang.annotation.Repeatable; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -@Documented -@Constraint(validatedBy = { AllNullOrNotNullValidator.class }) -@Repeatable(AllNullOrNotNull.List.class) -@Target({ TYPE, ANNOTATION_TYPE }) -@Retention(RUNTIME) -public @interface AllNullOrNotNull { - - String[] fields(); - - String message() default "{usi.si.seart.validation.constraints.AllNullOrNotNull.message}"; - - Class[] groups() default {}; - - Class[] payload() default {}; - - @Target({TYPE, ANNOTATION_TYPE}) - @Retention(RUNTIME) - @Documented - @interface List { - AllNullOrNotNull[] value(); - } -} diff --git a/dl4se-model/src/main/java/usi/si/seart/validation/constraints/AllNullOrNotNullValidator.java b/dl4se-model/src/main/java/usi/si/seart/validation/constraints/AllNullOrNotNullValidator.java deleted file mode 100644 index cf556849..00000000 --- a/dl4se-model/src/main/java/usi/si/seart/validation/constraints/AllNullOrNotNullValidator.java +++ /dev/null @@ -1,38 +0,0 @@ -package usi.si.seart.validation.constraints; - -import lombok.SneakyThrows; - -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; -import java.lang.reflect.Field; - -public class AllNullOrNotNullValidator implements ConstraintValidator { - - String[] fieldNames; - - @Override - public void initialize(AllNullOrNotNull annotation) { - fieldNames = annotation.fields(); - } - - @Override - @SneakyThrows - public boolean isValid(Object value, ConstraintValidatorContext context) { - if (value == null || fieldNames.length < 2) return true; - boolean result = true; - for (int i = 0; i < fieldNames.length - 1; i++) { - String fieldNameOne = fieldNames[i]; - String fieldNameTwo = fieldNames[i + 1]; - Field fieldOne = value.getClass().getDeclaredField(fieldNameOne); - Field fieldTwo = value.getClass().getDeclaredField(fieldNameTwo); - fieldOne.setAccessible(true); - fieldTwo.setAccessible(true); - Object fieldOneValue = fieldOne.get(value); - Object fieldTwoValue = fieldTwo.get(value); - boolean bothNull = fieldOneValue == null && fieldTwoValue == null; - boolean noneNull = fieldOneValue != null && fieldTwoValue != null; - result &= (bothNull || noneNull); - } - return result; - } -} diff --git a/dl4se-model/src/main/java/usi/si/seart/validation/constraints/NullOrRange.java b/dl4se-model/src/main/java/usi/si/seart/validation/constraints/NullOrRange.java deleted file mode 100644 index c949f020..00000000 --- a/dl4se-model/src/main/java/usi/si/seart/validation/constraints/NullOrRange.java +++ /dev/null @@ -1,43 +0,0 @@ -package usi.si.seart.validation.constraints; - -import org.hibernate.validator.constraints.CompositionType; -import org.hibernate.validator.constraints.ConstraintComposition; -import org.hibernate.validator.constraints.Range; - -import javax.validation.Constraint; -import javax.validation.OverridesAttribute; -import javax.validation.Payload; -import javax.validation.ReportAsSingleViolation; -import javax.validation.constraints.Null; -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE_USE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -@Documented -@ConstraintComposition(CompositionType.OR) -@Null -@Range -@Constraint(validatedBy = { }) -@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE }) -@Retention(RUNTIME) -@ReportAsSingleViolation -public @interface NullOrRange { - - @OverridesAttribute(constraint = Range.class, name = "min") long min() default 0; - - @OverridesAttribute(constraint = Range.class, name = "max") long max() default Long.MAX_VALUE; - - String message() default "{usi.si.seart.validation.constraints.NullOrRange.message}"; - - Class[] groups() default { }; - - Class< ? extends Payload>[] payload() default { }; -} diff --git a/dl4se-model/src/main/resources/ValidationMessages.properties b/dl4se-model/src/main/resources/ValidationMessages.properties index 88343c64..3254b689 100644 --- a/dl4se-model/src/main/resources/ValidationMessages.properties +++ b/dl4se-model/src/main/resources/ValidationMessages.properties @@ -1,6 +1,4 @@ -usi.si.seart.validation.constraints.AllNullOrNotNull.message=All fields must contain either a non-null value, or null usi.si.seart.validation.constraints.Hash.message=Not a valid hash usi.si.seart.validation.constraints.NullOrNotBlank.message=Value is neither unset, nor does it contain a single non-whitespace character -usi.si.seart.validation.constraints.NullOrRange.message=Value is neither unset, nor within the valid value range usi.si.seart.validation.constraints.OWASPEmail.message=Not an OWASP-compliant email address usi.si.seart.validation.constraints.Password.message=Not a valid password diff --git a/dl4se-model/src/test/java/usi/si/seart/validation/constraints/AllNullOrNotNullTest.java b/dl4se-model/src/test/java/usi/si/seart/validation/constraints/AllNullOrNotNullTest.java deleted file mode 100644 index d0072761..00000000 --- a/dl4se-model/src/test/java/usi/si/seart/validation/constraints/AllNullOrNotNullTest.java +++ /dev/null @@ -1,54 +0,0 @@ -package usi.si.seart.validation.constraints; - -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Cleanup; -import lombok.experimental.FieldDefaults; -import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; - -import javax.validation.ConstraintViolation; -import javax.validation.Validation; -import javax.validation.Validator; -import javax.validation.ValidatorFactory; -import java.util.Set; - -class AllNullOrNotNullTest { - - static Validator validator; - - @BeforeAll - static void setUp() { - @Cleanup ValidatorFactory factory = Validation.byDefaultProvider() - .configure() - .messageInterpolator(new ParameterMessageInterpolator()) - .buildValidatorFactory(); - validator = factory.getValidator(); - } - - @AllNullOrNotNull(fields = {"token", "percentage", "contiguous"}) - @AllArgsConstructor - @FieldDefaults(level = AccessLevel.PRIVATE) - private static final class Contract { - String token; - Integer percentage; - Boolean contiguous; - } - - @ParameterizedTest - @CsvSource({ "TOKEN,,", ",1,", ",,false", "TOKEN,1,", ",1,false" }) - void invalidTest(String token, Integer percentage, Boolean contiguous) { - Set> violations = validator.validate(new Contract(token, percentage, contiguous)); - Assertions.assertFalse(violations.isEmpty()); - } - - @ParameterizedTest - @CsvSource({ "TOKEN,1,false", ",," }) - void validTest(String token, Integer percentage, Boolean contiguous) { - Set> violations = validator.validate(new Contract(token, percentage, contiguous)); - Assertions.assertTrue(violations.isEmpty()); - } -} diff --git a/dl4se-model/src/test/java/usi/si/seart/validation/constraints/NullOrRangeTest.java b/dl4se-model/src/test/java/usi/si/seart/validation/constraints/NullOrRangeTest.java deleted file mode 100644 index 2d282ed7..00000000 --- a/dl4se-model/src/test/java/usi/si/seart/validation/constraints/NullOrRangeTest.java +++ /dev/null @@ -1,72 +0,0 @@ -package usi.si.seart.validation.constraints; - -import lombok.AllArgsConstructor; -import lombok.Cleanup; -import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import org.junit.jupiter.params.provider.NullSource; - -import javax.validation.ConstraintViolation; -import javax.validation.Validation; -import javax.validation.Validator; -import javax.validation.ValidatorFactory; -import java.util.Set; -import java.util.stream.Stream; - -class NullOrRangeTest { - - static Validator validator; - - @BeforeAll - static void setUp() { - @Cleanup ValidatorFactory factory = Validation.byDefaultProvider() - .configure() - .messageInterpolator(new ParameterMessageInterpolator()) - .buildValidatorFactory(); - validator = factory.getValidator(); - } - - @AllArgsConstructor - private static final class Contract { - @NullOrRange(min = 1, max = 100) - Integer percentage; - } - - @ParameterizedTest - @MethodSource("invalidIntegerProvider") - void invalidTest(Integer value) { - Set> violations = validator.validate(new Contract(value)); - Assertions.assertFalse(violations.isEmpty()); - } - - static Stream invalidIntegerProvider() { - return Stream.of( - Arguments.of(0), - Arguments.of(101), - Arguments.of(Integer.MIN_VALUE), - Arguments.of(Integer.MAX_VALUE) - ); - } - - @ParameterizedTest - @NullSource - @MethodSource("validIntegerProvider") - void validTest(Integer value) { - Set> violations = validator.validate(new Contract(value)); - Assertions.assertTrue(violations.isEmpty()); - } - - static Stream validIntegerProvider() { - return Stream.of( - Arguments.of(1), - Arguments.of(25), - Arguments.of(50), - Arguments.of(75), - Arguments.of(100) - ); - } -} From b20a8802f8f166818a9ef16266a8a26f3ecff40d Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 17 Oct 2023 11:50:50 +0200 Subject: [PATCH 0422/1089] Fix minor sonarlint warning in website `Dockerfile` --- deployment/website/Dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/deployment/website/Dockerfile b/deployment/website/Dockerfile index 4121cc51..6d53ba9a 100644 --- a/deployment/website/Dockerfile +++ b/deployment/website/Dockerfile @@ -1,11 +1,11 @@ -FROM node:18.7-alpine as install +FROM node:18.7-alpine AS install ARG WEBSITE_PORT ARG SERVER_URL COPY ./dl4se-website/package*.json ./ RUN npm install COPY ./dl4se-website . -FROM install as build +FROM install AS build ARG WEBSITE_PORT ARG SERVER_URL ARG NODE_ENV=production @@ -13,7 +13,7 @@ RUN apk update && apk add gettext RUN envsubst < .env.template > .env RUN npm run build -FROM nginx:1.23-alpine as production +FROM nginx:1.23-alpine AS production COPY --from=build /dist /usr/share/nginx/html COPY ./nginx/nginx.conf /etc/nginx/conf.d/default.conf -CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file +CMD ["nginx", "-g", "daemon off;"] From 640bd078752b907befdee31e59d029d2543c26e5 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 17 Oct 2023 11:52:59 +0200 Subject: [PATCH 0423/1089] Use single `RUN` instruction --- deployment/website/Dockerfile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/deployment/website/Dockerfile b/deployment/website/Dockerfile index 6d53ba9a..dc2915d3 100644 --- a/deployment/website/Dockerfile +++ b/deployment/website/Dockerfile @@ -9,9 +9,10 @@ FROM install AS build ARG WEBSITE_PORT ARG SERVER_URL ARG NODE_ENV=production -RUN apk update && apk add gettext -RUN envsubst < .env.template > .env -RUN npm run build +RUN apk update --quiet && \ + apk add --no-cache --quiet gettext && \ + envsubst < .env.template > .env && \ + npm run build FROM nginx:1.23-alpine AS production COPY --from=build /dist /usr/share/nginx/html From a5c751ecbb6bb4ddc9f9c758db33c84cbcf24472 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 17 Oct 2023 14:16:55 +0200 Subject: [PATCH 0424/1089] Completely removing `src2abs` from the dependency list --- deployment/crawler/Dockerfile | 3 +- deployment/server/Dockerfile | 4 +- dl4se-server/pom.xml | 5 - dl4se-src2abs/README.md | 127 ------ dl4se-src2abs/inputs/Class.java | 14 - dl4se-src2abs/inputs/Method.java | 6 - dl4se-src2abs/inputs/idioms.csv | 3 - dl4se-src2abs/lib/javalexer.jar | Bin 13504 -> 0 bytes dl4se-src2abs/pom.xml | 63 --- .../java/usi/si/seart/src2abs/Abstractor.java | 62 --- .../main/java/usi/si/seart/src2abs/Main.java | 58 --- .../java/usi/si/seart/src2abs/Parser.java | 117 ------ .../java/usi/si/seart/src2abs/Tokenizer.java | 392 ------------------ pom.xml | 1 - 14 files changed, 3 insertions(+), 852 deletions(-) delete mode 100644 dl4se-src2abs/README.md delete mode 100644 dl4se-src2abs/inputs/Class.java delete mode 100644 dl4se-src2abs/inputs/Method.java delete mode 100644 dl4se-src2abs/inputs/idioms.csv delete mode 100644 dl4se-src2abs/lib/javalexer.jar delete mode 100644 dl4se-src2abs/pom.xml delete mode 100644 dl4se-src2abs/src/main/java/usi/si/seart/src2abs/Abstractor.java delete mode 100644 dl4se-src2abs/src/main/java/usi/si/seart/src2abs/Main.java delete mode 100644 dl4se-src2abs/src/main/java/usi/si/seart/src2abs/Parser.java delete mode 100644 dl4se-src2abs/src/main/java/usi/si/seart/src2abs/Tokenizer.java diff --git a/deployment/crawler/Dockerfile b/deployment/crawler/Dockerfile index af853771..0efa2c08 100644 --- a/deployment/crawler/Dockerfile +++ b/deployment/crawler/Dockerfile @@ -5,7 +5,6 @@ COPY ./dl4se-analyzer /dl4se-analyzer COPY ./dl4se-crawler /dl4se-crawler COPY ./dl4se-model /dl4se-model COPY ./dl4se-server /dl4se-server -COPY ./dl4se-src2abs /dl4se-src2abs RUN mvn -e \ --no-transfer-progress \ @@ -36,4 +35,4 @@ RUN keytool \ -storepass changeit \ -noprompt -ENTRYPOINT java -jar crawler.jar \ No newline at end of file +ENTRYPOINT java -jar crawler.jar diff --git a/deployment/server/Dockerfile b/deployment/server/Dockerfile index fd172567..afcd4ef1 100644 --- a/deployment/server/Dockerfile +++ b/deployment/server/Dockerfile @@ -1,10 +1,10 @@ FROM maven:3.8.4-jdk-11-slim AS build COPY ./pom.xml /pom.xml +COPY ./dl4se-analyzer /dl4se-analyzer COPY ./dl4se-crawler /dl4se-crawler COPY ./dl4se-model /dl4se-model COPY ./dl4se-server /dl4se-server -COPY ./dl4se-src2abs /dl4se-src2abs RUN mvn -e --no-transfer-progress install:install-file \ -Dfile="./dl4se-src2abs/lib/javalexer.jar" \ @@ -21,4 +21,4 @@ COPY --from=build /dl4se-server/target/dl4se-server-*.jar /server.jar RUN apk update && apk add git -ENTRYPOINT java -jar server.jar \ No newline at end of file +ENTRYPOINT java -jar server.jar diff --git a/dl4se-server/pom.xml b/dl4se-server/pom.xml index adc2d0a7..89dbf18a 100644 --- a/dl4se-server/pom.xml +++ b/dl4se-server/pom.xml @@ -22,11 +22,6 @@ dl4se-model ${project.version} - - usi.si.seart - dl4se-src2abs - ${project.version} - io.jsonwebtoken jjwt-api diff --git a/dl4se-src2abs/README.md b/dl4se-src2abs/README.md deleted file mode 100644 index 8ea0bc18..00000000 --- a/dl4se-src2abs/README.md +++ /dev/null @@ -1,127 +0,0 @@ -# src2abs -`src2abs` is a tool that *abstracts* Java source code. - -It transforms this source code: -``` -public static void main(String[] args) { - console.println("Hello, World!"); -} -``` -into this abstract textual representation: -``` -public static void METHOD_1 ( TYPE_1 [ ] VAR_1 ) { VAR_2 . METHOD_2 ( STRING_1 ) ; } -``` -This abstract representations contains: -- Java Keywords; -- Code Separators; -- IDs in place of identifiers and literals; -- Idioms (optionally). - -### How it works -`src2abs` uses a Java Lexer to read and tokenize the source code. A Java Parser analyzes the code and discerns the type of each identifier and literal in the source code. Next, `src2abs` replaces each identifiers and literals in the stream of tokens with a unique ID which represents the type and role of the identifier/literal in the code. - -Each ID `_#` is formed by a prefix (_i.e.,_ `_`) whcih represents the type and role of the identifier/literal, and a numerical ID (_i.e.,_ `#`) which is assigned sequentially when reading the code. Note that these IDs are reused when the same identifier/literal appears again in the stream of tokens. Here is the list of supported IDs: - -*Identifiers* -- `TYPE_#` -- `METHOD_#` -- `VAR_#` - -*Literals* -- `INT_#` -- `FLOAT_#` -- `CHAR_#` -- `STRING_#` - -### Idioms -There are some identifiers and literals that occur so often in source code that they can almost be considered keywords of the language. For example, the variable names `i`, `index`, the method names `toString()`, `indexOf()`, literals such as `0`, `\n`, `1`, etc., provide meaningful semantic information that can be helpful in a variety of tasks. We refer to these frequent identifiers and literals as *idioms*. - -`src2abs` allows to specify a list of idioms (either identifier or literal values) that will be kept in the abstract representation and not replaced with IDs. For example, if the idioms `String` (a common Java type) and `args` (a common variable name) are specified, then `src2abs` will generate the following abstract source code for the previous example: -``` -public static void METHOD_1 ( String [ ] args ) { VAR_1 . METHOD_2 ( STRING_1 ) ; } -``` - - - - - -## Installation -Clone the project and enter in the corresponding folder: -``` -git clone https://gitlab.dev.si.usi.ch/devinta/src2abs.git -cd src2abs -``` -Use Maven to install dependencies and generate the runnable jar: -``` -mvn clean -mvn install:install-file -Dfile="lib/javalexer.jar" -DgroupId="edu.wm.cs" -DartifactId="javalexer" -Dversion="1" -Dpackaging="jar" -mvn package -``` -The generated jar is located in the target folder: -``` -target/src2abs-0.1-jar-with-dependencies.jar -``` - - -## Usage -`src2abs` supports two usage modes: -- *Single mode*: abstracts a single piece of source code; -- *Pair mode*: abstracts two pieces of source code. It reuses the IDs already generated for shared identifiers/literals in the pair. - -The single mode is suggested when analyzing code in isolation. The pair mode is recommended when analyzing the changes/evolution of the same piece of source code in a commit/revision. -Both modes can abstract code at two levels of granularities: -- Method -- Class - -### Single mode -``` -java -jar src2abs-0.1-jar-with-dependencies.jar single -``` - -Arguments: -- ``: code granularity (*i.e.,* either `method` or `class`); -- ``: path of the file containing the source code to abstract; -- ``: path of the file (to be created) where the abstract source code will be saved; -- ``: path of the file containing the list of idioms. - -### Pair mode -``` -java -jar src2abs-0.1-jar-with-dependencies.jar pair -``` -Arguments: -- ``: code granularity (*i.e.,* either `method` or `class`); -- ``: path of the *first* file containing the source code to abstract; -- ``: path of the *second* file containing the source code to abstract; -- ``: path of the file (to be created) where the *first* abstract source code will be saved; -- ``: path of the file (to be created) where the *second* abstract source code will be saved; -- ``: path of the file containing the list of idioms. - -## Credits -`src2abs` was built by [Michele Tufano](http://www.cs.wm.edu/~mtufano/) and [Cody Watson](http://www.cs.wm.edu/~cawatson/) and used and adapted in the context of the following research projects. If you are using `src2abs` for research purposes, please cite: - -- [1] On Learning Meaningful Code Changes via Neural Machine Translation -- [2] An Empirical Study on Learning Bug-Fixing Patches in the Wild via Neural Machine Translation - -## Bibliography -### [1] On Learning Meaningful Code Changes via Neural Machine Translation -``` -@inproceedings{Tufano-Learning-CodeChanges, - Author = {Michele Tufano and Jevgenija Pantiuchina and Cody Watson and Gabriele Bavota and Denys Poshyvanyk}, - title = {On Learning Meaningful Code Changes via Neural Machine Translation}, - booktitle = {Proceedings of the 41st International Conference on Software Engineering}, - series = {ICSE '19}, - year = {2019}, - location = {Montréal, Candada}, - numpages = {12} -} -``` -### [2] An Empirical Study on Learning Bug-Fixing Patches in the Wild via Neural Machine Translation -``` -@article{DBLP:journals/corr/abs-1812-08693, - author = {Michele Tufano and Cody Watson and Gabriele Bavota and Massimiliano Di Penta and Martin White and Denys Poshyvanyk}, - title = {An Empirical Study on Learning Bug-Fixing Patches in the Wild via Neural Machine Translation}, - journal = {TOSEM}, - volume = {abs/1812.08693}, - year = {2018} -} -``` \ No newline at end of file diff --git a/dl4se-src2abs/inputs/Class.java b/dl4se-src2abs/inputs/Class.java deleted file mode 100644 index 41a50629..00000000 --- a/dl4se-src2abs/inputs/Class.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.example; - -/** - * This is a JavaDoc comment - */ -public class App { - - /** - * This is another JavaDoc comment - */ - public static void main(String[] args) { - System.out.println("Hello World!"); - } -} \ No newline at end of file diff --git a/dl4se-src2abs/inputs/Method.java b/dl4se-src2abs/inputs/Method.java deleted file mode 100644 index 00a1740b..00000000 --- a/dl4se-src2abs/inputs/Method.java +++ /dev/null @@ -1,6 +0,0 @@ -/** - * This is a JavaDoc comment - */ -public static void main(String[] args) { - System.out.println("Hello World!"); -} \ No newline at end of file diff --git a/dl4se-src2abs/inputs/idioms.csv b/dl4se-src2abs/inputs/idioms.csv deleted file mode 100644 index 3c8dd8ae..00000000 --- a/dl4se-src2abs/inputs/idioms.csv +++ /dev/null @@ -1,3 +0,0 @@ -App -String -main \ No newline at end of file diff --git a/dl4se-src2abs/lib/javalexer.jar b/dl4se-src2abs/lib/javalexer.jar deleted file mode 100644 index 7a54bbbe8a8fe0b9fc75802492326be93242390a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13504 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 diff --git a/dl4se-src2abs/pom.xml b/dl4se-src2abs/pom.xml deleted file mode 100644 index 17017063..00000000 --- a/dl4se-src2abs/pom.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - 4.0.0 - - dl4se - usi.si.seart - ${revision} - ../pom.xml - - - dl4se-src2abs - - dl4se-src2abs - - - UTF-8 - - - - - - edu.wm.cs - javalexer - 1 - - - com.github.javaparser - javaparser-core - ${javaparser.version} - - - com.github.javaparser - javaparser-core-generators - ${javaparser.version} - - - org.antlr - antlr4 - 4.5.3 - - - commons-io - commons-io - 2.11.0 - - - - - - - maven-shade-plugin - - - package - - shade - - - - - - - diff --git a/dl4se-src2abs/src/main/java/usi/si/seart/src2abs/Abstractor.java b/dl4se-src2abs/src/main/java/usi/si/seart/src2abs/Abstractor.java deleted file mode 100644 index f721b989..00000000 --- a/dl4se-src2abs/src/main/java/usi/si/seart/src2abs/Abstractor.java +++ /dev/null @@ -1,62 +0,0 @@ -package usi.si.seart.src2abs; - -import lombok.Cleanup; -import lombok.SneakyThrows; -import lombok.experimental.UtilityClass; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -@UtilityClass -public class Abstractor { - - @SneakyThrows - public void abstractCode( - Parser.Granularity granularity, Path inputCodePath, Path outputCodePath, Path idiomsFilePath - ) { - String sourceCode = new String(Files.readAllBytes(inputCodePath)); - sourceCode = cleanCode(sourceCode); - - Set idioms; - @Cleanup Stream stream = Files.lines(idiomsFilePath); - idioms = stream.collect(Collectors.toSet()); - - Parser parser = new Parser(granularity); - parser.parse(sourceCode); - - Tokenizer tokenizer = new Tokenizer(parser, idioms); - String abstractCode = tokenizer.tokenize(sourceCode); - - Files.write(outputCodePath, abstractCode.getBytes()); - - String mapFileName = outputCodePath.getFileName() + ".map"; - Path mapOutputFile = outputCodePath.resolveSibling(mapFileName); - tokenizer.export(mapOutputFile); - } - - public static String cleanCode(String sourceCode) { - Pattern pattern = Pattern.compile("(\".+\")"); - Matcher matcher = pattern.matcher(sourceCode); - - String group; - String okGroup; - while (matcher.find()) { - for (int i = 0; i <= matcher.groupCount(); i++) { - group = matcher.group(i); - //okGroup = group.replaceAll("@", ""); - okGroup = group.replaceAll("//", ""); - sourceCode = sourceCode.replace(group, okGroup); - } - } - - sourceCode = sourceCode.replaceAll("(?:/\\*(?:[^*]|(?:\\*+[^*/]))*\\*+/)|(?://.*)", ""); - //sourceCode = sourceCode.replaceAll("@.+", ""); - - return sourceCode; - } -} diff --git a/dl4se-src2abs/src/main/java/usi/si/seart/src2abs/Main.java b/dl4se-src2abs/src/main/java/usi/si/seart/src2abs/Main.java deleted file mode 100644 index 12f78bca..00000000 --- a/dl4se-src2abs/src/main/java/usi/si/seart/src2abs/Main.java +++ /dev/null @@ -1,58 +0,0 @@ -package usi.si.seart.src2abs; - -import com.github.javaparser.ParseProblemException; - -import java.nio.file.Files; -import java.nio.file.NoSuchFileException; -import java.nio.file.Path; - -public class Main { - - public static void main(String[] args) { - int code = 0; - try { - Parser.Granularity granularity = Parser.Granularity.valueOf(args[0].toUpperCase()); - - Path inputPath = Path.of(args[1]); - Path outputPath = Path.of(args[2]); - Path idiomsPath = Path.of(args[3]); - - Path outputParent = outputPath.getParent(); - - if (Files.notExists(inputPath)) throw new NoSuchFileException(inputPath.toString()); - if (Files.notExists(outputParent)) throw new NoSuchFileException(outputParent.toString()); - if (Files.notExists(idiomsPath)) throw new NoSuchFileException(idiomsPath.toString()); - - Abstractor.abstractCode(granularity, inputPath, outputPath, idiomsPath); - } catch (ArrayIndexOutOfBoundsException ignored) { - System.err.println("Not enough arguments!"); - printUsage(); - code = 1; - } catch (IllegalArgumentException ignored) { - System.err.println("Wrong granularity!"); - printUsage(); - code = 1; - } catch (ParseProblemException ex) { - System.err.println("Parsing Error: "); - ex.printStackTrace(); - code = 1; - } catch (NoSuchFileException ex) { - System.err.println("File or directory does not exist: " + ex.getFile()); - code = 1; - } catch (Throwable thr) { - thr.printStackTrace(); - code = 1; - } finally { - System.exit(code); - } - } - - private static void printUsage() { - System.out.println("-----------------------"); - System.out.println("src2abs usage:"); - System.out.println("1. Granularity {method, class}"); - System.out.println("2. Source Code file path input"); - System.out.println("3. Abstract Code file path output"); - System.out.println("4. Idiom file path"); - } -} diff --git a/dl4se-src2abs/src/main/java/usi/si/seart/src2abs/Parser.java b/dl4se-src2abs/src/main/java/usi/si/seart/src2abs/Parser.java deleted file mode 100644 index f9e86649..00000000 --- a/dl4se-src2abs/src/main/java/usi/si/seart/src2abs/Parser.java +++ /dev/null @@ -1,117 +0,0 @@ -package usi.si.seart.src2abs; - -import com.github.javaparser.StaticJavaParser; -import com.github.javaparser.ast.Node; -import com.github.javaparser.ast.body.MethodDeclaration; -import com.github.javaparser.ast.expr.AnnotationExpr; -import com.github.javaparser.ast.expr.MethodCallExpr; -import com.github.javaparser.ast.expr.MethodReferenceExpr; -import com.github.javaparser.ast.type.Type; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import lombok.experimental.FieldDefaults; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Optional; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Stream; - -@Getter -@RequiredArgsConstructor -@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) -public class Parser { - - public enum Granularity { - METHOD, CLASS - } - - Set types = new HashSet<>(); - Set methods = new HashSet<>(); - Set annotations = new HashSet<>(); - - Granularity granularity; - - public Parser() { - this.granularity = null; - } - - public void parse(String sourceCode) { - Function parsingFunction = StaticJavaParser::parse; - if (granularity == Granularity.METHOD) { - parsingFunction = StaticJavaParser::parseMethodDeclaration; - } - - parse(sourceCode, parsingFunction); - } - - public void parse(String sourceCode, Function parsingFunction) { - Node node = parsingFunction.apply(sourceCode); - traverseNode(node); - } - - public void traverseNode(Node node) { - // create set of annotations - node.findAll(AnnotationExpr.class).stream() - .map(AnnotationExpr::getNameAsString) - .forEach(annotations::add); - - // create set of types - node.findAll(Type.class).stream() - .flatMap(type -> { - String[] allTypes = filterString(type.asString()); - return Stream.of(allTypes); - }) - .forEach(types::add); - - // create set of methods and insert declared methods - node.findAll(MethodDeclaration.class).stream() - .map(MethodDeclaration::getNameAsString) - .forEach(methods::add); - - // insert referenced methods into methods set - node.findAll(MethodCallExpr.class).stream() - .map(MethodCallExpr::getNameAsString) - .forEach(methods::add); - - // insert scope of methods into types - node.findAll(MethodCallExpr.class).stream() - .map(MethodCallExpr::getScope) - .flatMap(Optional::stream) - .filter(expression -> expression.isFieldAccessExpr() || expression.isNameExpr()) - .forEach(expression -> { - String exprStr = expression.toString(); - String[] fragments = exprStr.split("\\."); - String[] letters = fragments[fragments.length - 1].split(""); - if (!letters[0].equals(letters[0].toLowerCase())) { - String[] allTypes = filterString(exprStr); - types.addAll(Arrays.asList(allTypes)); - } - }); - - // insert scope of methods into types - node.findAll(MethodReferenceExpr.class).stream() - .map(MethodReferenceExpr::getIdentifier) - .forEach(methods::add); - } - - private String[] filterString(String typeString){ - String[] listString; - typeString = typeString.replaceAll("\\[", " "); - typeString = typeString.replaceAll("\\]", " "); - typeString = typeString.replaceAll("\\(", " "); - typeString = typeString.replaceAll("\\)", " "); - typeString = typeString.replaceAll(">", " "); - typeString = typeString.replaceAll("<", " "); - typeString = typeString.replaceAll("\\{", " "); - typeString = typeString.replaceAll("\\}", " "); - typeString = typeString.replaceAll("\\,", " "); - typeString = typeString.replaceAll("\\?", " "); - typeString = typeString.replaceAll("extends", " "); - typeString = typeString.replaceAll("implements", " "); - listString = typeString.split(" "); - return listString; - } -} diff --git a/dl4se-src2abs/src/main/java/usi/si/seart/src2abs/Tokenizer.java b/dl4se-src2abs/src/main/java/usi/si/seart/src2abs/Tokenizer.java deleted file mode 100644 index dd1b8140..00000000 --- a/dl4se-src2abs/src/main/java/usi/si/seart/src2abs/Tokenizer.java +++ /dev/null @@ -1,392 +0,0 @@ -package usi.si.seart.src2abs; - -import edu.wm.cs.compiler.tools.generators.scanners.JavaLexer; -import lombok.AccessLevel; -import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; -import lombok.experimental.FieldDefaults; -import org.antlr.v4.runtime.ANTLRInputStream; -import org.antlr.v4.runtime.Token; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Function; -import java.util.stream.Collector; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -@RequiredArgsConstructor(access = AccessLevel.PRIVATE) -@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) -public class Tokenizer { - - private static final String SPACED_DOT = " . "; - - Map stringLiterals = new LinkedHashMap<>(); - Map charLiterals = new LinkedHashMap<>(); - Map intLiterals = new LinkedHashMap<>(); - Map floatLiterals = new LinkedHashMap<>(); - Map typeMap = new LinkedHashMap<>(); - Map methodMap = new LinkedHashMap<>(); - Map annotationMap = new LinkedHashMap<>(); - Map varMap = new LinkedHashMap<>(); - - Set types; - Set methods; - Set annotations; - Set idioms; - - public Tokenizer(Parser parser, Set idioms) { - this(parser.getTypes(), parser.getMethods(), parser.getAnnotations(), idioms); - } - - public String tokenize(String sourceCode) { - List tokens = readTokens(sourceCode); - - StringBuilder sb = new StringBuilder(); - - for (int i = 0; i < tokens.size(); i++) { - String token = ""; - Token t = tokens.get(i); - - //Handling annotations - if (t.getType() == JavaLexer.AT){ - int j = i + 1; - Token nextToken = tokens.get(j); - - if (nextToken.getType() == JavaLexer.Identifier && annotations.contains(nextToken.getText())) { - //This is an annotation - token = getAnnotationID(nextToken.getText()); - i = j; - } - - } else if (t.getType() == JavaLexer.Identifier) { - String tokenName = t.getText(); - int j = i + 1; - - boolean expectDOT = true; - while (j < tokens.size()) { - Token nextToken = tokens.get(j); - if (expectDOT) { - if (nextToken.getType() == JavaLexer.DOT) { - tokenName += nextToken.getText(); - expectDOT = false; - } else { - i = j - 1; - break; - } - } else { - if ((nextToken.getType() == JavaLexer.Identifier || nextToken.getType() == JavaLexer.THIS - || nextToken.getType() == JavaLexer.CLASS || nextToken.getType() == JavaLexer.NEW) && - tokens.get(j-1).getType() == JavaLexer.DOT) { - tokenName += nextToken.getText(); - } else { - i = j-1; - break; - } - } - j++; - } - - - token = analyzeIdentifier(tokenName, tokens, i); - } else if (t.getType() == JavaLexer.CharacterLiteral) { - token = getCharId(t); - } else if (t.getType() == JavaLexer.FloatingPointLiteral) { - token = getFloatId(t); - } else if (t.getType() == JavaLexer.IntegerLiteral) { - token = getIntId(t); - } else if (t.getType() == JavaLexer.StringLiteral) { - token = getStringId(t); - } else { - token = t.getText(); - } - - sb.append(token).append(" "); - } - - return sb.toString().trim(); - } - - @SneakyThrows - public static List readTokens(String sourceCode) { - InputStream inputStream = new ByteArrayInputStream(sourceCode.getBytes(StandardCharsets.UTF_8)); - JavaLexer jLexer = new JavaLexer(new ANTLRInputStream(inputStream)); - jLexer.removeErrorListeners(); - - List tokens = new ArrayList<>(); - for (Token t = jLexer.nextToken(); t.getType() != Token.EOF; t = jLexer.nextToken()) { - tokens.add(t); - } - - return tokens; - } - - @SneakyThrows - public void export(Path outFile) { - Files.write(outFile, getKeysAndValues(export())); - } - - public Map export() { - return Stream.of( - typeMap.entrySet().stream(), - methodMap.entrySet().stream(), - varMap.entrySet().stream(), - annotationMap.entrySet().stream(), - charLiterals.entrySet().stream(), - floatLiterals.entrySet().stream(), - intLiterals.entrySet().stream(), - stringLiterals.entrySet().stream() - ) - .flatMap(Function.identity()) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> v2, LinkedHashMap::new)); - } - - private List getKeysAndValues(Map map){ - Collector commaCollector = Collectors.joining(","); - String keys = map.keySet().stream().collect(commaCollector); - String values = map.values().stream().collect(commaCollector); - return List.of(keys, values); - } - - private String analyzeIdentifier(String token, List tokens, int i) { - if (idioms.contains(token)) return token; - - String[] tokenParts = token.split("\\."); - - if (tokenParts.length > 1) { - String lastPart = tokenParts[tokenParts.length-1]; - String firstPart = token.substring(0, token.length()-lastPart.length()-1); - - if (idioms.contains(lastPart)) { - if (idioms.contains(firstPart)) { - // idiom . idiom - return firstPart + SPACED_DOT + lastPart; - } else if (types.contains(firstPart)) { - // type_# . idiom - return getTypeId(firstPart) + SPACED_DOT + lastPart; - } else { - // var_# . idiom - return getVarId(firstPart) + SPACED_DOT + lastPart; - } - } else if (idioms.contains(firstPart)){ - if (types.contains(lastPart)) { - // idiom . type_# - return firstPart + SPACED_DOT + getTypeId(lastPart); - } else { - // idiom . var_# - return firstPart + SPACED_DOT + getVarId(lastPart); - } - } - } - - if (types.contains(token)) { - // type_# - return getTypeId(token); - } - - //Check if it could be a method (the next token is a parenthesis) - boolean couldBeMethod = false; - if (i + 1 < tokens.size()) { - Token t = tokens.get(i + 1); - if (t.getType() == JavaLexer.LPAREN) { - couldBeMethod = true; - } - } - //MethodReference check (Type : : Method) - if (i > 2) { - Token t1 = tokens.get(i - 1); - Token t2 = tokens.get(i - 2); - - if (t1.getType() == JavaLexer.COLON && t2.getType() == JavaLexer.COLON) { - couldBeMethod = true; - } - } - - if (methods.contains(token) && couldBeMethod) { - // method_# - return getMethodId(token); - } - - if (tokenParts.length > 1) { - String lastPart = tokenParts[tokenParts.length - 1]; - String firstPart = token.substring(0, token.length()-lastPart.length() - 1); - - if (methods.contains(lastPart) && couldBeMethod) { - if (idioms.contains(firstPart)) { - // idiom . method_# - return firstPart + SPACED_DOT + getMethodId(lastPart); - } else if (types.contains(firstPart)) { - // type . method_# - return getTypeId(firstPart) + SPACED_DOT + getMethodId(lastPart); - } else { - // var_# . method_# - return getVarId(firstPart) + SPACED_DOT + getMethodId(lastPart); - } - } - } - - if (tokenParts.length > 1) { - String lastPart = tokenParts[tokenParts.length-1]; - String firstPart = token.substring(0, token.length()-lastPart.length() - 1); - - if (varMap.containsKey(lastPart)){ - if (idioms.contains(firstPart)) { - // idiom . var_# - return firstPart + SPACED_DOT + getVarId(lastPart); - } else if (types.contains(firstPart)) { - // type . var_# - return getTypeId(firstPart) + SPACED_DOT + getVarId(lastPart); - } else { - // var_# . var_# - return getVarId(firstPart) + SPACED_DOT + getVarId(lastPart); - } - } - } - - if (tokenParts.length > 1) { - String lastPart = tokenParts[tokenParts.length - 1]; - String firstPart = token.substring(0, token.length()-lastPart.length() - 1); - - if (types.contains(firstPart)){ - if (idioms.contains(lastPart) || lastPart.equals("this") || lastPart.equals("class")) { - // type_# . idiom - return getTypeId(firstPart) + SPACED_DOT + lastPart; - } else { - // type_# . var_# - return getTypeId(firstPart) + SPACED_DOT + getVarId(lastPart); - } - } else if (varMap.containsKey(firstPart)){ - if (idioms.contains(lastPart)) { - // var_# . idiom - return getVarId(firstPart) + SPACED_DOT + lastPart; - } else if (lastPart.equals("new")){ - return getVarId(firstPart) + SPACED_DOT + lastPart; - } else{ - // var_# . var_# - return getVarId(firstPart) + SPACED_DOT + getVarId(lastPart); - } - } - } - - // var_# . var_# - if (tokenParts.length > 1) { - String lastPart = tokenParts[tokenParts.length - 1]; - String firstPart = token.substring(0, token.length()-lastPart.length() - 1); - - if (lastPart.equals("this") || lastPart.equals("class")){ - if (idioms.contains(firstPart)){ - return firstPart + SPACED_DOT + lastPart; - } else { - return getVarId(firstPart) + SPACED_DOT + lastPart; - } - } - - if (idioms.contains(firstPart) && idioms.contains(lastPart)){ - return firstPart + SPACED_DOT + lastPart; - } else if (idioms.contains(firstPart)){ - return firstPart + SPACED_DOT + getVarId(lastPart); - } else if (idioms.contains(lastPart)){ - return getVarId(firstPart) + SPACED_DOT + lastPart; - } - - return getVarId(firstPart) + SPACED_DOT + getVarId(lastPart); - } - - // var_# - return getVarId(token); - } - - //------------------ IDs ---------------------- - - Function getTypeId = _idGetter(typeMap, "TYPE_"); - private String getTypeId(String token) { - return getTypeId.apply(token); - } - - Function getVarId = _idGetter(varMap, "VAR_"); - private String getVarId(String token) { - return getVarId.apply(token); - } - - Function getMethodId = _idGetter(methodMap, "METHOD_"); - private String getMethodId(String token) { - return getMethodId.apply(token); - } - - private Function _idGetter( - Map literals, String prefix - ) { - AtomicInteger counter = new AtomicInteger(); - return (text) -> { - if (literals.containsKey(text)) { - return literals.get(text); - } else { - String id = prefix + counter.incrementAndGet(); - literals.put(text, id); - return id; - } - }; - } - - AtomicInteger annotationsCounter = new AtomicInteger(); - private String getAnnotationID(String token) { - if (idioms.contains("@" + token)) { - return "@" + token; - } else if (annotationMap.containsKey(token)) { - return annotationMap.get(token); - } else { - String id = "ANNOTATION_" + annotationsCounter.incrementAndGet(); - annotationMap.put(token, id); - return id; - } - } - - //------------------ LITERALS ---------------------- - - Function getCharId = _literalIdGetter(charLiterals, "CHAR_"); - private String getCharId(Token token) { - return getCharId.apply(token); - } - - Function getFloatId = _literalIdGetter(floatLiterals, "FLOAT_"); - private String getFloatId(Token token) { - return getFloatId.apply(token); - } - - Function getIntId = _literalIdGetter(intLiterals, "INT_"); - private String getIntId(Token token) { - return getIntId.apply(token); - } - - Function getStringId = _literalIdGetter(stringLiterals, "STRING_"); - private String getStringId(Token token) { - return getStringId.apply(token); - } - - private Function _literalIdGetter( - Map literals, String prefix - ) { - AtomicInteger counter = new AtomicInteger(); - return (token) -> { - String text = token.getText(); - if (idioms.contains(text)) { - return text; - } else if (literals.containsKey(text)) { - return literals.get(text); - } else { - String id = prefix + counter.incrementAndGet(); - literals.put(text, id); - return id; - } - }; - } -} diff --git a/pom.xml b/pom.xml index 87fb0c3a..db998b2b 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,6 @@ dl4se-crawler dl4se-model dl4se-server - dl4se-src2abs dl4se-analyzer From 703a3510fc6f01ef27c168df4f60ca412293c3d5 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 17 Oct 2023 14:17:28 +0200 Subject: [PATCH 0425/1089] Correcting `dl4se-server` containerization --- deployment/server/Dockerfile | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/deployment/server/Dockerfile b/deployment/server/Dockerfile index afcd4ef1..15ed28c0 100644 --- a/deployment/server/Dockerfile +++ b/deployment/server/Dockerfile @@ -6,19 +6,21 @@ COPY ./dl4se-crawler /dl4se-crawler COPY ./dl4se-model /dl4se-model COPY ./dl4se-server /dl4se-server -RUN mvn -e --no-transfer-progress install:install-file \ - -Dfile="./dl4se-src2abs/lib/javalexer.jar" \ - -DgroupId="edu.wm.cs" \ - -DartifactId="javalexer" \ - -Dversion="1" \ - -Dpackaging="jar" - -RUN mvn -e --no-transfer-progress clean package -pl dl4se-server -am -DskipTests +RUN mvn -e \ + --no-transfer-progress \ + clean \ + package \ + -pl dl4se-server \ + -am -DskipTests FROM adoptopenjdk/openjdk11:jre-11.0.11_9-alpine COPY --from=build /dl4se-server/target/dl4se-server-*.jar /server.jar -RUN apk update && apk add git +RUN apk update --quiet && \ + apk add --no-cache \ + --quiet \ + git \ + libstdc++ ENTRYPOINT java -jar server.jar From 2aa51925a1f065b3cc904491785e26fc60489f90 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 17 Oct 2023 14:18:36 +0200 Subject: [PATCH 0426/1089] Using newer images for server build on Docker --- deployment/server/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deployment/server/Dockerfile b/deployment/server/Dockerfile index 15ed28c0..5d1409e6 100644 --- a/deployment/server/Dockerfile +++ b/deployment/server/Dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.8.4-jdk-11-slim AS build +FROM maven:3.9.3-eclipse-temurin-11-alpine AS build COPY ./pom.xml /pom.xml COPY ./dl4se-analyzer /dl4se-analyzer @@ -13,7 +13,7 @@ RUN mvn -e \ -pl dl4se-server \ -am -DskipTests -FROM adoptopenjdk/openjdk11:jre-11.0.11_9-alpine +FROM eclipse-temurin:11.0.20_8-jre-alpine COPY --from=build /dl4se-server/target/dl4se-server-*.jar /server.jar From 89b947756dfd4f82320dd5ac2d04d636c06a7d80 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 17 Oct 2023 14:22:00 +0200 Subject: [PATCH 0427/1089] Removing dependency on JavaParser --- dl4se-server/pom.xml | 5 ----- pom.xml | 1 - 2 files changed, 6 deletions(-) diff --git a/dl4se-server/pom.xml b/dl4se-server/pom.xml index 89dbf18a..ff346089 100644 --- a/dl4se-server/pom.xml +++ b/dl4se-server/pom.xml @@ -44,11 +44,6 @@ encoder 1.2.3 - - com.github.javaparser - javaparser-core - ${javaparser.version} - org.springframework.cloud spring-cloud-starter diff --git a/pom.xml b/pom.xml index db998b2b..ec2792cb 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,6 @@ 1.0.0 UTF-8 5.10.0 - 3.25.5 1.7.0 1.18.30 32.1.2-jre From f559cf299157dde8c1d7e7a66c15b2ab5a2b9bf4 Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 17 Oct 2023 14:55:42 +0200 Subject: [PATCH 0428/1089] Bumping minor version of `jjwt` `0.11.5` -> `0.12.3` --- .../main/java/usi/si/seart/config/JwtConfig.java | 13 ++++++------- .../usi/si/seart/security/jwt/JwtTokenProvider.java | 10 +++++----- pom.xml | 2 +- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/config/JwtConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/JwtConfig.java index 7074d52b..6374f2ff 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/JwtConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/JwtConfig.java @@ -3,7 +3,6 @@ import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.JwtParser; import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.security.Keys; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; @@ -18,24 +17,24 @@ import usi.si.seart.security.jwt.JwtTokenProvider; import usi.si.seart.service.UserService; -import java.security.Key; +import javax.crypto.SecretKey; @Configuration public class JwtConfig { @Bean - public Key secretKey(@Value("${jwt.secret}") String value) { + public SecretKey secretKey(@Value("${jwt.secret}") String value) { return Keys.hmacShaKeyFor(value.getBytes()); } @Bean - public JwtBuilder jwtBuilder(Key secretKey) { - return Jwts.builder().signWith(secretKey, SignatureAlgorithm.HS512); + public JwtBuilder jwtBuilder(SecretKey secretKey) { + return Jwts.builder().signWith(secretKey, Jwts.SIG.HS512); } @Bean - public JwtParser jwtParser(Key secretKey) { - return Jwts.parserBuilder().setSigningKey(secretKey).build(); + public JwtParser jwtParser(SecretKey secretKey) { + return Jwts.parser().verifyWith(secretKey).build(); } @Bean diff --git a/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtTokenProvider.java b/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtTokenProvider.java index 9d0f5e46..7814d828 100644 --- a/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtTokenProvider.java +++ b/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtTokenProvider.java @@ -28,20 +28,20 @@ public String generateToken(Authentication authentication) { Date issue = Date.from(now.toInstant()); Date expiry = Date.from(now.plusDays(7).toInstant()); return jwtBuilder - .setSubject(Long.toString(id)) - .setIssuedAt(issue) - .setExpiration(expiry) + .subject(Long.toString(id)) + .issuedAt(issue) + .expiration(expiry) .compact(); } public Long getUserIdFromJWT(String value) { - Claims claims = jwtParser.parseClaimsJws(value).getBody(); + Claims claims = jwtParser.parseSignedClaims(value).getPayload(); return Long.valueOf(claims.getSubject()); } public boolean validateToken(String token) { try { - jwtParser.parseClaimsJws(token); + jwtParser.parseSignedClaims(token); return true; } catch (RuntimeException ignored) { return false; diff --git a/pom.xml b/pom.xml index ec2792cb..66d632ec 100644 --- a/pom.xml +++ b/pom.xml @@ -40,7 +40,7 @@ 1.43.3 3.1.10 42.6.0 - 0.11.5 + 0.12.3 2.15.2 2.7.16 2021.0.8 From 6c498de0e95f132837e59eccbc36f5d685f73d5a Mon Sep 17 00:00:00 2001 From: dabico Date: Tue, 17 Oct 2023 15:25:25 +0200 Subject: [PATCH 0429/1089] Token validity duration now configurable via `application.properties` --- .../src/main/java/usi/si/seart/config/JwtConfig.java | 7 +++++-- .../usi/si/seart/security/jwt/JwtTokenProvider.java | 12 ++++++++---- .../src/main/resources/application.properties | 1 + 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/config/JwtConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/JwtConfig.java index 6374f2ff..a77b61bf 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/JwtConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/JwtConfig.java @@ -18,6 +18,7 @@ import usi.si.seart.service.UserService; import javax.crypto.SecretKey; +import java.time.Duration; @Configuration public class JwtConfig { @@ -38,8 +39,10 @@ public JwtParser jwtParser(SecretKey secretKey) { } @Bean - public JwtTokenProvider jwtTokenProvider(JwtBuilder builder, JwtParser parser) { - return new JwtTokenProvider(builder, parser); + public JwtTokenProvider jwtTokenProvider( + JwtBuilder builder, JwtParser parser, @Value("${jwt.token.valid-for}") Duration validFor + ) { + return new JwtTokenProvider(builder, parser, validFor); } @Bean diff --git a/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtTokenProvider.java b/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtTokenProvider.java index 7814d828..1e8d7564 100644 --- a/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtTokenProvider.java +++ b/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtTokenProvider.java @@ -9,6 +9,8 @@ import org.springframework.security.core.Authentication; import usi.si.seart.security.UserPrincipal; +import java.time.Duration; +import java.time.Instant; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.util.Date; @@ -21,16 +23,18 @@ public class JwtTokenProvider { JwtBuilder jwtBuilder; JwtParser jwtParser; + Duration validFor; + public String generateToken(Authentication authentication) { UserPrincipal principal = (UserPrincipal) authentication.getPrincipal(); Long id = principal.getId(); ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC); - Date issue = Date.from(now.toInstant()); - Date expiry = Date.from(now.plusDays(7).toInstant()); + Instant issued = now.toInstant(); + Instant expires = now.plus(validFor).toInstant(); return jwtBuilder .subject(Long.toString(id)) - .issuedAt(issue) - .expiration(expiry) + .issuedAt(Date.from(issued)) + .expiration(Date.from(expires)) .compact(); } diff --git a/dl4se-server/src/main/resources/application.properties b/dl4se-server/src/main/resources/application.properties index ef354cff..960f3758 100644 --- a/dl4se-server/src/main/resources/application.properties +++ b/dl4se-server/src/main/resources/application.properties @@ -80,6 +80,7 @@ website.url=${WEBSITE_URL:http://${website.host}:${website.port}} # JWT Configuration jwt.secret=${SERVER_JWT_SECRET} +jwt.token.valid-for=7d scheduling.task.task-cleaner.cron=0 */15 * * * * scheduling.task.repo-maintainer.cron=0 0 0 * * SUN From 44f086371a69cc81007fcee7af5b82c8ae24084d Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 18 Oct 2023 09:12:27 +0200 Subject: [PATCH 0430/1089] Like its `Task` counterpart, `update` in ``UserService` returns entity --- .../src/main/java/usi/si/seart/service/UserService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/service/UserService.java b/dl4se-server/src/main/java/usi/si/seart/service/UserService.java index 71aeae2b..c4f1d0cd 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/UserService.java +++ b/dl4se-server/src/main/java/usi/si/seart/service/UserService.java @@ -18,7 +18,7 @@ public interface UserService { User create(User user); - void update(User user); + User update(User user); Page getAll(Specification specification, Pageable pageable); User getWithId(Long id); User getWithUid(String uid); @@ -40,8 +40,8 @@ public User create(User user) { } @Override - public void update(User user) { - userRepository.save(user); + public User update(User user) { + return userRepository.save(user); } @Override From 8242243fabca95c555af7febc5f3dc1ff14dfcfe Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 18 Oct 2023 10:29:55 +0200 Subject: [PATCH 0431/1089] JwtRequestFilter now takes user enabled status into account --- .../seart/security/jwt/JwtRequestFilter.java | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtRequestFilter.java b/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtRequestFilter.java index 35b3627f..e4e954be 100644 --- a/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtRequestFilter.java +++ b/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtRequestFilter.java @@ -5,7 +5,6 @@ import lombok.experimental.FieldDefaults; import org.springframework.http.HttpHeaders; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.web.authentication.WebAuthenticationDetails; @@ -17,7 +16,6 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; -import java.util.Collection; import java.util.Optional; @AllArgsConstructor(access = AccessLevel.PROTECTED) @@ -33,21 +31,21 @@ protected void doFilterInternal( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain ) throws ServletException, IOException { String token = request.getHeader(HttpHeaders.AUTHORIZATION); - Optional optional = Optional.ofNullable(token) + Optional.ofNullable(token) .filter(value -> value.startsWith("Bearer ")) .map(value -> value.substring(7)) .filter(tokenProvider::validateToken) - .map(tokenProvider::getUserIdFromJWT); - optional.ifPresent(id -> { - UserDetails userDetails = getUserDetails(id); - Collection authorities = userDetails.getAuthorities(); - WebAuthenticationDetails details = new WebAuthenticationDetailsSource().buildDetails(request); - UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( - userDetails, null, authorities - ); - authentication.setDetails(details); - SecurityContextHolder.getContext().setAuthentication(authentication); - }); + .map(tokenProvider::getUserIdFromJWT) + .map(this::getUserDetails) + .filter(UserDetails::isEnabled) + .ifPresent(userDetails -> { + WebAuthenticationDetails details = new WebAuthenticationDetailsSource().buildDetails(request); + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( + userDetails, null, userDetails.getAuthorities() + ); + authentication.setDetails(details); + SecurityContextHolder.getContext().setAuthentication(authentication); + }); filterChain.doFilter(request, response); } } From e1073eafa3eb6f6ffa653ab3f9f1806a17ca41dd Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 18 Oct 2023 10:43:28 +0200 Subject: [PATCH 0432/1089] Added bean definition for `UserDetailsPasswordService` --- .../java/usi/si/seart/config/SecurityConfig.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java index 4272e3d9..0a4eaf26 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java @@ -12,6 +12,7 @@ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsPasswordService; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @@ -108,6 +109,19 @@ public UserDetailsService userDetailsService(UserService userService, Conversion }; } + @Bean + public UserDetailsPasswordService userDetailsPasswordService( + PasswordEncoder passwordEncoder, UserService userService, ConversionService conversionService + ) { + return (userDetails, newPassword) -> { + String email = userDetails.getUsername(); + User user = userService.getWithEmail(email); + user.setPassword(passwordEncoder.encode(newPassword)); + user = userService.update(user); + return conversionService.convert(user, UserPrincipal.class); + }; + } + @Bean public AuthenticationManager authenticationManager( PasswordEncoder passwordEncoder, UserDetailsService userDetailsService From 73fbd35b5d1d063eae74a388736d6d2b602e3dea Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 18 Oct 2023 10:45:19 +0200 Subject: [PATCH 0433/1089] Using existing implementations for Authentication Provider and Manager --- .../usi/si/seart/config/SecurityConfig.java | 40 ++++++++++--------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java index 0a4eaf26..798a7623 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java @@ -4,14 +4,14 @@ import org.springframework.context.annotation.Bean; import org.springframework.core.convert.ConversionService; import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.BadCredentialsException; -import org.springframework.security.authentication.DisabledException; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +import org.springframework.security.config.annotation.ObjectPostProcessor; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsPasswordService; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; @@ -123,20 +123,24 @@ public UserDetailsPasswordService userDetailsPasswordService( } @Bean - public AuthenticationManager authenticationManager( - PasswordEncoder passwordEncoder, UserDetailsService userDetailsService + public AuthenticationProvider authenticationProvider( + PasswordEncoder passwordEncoder, + UserDetailsService userDetailsService, + UserDetailsPasswordService userDetailsPasswordService ) { - return authentication -> { - String username = authentication.getName(); - String password = authentication.getCredentials().toString(); - UserDetails userDetails = userDetailsService.loadUserByUsername(username); - boolean enabled = userDetails.isEnabled(); - if (!enabled) - throw new DisabledException("User is currently disabled!"); - if (passwordEncoder.matches(password, userDetails.getPassword())) - return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); - else - throw new BadCredentialsException("Incorrect password!"); - }; + DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setPasswordEncoder(passwordEncoder); + provider.setUserDetailsService(userDetailsService); + provider.setUserDetailsPasswordService(userDetailsPasswordService); + return provider; + } + + @Bean + public AuthenticationManager authenticationManager( + ObjectPostProcessor objectPostProcessor, AuthenticationProvider authenticationProvider + ) throws Exception { + return new AuthenticationManagerBuilder(objectPostProcessor) + .authenticationProvider(authenticationProvider) + .build(); } } From a140bb3c5acd67519e845b2c8b5752c8d572fa6c Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 18 Oct 2023 11:15:44 +0200 Subject: [PATCH 0434/1089] Deleting run config that's not used all that much --- .../DL4SEApplication__debug_.xml | 44 ------------------- 1 file changed, 44 deletions(-) delete mode 100644 .idea/runConfigurations/DL4SEApplication__debug_.xml diff --git a/.idea/runConfigurations/DL4SEApplication__debug_.xml b/.idea/runConfigurations/DL4SEApplication__debug_.xml deleted file mode 100644 index 2383d796..00000000 --- a/.idea/runConfigurations/DL4SEApplication__debug_.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - \ No newline at end of file From 6244f6caa712c2b738e3c13745391460990e78aa Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 18 Oct 2023 11:20:43 +0200 Subject: [PATCH 0435/1089] Updating server main class name --- dl4se-server/pom.xml | 2 +- .../usi/si/seart/{DL4SEApplication.java => Application.java} | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename dl4se-server/src/main/java/usi/si/seart/{DL4SEApplication.java => Application.java} (70%) diff --git a/dl4se-server/pom.xml b/dl4se-server/pom.xml index ff346089..597fa859 100644 --- a/dl4se-server/pom.xml +++ b/dl4se-server/pom.xml @@ -102,7 +102,7 @@ spring-boot-maven-plugin ${springframework.version} - usi.si.seart.DL4SEApplication + usi.si.seart.Application diff --git a/dl4se-server/src/main/java/usi/si/seart/DL4SEApplication.java b/dl4se-server/src/main/java/usi/si/seart/Application.java similarity index 70% rename from dl4se-server/src/main/java/usi/si/seart/DL4SEApplication.java rename to dl4se-server/src/main/java/usi/si/seart/Application.java index 46df6c21..48e8f4d3 100644 --- a/dl4se-server/src/main/java/usi/si/seart/DL4SEApplication.java +++ b/dl4se-server/src/main/java/usi/si/seart/Application.java @@ -4,9 +4,9 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication -public class DL4SEApplication { +public class Application { public static void main(String[] args) { - SpringApplication.run(DL4SEApplication.class, args); + SpringApplication.run(Application.class, args); } } From fc9ef5131277fb514ad77809085d5c4156aff17c Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 18 Oct 2023 11:21:59 +0200 Subject: [PATCH 0436/1089] Deleting old run config --- .idea/runConfigurations/DL4SEApplication.xml | 26 -------------------- 1 file changed, 26 deletions(-) delete mode 100644 .idea/runConfigurations/DL4SEApplication.xml diff --git a/.idea/runConfigurations/DL4SEApplication.xml b/.idea/runConfigurations/DL4SEApplication.xml deleted file mode 100644 index 9566123e..00000000 --- a/.idea/runConfigurations/DL4SEApplication.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - \ No newline at end of file From 56361513590cc62a97d94f01ba535846eee58c85 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 18 Oct 2023 11:37:16 +0200 Subject: [PATCH 0437/1089] Added configuration for manual JPA entity scanning --- .../src/main/java/usi/si/seart/config/JpaConfig.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 dl4se-server/src/main/java/usi/si/seart/config/JpaConfig.java diff --git a/dl4se-server/src/main/java/usi/si/seart/config/JpaConfig.java b/dl4se-server/src/main/java/usi/si/seart/config/JpaConfig.java new file mode 100644 index 00000000..f7ef3eac --- /dev/null +++ b/dl4se-server/src/main/java/usi/si/seart/config/JpaConfig.java @@ -0,0 +1,12 @@ +package usi.si.seart.config; + +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EntityScan(basePackages = { + "usi.si.seart.model", + "usi.si.seart.views", +}) +public class JpaConfig { +} From f5b383461a548c5300d2ab2ddecad960c3078f04 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 18 Oct 2023 11:49:18 +0200 Subject: [PATCH 0438/1089] Removing dead code from `Boilerplate` --- .../java/usi/si/seart/model/code/Boilerplate.java | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/dl4se-model/src/main/java/usi/si/seart/model/code/Boilerplate.java b/dl4se-model/src/main/java/usi/si/seart/model/code/Boilerplate.java index 92219773..bdf37ae3 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/code/Boilerplate.java +++ b/dl4se-model/src/main/java/usi/si/seart/model/code/Boilerplate.java @@ -1,7 +1,5 @@ package usi.si.seart.model.code; -import java.util.Optional; - /** * @see Comparable#compareTo(Object) * @see Object#clone() @@ -127,13 +125,5 @@ public enum Boilerplate { /** * Methods that reverse serialization. */ - DESERIALIZER,; - - public static Boilerplate valueOfNullable(Object value) { - return Optional.ofNullable(value) - .filter(String.class::isInstance) - .map(String.class::cast) - .map(Boilerplate::valueOf) - .orElse(null); - } -} \ No newline at end of file + DESERIALIZER +} From e3e033a60ba6b962395aa341dd9d0a605d3f4cff Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 18 Oct 2023 12:00:56 +0200 Subject: [PATCH 0439/1089] Relocation of server classes to a dedicated subpackage --- dl4se-server/pom.xml | 2 +- .../si/seart/{ => server}/Application.java | 2 +- .../bean/ConfigurationInitializingBean.java | 4 ++-- .../bean/DirectoryInitializationBean.java | 2 +- .../bean/TaskRunnerRecoveryBean.java | 6 ++--- .../seart/{ => server}/config/JpaConfig.java | 2 +- .../seart/{ => server}/config/JwtConfig.java | 12 +++++----- .../seart/{ => server}/config/MainConfig.java | 4 ++-- .../{ => server}/config/SchedulerConfig.java | 20 ++++++++--------- .../{ => server}/config/SecurityConfig.java | 10 ++++----- .../seart/{ => server}/config/WebConfig.java | 12 +++++----- .../context/ConfigurationEnvironment.java} | 4 ++-- .../controller/AdminController.java | 16 +++++++------- .../ExceptionHandlerController.java | 6 ++--- .../controller/LanguageController.java | 4 ++-- .../controller/RootController.java | 2 +- .../controller/StatisticsController.java | 8 +++---- .../controller/TaskController.java | 18 +++++++-------- .../controller/UserController.java | 22 +++++++++---------- .../DtoToConfigurationConverter.java | 4 ++-- .../converter/DtoToUserConverter.java | 4 ++-- ...TaskSearchDtoToSpecificationConverter.java | 4 ++-- .../TaskToCodeSpecificationConverter.java | 2 +- ...UserSearchDtoToSpecificationConverter.java | 4 ++-- .../UserToUserPrincipalConverter.java | 4 ++-- .../{ => server}/dto/ConfigurationDto.java | 2 +- .../si/seart/{ => server}/dto/LoginDto.java | 2 +- .../seart/{ => server}/dto/RegisterDto.java | 2 +- .../seart/{ => server}/dto/task/TaskDto.java | 2 +- .../{ => server}/dto/task/TaskSearchDto.java | 2 +- .../seart/{ => server}/dto/user/EmailDto.java | 2 +- .../{ => server}/dto/user/PasswordDto.java | 2 +- .../{ => server}/dto/user/UserSearchDto.java | 2 +- .../ConfigurationNotFoundException.java | 2 +- .../exception/EntityNotFoundException.java | 2 +- .../exception/LanguageNotFoundException.java | 2 +- .../exception/TaskFailedException.java | 2 +- .../exception/TaskNotFoundException.java | 2 +- .../exception/TokenExpiredException.java | 2 +- .../exception/TokenNotFoundException.java | 2 +- .../exception/UserNotFoundException.java | 2 +- .../{ => server}/jackson/PageSerializer.java | 2 +- .../jackson/PaginationModule.java | 2 +- .../{ => server}/jackson/SortSerializer.java | 2 +- .../repository/CodeRepository.java | 4 ++-- .../repository/ConfigurationRepository.java | 2 +- .../repository/FileRepository.java | 2 +- .../repository/FunctionRepository.java | 2 +- .../repository/GitRepoRepository.java | 2 +- .../repository/LanguageRepository.java | 2 +- .../repository/TableRowCountRepository.java | 2 +- .../repository/TaskRepository.java | 2 +- .../repository/TokenRepository.java | 2 +- .../repository/UserRepository.java | 2 +- .../JpaStreamableSpecificationRepository.java | 2 +- ...StreamableSpecificationRepositoryImpl.java | 2 +- .../scheduling/RepoMaintainer.java | 4 ++-- .../{ => server}/scheduling/TaskCleaner.java | 6 ++--- .../{ => server}/scheduling/TaskRunner.java | 12 +++++----- .../scheduling/ViewMaintainer.java | 4 ++-- .../{ => server}/security/UserPrincipal.java | 2 +- .../annotation/AdminRestController.java | 2 +- .../security/jwt/JwtRequestFilter.java | 2 +- .../security/jwt/JwtTokenProvider.java | 4 ++-- .../{ => server}/service/CodeService.java | 4 ++-- .../service/ConfigurationService.java | 4 ++-- .../{ => server}/service/DatabaseService.java | 2 +- .../{ => server}/service/DownloadService.java | 8 +++---- .../{ => server}/service/EmailService.java | 4 ++-- .../service/FileSystemService.java | 2 +- .../{ => server}/service/GitRepoService.java | 4 ++-- .../{ => server}/service/LanguageService.java | 6 ++--- .../service/PasswordResetService.java | 10 ++++----- .../service/StatisticsService.java | 14 ++++++------ .../{ => server}/service/TaskService.java | 8 +++---- .../{ => server}/service/UserService.java | 6 ++--- .../service/VerificationService.java | 10 ++++----- .../util/unit/ReadableFileSize.java | 2 +- 78 files changed, 181 insertions(+), 181 deletions(-) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/Application.java (90%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/bean/ConfigurationInitializingBean.java (94%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/bean/DirectoryInitializationBean.java (96%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/bean/TaskRunnerRecoveryBean.java (86%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/config/JpaConfig.java (87%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/config/JwtConfig.java (86%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/config/MainConfig.java (91%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/config/SchedulerConfig.java (90%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/config/SecurityConfig.java (95%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/config/WebConfig.java (75%) rename dl4se-server/src/main/java/usi/si/seart/{context/DL4SEEnvironment.java => server/context/ConfigurationEnvironment.java} (90%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/controller/AdminController.java (91%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/controller/ExceptionHandlerController.java (94%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/controller/LanguageController.java (91%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/controller/RootController.java (89%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/controller/StatisticsController.java (95%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/controller/TaskController.java (94%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/controller/UserController.java (91%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/converter/DtoToConfigurationConverter.java (84%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/converter/DtoToUserConverter.java (85%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/converter/TaskSearchDtoToSpecificationConverter.java (91%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/converter/TaskToCodeSpecificationConverter.java (99%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/converter/UserSearchDtoToSpecificationConverter.java (94%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/converter/UserToUserPrincipalConverter.java (87%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/dto/ConfigurationDto.java (93%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/dto/LoginDto.java (93%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/dto/RegisterDto.java (95%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/dto/task/TaskDto.java (95%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/dto/task/TaskSearchDto.java (94%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/dto/user/EmailDto.java (91%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/dto/user/PasswordDto.java (91%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/dto/user/UserSearchDto.java (96%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/exception/ConfigurationNotFoundException.java (89%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/exception/EntityNotFoundException.java (94%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/exception/LanguageNotFoundException.java (88%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/exception/TaskFailedException.java (95%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/exception/TaskNotFoundException.java (88%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/exception/TokenExpiredException.java (88%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/exception/TokenNotFoundException.java (88%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/exception/UserNotFoundException.java (88%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/jackson/PageSerializer.java (97%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/jackson/PaginationModule.java (89%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/jackson/SortSerializer.java (96%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/repository/CodeRepository.java (79%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/repository/ConfigurationRepository.java (82%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/repository/FileRepository.java (91%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/repository/FunctionRepository.java (91%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/repository/GitRepoRepository.java (92%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/repository/LanguageRepository.java (86%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/repository/TableRowCountRepository.java (82%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/repository/TaskRepository.java (98%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/repository/TokenRepository.java (89%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/repository/UserRepository.java (92%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/repository/specification/JpaStreamableSpecificationRepository.java (87%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/repository/specification/JpaStreamableSpecificationRepositoryImpl.java (97%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/scheduling/RepoMaintainer.java (95%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/scheduling/TaskCleaner.java (86%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/scheduling/TaskRunner.java (96%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/scheduling/ViewMaintainer.java (87%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/security/UserPrincipal.java (97%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/security/annotation/AdminRestController.java (89%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/security/jwt/JwtRequestFilter.java (98%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/security/jwt/JwtTokenProvider.java (94%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/service/CodeService.java (92%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/service/ConfigurationService.java (97%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/service/DatabaseService.java (98%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/service/DownloadService.java (88%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/service/EmailService.java (97%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/service/FileSystemService.java (98%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/service/GitRepoService.java (91%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/service/LanguageService.java (86%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/service/PasswordResetService.java (90%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/service/StatisticsService.java (92%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/service/TaskService.java (96%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/service/UserService.java (93%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/service/VerificationService.java (88%) rename dl4se-server/src/main/java/usi/si/seart/{ => server}/util/unit/ReadableFileSize.java (96%) diff --git a/dl4se-server/pom.xml b/dl4se-server/pom.xml index 597fa859..6af7bb29 100644 --- a/dl4se-server/pom.xml +++ b/dl4se-server/pom.xml @@ -102,7 +102,7 @@ spring-boot-maven-plugin ${springframework.version} - usi.si.seart.Application + usi.si.seart.server.Application diff --git a/dl4se-server/src/main/java/usi/si/seart/Application.java b/dl4se-server/src/main/java/usi/si/seart/server/Application.java similarity index 90% rename from dl4se-server/src/main/java/usi/si/seart/Application.java rename to dl4se-server/src/main/java/usi/si/seart/server/Application.java index 48e8f4d3..346043c1 100644 --- a/dl4se-server/src/main/java/usi/si/seart/Application.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/Application.java @@ -1,4 +1,4 @@ -package usi.si.seart; +package usi.si.seart.server; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/dl4se-server/src/main/java/usi/si/seart/bean/ConfigurationInitializingBean.java b/dl4se-server/src/main/java/usi/si/seart/server/bean/ConfigurationInitializingBean.java similarity index 94% rename from dl4se-server/src/main/java/usi/si/seart/bean/ConfigurationInitializingBean.java rename to dl4se-server/src/main/java/usi/si/seart/server/bean/ConfigurationInitializingBean.java index 3c2fc110..ace17e9b 100644 --- a/dl4se-server/src/main/java/usi/si/seart/bean/ConfigurationInitializingBean.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/bean/ConfigurationInitializingBean.java @@ -1,4 +1,4 @@ -package usi.si.seart.bean; +package usi.si.seart.server.bean; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -10,7 +10,7 @@ import org.springframework.core.io.support.PropertiesLoaderUtils; import org.springframework.stereotype.Component; import usi.si.seart.model.Configuration; -import usi.si.seart.repository.ConfigurationRepository; +import usi.si.seart.server.repository.ConfigurationRepository; import java.util.Map; import java.util.Properties; diff --git a/dl4se-server/src/main/java/usi/si/seart/bean/DirectoryInitializationBean.java b/dl4se-server/src/main/java/usi/si/seart/server/bean/DirectoryInitializationBean.java similarity index 96% rename from dl4se-server/src/main/java/usi/si/seart/bean/DirectoryInitializationBean.java rename to dl4se-server/src/main/java/usi/si/seart/server/bean/DirectoryInitializationBean.java index 4be5dd79..b2bbf2b5 100644 --- a/dl4se-server/src/main/java/usi/si/seart/bean/DirectoryInitializationBean.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/bean/DirectoryInitializationBean.java @@ -1,4 +1,4 @@ -package usi.si.seart.bean; +package usi.si.seart.server.bean; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; diff --git a/dl4se-server/src/main/java/usi/si/seart/bean/TaskRunnerRecoveryBean.java b/dl4se-server/src/main/java/usi/si/seart/server/bean/TaskRunnerRecoveryBean.java similarity index 86% rename from dl4se-server/src/main/java/usi/si/seart/bean/TaskRunnerRecoveryBean.java rename to dl4se-server/src/main/java/usi/si/seart/server/bean/TaskRunnerRecoveryBean.java index 63f4737f..4ce79bb0 100644 --- a/dl4se-server/src/main/java/usi/si/seart/bean/TaskRunnerRecoveryBean.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/bean/TaskRunnerRecoveryBean.java @@ -1,4 +1,4 @@ -package usi.si.seart.bean; +package usi.si.seart.server.bean; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -6,8 +6,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import usi.si.seart.model.task.Status; -import usi.si.seart.service.StatisticsService; -import usi.si.seart.service.TaskService; +import usi.si.seart.server.service.StatisticsService; +import usi.si.seart.server.service.TaskService; @Slf4j @Component("TaskRunnerRecoveryBean") diff --git a/dl4se-server/src/main/java/usi/si/seart/config/JpaConfig.java b/dl4se-server/src/main/java/usi/si/seart/server/config/JpaConfig.java similarity index 87% rename from dl4se-server/src/main/java/usi/si/seart/config/JpaConfig.java rename to dl4se-server/src/main/java/usi/si/seart/server/config/JpaConfig.java index f7ef3eac..ec580890 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/JpaConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/config/JpaConfig.java @@ -1,4 +1,4 @@ -package usi.si.seart.config; +package usi.si.seart.server.config; import org.springframework.boot.autoconfigure.domain.EntityScan; import org.springframework.context.annotation.Configuration; diff --git a/dl4se-server/src/main/java/usi/si/seart/config/JwtConfig.java b/dl4se-server/src/main/java/usi/si/seart/server/config/JwtConfig.java similarity index 86% rename from dl4se-server/src/main/java/usi/si/seart/config/JwtConfig.java rename to dl4se-server/src/main/java/usi/si/seart/server/config/JwtConfig.java index a77b61bf..5c525906 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/JwtConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/config/JwtConfig.java @@ -1,4 +1,4 @@ -package usi.si.seart.config; +package usi.si.seart.server.config; import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.JwtParser; @@ -10,12 +10,12 @@ import org.springframework.core.convert.ConversionService; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; -import usi.si.seart.exception.UserNotFoundException; import usi.si.seart.model.user.User; -import usi.si.seart.security.UserPrincipal; -import usi.si.seart.security.jwt.JwtRequestFilter; -import usi.si.seart.security.jwt.JwtTokenProvider; -import usi.si.seart.service.UserService; +import usi.si.seart.server.exception.UserNotFoundException; +import usi.si.seart.server.security.UserPrincipal; +import usi.si.seart.server.security.jwt.JwtRequestFilter; +import usi.si.seart.server.security.jwt.JwtTokenProvider; +import usi.si.seart.server.service.UserService; import javax.crypto.SecretKey; import java.time.Duration; diff --git a/dl4se-server/src/main/java/usi/si/seart/config/MainConfig.java b/dl4se-server/src/main/java/usi/si/seart/server/config/MainConfig.java similarity index 91% rename from dl4se-server/src/main/java/usi/si/seart/config/MainConfig.java rename to dl4se-server/src/main/java/usi/si/seart/server/config/MainConfig.java index e235752f..ea30328c 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/MainConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/config/MainConfig.java @@ -1,11 +1,11 @@ -package usi.si.seart.config; +package usi.si.seart.server.config; import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import usi.si.seart.jackson.PaginationModule; +import usi.si.seart.server.jackson.PaginationModule; import java.nio.file.Path; import java.text.DateFormat; diff --git a/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java b/dl4se-server/src/main/java/usi/si/seart/server/config/SchedulerConfig.java similarity index 90% rename from dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java rename to dl4se-server/src/main/java/usi/si/seart/server/config/SchedulerConfig.java index 4f4cee7d..5dee8fd5 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/SchedulerConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/config/SchedulerConfig.java @@ -1,4 +1,4 @@ -package usi.si.seart.config; +package usi.si.seart.server.config; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -13,16 +13,16 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.scheduling.support.CronTrigger; import org.springframework.util.ErrorHandler; -import usi.si.seart.exception.TaskFailedException; import usi.si.seart.model.task.Task; -import usi.si.seart.scheduling.RepoMaintainer; -import usi.si.seart.scheduling.TaskCleaner; -import usi.si.seart.scheduling.TaskRunner; -import usi.si.seart.scheduling.ViewMaintainer; -import usi.si.seart.service.ConfigurationService; -import usi.si.seart.service.EmailService; -import usi.si.seart.service.FileSystemService; -import usi.si.seart.service.TaskService; +import usi.si.seart.server.exception.TaskFailedException; +import usi.si.seart.server.scheduling.RepoMaintainer; +import usi.si.seart.server.scheduling.TaskCleaner; +import usi.si.seart.server.scheduling.TaskRunner; +import usi.si.seart.server.scheduling.ViewMaintainer; +import usi.si.seart.server.service.ConfigurationService; +import usi.si.seart.server.service.EmailService; +import usi.si.seart.server.service.FileSystemService; +import usi.si.seart.server.service.TaskService; import java.time.Clock; import java.util.HashSet; diff --git a/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java b/dl4se-server/src/main/java/usi/si/seart/server/config/SecurityConfig.java similarity index 95% rename from dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java rename to dl4se-server/src/main/java/usi/si/seart/server/config/SecurityConfig.java index 798a7623..9ff14144 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/SecurityConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/config/SecurityConfig.java @@ -1,4 +1,4 @@ -package usi.si.seart.config; +package usi.si.seart.server.config; import org.owasp.encoder.Encode; import org.springframework.context.annotation.Bean; @@ -20,11 +20,11 @@ import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -import usi.si.seart.exception.UserNotFoundException; import usi.si.seart.model.user.User; -import usi.si.seart.security.UserPrincipal; -import usi.si.seart.security.jwt.JwtRequestFilter; -import usi.si.seart.service.UserService; +import usi.si.seart.server.exception.UserNotFoundException; +import usi.si.seart.server.security.UserPrincipal; +import usi.si.seart.server.security.jwt.JwtRequestFilter; +import usi.si.seart.server.service.UserService; import javax.servlet.http.HttpServletResponse; diff --git a/dl4se-server/src/main/java/usi/si/seart/config/WebConfig.java b/dl4se-server/src/main/java/usi/si/seart/server/config/WebConfig.java similarity index 75% rename from dl4se-server/src/main/java/usi/si/seart/config/WebConfig.java rename to dl4se-server/src/main/java/usi/si/seart/server/config/WebConfig.java index 7217c291..1c160651 100644 --- a/dl4se-server/src/main/java/usi/si/seart/config/WebConfig.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/config/WebConfig.java @@ -1,15 +1,15 @@ -package usi.si.seart.config; +package usi.si.seart.server.config; import org.springframework.context.annotation.Configuration; import org.springframework.data.web.config.EnableSpringDataWebSupport; import org.springframework.format.FormatterRegistry; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import usi.si.seart.converter.DtoToConfigurationConverter; -import usi.si.seart.converter.DtoToUserConverter; -import usi.si.seart.converter.TaskSearchDtoToSpecificationConverter; -import usi.si.seart.converter.UserSearchDtoToSpecificationConverter; -import usi.si.seart.converter.UserToUserPrincipalConverter; +import usi.si.seart.server.converter.DtoToConfigurationConverter; +import usi.si.seart.server.converter.DtoToUserConverter; +import usi.si.seart.server.converter.TaskSearchDtoToSpecificationConverter; +import usi.si.seart.server.converter.UserSearchDtoToSpecificationConverter; +import usi.si.seart.server.converter.UserToUserPrincipalConverter; @Configuration @EnableSpringDataWebSupport diff --git a/dl4se-server/src/main/java/usi/si/seart/context/DL4SEEnvironment.java b/dl4se-server/src/main/java/usi/si/seart/server/context/ConfigurationEnvironment.java similarity index 90% rename from dl4se-server/src/main/java/usi/si/seart/context/DL4SEEnvironment.java rename to dl4se-server/src/main/java/usi/si/seart/server/context/ConfigurationEnvironment.java index 2a87099d..890927fe 100644 --- a/dl4se-server/src/main/java/usi/si/seart/context/DL4SEEnvironment.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/context/ConfigurationEnvironment.java @@ -1,4 +1,4 @@ -package usi.si.seart.context; +package usi.si.seart.server.context; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -8,7 +8,7 @@ import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; -import usi.si.seart.service.ConfigurationService; +import usi.si.seart.server.service.ConfigurationService; @Component @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) diff --git a/dl4se-server/src/main/java/usi/si/seart/controller/AdminController.java b/dl4se-server/src/main/java/usi/si/seart/server/controller/AdminController.java similarity index 91% rename from dl4se-server/src/main/java/usi/si/seart/controller/AdminController.java rename to dl4se-server/src/main/java/usi/si/seart/server/controller/AdminController.java index ca3b6760..d4099bbc 100644 --- a/dl4se-server/src/main/java/usi/si/seart/controller/AdminController.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/controller/AdminController.java @@ -1,4 +1,4 @@ -package usi.si.seart.controller; +package usi.si.seart.server.controller; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -16,9 +16,6 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; -import usi.si.seart.dto.task.TaskSearchDto; -import usi.si.seart.dto.user.UserSearchDto; -import usi.si.seart.exception.ConfigurationNotFoundException; import usi.si.seart.model.Configuration; import usi.si.seart.model.Configuration_; import usi.si.seart.model.task.Task; @@ -26,10 +23,13 @@ import usi.si.seart.model.user.Role; import usi.si.seart.model.user.User; import usi.si.seart.model.user.User_; -import usi.si.seart.security.annotation.AdminRestController; -import usi.si.seart.service.ConfigurationService; -import usi.si.seart.service.TaskService; -import usi.si.seart.service.UserService; +import usi.si.seart.server.dto.task.TaskSearchDto; +import usi.si.seart.server.dto.user.UserSearchDto; +import usi.si.seart.server.exception.ConfigurationNotFoundException; +import usi.si.seart.server.security.annotation.AdminRestController; +import usi.si.seart.server.service.ConfigurationService; +import usi.si.seart.server.service.TaskService; +import usi.si.seart.server.service.UserService; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; diff --git a/dl4se-server/src/main/java/usi/si/seart/controller/ExceptionHandlerController.java b/dl4se-server/src/main/java/usi/si/seart/server/controller/ExceptionHandlerController.java similarity index 94% rename from dl4se-server/src/main/java/usi/si/seart/controller/ExceptionHandlerController.java rename to dl4se-server/src/main/java/usi/si/seart/server/controller/ExceptionHandlerController.java index 86cf647f..c1e4c88d 100644 --- a/dl4se-server/src/main/java/usi/si/seart/controller/ExceptionHandlerController.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/controller/ExceptionHandlerController.java @@ -1,4 +1,4 @@ -package usi.si.seart.controller; +package usi.si.seart.server.controller; import lombok.extern.slf4j.Slf4j; import org.hibernate.exception.ConstraintViolationException; @@ -11,8 +11,8 @@ import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; -import usi.si.seart.exception.EntityNotFoundException; -import usi.si.seart.exception.TokenExpiredException; +import usi.si.seart.server.exception.EntityNotFoundException; +import usi.si.seart.server.exception.TokenExpiredException; import java.io.FileNotFoundException; diff --git a/dl4se-server/src/main/java/usi/si/seart/controller/LanguageController.java b/dl4se-server/src/main/java/usi/si/seart/server/controller/LanguageController.java similarity index 91% rename from dl4se-server/src/main/java/usi/si/seart/controller/LanguageController.java rename to dl4se-server/src/main/java/usi/si/seart/server/controller/LanguageController.java index a9b6c303..5289d710 100644 --- a/dl4se-server/src/main/java/usi/si/seart/controller/LanguageController.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/controller/LanguageController.java @@ -1,4 +1,4 @@ -package usi.si.seart.controller; +package usi.si.seart.server.controller; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -9,7 +9,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import usi.si.seart.model.Language; -import usi.si.seart.service.LanguageService; +import usi.si.seart.server.service.LanguageService; import java.util.List; import java.util.stream.Collectors; diff --git a/dl4se-server/src/main/java/usi/si/seart/controller/RootController.java b/dl4se-server/src/main/java/usi/si/seart/server/controller/RootController.java similarity index 89% rename from dl4se-server/src/main/java/usi/si/seart/controller/RootController.java rename to dl4se-server/src/main/java/usi/si/seart/server/controller/RootController.java index 7301be20..45b69dbb 100644 --- a/dl4se-server/src/main/java/usi/si/seart/controller/RootController.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/controller/RootController.java @@ -1,4 +1,4 @@ -package usi.si.seart.controller; +package usi.si.seart.server.controller; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; diff --git a/dl4se-server/src/main/java/usi/si/seart/controller/StatisticsController.java b/dl4se-server/src/main/java/usi/si/seart/server/controller/StatisticsController.java similarity index 95% rename from dl4se-server/src/main/java/usi/si/seart/controller/StatisticsController.java rename to dl4se-server/src/main/java/usi/si/seart/server/controller/StatisticsController.java index ec903cc0..badae016 100644 --- a/dl4se-server/src/main/java/usi/si/seart/controller/StatisticsController.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/controller/StatisticsController.java @@ -1,4 +1,4 @@ -package usi.si.seart.controller; +package usi.si.seart.server.controller; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -11,9 +11,9 @@ import org.springframework.web.bind.annotation.RestController; import usi.si.seart.model.Language; import usi.si.seart.model.user.User; -import usi.si.seart.security.UserPrincipal; -import usi.si.seart.service.StatisticsService; -import usi.si.seart.service.UserService; +import usi.si.seart.server.security.UserPrincipal; +import usi.si.seart.server.service.StatisticsService; +import usi.si.seart.server.service.UserService; import java.util.Map; import java.util.TreeMap; diff --git a/dl4se-server/src/main/java/usi/si/seart/controller/TaskController.java b/dl4se-server/src/main/java/usi/si/seart/server/controller/TaskController.java similarity index 94% rename from dl4se-server/src/main/java/usi/si/seart/controller/TaskController.java rename to dl4se-server/src/main/java/usi/si/seart/server/controller/TaskController.java index 979d1c32..96a10113 100644 --- a/dl4se-server/src/main/java/usi/si/seart/controller/TaskController.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/controller/TaskController.java @@ -1,4 +1,4 @@ -package usi.si.seart.controller; +package usi.si.seart.server.controller; import com.fasterxml.jackson.databind.JsonNode; import lombok.AccessLevel; @@ -26,8 +26,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import usi.si.seart.dto.task.TaskDto; -import usi.si.seart.dto.task.TaskSearchDto; import usi.si.seart.model.job.Job; import usi.si.seart.model.task.Status; import usi.si.seart.model.task.Task; @@ -36,12 +34,14 @@ import usi.si.seart.model.user.User; import usi.si.seart.model.user.User_; import usi.si.seart.model.user.token.Token; -import usi.si.seart.security.UserPrincipal; -import usi.si.seart.service.ConfigurationService; -import usi.si.seart.service.DownloadService; -import usi.si.seart.service.FileSystemService; -import usi.si.seart.service.TaskService; -import usi.si.seart.service.UserService; +import usi.si.seart.server.dto.task.TaskDto; +import usi.si.seart.server.dto.task.TaskSearchDto; +import usi.si.seart.server.security.UserPrincipal; +import usi.si.seart.server.service.ConfigurationService; +import usi.si.seart.server.service.DownloadService; +import usi.si.seart.server.service.FileSystemService; +import usi.si.seart.server.service.TaskService; +import usi.si.seart.server.service.UserService; import javax.validation.Valid; import javax.validation.constraints.NotBlank; diff --git a/dl4se-server/src/main/java/usi/si/seart/controller/UserController.java b/dl4se-server/src/main/java/usi/si/seart/server/controller/UserController.java similarity index 91% rename from dl4se-server/src/main/java/usi/si/seart/controller/UserController.java rename to dl4se-server/src/main/java/usi/si/seart/server/controller/UserController.java index a6ce20c4..cb935e67 100644 --- a/dl4se-server/src/main/java/usi/si/seart/controller/UserController.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/controller/UserController.java @@ -1,4 +1,4 @@ -package usi.si.seart.controller; +package usi.si.seart.server.controller; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; @@ -25,18 +25,18 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.util.UriComponentsBuilder; -import usi.si.seart.dto.LoginDto; -import usi.si.seart.dto.RegisterDto; -import usi.si.seart.dto.user.EmailDto; -import usi.si.seart.dto.user.PasswordDto; import usi.si.seart.model.user.User; import usi.si.seart.model.user.token.Token; -import usi.si.seart.security.UserPrincipal; -import usi.si.seart.security.jwt.JwtTokenProvider; -import usi.si.seart.service.EmailService; -import usi.si.seart.service.PasswordResetService; -import usi.si.seart.service.UserService; -import usi.si.seart.service.VerificationService; +import usi.si.seart.server.dto.LoginDto; +import usi.si.seart.server.dto.RegisterDto; +import usi.si.seart.server.dto.user.EmailDto; +import usi.si.seart.server.dto.user.PasswordDto; +import usi.si.seart.server.security.UserPrincipal; +import usi.si.seart.server.security.jwt.JwtTokenProvider; +import usi.si.seart.server.service.EmailService; +import usi.si.seart.server.service.PasswordResetService; +import usi.si.seart.server.service.UserService; +import usi.si.seart.server.service.VerificationService; import javax.validation.Valid; import javax.validation.constraints.NotBlank; diff --git a/dl4se-server/src/main/java/usi/si/seart/converter/DtoToConfigurationConverter.java b/dl4se-server/src/main/java/usi/si/seart/server/converter/DtoToConfigurationConverter.java similarity index 84% rename from dl4se-server/src/main/java/usi/si/seart/converter/DtoToConfigurationConverter.java rename to dl4se-server/src/main/java/usi/si/seart/server/converter/DtoToConfigurationConverter.java index f53558f2..e92bb84c 100644 --- a/dl4se-server/src/main/java/usi/si/seart/converter/DtoToConfigurationConverter.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/converter/DtoToConfigurationConverter.java @@ -1,9 +1,9 @@ -package usi.si.seart.converter; +package usi.si.seart.server.converter; import org.springframework.core.convert.converter.Converter; import org.springframework.lang.NonNull; -import usi.si.seart.dto.ConfigurationDto; import usi.si.seart.model.Configuration; +import usi.si.seart.server.dto.ConfigurationDto; public class DtoToConfigurationConverter implements Converter { diff --git a/dl4se-server/src/main/java/usi/si/seart/converter/DtoToUserConverter.java b/dl4se-server/src/main/java/usi/si/seart/server/converter/DtoToUserConverter.java similarity index 85% rename from dl4se-server/src/main/java/usi/si/seart/converter/DtoToUserConverter.java rename to dl4se-server/src/main/java/usi/si/seart/server/converter/DtoToUserConverter.java index dddddac8..23a1951f 100644 --- a/dl4se-server/src/main/java/usi/si/seart/converter/DtoToUserConverter.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/converter/DtoToUserConverter.java @@ -1,9 +1,9 @@ -package usi.si.seart.converter; +package usi.si.seart.server.converter; import org.springframework.core.convert.converter.Converter; import org.springframework.lang.NonNull; -import usi.si.seart.dto.RegisterDto; import usi.si.seart.model.user.User; +import usi.si.seart.server.dto.RegisterDto; public class DtoToUserConverter implements Converter { diff --git a/dl4se-server/src/main/java/usi/si/seart/converter/TaskSearchDtoToSpecificationConverter.java b/dl4se-server/src/main/java/usi/si/seart/server/converter/TaskSearchDtoToSpecificationConverter.java similarity index 91% rename from dl4se-server/src/main/java/usi/si/seart/converter/TaskSearchDtoToSpecificationConverter.java rename to dl4se-server/src/main/java/usi/si/seart/server/converter/TaskSearchDtoToSpecificationConverter.java index 87f52edb..25695b9c 100644 --- a/dl4se-server/src/main/java/usi/si/seart/converter/TaskSearchDtoToSpecificationConverter.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/converter/TaskSearchDtoToSpecificationConverter.java @@ -1,11 +1,11 @@ -package usi.si.seart.converter; +package usi.si.seart.server.converter; import org.springframework.core.convert.converter.Converter; import org.springframework.data.jpa.domain.Specification; import org.springframework.lang.NonNull; -import usi.si.seart.dto.task.TaskSearchDto; import usi.si.seart.model.task.Task; import usi.si.seart.model.task.Task_; +import usi.si.seart.server.dto.task.TaskSearchDto; public class TaskSearchDtoToSpecificationConverter implements Converter> { diff --git a/dl4se-server/src/main/java/usi/si/seart/converter/TaskToCodeSpecificationConverter.java b/dl4se-server/src/main/java/usi/si/seart/server/converter/TaskToCodeSpecificationConverter.java similarity index 99% rename from dl4se-server/src/main/java/usi/si/seart/converter/TaskToCodeSpecificationConverter.java rename to dl4se-server/src/main/java/usi/si/seart/server/converter/TaskToCodeSpecificationConverter.java index 39c19849..7bc19766 100644 --- a/dl4se-server/src/main/java/usi/si/seart/converter/TaskToCodeSpecificationConverter.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/converter/TaskToCodeSpecificationConverter.java @@ -1,4 +1,4 @@ -package usi.si.seart.converter; +package usi.si.seart.server.converter; import com.fasterxml.jackson.databind.JsonNode; import org.springframework.core.convert.converter.Converter; diff --git a/dl4se-server/src/main/java/usi/si/seart/converter/UserSearchDtoToSpecificationConverter.java b/dl4se-server/src/main/java/usi/si/seart/server/converter/UserSearchDtoToSpecificationConverter.java similarity index 94% rename from dl4se-server/src/main/java/usi/si/seart/converter/UserSearchDtoToSpecificationConverter.java rename to dl4se-server/src/main/java/usi/si/seart/server/converter/UserSearchDtoToSpecificationConverter.java index e49d5ec8..779836ba 100644 --- a/dl4se-server/src/main/java/usi/si/seart/converter/UserSearchDtoToSpecificationConverter.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/converter/UserSearchDtoToSpecificationConverter.java @@ -1,11 +1,11 @@ -package usi.si.seart.converter; +package usi.si.seart.server.converter; import org.springframework.core.convert.converter.Converter; import org.springframework.data.jpa.domain.Specification; import org.springframework.lang.NonNull; -import usi.si.seart.dto.user.UserSearchDto; import usi.si.seart.model.user.User; import usi.si.seart.model.user.User_; +import usi.si.seart.server.dto.user.UserSearchDto; public class UserSearchDtoToSpecificationConverter implements Converter> { diff --git a/dl4se-server/src/main/java/usi/si/seart/converter/UserToUserPrincipalConverter.java b/dl4se-server/src/main/java/usi/si/seart/server/converter/UserToUserPrincipalConverter.java similarity index 87% rename from dl4se-server/src/main/java/usi/si/seart/converter/UserToUserPrincipalConverter.java rename to dl4se-server/src/main/java/usi/si/seart/server/converter/UserToUserPrincipalConverter.java index ea5173cc..17a78fd8 100644 --- a/dl4se-server/src/main/java/usi/si/seart/converter/UserToUserPrincipalConverter.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/converter/UserToUserPrincipalConverter.java @@ -1,8 +1,8 @@ -package usi.si.seart.converter; +package usi.si.seart.server.converter; import org.springframework.core.convert.converter.Converter; import usi.si.seart.model.user.User; -import usi.si.seart.security.UserPrincipal; +import usi.si.seart.server.security.UserPrincipal; public class UserToUserPrincipalConverter implements Converter { diff --git a/dl4se-server/src/main/java/usi/si/seart/dto/ConfigurationDto.java b/dl4se-server/src/main/java/usi/si/seart/server/dto/ConfigurationDto.java similarity index 93% rename from dl4se-server/src/main/java/usi/si/seart/dto/ConfigurationDto.java rename to dl4se-server/src/main/java/usi/si/seart/server/dto/ConfigurationDto.java index 6ee16335..826d50c3 100644 --- a/dl4se-server/src/main/java/usi/si/seart/dto/ConfigurationDto.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/dto/ConfigurationDto.java @@ -1,4 +1,4 @@ -package usi.si.seart.dto; +package usi.si.seart.server.dto; import lombok.AccessLevel; import lombok.AllArgsConstructor; diff --git a/dl4se-server/src/main/java/usi/si/seart/dto/LoginDto.java b/dl4se-server/src/main/java/usi/si/seart/server/dto/LoginDto.java similarity index 93% rename from dl4se-server/src/main/java/usi/si/seart/dto/LoginDto.java rename to dl4se-server/src/main/java/usi/si/seart/server/dto/LoginDto.java index 55fb1de5..9c8daa39 100644 --- a/dl4se-server/src/main/java/usi/si/seart/dto/LoginDto.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/dto/LoginDto.java @@ -1,4 +1,4 @@ -package usi.si.seart.dto; +package usi.si.seart.server.dto; import lombok.AccessLevel; import lombok.AllArgsConstructor; diff --git a/dl4se-server/src/main/java/usi/si/seart/dto/RegisterDto.java b/dl4se-server/src/main/java/usi/si/seart/server/dto/RegisterDto.java similarity index 95% rename from dl4se-server/src/main/java/usi/si/seart/dto/RegisterDto.java rename to dl4se-server/src/main/java/usi/si/seart/server/dto/RegisterDto.java index 31376552..b793221a 100644 --- a/dl4se-server/src/main/java/usi/si/seart/dto/RegisterDto.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/dto/RegisterDto.java @@ -1,4 +1,4 @@ -package usi.si.seart.dto; +package usi.si.seart.server.dto; import lombok.AccessLevel; import lombok.AllArgsConstructor; diff --git a/dl4se-server/src/main/java/usi/si/seart/dto/task/TaskDto.java b/dl4se-server/src/main/java/usi/si/seart/server/dto/task/TaskDto.java similarity index 95% rename from dl4se-server/src/main/java/usi/si/seart/dto/task/TaskDto.java rename to dl4se-server/src/main/java/usi/si/seart/server/dto/task/TaskDto.java index 72dbe58f..c85205a5 100644 --- a/dl4se-server/src/main/java/usi/si/seart/dto/task/TaskDto.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/dto/task/TaskDto.java @@ -1,4 +1,4 @@ -package usi.si.seart.dto.task; +package usi.si.seart.server.dto.task; import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.annotation.Nulls; diff --git a/dl4se-server/src/main/java/usi/si/seart/dto/task/TaskSearchDto.java b/dl4se-server/src/main/java/usi/si/seart/server/dto/task/TaskSearchDto.java similarity index 94% rename from dl4se-server/src/main/java/usi/si/seart/dto/task/TaskSearchDto.java rename to dl4se-server/src/main/java/usi/si/seart/server/dto/task/TaskSearchDto.java index 9392fdec..9567cdb4 100644 --- a/dl4se-server/src/main/java/usi/si/seart/dto/task/TaskSearchDto.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/dto/task/TaskSearchDto.java @@ -1,4 +1,4 @@ -package usi.si.seart.dto.task; +package usi.si.seart.server.dto.task; import lombok.AccessLevel; import lombok.AllArgsConstructor; diff --git a/dl4se-server/src/main/java/usi/si/seart/dto/user/EmailDto.java b/dl4se-server/src/main/java/usi/si/seart/server/dto/user/EmailDto.java similarity index 91% rename from dl4se-server/src/main/java/usi/si/seart/dto/user/EmailDto.java rename to dl4se-server/src/main/java/usi/si/seart/server/dto/user/EmailDto.java index 60f8bd63..d8b3fe3b 100644 --- a/dl4se-server/src/main/java/usi/si/seart/dto/user/EmailDto.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/dto/user/EmailDto.java @@ -1,4 +1,4 @@ -package usi.si.seart.dto.user; +package usi.si.seart.server.dto.user; import lombok.AccessLevel; import lombok.AllArgsConstructor; diff --git a/dl4se-server/src/main/java/usi/si/seart/dto/user/PasswordDto.java b/dl4se-server/src/main/java/usi/si/seart/server/dto/user/PasswordDto.java similarity index 91% rename from dl4se-server/src/main/java/usi/si/seart/dto/user/PasswordDto.java rename to dl4se-server/src/main/java/usi/si/seart/server/dto/user/PasswordDto.java index 3872e72a..0d248839 100644 --- a/dl4se-server/src/main/java/usi/si/seart/dto/user/PasswordDto.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/dto/user/PasswordDto.java @@ -1,4 +1,4 @@ -package usi.si.seart.dto.user; +package usi.si.seart.server.dto.user; import lombok.AccessLevel; import lombok.AllArgsConstructor; diff --git a/dl4se-server/src/main/java/usi/si/seart/dto/user/UserSearchDto.java b/dl4se-server/src/main/java/usi/si/seart/server/dto/user/UserSearchDto.java similarity index 96% rename from dl4se-server/src/main/java/usi/si/seart/dto/user/UserSearchDto.java rename to dl4se-server/src/main/java/usi/si/seart/server/dto/user/UserSearchDto.java index 7f88e70f..eea511c6 100644 --- a/dl4se-server/src/main/java/usi/si/seart/dto/user/UserSearchDto.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/dto/user/UserSearchDto.java @@ -1,4 +1,4 @@ -package usi.si.seart.dto.user; +package usi.si.seart.server.dto.user; import lombok.AccessLevel; import lombok.AllArgsConstructor; diff --git a/dl4se-server/src/main/java/usi/si/seart/exception/ConfigurationNotFoundException.java b/dl4se-server/src/main/java/usi/si/seart/server/exception/ConfigurationNotFoundException.java similarity index 89% rename from dl4se-server/src/main/java/usi/si/seart/exception/ConfigurationNotFoundException.java rename to dl4se-server/src/main/java/usi/si/seart/server/exception/ConfigurationNotFoundException.java index 5cd475de..1daa0229 100644 --- a/dl4se-server/src/main/java/usi/si/seart/exception/ConfigurationNotFoundException.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/exception/ConfigurationNotFoundException.java @@ -1,4 +1,4 @@ -package usi.si.seart.exception; +package usi.si.seart.server.exception; import usi.si.seart.model.Configuration; diff --git a/dl4se-server/src/main/java/usi/si/seart/exception/EntityNotFoundException.java b/dl4se-server/src/main/java/usi/si/seart/server/exception/EntityNotFoundException.java similarity index 94% rename from dl4se-server/src/main/java/usi/si/seart/exception/EntityNotFoundException.java rename to dl4se-server/src/main/java/usi/si/seart/server/exception/EntityNotFoundException.java index 82d17f6d..22bfa776 100644 --- a/dl4se-server/src/main/java/usi/si/seart/exception/EntityNotFoundException.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/exception/EntityNotFoundException.java @@ -1,4 +1,4 @@ -package usi.si.seart.exception; +package usi.si.seart.server.exception; import lombok.AccessLevel; import lombok.experimental.StandardException; diff --git a/dl4se-server/src/main/java/usi/si/seart/exception/LanguageNotFoundException.java b/dl4se-server/src/main/java/usi/si/seart/server/exception/LanguageNotFoundException.java similarity index 88% rename from dl4se-server/src/main/java/usi/si/seart/exception/LanguageNotFoundException.java rename to dl4se-server/src/main/java/usi/si/seart/server/exception/LanguageNotFoundException.java index 3c1507d3..82140f99 100644 --- a/dl4se-server/src/main/java/usi/si/seart/exception/LanguageNotFoundException.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/exception/LanguageNotFoundException.java @@ -1,4 +1,4 @@ -package usi.si.seart.exception; +package usi.si.seart.server.exception; import usi.si.seart.model.Language; diff --git a/dl4se-server/src/main/java/usi/si/seart/exception/TaskFailedException.java b/dl4se-server/src/main/java/usi/si/seart/server/exception/TaskFailedException.java similarity index 95% rename from dl4se-server/src/main/java/usi/si/seart/exception/TaskFailedException.java rename to dl4se-server/src/main/java/usi/si/seart/server/exception/TaskFailedException.java index cbfcd02a..7d48bffa 100644 --- a/dl4se-server/src/main/java/usi/si/seart/exception/TaskFailedException.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/exception/TaskFailedException.java @@ -1,4 +1,4 @@ -package usi.si.seart.exception; +package usi.si.seart.server.exception; import lombok.Getter; import usi.si.seart.model.task.Task; diff --git a/dl4se-server/src/main/java/usi/si/seart/exception/TaskNotFoundException.java b/dl4se-server/src/main/java/usi/si/seart/server/exception/TaskNotFoundException.java similarity index 88% rename from dl4se-server/src/main/java/usi/si/seart/exception/TaskNotFoundException.java rename to dl4se-server/src/main/java/usi/si/seart/server/exception/TaskNotFoundException.java index e1a85cb5..56e8ef79 100644 --- a/dl4se-server/src/main/java/usi/si/seart/exception/TaskNotFoundException.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/exception/TaskNotFoundException.java @@ -1,4 +1,4 @@ -package usi.si.seart.exception; +package usi.si.seart.server.exception; import usi.si.seart.model.task.Task; diff --git a/dl4se-server/src/main/java/usi/si/seart/exception/TokenExpiredException.java b/dl4se-server/src/main/java/usi/si/seart/server/exception/TokenExpiredException.java similarity index 88% rename from dl4se-server/src/main/java/usi/si/seart/exception/TokenExpiredException.java rename to dl4se-server/src/main/java/usi/si/seart/server/exception/TokenExpiredException.java index 96d2b33e..5b8b40b1 100644 --- a/dl4se-server/src/main/java/usi/si/seart/exception/TokenExpiredException.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/exception/TokenExpiredException.java @@ -1,4 +1,4 @@ -package usi.si.seart.exception; +package usi.si.seart.server.exception; import usi.si.seart.model.user.token.Token; diff --git a/dl4se-server/src/main/java/usi/si/seart/exception/TokenNotFoundException.java b/dl4se-server/src/main/java/usi/si/seart/server/exception/TokenNotFoundException.java similarity index 88% rename from dl4se-server/src/main/java/usi/si/seart/exception/TokenNotFoundException.java rename to dl4se-server/src/main/java/usi/si/seart/server/exception/TokenNotFoundException.java index f0696992..e45bbacd 100644 --- a/dl4se-server/src/main/java/usi/si/seart/exception/TokenNotFoundException.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/exception/TokenNotFoundException.java @@ -1,4 +1,4 @@ -package usi.si.seart.exception; +package usi.si.seart.server.exception; import usi.si.seart.model.user.token.Token; diff --git a/dl4se-server/src/main/java/usi/si/seart/exception/UserNotFoundException.java b/dl4se-server/src/main/java/usi/si/seart/server/exception/UserNotFoundException.java similarity index 88% rename from dl4se-server/src/main/java/usi/si/seart/exception/UserNotFoundException.java rename to dl4se-server/src/main/java/usi/si/seart/server/exception/UserNotFoundException.java index 56cec153..d6411f73 100644 --- a/dl4se-server/src/main/java/usi/si/seart/exception/UserNotFoundException.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/exception/UserNotFoundException.java @@ -1,4 +1,4 @@ -package usi.si.seart.exception; +package usi.si.seart.server.exception; import usi.si.seart.model.user.User; diff --git a/dl4se-server/src/main/java/usi/si/seart/jackson/PageSerializer.java b/dl4se-server/src/main/java/usi/si/seart/server/jackson/PageSerializer.java similarity index 97% rename from dl4se-server/src/main/java/usi/si/seart/jackson/PageSerializer.java rename to dl4se-server/src/main/java/usi/si/seart/server/jackson/PageSerializer.java index de4dc47d..a8a7ab01 100644 --- a/dl4se-server/src/main/java/usi/si/seart/jackson/PageSerializer.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/jackson/PageSerializer.java @@ -1,4 +1,4 @@ -package usi.si.seart.jackson; +package usi.si.seart.server.jackson; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.SerializerProvider; diff --git a/dl4se-server/src/main/java/usi/si/seart/jackson/PaginationModule.java b/dl4se-server/src/main/java/usi/si/seart/server/jackson/PaginationModule.java similarity index 89% rename from dl4se-server/src/main/java/usi/si/seart/jackson/PaginationModule.java rename to dl4se-server/src/main/java/usi/si/seart/server/jackson/PaginationModule.java index 56e47942..aa881da3 100644 --- a/dl4se-server/src/main/java/usi/si/seart/jackson/PaginationModule.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/jackson/PaginationModule.java @@ -1,4 +1,4 @@ -package usi.si.seart.jackson; +package usi.si.seart.server.jackson; import com.fasterxml.jackson.databind.module.SimpleModule; diff --git a/dl4se-server/src/main/java/usi/si/seart/jackson/SortSerializer.java b/dl4se-server/src/main/java/usi/si/seart/server/jackson/SortSerializer.java similarity index 96% rename from dl4se-server/src/main/java/usi/si/seart/jackson/SortSerializer.java rename to dl4se-server/src/main/java/usi/si/seart/server/jackson/SortSerializer.java index 10d71dd4..68480dd2 100644 --- a/dl4se-server/src/main/java/usi/si/seart/jackson/SortSerializer.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/jackson/SortSerializer.java @@ -1,4 +1,4 @@ -package usi.si.seart.jackson; +package usi.si.seart.server.jackson; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.SerializerProvider; diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/CodeRepository.java b/dl4se-server/src/main/java/usi/si/seart/server/repository/CodeRepository.java similarity index 79% rename from dl4se-server/src/main/java/usi/si/seart/repository/CodeRepository.java rename to dl4se-server/src/main/java/usi/si/seart/server/repository/CodeRepository.java index 3630b2bb..a50d8dbe 100644 --- a/dl4se-server/src/main/java/usi/si/seart/repository/CodeRepository.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/repository/CodeRepository.java @@ -1,10 +1,10 @@ -package usi.si.seart.repository; +package usi.si.seart.server.repository; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import usi.si.seart.model.code.Code; -import usi.si.seart.repository.specification.JpaStreamableSpecificationRepository; +import usi.si.seart.server.repository.specification.JpaStreamableSpecificationRepository; public interface CodeRepository extends JpaRepository, diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/ConfigurationRepository.java b/dl4se-server/src/main/java/usi/si/seart/server/repository/ConfigurationRepository.java similarity index 82% rename from dl4se-server/src/main/java/usi/si/seart/repository/ConfigurationRepository.java rename to dl4se-server/src/main/java/usi/si/seart/server/repository/ConfigurationRepository.java index 5ffc4392..9f8a3229 100644 --- a/dl4se-server/src/main/java/usi/si/seart/repository/ConfigurationRepository.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/repository/ConfigurationRepository.java @@ -1,4 +1,4 @@ -package usi.si.seart.repository; +package usi.si.seart.server.repository; import org.springframework.data.jpa.repository.JpaRepository; import usi.si.seart.model.Configuration; diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/FileRepository.java b/dl4se-server/src/main/java/usi/si/seart/server/repository/FileRepository.java similarity index 91% rename from dl4se-server/src/main/java/usi/si/seart/repository/FileRepository.java rename to dl4se-server/src/main/java/usi/si/seart/server/repository/FileRepository.java index 72cfe9a9..78ad3876 100644 --- a/dl4se-server/src/main/java/usi/si/seart/repository/FileRepository.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/repository/FileRepository.java @@ -1,4 +1,4 @@ -package usi.si.seart.repository; +package usi.si.seart.server.repository; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/FunctionRepository.java b/dl4se-server/src/main/java/usi/si/seart/server/repository/FunctionRepository.java similarity index 91% rename from dl4se-server/src/main/java/usi/si/seart/repository/FunctionRepository.java rename to dl4se-server/src/main/java/usi/si/seart/server/repository/FunctionRepository.java index 6c65c176..95824b54 100644 --- a/dl4se-server/src/main/java/usi/si/seart/repository/FunctionRepository.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/repository/FunctionRepository.java @@ -1,4 +1,4 @@ -package usi.si.seart.repository; +package usi.si.seart.server.repository; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/GitRepoRepository.java b/dl4se-server/src/main/java/usi/si/seart/server/repository/GitRepoRepository.java similarity index 92% rename from dl4se-server/src/main/java/usi/si/seart/repository/GitRepoRepository.java rename to dl4se-server/src/main/java/usi/si/seart/server/repository/GitRepoRepository.java index da0feebf..d8e50f42 100644 --- a/dl4se-server/src/main/java/usi/si/seart/repository/GitRepoRepository.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/repository/GitRepoRepository.java @@ -1,4 +1,4 @@ -package usi.si.seart.repository; +package usi.si.seart.server.repository; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/LanguageRepository.java b/dl4se-server/src/main/java/usi/si/seart/server/repository/LanguageRepository.java similarity index 86% rename from dl4se-server/src/main/java/usi/si/seart/repository/LanguageRepository.java rename to dl4se-server/src/main/java/usi/si/seart/server/repository/LanguageRepository.java index 17a4b821..6dd087d2 100644 --- a/dl4se-server/src/main/java/usi/si/seart/repository/LanguageRepository.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/repository/LanguageRepository.java @@ -1,4 +1,4 @@ -package usi.si.seart.repository; +package usi.si.seart.server.repository; import org.springframework.data.jpa.repository.JpaRepository; import usi.si.seart.model.Language; diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/TableRowCountRepository.java b/dl4se-server/src/main/java/usi/si/seart/server/repository/TableRowCountRepository.java similarity index 82% rename from dl4se-server/src/main/java/usi/si/seart/repository/TableRowCountRepository.java rename to dl4se-server/src/main/java/usi/si/seart/server/repository/TableRowCountRepository.java index c4c05fe0..8eec89ea 100644 --- a/dl4se-server/src/main/java/usi/si/seart/repository/TableRowCountRepository.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/repository/TableRowCountRepository.java @@ -1,4 +1,4 @@ -package usi.si.seart.repository; +package usi.si.seart.server.repository; import org.springframework.data.jpa.repository.JpaRepository; import usi.si.seart.views.TableRowCount; diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/TaskRepository.java b/dl4se-server/src/main/java/usi/si/seart/server/repository/TaskRepository.java similarity index 98% rename from dl4se-server/src/main/java/usi/si/seart/repository/TaskRepository.java rename to dl4se-server/src/main/java/usi/si/seart/server/repository/TaskRepository.java index 5a6fa58b..2b99d525 100644 --- a/dl4se-server/src/main/java/usi/si/seart/repository/TaskRepository.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/repository/TaskRepository.java @@ -1,4 +1,4 @@ -package usi.si.seart.repository; +package usi.si.seart.server.repository; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/TokenRepository.java b/dl4se-server/src/main/java/usi/si/seart/server/repository/TokenRepository.java similarity index 89% rename from dl4se-server/src/main/java/usi/si/seart/repository/TokenRepository.java rename to dl4se-server/src/main/java/usi/si/seart/server/repository/TokenRepository.java index f08f1bae..7499963a 100644 --- a/dl4se-server/src/main/java/usi/si/seart/repository/TokenRepository.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/repository/TokenRepository.java @@ -1,4 +1,4 @@ -package usi.si.seart.repository; +package usi.si.seart.server.repository; import org.springframework.data.jpa.repository.JpaRepository; import usi.si.seart.model.user.User; diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/UserRepository.java b/dl4se-server/src/main/java/usi/si/seart/server/repository/UserRepository.java similarity index 92% rename from dl4se-server/src/main/java/usi/si/seart/repository/UserRepository.java rename to dl4se-server/src/main/java/usi/si/seart/server/repository/UserRepository.java index d49bf24a..80ab063e 100644 --- a/dl4se-server/src/main/java/usi/si/seart/repository/UserRepository.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/repository/UserRepository.java @@ -1,4 +1,4 @@ -package usi.si.seart.repository; +package usi.si.seart.server.repository; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/specification/JpaStreamableSpecificationRepository.java b/dl4se-server/src/main/java/usi/si/seart/server/repository/specification/JpaStreamableSpecificationRepository.java similarity index 87% rename from dl4se-server/src/main/java/usi/si/seart/repository/specification/JpaStreamableSpecificationRepository.java rename to dl4se-server/src/main/java/usi/si/seart/server/repository/specification/JpaStreamableSpecificationRepository.java index cf69f3d8..7337c760 100644 --- a/dl4se-server/src/main/java/usi/si/seart/repository/specification/JpaStreamableSpecificationRepository.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/repository/specification/JpaStreamableSpecificationRepository.java @@ -1,4 +1,4 @@ -package usi.si.seart.repository.specification; +package usi.si.seart.server.repository.specification; import org.springframework.data.domain.Sort; import org.springframework.data.jpa.domain.Specification; diff --git a/dl4se-server/src/main/java/usi/si/seart/repository/specification/JpaStreamableSpecificationRepositoryImpl.java b/dl4se-server/src/main/java/usi/si/seart/server/repository/specification/JpaStreamableSpecificationRepositoryImpl.java similarity index 97% rename from dl4se-server/src/main/java/usi/si/seart/repository/specification/JpaStreamableSpecificationRepositoryImpl.java rename to dl4se-server/src/main/java/usi/si/seart/server/repository/specification/JpaStreamableSpecificationRepositoryImpl.java index 8678a3c5..c08628e4 100644 --- a/dl4se-server/src/main/java/usi/si/seart/repository/specification/JpaStreamableSpecificationRepositoryImpl.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/repository/specification/JpaStreamableSpecificationRepositoryImpl.java @@ -1,4 +1,4 @@ -package usi.si.seart.repository.specification; +package usi.si.seart.server.repository.specification; import lombok.AllArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; diff --git a/dl4se-server/src/main/java/usi/si/seart/scheduling/RepoMaintainer.java b/dl4se-server/src/main/java/usi/si/seart/server/scheduling/RepoMaintainer.java similarity index 95% rename from dl4se-server/src/main/java/usi/si/seart/scheduling/RepoMaintainer.java rename to dl4se-server/src/main/java/usi/si/seart/server/scheduling/RepoMaintainer.java index 906a8348..7c6b218a 100644 --- a/dl4se-server/src/main/java/usi/si/seart/scheduling/RepoMaintainer.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/scheduling/RepoMaintainer.java @@ -1,4 +1,4 @@ -package usi.si.seart.scheduling; +package usi.si.seart.server.scheduling; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -8,7 +8,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import usi.si.seart.model.GitRepo; -import usi.si.seart.service.GitRepoService; +import usi.si.seart.server.service.GitRepoService; import java.io.IOException; import java.util.concurrent.TimeUnit; diff --git a/dl4se-server/src/main/java/usi/si/seart/scheduling/TaskCleaner.java b/dl4se-server/src/main/java/usi/si/seart/server/scheduling/TaskCleaner.java similarity index 86% rename from dl4se-server/src/main/java/usi/si/seart/scheduling/TaskCleaner.java rename to dl4se-server/src/main/java/usi/si/seart/server/scheduling/TaskCleaner.java index 959c7d92..bc7d3917 100644 --- a/dl4se-server/src/main/java/usi/si/seart/scheduling/TaskCleaner.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/scheduling/TaskCleaner.java @@ -1,4 +1,4 @@ -package usi.si.seart.scheduling; +package usi.si.seart.server.scheduling; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -7,8 +7,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import usi.si.seart.model.task.Task; -import usi.si.seart.service.FileSystemService; -import usi.si.seart.service.TaskService; +import usi.si.seart.server.service.FileSystemService; +import usi.si.seart.server.service.TaskService; @Slf4j @Component diff --git a/dl4se-server/src/main/java/usi/si/seart/scheduling/TaskRunner.java b/dl4se-server/src/main/java/usi/si/seart/server/scheduling/TaskRunner.java similarity index 96% rename from dl4se-server/src/main/java/usi/si/seart/scheduling/TaskRunner.java rename to dl4se-server/src/main/java/usi/si/seart/server/scheduling/TaskRunner.java index 804d3b7e..474a6819 100644 --- a/dl4se-server/src/main/java/usi/si/seart/scheduling/TaskRunner.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/scheduling/TaskRunner.java @@ -1,4 +1,4 @@ -package usi.si.seart.scheduling; +package usi.si.seart.server.scheduling; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.json.JsonMapper; @@ -20,15 +20,15 @@ import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; -import usi.si.seart.exception.TaskFailedException; import usi.si.seart.model.code.Code; import usi.si.seart.model.job.Job; import usi.si.seart.model.task.Status; import usi.si.seart.model.task.Task; -import usi.si.seart.service.CodeService; -import usi.si.seart.service.EmailService; -import usi.si.seart.service.FileSystemService; -import usi.si.seart.service.TaskService; +import usi.si.seart.server.exception.TaskFailedException; +import usi.si.seart.server.service.CodeService; +import usi.si.seart.server.service.EmailService; +import usi.si.seart.server.service.FileSystemService; +import usi.si.seart.server.service.TaskService; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; diff --git a/dl4se-server/src/main/java/usi/si/seart/scheduling/ViewMaintainer.java b/dl4se-server/src/main/java/usi/si/seart/server/scheduling/ViewMaintainer.java similarity index 87% rename from dl4se-server/src/main/java/usi/si/seart/scheduling/ViewMaintainer.java rename to dl4se-server/src/main/java/usi/si/seart/server/scheduling/ViewMaintainer.java index 857bf226..8150626b 100644 --- a/dl4se-server/src/main/java/usi/si/seart/scheduling/ViewMaintainer.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/scheduling/ViewMaintainer.java @@ -1,4 +1,4 @@ -package usi.si.seart.scheduling; +package usi.si.seart.server.scheduling; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -6,7 +6,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import usi.si.seart.service.DatabaseService; +import usi.si.seart.server.service.DatabaseService; @Slf4j @Component diff --git a/dl4se-server/src/main/java/usi/si/seart/security/UserPrincipal.java b/dl4se-server/src/main/java/usi/si/seart/server/security/UserPrincipal.java similarity index 97% rename from dl4se-server/src/main/java/usi/si/seart/security/UserPrincipal.java rename to dl4se-server/src/main/java/usi/si/seart/server/security/UserPrincipal.java index 10e74247..350e4527 100644 --- a/dl4se-server/src/main/java/usi/si/seart/security/UserPrincipal.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/security/UserPrincipal.java @@ -1,4 +1,4 @@ -package usi.si.seart.security; +package usi.si.seart.server.security; import lombok.AccessLevel; import lombok.AllArgsConstructor; diff --git a/dl4se-server/src/main/java/usi/si/seart/security/annotation/AdminRestController.java b/dl4se-server/src/main/java/usi/si/seart/server/security/annotation/AdminRestController.java similarity index 89% rename from dl4se-server/src/main/java/usi/si/seart/security/annotation/AdminRestController.java rename to dl4se-server/src/main/java/usi/si/seart/server/security/annotation/AdminRestController.java index b9a9bd1f..ac1e2e39 100644 --- a/dl4se-server/src/main/java/usi/si/seart/security/annotation/AdminRestController.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/security/annotation/AdminRestController.java @@ -1,4 +1,4 @@ -package usi.si.seart.security.annotation; +package usi.si.seart.server.security.annotation; import org.springframework.security.access.annotation.Secured; import org.springframework.web.bind.annotation.RestController; diff --git a/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtRequestFilter.java b/dl4se-server/src/main/java/usi/si/seart/server/security/jwt/JwtRequestFilter.java similarity index 98% rename from dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtRequestFilter.java rename to dl4se-server/src/main/java/usi/si/seart/server/security/jwt/JwtRequestFilter.java index e4e954be..58adbdd6 100644 --- a/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtRequestFilter.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/security/jwt/JwtRequestFilter.java @@ -1,4 +1,4 @@ -package usi.si.seart.security.jwt; +package usi.si.seart.server.security.jwt; import lombok.AccessLevel; import lombok.AllArgsConstructor; diff --git a/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtTokenProvider.java b/dl4se-server/src/main/java/usi/si/seart/server/security/jwt/JwtTokenProvider.java similarity index 94% rename from dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtTokenProvider.java rename to dl4se-server/src/main/java/usi/si/seart/server/security/jwt/JwtTokenProvider.java index 1e8d7564..04485ac3 100644 --- a/dl4se-server/src/main/java/usi/si/seart/security/jwt/JwtTokenProvider.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/security/jwt/JwtTokenProvider.java @@ -1,4 +1,4 @@ -package usi.si.seart.security.jwt; +package usi.si.seart.server.security.jwt; import io.jsonwebtoken.Claims; import io.jsonwebtoken.JwtBuilder; @@ -7,7 +7,7 @@ import lombok.AllArgsConstructor; import lombok.experimental.FieldDefaults; import org.springframework.security.core.Authentication; -import usi.si.seart.security.UserPrincipal; +import usi.si.seart.server.security.UserPrincipal; import java.time.Duration; import java.time.Instant; diff --git a/dl4se-server/src/main/java/usi/si/seart/service/CodeService.java b/dl4se-server/src/main/java/usi/si/seart/server/service/CodeService.java similarity index 92% rename from dl4se-server/src/main/java/usi/si/seart/service/CodeService.java rename to dl4se-server/src/main/java/usi/si/seart/server/service/CodeService.java index c1df4ab9..b67c6516 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/CodeService.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/service/CodeService.java @@ -1,4 +1,4 @@ -package usi.si.seart.service; +package usi.si.seart.server.service; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -7,7 +7,7 @@ import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; import usi.si.seart.model.code.Code; -import usi.si.seart.repository.CodeRepository; +import usi.si.seart.server.repository.CodeRepository; import java.util.stream.Stream; diff --git a/dl4se-server/src/main/java/usi/si/seart/service/ConfigurationService.java b/dl4se-server/src/main/java/usi/si/seart/server/service/ConfigurationService.java similarity index 97% rename from dl4se-server/src/main/java/usi/si/seart/service/ConfigurationService.java rename to dl4se-server/src/main/java/usi/si/seart/server/service/ConfigurationService.java index dddd0dc0..128472ed 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/ConfigurationService.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/service/ConfigurationService.java @@ -1,4 +1,4 @@ -package usi.si.seart.service; +package usi.si.seart.server.service; import lombok.AccessLevel; import lombok.experimental.FieldDefaults; @@ -8,7 +8,7 @@ import org.springframework.core.env.PropertySource; import org.springframework.stereotype.Service; import usi.si.seart.model.Configuration; -import usi.si.seart.repository.ConfigurationRepository; +import usi.si.seart.server.repository.ConfigurationRepository; import java.util.Collection; import java.util.Map; diff --git a/dl4se-server/src/main/java/usi/si/seart/service/DatabaseService.java b/dl4se-server/src/main/java/usi/si/seart/server/service/DatabaseService.java similarity index 98% rename from dl4se-server/src/main/java/usi/si/seart/service/DatabaseService.java rename to dl4se-server/src/main/java/usi/si/seart/server/service/DatabaseService.java index 0e2509b7..f8e00b14 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/DatabaseService.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/service/DatabaseService.java @@ -1,4 +1,4 @@ -package usi.si.seart.service; +package usi.si.seart.server.service; import lombok.AccessLevel; import lombok.AllArgsConstructor; diff --git a/dl4se-server/src/main/java/usi/si/seart/service/DownloadService.java b/dl4se-server/src/main/java/usi/si/seart/server/service/DownloadService.java similarity index 88% rename from dl4se-server/src/main/java/usi/si/seart/service/DownloadService.java rename to dl4se-server/src/main/java/usi/si/seart/server/service/DownloadService.java index f612626d..b751d6d2 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/DownloadService.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/service/DownloadService.java @@ -1,17 +1,17 @@ -package usi.si.seart.service; +package usi.si.seart.server.service; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import lombok.experimental.FieldDefaults; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import usi.si.seart.exception.TokenExpiredException; -import usi.si.seart.exception.TokenNotFoundException; import usi.si.seart.model.user.User; import usi.si.seart.model.user.token.DownloadToken; import usi.si.seart.model.user.token.Token; import usi.si.seart.model.user.token.Token_; -import usi.si.seart.repository.TokenRepository; +import usi.si.seart.server.exception.TokenExpiredException; +import usi.si.seart.server.exception.TokenNotFoundException; +import usi.si.seart.server.repository.TokenRepository; import java.util.UUID; diff --git a/dl4se-server/src/main/java/usi/si/seart/service/EmailService.java b/dl4se-server/src/main/java/usi/si/seart/server/service/EmailService.java similarity index 97% rename from dl4se-server/src/main/java/usi/si/seart/service/EmailService.java rename to dl4se-server/src/main/java/usi/si/seart/server/service/EmailService.java index f2369a8f..d1b5387e 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/EmailService.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/service/EmailService.java @@ -1,4 +1,4 @@ -package usi.si.seart.service; +package usi.si.seart.server.service; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; @@ -14,7 +14,7 @@ import org.thymeleaf.context.Context; import org.thymeleaf.spring5.SpringTemplateEngine; import usi.si.seart.model.task.Task; -import usi.si.seart.util.unit.ReadableFileSize; +import usi.si.seart.server.util.unit.ReadableFileSize; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; diff --git a/dl4se-server/src/main/java/usi/si/seart/service/FileSystemService.java b/dl4se-server/src/main/java/usi/si/seart/server/service/FileSystemService.java similarity index 98% rename from dl4se-server/src/main/java/usi/si/seart/service/FileSystemService.java rename to dl4se-server/src/main/java/usi/si/seart/server/service/FileSystemService.java index a42bab8a..0dc1d353 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/FileSystemService.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/service/FileSystemService.java @@ -1,4 +1,4 @@ -package usi.si.seart.service; +package usi.si.seart.server.service; import lombok.AccessLevel; import lombok.AllArgsConstructor; diff --git a/dl4se-server/src/main/java/usi/si/seart/service/GitRepoService.java b/dl4se-server/src/main/java/usi/si/seart/server/service/GitRepoService.java similarity index 91% rename from dl4se-server/src/main/java/usi/si/seart/service/GitRepoService.java rename to dl4se-server/src/main/java/usi/si/seart/server/service/GitRepoService.java index 6f5118e0..99ab9d1e 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/GitRepoService.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/service/GitRepoService.java @@ -1,4 +1,4 @@ -package usi.si.seart.service; +package usi.si.seart.server.service; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -9,7 +9,7 @@ import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import usi.si.seart.model.GitRepo; -import usi.si.seart.repository.GitRepoRepository; +import usi.si.seart.server.repository.GitRepoRepository; import java.util.function.Consumer; import java.util.stream.Stream; diff --git a/dl4se-server/src/main/java/usi/si/seart/service/LanguageService.java b/dl4se-server/src/main/java/usi/si/seart/server/service/LanguageService.java similarity index 86% rename from dl4se-server/src/main/java/usi/si/seart/service/LanguageService.java rename to dl4se-server/src/main/java/usi/si/seart/server/service/LanguageService.java index 18ecde59..28c65b1c 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/LanguageService.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/service/LanguageService.java @@ -1,14 +1,14 @@ -package usi.si.seart.service; +package usi.si.seart.server.service; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.experimental.FieldDefaults; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import usi.si.seart.exception.LanguageNotFoundException; import usi.si.seart.model.Language; import usi.si.seart.model.Language_; -import usi.si.seart.repository.LanguageRepository; +import usi.si.seart.server.exception.LanguageNotFoundException; +import usi.si.seart.server.repository.LanguageRepository; import java.util.List; diff --git a/dl4se-server/src/main/java/usi/si/seart/service/PasswordResetService.java b/dl4se-server/src/main/java/usi/si/seart/server/service/PasswordResetService.java similarity index 90% rename from dl4se-server/src/main/java/usi/si/seart/service/PasswordResetService.java rename to dl4se-server/src/main/java/usi/si/seart/server/service/PasswordResetService.java index ba60e675..b6e80ba8 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/PasswordResetService.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/service/PasswordResetService.java @@ -1,4 +1,4 @@ -package usi.si.seart.service; +package usi.si.seart.server.service; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; @@ -6,14 +6,14 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; -import usi.si.seart.exception.TokenExpiredException; -import usi.si.seart.exception.TokenNotFoundException; import usi.si.seart.model.user.User; import usi.si.seart.model.user.token.PasswordResetToken; import usi.si.seart.model.user.token.Token; import usi.si.seart.model.user.token.Token_; -import usi.si.seart.repository.TokenRepository; -import usi.si.seart.repository.UserRepository; +import usi.si.seart.server.exception.TokenExpiredException; +import usi.si.seart.server.exception.TokenNotFoundException; +import usi.si.seart.server.repository.TokenRepository; +import usi.si.seart.server.repository.UserRepository; import java.util.UUID; diff --git a/dl4se-server/src/main/java/usi/si/seart/service/StatisticsService.java b/dl4se-server/src/main/java/usi/si/seart/server/service/StatisticsService.java similarity index 92% rename from dl4se-server/src/main/java/usi/si/seart/service/StatisticsService.java rename to dl4se-server/src/main/java/usi/si/seart/server/service/StatisticsService.java index 2f9b12a0..763ca801 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/StatisticsService.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/service/StatisticsService.java @@ -1,4 +1,4 @@ -package usi.si.seart.service; +package usi.si.seart.server.service; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -11,12 +11,12 @@ import usi.si.seart.model.code.Function; import usi.si.seart.model.task.Status; import usi.si.seart.model.user.User; -import usi.si.seart.repository.CodeRepository; -import usi.si.seart.repository.FileRepository; -import usi.si.seart.repository.FunctionRepository; -import usi.si.seart.repository.GitRepoRepository; -import usi.si.seart.repository.TableRowCountRepository; -import usi.si.seart.repository.TaskRepository; +import usi.si.seart.server.repository.CodeRepository; +import usi.si.seart.server.repository.FileRepository; +import usi.si.seart.server.repository.FunctionRepository; +import usi.si.seart.server.repository.GitRepoRepository; +import usi.si.seart.server.repository.TableRowCountRepository; +import usi.si.seart.server.repository.TaskRepository; import usi.si.seart.views.GroupedCount; import usi.si.seart.views.TableRowCount; diff --git a/dl4se-server/src/main/java/usi/si/seart/service/TaskService.java b/dl4se-server/src/main/java/usi/si/seart/server/service/TaskService.java similarity index 96% rename from dl4se-server/src/main/java/usi/si/seart/service/TaskService.java rename to dl4se-server/src/main/java/usi/si/seart/server/service/TaskService.java index 4fb915f6..3609dcf8 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/TaskService.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/service/TaskService.java @@ -1,4 +1,4 @@ -package usi.si.seart.service; +package usi.si.seart.server.service; import com.fasterxml.jackson.databind.JsonNode; import lombok.AccessLevel; @@ -13,14 +13,14 @@ import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.ConcurrentReferenceHashMap; -import usi.si.seart.exception.TaskFailedException; -import usi.si.seart.exception.TaskNotFoundException; import usi.si.seart.model.job.Job; import usi.si.seart.model.task.Status; import usi.si.seart.model.task.Task; import usi.si.seart.model.task.Task_; import usi.si.seart.model.user.User; -import usi.si.seart.repository.TaskRepository; +import usi.si.seart.server.exception.TaskFailedException; +import usi.si.seart.server.exception.TaskNotFoundException; +import usi.si.seart.server.repository.TaskRepository; import java.io.PrintWriter; import java.io.StringWriter; diff --git a/dl4se-server/src/main/java/usi/si/seart/service/UserService.java b/dl4se-server/src/main/java/usi/si/seart/server/service/UserService.java similarity index 93% rename from dl4se-server/src/main/java/usi/si/seart/service/UserService.java rename to dl4se-server/src/main/java/usi/si/seart/server/service/UserService.java index c4f1d0cd..3aa925d1 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/UserService.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/service/UserService.java @@ -1,4 +1,4 @@ -package usi.si.seart.service; +package usi.si.seart.server.service; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -9,11 +9,11 @@ import org.springframework.data.jpa.domain.Specification; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; -import usi.si.seart.exception.UserNotFoundException; import usi.si.seart.model.user.Role; import usi.si.seart.model.user.User; import usi.si.seart.model.user.User_; -import usi.si.seart.repository.UserRepository; +import usi.si.seart.server.exception.UserNotFoundException; +import usi.si.seart.server.repository.UserRepository; public interface UserService { diff --git a/dl4se-server/src/main/java/usi/si/seart/service/VerificationService.java b/dl4se-server/src/main/java/usi/si/seart/server/service/VerificationService.java similarity index 88% rename from dl4se-server/src/main/java/usi/si/seart/service/VerificationService.java rename to dl4se-server/src/main/java/usi/si/seart/server/service/VerificationService.java index 7d6c6457..bb533649 100644 --- a/dl4se-server/src/main/java/usi/si/seart/service/VerificationService.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/service/VerificationService.java @@ -1,18 +1,18 @@ -package usi.si.seart.service; +package usi.si.seart.server.service; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import lombok.experimental.FieldDefaults; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import usi.si.seart.exception.TokenExpiredException; -import usi.si.seart.exception.TokenNotFoundException; import usi.si.seart.model.user.User; import usi.si.seart.model.user.token.Token; import usi.si.seart.model.user.token.Token_; import usi.si.seart.model.user.token.VerificationToken; -import usi.si.seart.repository.TokenRepository; -import usi.si.seart.repository.UserRepository; +import usi.si.seart.server.exception.TokenExpiredException; +import usi.si.seart.server.exception.TokenNotFoundException; +import usi.si.seart.server.repository.TokenRepository; +import usi.si.seart.server.repository.UserRepository; import java.util.UUID; diff --git a/dl4se-server/src/main/java/usi/si/seart/util/unit/ReadableFileSize.java b/dl4se-server/src/main/java/usi/si/seart/server/util/unit/ReadableFileSize.java similarity index 96% rename from dl4se-server/src/main/java/usi/si/seart/util/unit/ReadableFileSize.java rename to dl4se-server/src/main/java/usi/si/seart/server/util/unit/ReadableFileSize.java index 897ef2fc..27102a2d 100644 --- a/dl4se-server/src/main/java/usi/si/seart/util/unit/ReadableFileSize.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/util/unit/ReadableFileSize.java @@ -1,4 +1,4 @@ -package usi.si.seart.util.unit; +package usi.si.seart.server.util.unit; import lombok.AccessLevel; import lombok.AllArgsConstructor; From 921133b01a6bbcfa987aa9e8afe87318be7fc32c Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 18 Oct 2023 12:01:17 +0200 Subject: [PATCH 0440/1089] Renamed `DL4SEEnvironment` to more general `ConfigurationEnvironment` --- .../usi/si/seart/server/context/ConfigurationEnvironment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dl4se-server/src/main/java/usi/si/seart/server/context/ConfigurationEnvironment.java b/dl4se-server/src/main/java/usi/si/seart/server/context/ConfigurationEnvironment.java index 890927fe..af0b4ee0 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/context/ConfigurationEnvironment.java +++ b/dl4se-server/src/main/java/usi/si/seart/server/context/ConfigurationEnvironment.java @@ -13,7 +13,7 @@ @Component @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) @AllArgsConstructor(onConstructor_ = @Autowired) -public class DL4SEEnvironment implements EnvironmentAware { +public class ConfigurationEnvironment implements EnvironmentAware { ConfigurationService configurationService; From 740c82790038c996a361c796ea26800a0650f335 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 18 Oct 2023 12:02:31 +0200 Subject: [PATCH 0441/1089] Isolating main class name setting --- dl4se-server/pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dl4se-server/pom.xml b/dl4se-server/pom.xml index 6af7bb29..4814601b 100644 --- a/dl4se-server/pom.xml +++ b/dl4se-server/pom.xml @@ -14,6 +14,7 @@ UTF-8 + usi.si.seart.server.Application @@ -102,7 +103,7 @@ spring-boot-maven-plugin ${springframework.version} - usi.si.seart.server.Application + ${project.module.mainClass} From 071db22e9341ef9769a4714e47e1407316d30078 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 18 Oct 2023 16:13:58 +0200 Subject: [PATCH 0442/1089] GLOBAL RELOCATION: Adding `ch` top level domain prefix to GID --- dl4se-analyzer/pom.xml | 4 +- .../usi/si/seart/analyzer/Analyzer.java | 52 +++++++++---------- .../usi/si/seart/analyzer/LocalClone.java | 4 +- .../seart/analyzer/count/AbstractCounter.java | 2 +- .../analyzer/count/CharacterCounter.java | 2 +- .../analyzer/count/CodeTokenCounter.java | 2 +- .../usi/si/seart/analyzer/count/Counter.java | 2 +- .../analyzer/count/JavaTokenCounter.java | 2 +- .../si/seart/analyzer/count/LineCounter.java | 2 +- .../count/PythonCodeTokenCounter.java | 2 +- .../analyzer/count/PythonTokenCounter.java | 2 +- .../si/seart/analyzer/count/TokenCounter.java | 2 +- .../seart/analyzer/count/TraverseCounter.java | 2 +- .../enumerator/BoilerplateEnumerator.java | 4 +- .../seart/analyzer/enumerator/Enumerator.java | 2 +- .../enumerator/JavaBoilerplateEnumerator.java | 4 +- .../PythonBoilerplateEnumerator.java | 4 +- .../si/seart/analyzer/hash/ContentHasher.java | 2 +- .../usi/si/seart/analyzer/hash/Hasher.java | 2 +- .../si/seart/analyzer/hash/SHA256Hasher.java | 2 +- .../seart/analyzer/hash/SyntaxTreeHasher.java | 2 +- .../seart/analyzer/io/NullFilteredReader.java | 2 +- .../node/ContainsErrorPredicate.java | 2 +- .../node/ContainsNonAsciiPredicate.java | 2 +- .../predicate/node/NodePredicate.java | 2 +- .../predicate/path/JavaTestFilePredicate.java | 2 +- .../path/PythonTestFilePredicate.java | 2 +- .../predicate/path/TestFilePredicate.java | 2 +- .../analyzer/printer/AbstractPrinter.java | 2 +- .../seart/analyzer/printer/NodePrinter.java | 2 +- .../printer/OffsetSyntaxTreePrinter.java | 2 +- .../si/seart/analyzer/printer/Printer.java | 2 +- .../printer/SymbolicExpressionPrinter.java | 4 +- .../analyzer/printer/SyntaxTreePrinter.java | 4 +- .../usi/si/seart/analyzer/query/Queries.java | 2 +- .../query/multi/JavaMultiCaptureQueries.java | 2 +- .../query/multi/MultiCaptureQueries.java | 4 +- .../multi/PythonMultiCaptureQueries.java | 2 +- .../single/JavaSingleCaptureQueries.java | 2 +- .../single/PythonSingleCaptureQueries.java | 2 +- .../query/single/SingleCaptureQueries.java | 4 +- .../DelimiterSuffixedStringCollector.java | 2 +- .../stream/MinimumSizeLimitCollector.java | 2 +- .../count/JavaCharacterCounterTest.java | 6 +-- .../count/JavaCodeTokenCounterTest.java | 6 +-- .../analyzer/count/JavaLineCounterTest.java | 6 +-- .../analyzer/count/JavaTokenCounterTest.java | 6 +-- .../count/PythonCodeTokenCounterTest.java | 6 +-- .../count/PythonTokenCounterTest.java | 4 +- .../JavaBoilerplateEnumeratorTest.java | 6 +-- .../PythonBoilerplateEnumeratorTest.java | 6 +-- .../analyzer/hash/JavaContentHasherTest.java | 4 +- .../seart/analyzer/hash/JavaHasherTest.java | 4 +- .../hash/JavaSyntaxTreeHasherTest.java | 4 +- .../analyzer/io/NullFilteredReaderTest.java | 2 +- .../usi/si/seart/analyzer/io/ReaderTest.java | 2 +- .../node/ContainsErrorPredicateTest.java | 4 +- .../node/ContainsNonAsciiPredicateTest.java | 4 +- .../predicate/node/PredicateTest.java | 4 +- .../path/JavaTestFilePredicateTest.java | 4 +- .../path/PythonTestFilePredicateTest.java | 4 +- .../predicate/path/TestFilePredicateTest.java | 4 +- .../analyzer/printer/NodePrinterTest.java | 6 +-- .../printer/OffsetSyntaxTreePrinterTest.java | 6 +-- .../SymbolicExpressionPrinterTest.java | 6 +-- .../printer/SyntaxTreePrinterTest.java | 6 +-- .../usi/si/seart/analyzer/test/BaseTest.java | 2 +- .../si/seart/analyzer/test/JavaBaseTest.java | 2 +- .../seart/analyzer/test/PythonBaseTest.java | 2 +- .../DelimiterSuffixedStringCollectorTest.java | 4 +- dl4se-crawler/pom.xml | 8 +-- .../ch/usi/si/seart/crawler}/Application.java | 2 +- .../bean/CrawlJobInitializingBean.java | 8 +-- .../bean/LanguageInitializingBean.java | 6 +-- .../crawler/bean/NativeLibraryLoaderBean.java | 2 +- .../seart/crawler/component/CodeCrawler.java | 34 ++++++------ .../seart/crawler/component/HttpClient.java | 4 +- .../seart/crawler/config/ConverterConfig.java | 6 +-- .../seart/crawler/config/CrawlerConfig.java | 4 +- .../si/seart/crawler/config/HttpConfig.java | 2 +- .../si/seart/crawler/config/JpaConfig.java | 4 +- .../seart/crawler/config/SchedulerConfig.java | 2 +- .../DateToLocalDateTimeConverter.java | 2 +- .../SearchResultDtoToGitRepoConverter.java | 6 +-- .../si/seart/crawler/dto/SearchResultDto.java | 4 +- .../usi/si/seart/crawler/git/Git.java | 4 +- .../si/seart/crawler/git/GitException.java | 2 +- .../crawler/io/ExtensionBasedFileVisitor.java | 2 +- .../repository/CrawlJobRepository.java | 6 +-- .../crawler/repository/FileRepository.java | 6 +-- .../crawler/repository/GitRepoRepository.java | 4 +- .../repository/LanguageRepository.java | 4 +- .../crawler/service/CrawlJobService.java | 8 +-- .../si/seart/crawler/service/FileService.java | 8 +-- .../seart/crawler/service/GitRepoService.java | 6 +-- .../crawler/service/LanguageService.java | 6 +-- .../src/main/resources/application.properties | 2 +- .../{ => ch}/usi/si/seart/git/GitTest.java | 10 ++-- .../io/ExtensionBasedFileVisitorTest.java | 6 +-- dl4se-model/pom.xml | 2 +- .../usi/si/seart/model/Configuration.java | 2 +- .../{ => ch}/usi/si/seart/model/GitRepo.java | 8 +-- .../{ => ch}/usi/si/seart/model/Language.java | 2 +- .../usi/si/seart/model/code/Boilerplate.java | 2 +- .../usi/si/seart/model/code/Code.java | 8 +-- .../usi/si/seart/model/code/File.java | 2 +- .../usi/si/seart/model/code/Function.java | 4 +- .../usi/si/seart/model/job/CrawlJob.java | 4 +- .../{ => ch}/usi/si/seart/model/job/Job.java | 2 +- .../usi/si/seart/model/task/Status.java | 2 +- .../usi/si/seart/model/task/Task.java | 8 +-- .../si/seart/model/type/StringEnumType.java | 2 +- .../usi/si/seart/model/user/Role.java | 2 +- .../usi/si/seart/model/user/User.java | 8 +-- .../seart/model/user/token/DownloadToken.java | 2 +- .../model/user/token/PasswordResetToken.java | 2 +- .../usi/si/seart/model/user/token/Token.java | 4 +- .../model/user/token/VerificationToken.java | 2 +- .../si/seart/validation/constraints/Hash.java | 4 +- .../constraints/NullOrNotBlank.java | 4 +- .../validation/constraints/OWASPEmail.java | 4 +- .../validation/constraints/Password.java | 4 +- .../usi/si/seart/views/GroupedCount.java | 2 +- .../usi/si/seart/views/TableRowCount.java | 2 +- .../seart/views/code/FileAstHashDistinct.java | 2 +- .../views/code/FileContentHashDistinct.java | 2 +- .../views/code/FunctionAstHashDistinct.java | 2 +- .../code/FunctionContentHashDistinct.java | 2 +- .../usi/si/seart/views/code/HashDistinct.java | 4 +- .../seart/views/language/CountByLanguage.java | 6 +-- .../views/language/FileCountByLanguage.java | 2 +- .../language/FunctionCountByLanguage.java | 2 +- .../language/GitRepoCountByLanguage.java | 2 +- .../resources/ValidationMessages.properties | 8 +-- .../usi/si/seart/model/code/CodeTest.java | 4 +- .../validation/constraints/HashTest.java | 2 +- .../constraints/NullOrNotBlankTest.java | 2 +- .../constraints/OWASPEmailTest.java | 2 +- .../validation/constraints/PasswordTest.java | 2 +- dl4se-server/pom.xml | 6 +-- .../ch/usi/si/seart/server}/Application.java | 2 +- .../bean/ConfigurationInitializingBean.java | 6 +-- .../bean/DirectoryInitializationBean.java | 2 +- .../server/bean/TaskRunnerRecoveryBean.java | 8 +-- .../usi/si/seart/server/config/JpaConfig.java | 6 +-- .../usi/si/seart/server/config/JwtConfig.java | 14 ++--- .../si/seart/server/config/MainConfig.java | 4 +- .../seart/server/config/SchedulerConfig.java | 22 ++++---- .../seart/server/config/SecurityConfig.java | 12 ++--- .../usi/si/seart/server/config/WebConfig.java | 12 ++--- .../context/ConfigurationEnvironment.java | 4 +- .../server/controller/AdminController.java | 32 ++++++------ .../ExceptionHandlerController.java | 6 +-- .../server/controller/LanguageController.java | 6 +-- .../server/controller/RootController.java | 2 +- .../controller/StatisticsController.java | 12 ++--- .../server/controller/TaskController.java | 36 ++++++------- .../server/controller/UserController.java | 28 +++++----- .../DtoToConfigurationConverter.java | 6 +-- .../server/converter/DtoToUserConverter.java | 6 +-- ...TaskSearchDtoToSpecificationConverter.java | 8 +-- .../TaskToCodeSpecificationConverter.java | 26 +++++----- ...UserSearchDtoToSpecificationConverter.java | 8 +-- .../UserToUserPrincipalConverter.java | 6 +-- .../si/seart/server/dto/ConfigurationDto.java | 2 +- .../usi/si/seart/server/dto/LoginDto.java | 6 +-- .../usi/si/seart/server/dto/RegisterDto.java | 6 +-- .../usi/si/seart/server/dto/task/TaskDto.java | 2 +- .../seart/server/dto/task/TaskSearchDto.java | 2 +- .../si/seart/server/dto/user/EmailDto.java | 4 +- .../si/seart/server/dto/user/PasswordDto.java | 4 +- .../seart/server/dto/user/UserSearchDto.java | 2 +- .../ConfigurationNotFoundException.java | 4 +- .../exception/EntityNotFoundException.java | 2 +- .../exception/LanguageNotFoundException.java | 4 +- .../server/exception/TaskFailedException.java | 4 +- .../exception/TaskNotFoundException.java | 4 +- .../exception/TokenExpiredException.java | 4 +- .../exception/TokenNotFoundException.java | 4 +- .../exception/UserNotFoundException.java | 4 +- .../seart/server/jackson/PageSerializer.java | 2 +- .../server/jackson/PaginationModule.java | 2 +- .../seart/server/jackson/SortSerializer.java | 2 +- .../server/repository/CodeRepository.java | 6 +-- .../repository/ConfigurationRepository.java | 4 +- .../server/repository/FileRepository.java | 8 +-- .../server/repository/FunctionRepository.java | 8 +-- .../server/repository/GitRepoRepository.java | 8 +-- .../server/repository/LanguageRepository.java | 4 +- .../repository/TableRowCountRepository.java | 4 +- .../server/repository/TaskRepository.java | 10 ++-- .../server/repository/TokenRepository.java | 6 +-- .../server/repository/UserRepository.java | 4 +- .../JpaStreamableSpecificationRepository.java | 2 +- ...StreamableSpecificationRepositoryImpl.java | 2 +- .../server/scheduling/RepoMaintainer.java | 6 +-- .../seart/server/scheduling/TaskCleaner.java | 8 +-- .../seart/server/scheduling/TaskRunner.java | 22 ++++---- .../server/scheduling/ViewMaintainer.java | 4 +- .../seart/server/security/UserPrincipal.java | 4 +- .../annotation/AdminRestController.java | 2 +- .../server/security/jwt/JwtRequestFilter.java | 2 +- .../server/security/jwt/JwtTokenProvider.java | 4 +- .../si/seart/server/service/CodeService.java | 6 +-- .../server/service/ConfigurationService.java | 6 +-- .../seart/server/service/DatabaseService.java | 2 +- .../seart/server/service/DownloadService.java | 18 +++---- .../si/seart/server/service/EmailService.java | 6 +-- .../server/service/FileSystemService.java | 4 +- .../seart/server/service/GitRepoService.java | 6 +-- .../seart/server/service/LanguageService.java | 10 ++-- .../server/service/PasswordResetService.java | 18 +++---- .../server/service/StatisticsService.java | 32 ++++++------ .../si/seart/server/service/TaskService.java | 20 +++---- .../si/seart/server/service/UserService.java | 12 ++--- .../server/service/VerificationService.java | 18 +++---- .../server/util/unit/ReadableFileSize.java | 2 +- .../src/main/resources/application.properties | 3 +- pom.xml | 2 +- 219 files changed, 601 insertions(+), 600 deletions(-) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/Analyzer.java (86%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/LocalClone.java (85%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/count/AbstractCounter.java (91%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/count/CharacterCounter.java (91%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/count/CodeTokenCounter.java (93%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/count/Counter.java (83%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/count/JavaTokenCounter.java (96%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/count/LineCounter.java (97%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/count/PythonCodeTokenCounter.java (93%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/count/PythonTokenCounter.java (95%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/count/TokenCounter.java (95%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/count/TraverseCounter.java (96%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/enumerator/BoilerplateEnumerator.java (83%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/enumerator/Enumerator.java (72%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumerator.java (93%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumerator.java (97%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/hash/ContentHasher.java (95%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/hash/Hasher.java (83%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/hash/SHA256Hasher.java (96%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/hash/SyntaxTreeHasher.java (94%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/io/NullFilteredReader.java (96%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicate.java (79%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicate.java (82%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/predicate/node/NodePredicate.java (91%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/predicate/path/JavaTestFilePredicate.java (94%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/predicate/path/PythonTestFilePredicate.java (93%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/predicate/path/TestFilePredicate.java (94%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/printer/AbstractPrinter.java (94%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/printer/NodePrinter.java (96%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java (91%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/printer/Printer.java (82%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/printer/SymbolicExpressionPrinter.java (87%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java (93%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/query/Queries.java (91%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/query/multi/JavaMultiCaptureQueries.java (95%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java (96%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/query/multi/PythonMultiCaptureQueries.java (94%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/query/single/JavaSingleCaptureQueries.java (92%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/query/single/PythonSingleCaptureQueries.java (96%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/query/single/SingleCaptureQueries.java (94%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/util/stream/DelimiterSuffixedStringCollector.java (96%) rename dl4se-analyzer/src/main/java/{ => ch}/usi/si/seart/analyzer/util/stream/MinimumSizeLimitCollector.java (97%) rename dl4se-analyzer/src/test/java/{ => ch}/usi/si/seart/analyzer/count/JavaCharacterCounterTest.java (93%) rename dl4se-analyzer/src/test/java/{ => ch}/usi/si/seart/analyzer/count/JavaCodeTokenCounterTest.java (93%) rename dl4se-analyzer/src/test/java/{ => ch}/usi/si/seart/analyzer/count/JavaLineCounterTest.java (94%) rename dl4se-analyzer/src/test/java/{ => ch}/usi/si/seart/analyzer/count/JavaTokenCounterTest.java (93%) rename dl4se-analyzer/src/test/java/{ => ch}/usi/si/seart/analyzer/count/PythonCodeTokenCounterTest.java (92%) rename dl4se-analyzer/src/test/java/{ => ch}/usi/si/seart/analyzer/count/PythonTokenCounterTest.java (93%) rename dl4se-analyzer/src/test/java/{ => ch}/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java (97%) rename dl4se-analyzer/src/test/java/{ => ch}/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java (98%) rename dl4se-analyzer/src/test/java/{ => ch}/usi/si/seart/analyzer/hash/JavaContentHasherTest.java (97%) rename dl4se-analyzer/src/test/java/{ => ch}/usi/si/seart/analyzer/hash/JavaHasherTest.java (96%) rename dl4se-analyzer/src/test/java/{ => ch}/usi/si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java (98%) rename dl4se-analyzer/src/test/java/{ => ch}/usi/si/seart/analyzer/io/NullFilteredReaderTest.java (91%) rename dl4se-analyzer/src/test/java/{ => ch}/usi/si/seart/analyzer/io/ReaderTest.java (95%) rename dl4se-analyzer/src/test/java/{ => ch}/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicateTest.java (96%) rename dl4se-analyzer/src/test/java/{ => ch}/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicateTest.java (97%) rename dl4se-analyzer/src/test/java/{ => ch}/usi/si/seart/analyzer/predicate/node/PredicateTest.java (81%) rename dl4se-analyzer/src/test/java/{ => ch}/usi/si/seart/analyzer/predicate/path/JavaTestFilePredicateTest.java (97%) rename dl4se-analyzer/src/test/java/{ => ch}/usi/si/seart/analyzer/predicate/path/PythonTestFilePredicateTest.java (96%) rename dl4se-analyzer/src/test/java/{ => ch}/usi/si/seart/analyzer/predicate/path/TestFilePredicateTest.java (96%) rename dl4se-analyzer/src/test/java/{ => ch}/usi/si/seart/analyzer/printer/NodePrinterTest.java (95%) rename dl4se-analyzer/src/test/java/{ => ch}/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinterTest.java (98%) rename dl4se-analyzer/src/test/java/{ => ch}/usi/si/seart/analyzer/printer/SymbolicExpressionPrinterTest.java (98%) rename dl4se-analyzer/src/test/java/{ => ch}/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java (99%) rename dl4se-analyzer/src/test/java/{ => ch}/usi/si/seart/analyzer/test/BaseTest.java (97%) rename dl4se-analyzer/src/test/java/{ => ch}/usi/si/seart/analyzer/test/JavaBaseTest.java (98%) rename dl4se-analyzer/src/test/java/{ => ch}/usi/si/seart/analyzer/test/PythonBaseTest.java (96%) rename dl4se-analyzer/src/test/java/{ => ch}/usi/si/seart/analyzer/util/stream/DelimiterSuffixedStringCollectorTest.java (96%) rename {dl4se-server/src/main/java/usi/si/seart/server => dl4se-crawler/src/main/java/ch/usi/si/seart/crawler}/Application.java (89%) rename dl4se-crawler/src/main/java/{ => ch}/usi/si/seart/crawler/bean/CrawlJobInitializingBean.java (85%) rename dl4se-crawler/src/main/java/{ => ch}/usi/si/seart/crawler/bean/LanguageInitializingBean.java (91%) rename dl4se-crawler/src/main/java/{ => ch}/usi/si/seart/crawler/bean/NativeLibraryLoaderBean.java (91%) rename dl4se-crawler/src/main/java/{ => ch}/usi/si/seart/crawler/component/CodeCrawler.java (92%) rename dl4se-crawler/src/main/java/{ => ch}/usi/si/seart/crawler/component/HttpClient.java (95%) rename dl4se-crawler/src/main/java/{ => ch}/usi/si/seart/crawler/config/ConverterConfig.java (84%) rename dl4se-crawler/src/main/java/{ => ch}/usi/si/seart/crawler/config/CrawlerConfig.java (98%) rename dl4se-crawler/src/main/java/{ => ch}/usi/si/seart/crawler/config/HttpConfig.java (98%) rename dl4se-crawler/src/main/java/{ => ch}/usi/si/seart/crawler/config/JpaConfig.java (64%) rename dl4se-crawler/src/main/java/{ => ch}/usi/si/seart/crawler/config/SchedulerConfig.java (95%) rename dl4se-crawler/src/main/java/{ => ch}/usi/si/seart/crawler/converter/DateToLocalDateTimeConverter.java (89%) rename dl4se-crawler/src/main/java/{ => ch}/usi/si/seart/crawler/converter/SearchResultDtoToGitRepoConverter.java (90%) rename dl4se-crawler/src/main/java/{ => ch}/usi/si/seart/crawler/dto/SearchResultDto.java (96%) rename dl4se-crawler/src/main/java/{ => ch}/usi/si/seart/crawler/git/Git.java (99%) rename dl4se-crawler/src/main/java/{ => ch}/usi/si/seart/crawler/git/GitException.java (75%) rename dl4se-crawler/src/main/java/{ => ch}/usi/si/seart/crawler/io/ExtensionBasedFileVisitor.java (99%) rename dl4se-crawler/src/main/java/{ => ch}/usi/si/seart/crawler/repository/CrawlJobRepository.java (68%) rename dl4se-crawler/src/main/java/{ => ch}/usi/si/seart/crawler/repository/FileRepository.java (87%) rename dl4se-crawler/src/main/java/{ => ch}/usi/si/seart/crawler/repository/GitRepoRepository.java (89%) rename dl4se-crawler/src/main/java/{ => ch}/usi/si/seart/crawler/repository/LanguageRepository.java (77%) rename dl4se-crawler/src/main/java/{ => ch}/usi/si/seart/crawler/service/CrawlJobService.java (87%) rename dl4se-crawler/src/main/java/{ => ch}/usi/si/seart/crawler/service/FileService.java (88%) rename dl4se-crawler/src/main/java/{ => ch}/usi/si/seart/crawler/service/GitRepoService.java (87%) rename dl4se-crawler/src/main/java/{ => ch}/usi/si/seart/crawler/service/LanguageService.java (82%) rename dl4se-crawler/src/test/java/{ => ch}/usi/si/seart/git/GitTest.java (98%) rename dl4se-crawler/src/test/java/{ => ch}/usi/si/seart/io/ExtensionBasedFileVisitorTest.java (96%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/model/Configuration.java (95%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/model/GitRepo.java (94%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/model/Language.java (98%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/model/code/Boilerplate.java (98%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/model/code/Code.java (93%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/model/code/File.java (97%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/model/code/Function.java (96%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/model/job/CrawlJob.java (93%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/model/job/Job.java (55%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/model/task/Status.java (92%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/model/task/Task.java (95%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/model/type/StringEnumType.java (95%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/model/user/Role.java (51%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/model/user/User.java (93%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/model/user/token/DownloadToken.java (94%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/model/user/token/PasswordResetToken.java (94%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/model/user/token/Token.java (95%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/model/user/token/VerificationToken.java (94%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/validation/constraints/Hash.java (90%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/validation/constraints/NullOrNotBlank.java (89%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/validation/constraints/OWASPEmail.java (92%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/validation/constraints/Password.java (91%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/views/GroupedCount.java (91%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/views/TableRowCount.java (97%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/views/code/FileAstHashDistinct.java (82%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/views/code/FileContentHashDistinct.java (83%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/views/code/FunctionAstHashDistinct.java (83%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/views/code/FunctionContentHashDistinct.java (84%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/views/code/HashDistinct.java (92%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/views/language/CountByLanguage.java (92%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/views/language/FileCountByLanguage.java (81%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/views/language/FunctionCountByLanguage.java (82%) rename dl4se-model/src/main/java/{ => ch}/usi/si/seart/views/language/GitRepoCountByLanguage.java (82%) rename dl4se-model/src/test/java/{ => ch}/usi/si/seart/model/code/CodeTest.java (93%) rename dl4se-model/src/test/java/{ => ch}/usi/si/seart/validation/constraints/HashTest.java (97%) rename dl4se-model/src/test/java/{ => ch}/usi/si/seart/validation/constraints/NullOrNotBlankTest.java (97%) rename dl4se-model/src/test/java/{ => ch}/usi/si/seart/validation/constraints/OWASPEmailTest.java (97%) rename dl4se-model/src/test/java/{ => ch}/usi/si/seart/validation/constraints/PasswordTest.java (97%) rename {dl4se-crawler/src/main/java/usi/si/seart/crawler => dl4se-server/src/main/java/ch/usi/si/seart/server}/Application.java (89%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/bean/ConfigurationInitializingBean.java (91%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/bean/DirectoryInitializationBean.java (96%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/bean/TaskRunnerRecoveryBean.java (82%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/config/JpaConfig.java (65%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/config/JwtConfig.java (83%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/config/MainConfig.java (91%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/config/SchedulerConfig.java (89%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/config/SecurityConfig.java (95%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/config/WebConfig.java (74%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/context/ConfigurationEnvironment.java (90%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/controller/AdminController.java (86%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/controller/ExceptionHandlerController.java (93%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/controller/LanguageController.java (87%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/controller/RootController.java (88%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/controller/StatisticsController.java (93%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/controller/TaskController.java (89%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/controller/UserController.java (89%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/converter/DtoToConfigurationConverter.java (76%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/converter/DtoToUserConverter.java (78%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/converter/TaskSearchDtoToSpecificationConverter.java (82%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/converter/TaskToCodeSpecificationConverter.java (96%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/converter/UserSearchDtoToSpecificationConverter.java (90%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/converter/UserToUserPrincipalConverter.java (81%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/dto/ConfigurationDto.java (92%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/dto/LoginDto.java (71%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/dto/RegisterDto.java (77%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/dto/task/TaskDto.java (95%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/dto/task/TaskSearchDto.java (94%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/dto/user/EmailDto.java (77%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/dto/user/PasswordDto.java (78%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/dto/user/UserSearchDto.java (95%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/exception/ConfigurationNotFoundException.java (76%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/exception/EntityNotFoundException.java (94%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/exception/LanguageNotFoundException.java (76%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/exception/TaskFailedException.java (91%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/exception/TaskNotFoundException.java (75%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/exception/TokenExpiredException.java (73%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/exception/TokenNotFoundException.java (74%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/exception/UserNotFoundException.java (75%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/jackson/PageSerializer.java (96%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/jackson/PaginationModule.java (88%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/jackson/SortSerializer.java (96%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/repository/CodeRepository.java (72%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/repository/ConfigurationRepository.java (63%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/repository/FileRepository.java (66%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/repository/FunctionRepository.java (66%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/repository/GitRepoRepository.java (71%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/repository/LanguageRepository.java (72%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/repository/TableRowCountRepository.java (63%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/repository/TaskRepository.java (89%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/repository/TokenRepository.java (67%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/repository/UserRepository.java (83%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/repository/specification/JpaStreamableSpecificationRepository.java (86%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/repository/specification/JpaStreamableSpecificationRepositoryImpl.java (97%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/scheduling/RepoMaintainer.java (92%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/scheduling/TaskCleaner.java (82%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/scheduling/TaskRunner.java (94%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/scheduling/ViewMaintainer.java (87%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/security/UserPrincipal.java (94%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/security/annotation/AdminRestController.java (89%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/security/jwt/JwtRequestFilter.java (98%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/security/jwt/JwtTokenProvider.java (93%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/service/CodeService.java (88%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/service/ConfigurationService.java (96%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/service/DatabaseService.java (98%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/service/DownloadService.java (77%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/service/EmailService.java (96%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/service/FileSystemService.java (96%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/service/GitRepoService.java (88%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/service/LanguageService.java (79%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/service/PasswordResetService.java (82%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/service/StatisticsService.java (86%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/service/TaskService.java (93%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/service/UserService.java (88%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/service/VerificationService.java (80%) rename dl4se-server/src/main/java/{ => ch}/usi/si/seart/server/util/unit/ReadableFileSize.java (95%) diff --git a/dl4se-analyzer/pom.xml b/dl4se-analyzer/pom.xml index 159a5075..7076b0e9 100644 --- a/dl4se-analyzer/pom.xml +++ b/dl4se-analyzer/pom.xml @@ -3,7 +3,7 @@ 4.0.0 dl4se - usi.si.seart + ch.usi.si.seart ${revision} ../pom.xml @@ -18,7 +18,7 @@ - usi.si.seart + ch.usi.si.seart dl4se-model ${project.version} diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/Analyzer.java similarity index 86% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/Analyzer.java index c7c1400a..82e5bdeb 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/Analyzer.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/Analyzer.java @@ -1,5 +1,29 @@ -package usi.si.seart.analyzer; - +package ch.usi.si.seart.analyzer; + +import ch.usi.si.seart.analyzer.count.CharacterCounter; +import ch.usi.si.seart.analyzer.count.CodeTokenCounter; +import ch.usi.si.seart.analyzer.count.Counter; +import ch.usi.si.seart.analyzer.count.LineCounter; +import ch.usi.si.seart.analyzer.count.TokenCounter; +import ch.usi.si.seart.analyzer.enumerator.BoilerplateEnumerator; +import ch.usi.si.seart.analyzer.enumerator.Enumerator; +import ch.usi.si.seart.analyzer.hash.ContentHasher; +import ch.usi.si.seart.analyzer.hash.Hasher; +import ch.usi.si.seart.analyzer.hash.SyntaxTreeHasher; +import ch.usi.si.seart.analyzer.io.NullFilteredReader; +import ch.usi.si.seart.analyzer.predicate.node.ContainsErrorPredicate; +import ch.usi.si.seart.analyzer.predicate.node.ContainsNonAsciiPredicate; +import ch.usi.si.seart.analyzer.predicate.node.NodePredicate; +import ch.usi.si.seart.analyzer.predicate.path.TestFilePredicate; +import ch.usi.si.seart.analyzer.printer.NodePrinter; +import ch.usi.si.seart.analyzer.printer.OffsetSyntaxTreePrinter; +import ch.usi.si.seart.analyzer.printer.Printer; +import ch.usi.si.seart.analyzer.printer.SymbolicExpressionPrinter; +import ch.usi.si.seart.analyzer.printer.SyntaxTreePrinter; +import ch.usi.si.seart.analyzer.query.multi.MultiCaptureQueries; +import ch.usi.si.seart.model.code.Boilerplate; +import ch.usi.si.seart.model.code.File; +import ch.usi.si.seart.model.code.Function; import ch.usi.si.seart.treesitter.Language; import ch.usi.si.seart.treesitter.Node; import ch.usi.si.seart.treesitter.Parser; @@ -12,30 +36,6 @@ import lombok.Getter; import lombok.experimental.FieldDefaults; import org.apache.commons.lang3.tuple.Pair; -import usi.si.seart.analyzer.count.CharacterCounter; -import usi.si.seart.analyzer.count.CodeTokenCounter; -import usi.si.seart.analyzer.count.Counter; -import usi.si.seart.analyzer.count.LineCounter; -import usi.si.seart.analyzer.count.TokenCounter; -import usi.si.seart.analyzer.enumerator.BoilerplateEnumerator; -import usi.si.seart.analyzer.enumerator.Enumerator; -import usi.si.seart.analyzer.hash.ContentHasher; -import usi.si.seart.analyzer.hash.Hasher; -import usi.si.seart.analyzer.hash.SyntaxTreeHasher; -import usi.si.seart.analyzer.io.NullFilteredReader; -import usi.si.seart.analyzer.predicate.node.ContainsErrorPredicate; -import usi.si.seart.analyzer.predicate.node.ContainsNonAsciiPredicate; -import usi.si.seart.analyzer.predicate.node.NodePredicate; -import usi.si.seart.analyzer.predicate.path.TestFilePredicate; -import usi.si.seart.analyzer.printer.NodePrinter; -import usi.si.seart.analyzer.printer.OffsetSyntaxTreePrinter; -import usi.si.seart.analyzer.printer.Printer; -import usi.si.seart.analyzer.printer.SymbolicExpressionPrinter; -import usi.si.seart.analyzer.printer.SyntaxTreePrinter; -import usi.si.seart.analyzer.query.multi.MultiCaptureQueries; -import usi.si.seart.model.code.Boilerplate; -import usi.si.seart.model.code.File; -import usi.si.seart.model.code.Function; import java.io.FileReader; import java.io.IOException; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/LocalClone.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/LocalClone.java similarity index 85% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/LocalClone.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/LocalClone.java index 85b3c4d4..fac4d21f 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/LocalClone.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/LocalClone.java @@ -1,10 +1,10 @@ -package usi.si.seart.analyzer; +package ch.usi.si.seart.analyzer; +import ch.usi.si.seart.model.GitRepo; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.experimental.FieldDefaults; -import usi.si.seart.model.GitRepo; import java.nio.file.Path; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/AbstractCounter.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/AbstractCounter.java similarity index 91% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/AbstractCounter.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/AbstractCounter.java index c4c38419..785449bd 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/AbstractCounter.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/AbstractCounter.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.count; +package ch.usi.si.seart.analyzer.count; import ch.usi.si.seart.treesitter.Node; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CharacterCounter.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/CharacterCounter.java similarity index 91% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CharacterCounter.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/CharacterCounter.java index 66c3f4da..97338aeb 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CharacterCounter.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/CharacterCounter.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.count; +package ch.usi.si.seart.analyzer.count; import ch.usi.si.seart.treesitter.Node; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CodeTokenCounter.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/CodeTokenCounter.java similarity index 93% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CodeTokenCounter.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/CodeTokenCounter.java index e531c703..e616a391 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/CodeTokenCounter.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/CodeTokenCounter.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.count; +package ch.usi.si.seart.analyzer.count; import ch.usi.si.seart.treesitter.Language; import ch.usi.si.seart.treesitter.Node; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/Counter.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/Counter.java similarity index 83% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/Counter.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/Counter.java index ce6affc5..a2cb99d9 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/Counter.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/Counter.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.count; +package ch.usi.si.seart.analyzer.count; import ch.usi.si.seart.treesitter.Node; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/JavaTokenCounter.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/JavaTokenCounter.java similarity index 96% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/JavaTokenCounter.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/JavaTokenCounter.java index 894bc7a8..2eca40f6 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/JavaTokenCounter.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/JavaTokenCounter.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.count; +package ch.usi.si.seart.analyzer.count; import ch.usi.si.seart.treesitter.Node; import org.apache.commons.lang3.StringUtils; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/LineCounter.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/LineCounter.java similarity index 97% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/LineCounter.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/LineCounter.java index 9965a926..aadb8f1d 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/LineCounter.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/LineCounter.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.count; +package ch.usi.si.seart.analyzer.count; import ch.usi.si.seart.treesitter.Node; import ch.usi.si.seart.treesitter.Point; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/PythonCodeTokenCounter.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/PythonCodeTokenCounter.java similarity index 93% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/PythonCodeTokenCounter.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/PythonCodeTokenCounter.java index 8ece76bc..cbf351cf 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/PythonCodeTokenCounter.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/PythonCodeTokenCounter.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.count; +package ch.usi.si.seart.analyzer.count; import ch.usi.si.seart.treesitter.Node; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/PythonTokenCounter.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/PythonTokenCounter.java similarity index 95% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/PythonTokenCounter.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/PythonTokenCounter.java index d6c4e244..498e855f 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/PythonTokenCounter.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/PythonTokenCounter.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.count; +package ch.usi.si.seart.analyzer.count; import ch.usi.si.seart.treesitter.Node; import org.apache.commons.lang3.StringUtils; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TokenCounter.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/TokenCounter.java similarity index 95% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TokenCounter.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/TokenCounter.java index ccee7b9d..23c944d4 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TokenCounter.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/TokenCounter.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.count; +package ch.usi.si.seart.analyzer.count; import ch.usi.si.seart.treesitter.Language; import ch.usi.si.seart.treesitter.Node; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TraverseCounter.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/TraverseCounter.java similarity index 96% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TraverseCounter.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/TraverseCounter.java index 1baf141d..2ad83584 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/count/TraverseCounter.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/count/TraverseCounter.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.count; +package ch.usi.si.seart.analyzer.count; import ch.usi.si.seart.treesitter.Node; import ch.usi.si.seart.treesitter.TreeCursor; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/BoilerplateEnumerator.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/enumerator/BoilerplateEnumerator.java similarity index 83% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/BoilerplateEnumerator.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/enumerator/BoilerplateEnumerator.java index f9ab5bd6..3f830dac 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/BoilerplateEnumerator.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/enumerator/BoilerplateEnumerator.java @@ -1,7 +1,7 @@ -package usi.si.seart.analyzer.enumerator; +package ch.usi.si.seart.analyzer.enumerator; +import ch.usi.si.seart.model.code.Boilerplate; import ch.usi.si.seart.treesitter.Language; -import usi.si.seart.model.code.Boilerplate; public abstract class BoilerplateEnumerator implements Enumerator { diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/Enumerator.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/enumerator/Enumerator.java similarity index 72% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/Enumerator.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/enumerator/Enumerator.java index 3c3ca81c..ee891426 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/Enumerator.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/enumerator/Enumerator.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.enumerator; +package ch.usi.si.seart.analyzer.enumerator; import ch.usi.si.seart.treesitter.Node; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumerator.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumerator.java similarity index 93% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumerator.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumerator.java index 76492f8f..cbba7bb9 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumerator.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumerator.java @@ -1,7 +1,7 @@ -package usi.si.seart.analyzer.enumerator; +package ch.usi.si.seart.analyzer.enumerator; +import ch.usi.si.seart.model.code.Boilerplate; import ch.usi.si.seart.treesitter.Node; -import usi.si.seart.model.code.Boilerplate; public class JavaBoilerplateEnumerator extends BoilerplateEnumerator { diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumerator.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumerator.java similarity index 97% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumerator.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumerator.java index 8f218f9f..88d61c77 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumerator.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumerator.java @@ -1,7 +1,7 @@ -package usi.si.seart.analyzer.enumerator; +package ch.usi.si.seart.analyzer.enumerator; +import ch.usi.si.seart.model.code.Boilerplate; import ch.usi.si.seart.treesitter.Node; -import usi.si.seart.model.code.Boilerplate; public class PythonBoilerplateEnumerator extends BoilerplateEnumerator { diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/hash/ContentHasher.java similarity index 95% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/hash/ContentHasher.java index 299f3030..a969a99d 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/ContentHasher.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/hash/ContentHasher.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.hash; +package ch.usi.si.seart.analyzer.hash; import ch.usi.si.seart.treesitter.Node; import ch.usi.si.seart.treesitter.TreeCursor; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/Hasher.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/hash/Hasher.java similarity index 83% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/Hasher.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/hash/Hasher.java index 7d5fd20a..6a0ec185 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/Hasher.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/hash/Hasher.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.hash; +package ch.usi.si.seart.analyzer.hash; import ch.usi.si.seart.treesitter.Node; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SHA256Hasher.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/hash/SHA256Hasher.java similarity index 96% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SHA256Hasher.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/hash/SHA256Hasher.java index a84ef800..6d02183a 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SHA256Hasher.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/hash/SHA256Hasher.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.hash; +package ch.usi.si.seart.analyzer.hash; import ch.usi.si.seart.treesitter.Node; import lombok.SneakyThrows; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SyntaxTreeHasher.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/hash/SyntaxTreeHasher.java similarity index 94% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SyntaxTreeHasher.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/hash/SyntaxTreeHasher.java index 384e3582..505de19c 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/hash/SyntaxTreeHasher.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/hash/SyntaxTreeHasher.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.hash; +package ch.usi.si.seart.analyzer.hash; import ch.usi.si.seart.treesitter.Node; import ch.usi.si.seart.treesitter.TreeCursor; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/io/NullFilteredReader.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/io/NullFilteredReader.java similarity index 96% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/io/NullFilteredReader.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/io/NullFilteredReader.java index e5c5b8c4..49c26eb8 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/io/NullFilteredReader.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/io/NullFilteredReader.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.io; +package ch.usi.si.seart.analyzer.io; import java.io.FilterReader; import java.io.IOException; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicate.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicate.java similarity index 79% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicate.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicate.java index b97c9ee7..88158441 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicate.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicate.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.predicate.node; +package ch.usi.si.seart.analyzer.predicate.node; import ch.usi.si.seart.treesitter.Node; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicate.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicate.java similarity index 82% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicate.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicate.java index 436510af..4e7bbc82 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicate.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicate.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.predicate.node; +package ch.usi.si.seart.analyzer.predicate.node; import ch.usi.si.seart.treesitter.Node; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/NodePredicate.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/predicate/node/NodePredicate.java similarity index 91% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/NodePredicate.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/predicate/node/NodePredicate.java index 36a0a158..22f04115 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/node/NodePredicate.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/predicate/node/NodePredicate.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.predicate.node; +package ch.usi.si.seart.analyzer.predicate.node; import ch.usi.si.seart.treesitter.Node; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/path/JavaTestFilePredicate.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/predicate/path/JavaTestFilePredicate.java similarity index 94% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/path/JavaTestFilePredicate.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/predicate/path/JavaTestFilePredicate.java index bd9515e9..53501caf 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/path/JavaTestFilePredicate.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/predicate/path/JavaTestFilePredicate.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.predicate.path; +package ch.usi.si.seart.analyzer.predicate.path; import java.nio.file.FileSystems; import java.nio.file.Path; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/path/PythonTestFilePredicate.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/predicate/path/PythonTestFilePredicate.java similarity index 93% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/path/PythonTestFilePredicate.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/predicate/path/PythonTestFilePredicate.java index b543dcf0..ebe9dc64 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/path/PythonTestFilePredicate.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/predicate/path/PythonTestFilePredicate.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.predicate.path; +package ch.usi.si.seart.analyzer.predicate.path; import java.nio.file.FileSystems; import java.nio.file.Path; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/path/TestFilePredicate.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/predicate/path/TestFilePredicate.java similarity index 94% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/path/TestFilePredicate.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/predicate/path/TestFilePredicate.java index 81fc2d79..32b37c42 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/predicate/path/TestFilePredicate.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/predicate/path/TestFilePredicate.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.predicate.path; +package ch.usi.si.seart.analyzer.predicate.path; import ch.usi.si.seart.treesitter.Language; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/AbstractPrinter.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/printer/AbstractPrinter.java similarity index 94% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/AbstractPrinter.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/printer/AbstractPrinter.java index ab3a8502..f001b66f 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/AbstractPrinter.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/printer/AbstractPrinter.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.printer; +package ch.usi.si.seart.analyzer.printer; import ch.usi.si.seart.treesitter.Node; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/printer/NodePrinter.java similarity index 96% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/printer/NodePrinter.java index 014a8e20..86ef0cab 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/NodePrinter.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/printer/NodePrinter.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.printer; +package ch.usi.si.seart.analyzer.printer; import ch.usi.si.seart.treesitter.Node; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java similarity index 91% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java index 286a2a7a..fb8b4fe6 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinter.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.printer; +package ch.usi.si.seart.analyzer.printer; import ch.usi.si.seart.treesitter.Node; import ch.usi.si.seart.treesitter.OffsetTreeCursor; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/Printer.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/printer/Printer.java similarity index 82% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/Printer.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/printer/Printer.java index 35635d12..d90aaeeb 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/Printer.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/printer/Printer.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.printer; +package ch.usi.si.seart.analyzer.printer; import ch.usi.si.seart.treesitter.Node; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinter.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/printer/SymbolicExpressionPrinter.java similarity index 87% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinter.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/printer/SymbolicExpressionPrinter.java index c41a0bd0..04b6a948 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinter.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/printer/SymbolicExpressionPrinter.java @@ -1,7 +1,7 @@ -package usi.si.seart.analyzer.printer; +package ch.usi.si.seart.analyzer.printer; +import ch.usi.si.seart.analyzer.util.stream.MinimumSizeLimitCollector; import ch.usi.si.seart.treesitter.Node; -import usi.si.seart.analyzer.util.stream.MinimumSizeLimitCollector; import java.util.stream.Collector; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java similarity index 93% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java index b4e22287..d3ca85a0 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/printer/SyntaxTreePrinter.java @@ -1,11 +1,11 @@ -package usi.si.seart.analyzer.printer; +package ch.usi.si.seart.analyzer.printer; +import ch.usi.si.seart.analyzer.util.stream.MinimumSizeLimitCollector; import ch.usi.si.seart.treesitter.Node; import ch.usi.si.seart.treesitter.TreeCursor; import ch.usi.si.seart.treesitter.printer.TreePrinter; import ch.usi.si.seart.treesitter.printer.XMLPrinter; import lombok.Cleanup; -import usi.si.seart.analyzer.util.stream.MinimumSizeLimitCollector; import java.util.stream.Collector; import java.util.stream.Stream; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/Queries.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/query/Queries.java similarity index 91% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/Queries.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/query/Queries.java index 4fb9b5bb..df67d61b 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/Queries.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/query/Queries.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.query; +package ch.usi.si.seart.analyzer.query; import ch.usi.si.seart.treesitter.Node; import ch.usi.si.seart.treesitter.Query; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/JavaMultiCaptureQueries.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/query/multi/JavaMultiCaptureQueries.java similarity index 95% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/JavaMultiCaptureQueries.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/query/multi/JavaMultiCaptureQueries.java index b84e2331..2364d8db 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/JavaMultiCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/query/multi/JavaMultiCaptureQueries.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.query.multi; +package ch.usi.si.seart.analyzer.query.multi; import ch.usi.si.seart.treesitter.Language; import ch.usi.si.seart.treesitter.Node; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java similarity index 96% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java index f75f27b6..a1b2d919 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/query/multi/MultiCaptureQueries.java @@ -1,5 +1,6 @@ -package usi.si.seart.analyzer.query.multi; +package ch.usi.si.seart.analyzer.query.multi; +import ch.usi.si.seart.analyzer.query.Queries; import ch.usi.si.seart.treesitter.Capture; import ch.usi.si.seart.treesitter.Language; import ch.usi.si.seart.treesitter.Node; @@ -10,7 +11,6 @@ import lombok.AllArgsConstructor; import lombok.Cleanup; import org.apache.commons.lang3.tuple.Pair; -import usi.si.seart.analyzer.query.Queries; import java.util.ArrayList; import java.util.Collection; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/PythonMultiCaptureQueries.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/query/multi/PythonMultiCaptureQueries.java similarity index 94% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/PythonMultiCaptureQueries.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/query/multi/PythonMultiCaptureQueries.java index 173c05a4..dc9d7b18 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/multi/PythonMultiCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/query/multi/PythonMultiCaptureQueries.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.query.multi; +package ch.usi.si.seart.analyzer.query.multi; import ch.usi.si.seart.treesitter.Language; import ch.usi.si.seart.treesitter.Node; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/JavaSingleCaptureQueries.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/query/single/JavaSingleCaptureQueries.java similarity index 92% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/JavaSingleCaptureQueries.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/query/single/JavaSingleCaptureQueries.java index 0a3ff080..52ff720b 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/JavaSingleCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/query/single/JavaSingleCaptureQueries.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.query.single; +package ch.usi.si.seart.analyzer.query.single; import ch.usi.si.seart.treesitter.Language; import ch.usi.si.seart.treesitter.Node; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/PythonSingleCaptureQueries.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/query/single/PythonSingleCaptureQueries.java similarity index 96% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/PythonSingleCaptureQueries.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/query/single/PythonSingleCaptureQueries.java index adbd61c8..b0981d9d 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/PythonSingleCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/query/single/PythonSingleCaptureQueries.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.query.single; +package ch.usi.si.seart.analyzer.query.single; import ch.usi.si.seart.treesitter.Language; import ch.usi.si.seart.treesitter.Node; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/SingleCaptureQueries.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/query/single/SingleCaptureQueries.java similarity index 94% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/SingleCaptureQueries.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/query/single/SingleCaptureQueries.java index f8fa31ee..c03c4cbf 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/query/single/SingleCaptureQueries.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/query/single/SingleCaptureQueries.java @@ -1,5 +1,6 @@ -package usi.si.seart.analyzer.query.single; +package ch.usi.si.seart.analyzer.query.single; +import ch.usi.si.seart.analyzer.query.Queries; import ch.usi.si.seart.treesitter.Language; import ch.usi.si.seart.treesitter.Node; import ch.usi.si.seart.treesitter.Query; @@ -8,7 +9,6 @@ import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Cleanup; -import usi.si.seart.analyzer.query.Queries; import java.util.Collection; import java.util.Collections; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/util/stream/DelimiterSuffixedStringCollector.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/util/stream/DelimiterSuffixedStringCollector.java similarity index 96% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/util/stream/DelimiterSuffixedStringCollector.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/util/stream/DelimiterSuffixedStringCollector.java index aa96d27a..2ddc5721 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/util/stream/DelimiterSuffixedStringCollector.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/util/stream/DelimiterSuffixedStringCollector.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.util.stream; +package ch.usi.si.seart.analyzer.util.stream; import lombok.AccessLevel; import lombok.AllArgsConstructor; diff --git a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/util/stream/MinimumSizeLimitCollector.java b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/util/stream/MinimumSizeLimitCollector.java similarity index 97% rename from dl4se-analyzer/src/main/java/usi/si/seart/analyzer/util/stream/MinimumSizeLimitCollector.java rename to dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/util/stream/MinimumSizeLimitCollector.java index 32396157..085ff499 100644 --- a/dl4se-analyzer/src/main/java/usi/si/seart/analyzer/util/stream/MinimumSizeLimitCollector.java +++ b/dl4se-analyzer/src/main/java/ch/usi/si/seart/analyzer/util/stream/MinimumSizeLimitCollector.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.util.stream; +package ch.usi.si.seart.analyzer.util.stream; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCharacterCounterTest.java b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/count/JavaCharacterCounterTest.java similarity index 93% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCharacterCounterTest.java rename to dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/count/JavaCharacterCounterTest.java index 2e0e3b03..ddcc1f9f 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCharacterCounterTest.java +++ b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/count/JavaCharacterCounterTest.java @@ -1,9 +1,9 @@ -package usi.si.seart.analyzer.count; +package ch.usi.si.seart.analyzer.count; +import ch.usi.si.seart.analyzer.test.JavaBaseTest; import ch.usi.si.seart.treesitter.Node; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import usi.si.seart.analyzer.test.JavaBaseTest; import java.util.HashSet; @@ -36,4 +36,4 @@ void countChildrenTest() { // Remove 2 for the space in string and comment Assertions.assertEquals(getJoinedTokens().length() - 2, actual, message); } -} \ No newline at end of file +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCodeTokenCounterTest.java b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/count/JavaCodeTokenCounterTest.java similarity index 93% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCodeTokenCounterTest.java rename to dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/count/JavaCodeTokenCounterTest.java index 9e15ee71..f46fb87f 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaCodeTokenCounterTest.java +++ b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/count/JavaCodeTokenCounterTest.java @@ -1,9 +1,9 @@ -package usi.si.seart.analyzer.count; +package ch.usi.si.seart.analyzer.count; +import ch.usi.si.seart.analyzer.test.JavaBaseTest; import ch.usi.si.seart.treesitter.Node; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import usi.si.seart.analyzer.test.JavaBaseTest; import java.util.HashSet; @@ -36,4 +36,4 @@ void countChildrenTest() { // Remove 1 for the comment node Assertions.assertEquals(getNodes().size() - 1, actual, message); } -} \ No newline at end of file +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaLineCounterTest.java b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/count/JavaLineCounterTest.java similarity index 94% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaLineCounterTest.java rename to dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/count/JavaLineCounterTest.java index ed71363e..6cbffe6f 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaLineCounterTest.java +++ b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/count/JavaLineCounterTest.java @@ -1,11 +1,11 @@ -package usi.si.seart.analyzer.count; +package ch.usi.si.seart.analyzer.count; +import ch.usi.si.seart.analyzer.test.JavaBaseTest; import ch.usi.si.seart.treesitter.Node; import ch.usi.si.seart.treesitter.Tree; import lombok.Cleanup; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import usi.si.seart.analyzer.test.JavaBaseTest; import java.util.HashSet; @@ -49,4 +49,4 @@ void countChildrenOnSameLineTest() { Long actual = counter.count(comment, class_declaration); Assertions.assertEquals(input.lines().count(), actual); } -} \ No newline at end of file +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaTokenCounterTest.java b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/count/JavaTokenCounterTest.java similarity index 93% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaTokenCounterTest.java rename to dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/count/JavaTokenCounterTest.java index 28e77e5a..cee51da5 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/JavaTokenCounterTest.java +++ b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/count/JavaTokenCounterTest.java @@ -1,9 +1,9 @@ -package usi.si.seart.analyzer.count; +package ch.usi.si.seart.analyzer.count; +import ch.usi.si.seart.analyzer.test.JavaBaseTest; import ch.usi.si.seart.treesitter.Node; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import usi.si.seart.analyzer.test.JavaBaseTest; import java.util.HashSet; @@ -36,4 +36,4 @@ void countChildrenTest() { // Add 2 for the individual comment words Assertions.assertEquals(getNodes().size() + 2, actual, message); } -} \ No newline at end of file +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/PythonCodeTokenCounterTest.java b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/count/PythonCodeTokenCounterTest.java similarity index 92% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/PythonCodeTokenCounterTest.java rename to dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/count/PythonCodeTokenCounterTest.java index e3e195a8..055e03c0 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/PythonCodeTokenCounterTest.java +++ b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/count/PythonCodeTokenCounterTest.java @@ -1,9 +1,9 @@ -package usi.si.seart.analyzer.count; +package ch.usi.si.seart.analyzer.count; +import ch.usi.si.seart.analyzer.test.PythonBaseTest; import ch.usi.si.seart.treesitter.Node; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import usi.si.seart.analyzer.test.PythonBaseTest; import java.util.HashSet; @@ -36,4 +36,4 @@ void countChildrenTest() { // Remove 1 for the comment node Assertions.assertEquals(getNodes().size() - 1, actual, message); } -} \ No newline at end of file +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/PythonTokenCounterTest.java b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/count/PythonTokenCounterTest.java similarity index 93% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/PythonTokenCounterTest.java rename to dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/count/PythonTokenCounterTest.java index aec1ebbd..c1217d2b 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/count/PythonTokenCounterTest.java +++ b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/count/PythonTokenCounterTest.java @@ -1,9 +1,9 @@ -package usi.si.seart.analyzer.count; +package ch.usi.si.seart.analyzer.count; +import ch.usi.si.seart.analyzer.test.PythonBaseTest; import ch.usi.si.seart.treesitter.Node; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import usi.si.seart.analyzer.test.PythonBaseTest; import java.util.HashSet; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java similarity index 97% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java rename to dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java index 51a07a23..12014e60 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java +++ b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/enumerator/JavaBoilerplateEnumeratorTest.java @@ -1,5 +1,6 @@ -package usi.si.seart.analyzer.enumerator; +package ch.usi.si.seart.analyzer.enumerator; +import ch.usi.si.seart.model.code.Boilerplate; import ch.usi.si.seart.treesitter.Language; import ch.usi.si.seart.treesitter.Node; import ch.usi.si.seart.treesitter.Parser; @@ -11,7 +12,6 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.ArgumentsProvider; import org.junit.jupiter.params.provider.ArgumentsSource; -import usi.si.seart.model.code.Boilerplate; import java.util.stream.Stream; @@ -56,4 +56,4 @@ void asEnumTest(String source, Boilerplate expected) { Boilerplate actual = enumerator.asEnum(callable_declaration); Assertions.assertEquals(expected, actual); } -} \ No newline at end of file +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java similarity index 98% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java rename to dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java index d3155c97..1793e96c 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java +++ b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/enumerator/PythonBoilerplateEnumeratorTest.java @@ -1,5 +1,6 @@ -package usi.si.seart.analyzer.enumerator; +package ch.usi.si.seart.analyzer.enumerator; +import ch.usi.si.seart.model.code.Boilerplate; import ch.usi.si.seart.treesitter.Language; import ch.usi.si.seart.treesitter.Node; import ch.usi.si.seart.treesitter.Parser; @@ -11,7 +12,6 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.ArgumentsProvider; import org.junit.jupiter.params.provider.ArgumentsSource; -import usi.si.seart.model.code.Boilerplate; import java.util.List; import java.util.stream.Stream; @@ -154,4 +154,4 @@ void asEnumTestSpecial(String source, Boilerplate expected) { Boilerplate actual = enumerator.asEnum(function_definition); Assertions.assertEquals(expected, actual); } -} \ No newline at end of file +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaContentHasherTest.java b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/hash/JavaContentHasherTest.java similarity index 97% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaContentHasherTest.java rename to dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/hash/JavaContentHasherTest.java index 3d53d1cd..b5ee327f 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaContentHasherTest.java +++ b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/hash/JavaContentHasherTest.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.hash; +package ch.usi.si.seart.analyzer.hash; import ch.usi.si.seart.treesitter.Tree; import org.junit.jupiter.api.Assertions; @@ -52,4 +52,4 @@ void noCommentImpactTest() { String expected = hasher_2.hash(other.getRootNode()); Assertions.assertEquals(expected, actual, "Comments should not impact the hashing result!"); } -} \ No newline at end of file +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaHasherTest.java b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/hash/JavaHasherTest.java similarity index 96% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaHasherTest.java rename to dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/hash/JavaHasherTest.java index b4ec7419..3b1dcc2a 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaHasherTest.java +++ b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/hash/JavaHasherTest.java @@ -1,7 +1,7 @@ -package usi.si.seart.analyzer.hash; +package ch.usi.si.seart.analyzer.hash; +import ch.usi.si.seart.analyzer.test.JavaBaseTest; import lombok.SneakyThrows; -import usi.si.seart.analyzer.test.JavaBaseTest; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java similarity index 98% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java rename to dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java index 5be49487..cb6c20af 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java +++ b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/hash/JavaSyntaxTreeHasherTest.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.hash; +package ch.usi.si.seart.analyzer.hash; import ch.usi.si.seart.treesitter.Tree; import org.junit.jupiter.api.Assertions; @@ -57,4 +57,4 @@ void noCommentImpactTest() { protected Charset getCharset() { return Charset.defaultCharset(); } -} \ No newline at end of file +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/io/NullFilteredReaderTest.java b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/io/NullFilteredReaderTest.java similarity index 91% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/io/NullFilteredReaderTest.java rename to dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/io/NullFilteredReaderTest.java index 06768896..a9ebe727 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/io/NullFilteredReaderTest.java +++ b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/io/NullFilteredReaderTest.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.io; +package ch.usi.si.seart.analyzer.io; import java.io.Reader; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/io/ReaderTest.java b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/io/ReaderTest.java similarity index 95% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/io/ReaderTest.java rename to dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/io/ReaderTest.java index 0b91ca4f..a25aa423 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/io/ReaderTest.java +++ b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/io/ReaderTest.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.io; +package ch.usi.si.seart.analyzer.io; import com.google.common.io.CharStreams; import lombok.Cleanup; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicateTest.java b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicateTest.java similarity index 96% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicateTest.java rename to dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicateTest.java index 700b68e8..554f5f7f 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicateTest.java +++ b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/predicate/node/ContainsErrorPredicateTest.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.predicate.node; +package ch.usi.si.seart.analyzer.predicate.node; import ch.usi.si.seart.treesitter.Language; import ch.usi.si.seart.treesitter.Node; @@ -47,4 +47,4 @@ void anyContainsErrorTest() { boolean result = predicate.test(declaration, function_definition); Assertions.assertTrue(result); } -} \ No newline at end of file +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicateTest.java b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicateTest.java similarity index 97% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicateTest.java rename to dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicateTest.java index dd35e9ec..0ed36e07 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicateTest.java +++ b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/predicate/node/ContainsNonAsciiPredicateTest.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.predicate.node; +package ch.usi.si.seart.analyzer.predicate.node; import ch.usi.si.seart.treesitter.Node; import ch.usi.si.seart.treesitter.Tree; @@ -52,4 +52,4 @@ void anyContainsNonAscii() { boolean result = predicate.test(package_declaration, class_declaration); Assertions.assertTrue(result); } -} \ No newline at end of file +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/PredicateTest.java b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/predicate/node/PredicateTest.java similarity index 81% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/PredicateTest.java rename to dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/predicate/node/PredicateTest.java index a65578f8..4880e2b5 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/node/PredicateTest.java +++ b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/predicate/node/PredicateTest.java @@ -1,6 +1,6 @@ -package usi.si.seart.analyzer.predicate.node; +package ch.usi.si.seart.analyzer.predicate.node; -import usi.si.seart.analyzer.test.JavaBaseTest; +import ch.usi.si.seart.analyzer.test.JavaBaseTest; public abstract class PredicateTest extends JavaBaseTest { diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/JavaTestFilePredicateTest.java b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/predicate/path/JavaTestFilePredicateTest.java similarity index 97% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/JavaTestFilePredicateTest.java rename to dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/predicate/path/JavaTestFilePredicateTest.java index 9382be55..9f15bcb8 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/JavaTestFilePredicateTest.java +++ b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/predicate/path/JavaTestFilePredicateTest.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.predicate.path; +package ch.usi.si.seart.analyzer.predicate.path; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.extension.ExtensionContext; @@ -40,4 +40,4 @@ void pathPredicateTest(Path path, boolean expected) { Predicate predicate = new JavaTestFilePredicate(); Assertions.assertEquals(expected, predicate.test(path)); } -} \ No newline at end of file +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/PythonTestFilePredicateTest.java b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/predicate/path/PythonTestFilePredicateTest.java similarity index 96% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/PythonTestFilePredicateTest.java rename to dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/predicate/path/PythonTestFilePredicateTest.java index 4c87b0ff..07c42722 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/PythonTestFilePredicateTest.java +++ b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/predicate/path/PythonTestFilePredicateTest.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.predicate.path; +package ch.usi.si.seart.analyzer.predicate.path; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.extension.ExtensionContext; @@ -36,4 +36,4 @@ void pathPredicateTest(Path path, boolean expected) { Predicate predicate = new PythonTestFilePredicate(); Assertions.assertEquals(expected, predicate.test(path)); } -} \ No newline at end of file +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/TestFilePredicateTest.java b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/predicate/path/TestFilePredicateTest.java similarity index 96% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/TestFilePredicateTest.java rename to dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/predicate/path/TestFilePredicateTest.java index c6074e7b..664e637a 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/predicate/path/TestFilePredicateTest.java +++ b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/predicate/path/TestFilePredicateTest.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.predicate.path; +package ch.usi.si.seart.analyzer.predicate.path; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.extension.ExtensionContext; @@ -34,4 +34,4 @@ void pathPredicateTest(Path path, boolean expected) { Predicate predicate = new TestFilePredicate() {}; Assertions.assertEquals(expected, predicate.test(path)); } -} \ No newline at end of file +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/printer/NodePrinterTest.java similarity index 95% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java rename to dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/printer/NodePrinterTest.java index 7bb06338..6044db3b 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/NodePrinterTest.java +++ b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/printer/NodePrinterTest.java @@ -1,9 +1,9 @@ -package usi.si.seart.analyzer.printer; +package ch.usi.si.seart.analyzer.printer; +import ch.usi.si.seart.analyzer.test.JavaBaseTest; import ch.usi.si.seart.treesitter.Node; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import usi.si.seart.analyzer.test.JavaBaseTest; import java.util.HashSet; @@ -58,4 +58,4 @@ void printMultipleTest() { "}"; Assertions.assertEquals(expected, actual); } -} \ No newline at end of file +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinterTest.java b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinterTest.java similarity index 98% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinterTest.java rename to dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinterTest.java index e6944bff..fa6bfbe0 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinterTest.java +++ b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/printer/OffsetSyntaxTreePrinterTest.java @@ -1,10 +1,10 @@ -package usi.si.seart.analyzer.printer; +package ch.usi.si.seart.analyzer.printer; +import ch.usi.si.seart.analyzer.test.JavaBaseTest; import ch.usi.si.seart.treesitter.Node; import ch.usi.si.seart.treesitter.Point; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import usi.si.seart.analyzer.test.JavaBaseTest; class OffsetSyntaxTreePrinterTest extends JavaBaseTest { @@ -113,4 +113,4 @@ void offsetTest() { OffsetSyntaxTreePrinter.TAG_CLOSE; Assertions.assertEquals(expected, actual); } -} \ No newline at end of file +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinterTest.java b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/printer/SymbolicExpressionPrinterTest.java similarity index 98% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinterTest.java rename to dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/printer/SymbolicExpressionPrinterTest.java index 9b545668..6130c505 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SymbolicExpressionPrinterTest.java +++ b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/printer/SymbolicExpressionPrinterTest.java @@ -1,9 +1,9 @@ -package usi.si.seart.analyzer.printer; +package ch.usi.si.seart.analyzer.printer; +import ch.usi.si.seart.analyzer.test.JavaBaseTest; import ch.usi.si.seart.treesitter.Node; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import usi.si.seart.analyzer.test.JavaBaseTest; import java.util.HashSet; @@ -168,4 +168,4 @@ void printMultipleTest() { ")"; Assertions.assertEquals(expected, actual); } -} \ No newline at end of file +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java similarity index 99% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java rename to dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java index 7ea05840..79e46146 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java +++ b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/printer/SyntaxTreePrinterTest.java @@ -1,9 +1,9 @@ -package usi.si.seart.analyzer.printer; +package ch.usi.si.seart.analyzer.printer; +import ch.usi.si.seart.analyzer.test.JavaBaseTest; import ch.usi.si.seart.treesitter.Node; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import usi.si.seart.analyzer.test.JavaBaseTest; import java.util.HashSet; @@ -216,4 +216,4 @@ void printMultipleTest() { SyntaxTreePrinter.TAG_CLOSE; Assertions.assertEquals(expected, actual); } -} \ No newline at end of file +} diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/test/BaseTest.java similarity index 97% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java rename to dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/test/BaseTest.java index 8db76888..4e138866 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/BaseTest.java +++ b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/test/BaseTest.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.test; +package ch.usi.si.seart.analyzer.test; import ch.usi.si.seart.treesitter.Language; import ch.usi.si.seart.treesitter.LibraryLoader; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/JavaBaseTest.java b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/test/JavaBaseTest.java similarity index 98% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/JavaBaseTest.java rename to dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/test/JavaBaseTest.java index 2f02afa9..c4d9dc6a 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/JavaBaseTest.java +++ b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/test/JavaBaseTest.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.test; +package ch.usi.si.seart.analyzer.test; import ch.usi.si.seart.treesitter.Language; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/PythonBaseTest.java b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/test/PythonBaseTest.java similarity index 96% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/PythonBaseTest.java rename to dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/test/PythonBaseTest.java index 97c0ee08..e22f78ec 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/test/PythonBaseTest.java +++ b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/test/PythonBaseTest.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.test; +package ch.usi.si.seart.analyzer.test; import ch.usi.si.seart.treesitter.Language; diff --git a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/util/stream/DelimiterSuffixedStringCollectorTest.java b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/util/stream/DelimiterSuffixedStringCollectorTest.java similarity index 96% rename from dl4se-analyzer/src/test/java/usi/si/seart/analyzer/util/stream/DelimiterSuffixedStringCollectorTest.java rename to dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/util/stream/DelimiterSuffixedStringCollectorTest.java index 8b2bd693..7e703240 100644 --- a/dl4se-analyzer/src/test/java/usi/si/seart/analyzer/util/stream/DelimiterSuffixedStringCollectorTest.java +++ b/dl4se-analyzer/src/test/java/ch/usi/si/seart/analyzer/util/stream/DelimiterSuffixedStringCollectorTest.java @@ -1,4 +1,4 @@ -package usi.si.seart.analyzer.util.stream; +package ch.usi.si.seart.analyzer.util.stream; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -37,4 +37,4 @@ void customEmptyTest() { Stream input = Stream.of(); Assertions.assertEquals(expected, input.collect(new DelimiterSuffixedStringCollector(" ", expected))); } -} \ No newline at end of file +} diff --git a/dl4se-crawler/pom.xml b/dl4se-crawler/pom.xml index 5b85fdb2..a61f41dc 100644 --- a/dl4se-crawler/pom.xml +++ b/dl4se-crawler/pom.xml @@ -3,7 +3,7 @@ 4.0.0 dl4se - usi.si.seart + ch.usi.si.seart ${revision} ../pom.xml @@ -14,17 +14,17 @@ UTF-8 - usi.si.seart.crawler.Application + ch.usi.si.seart.crawler.Application - usi.si.seart + ch.usi.si.seart dl4se-model ${project.version} - usi.si.seart + ch.usi.si.seart dl4se-analyzer ${project.version} diff --git a/dl4se-server/src/main/java/usi/si/seart/server/Application.java b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/Application.java similarity index 89% rename from dl4se-server/src/main/java/usi/si/seart/server/Application.java rename to dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/Application.java index 346043c1..74963890 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/Application.java +++ b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/Application.java @@ -1,4 +1,4 @@ -package usi.si.seart.server; +package ch.usi.si.seart.crawler; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/CrawlJobInitializingBean.java b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/bean/CrawlJobInitializingBean.java similarity index 85% rename from dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/CrawlJobInitializingBean.java rename to dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/bean/CrawlJobInitializingBean.java index fcdd1a3f..33bda777 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/CrawlJobInitializingBean.java +++ b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/bean/CrawlJobInitializingBean.java @@ -1,14 +1,14 @@ -package usi.si.seart.crawler.bean; +package ch.usi.si.seart.crawler.bean; +import ch.usi.si.seart.crawler.repository.CrawlJobRepository; +import ch.usi.si.seart.model.job.CrawlJob; +import ch.usi.si.seart.model.job.Job; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.experimental.FieldDefaults; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import usi.si.seart.crawler.repository.CrawlJobRepository; -import usi.si.seart.model.job.CrawlJob; -import usi.si.seart.model.job.Job; import java.time.LocalDateTime; import java.util.Optional; diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/LanguageInitializingBean.java b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/bean/LanguageInitializingBean.java similarity index 91% rename from dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/LanguageInitializingBean.java rename to dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/bean/LanguageInitializingBean.java index 6ac3412b..0c844ba4 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/LanguageInitializingBean.java +++ b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/bean/LanguageInitializingBean.java @@ -1,5 +1,7 @@ -package usi.si.seart.crawler.bean; +package ch.usi.si.seart.crawler.bean; +import ch.usi.si.seart.crawler.repository.LanguageRepository; +import ch.usi.si.seart.model.Language; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.experimental.FieldDefaults; @@ -9,8 +11,6 @@ import org.springframework.core.io.Resource; import org.springframework.stereotype.Component; import org.yaml.snakeyaml.Yaml; -import usi.si.seart.crawler.repository.LanguageRepository; -import usi.si.seart.model.Language; import java.io.InputStream; import java.util.List; diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/NativeLibraryLoaderBean.java b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/bean/NativeLibraryLoaderBean.java similarity index 91% rename from dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/NativeLibraryLoaderBean.java rename to dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/bean/NativeLibraryLoaderBean.java index 17602dcd..2219da50 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/bean/NativeLibraryLoaderBean.java +++ b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/bean/NativeLibraryLoaderBean.java @@ -1,4 +1,4 @@ -package usi.si.seart.crawler.bean; +package ch.usi.si.seart.crawler.bean; import ch.usi.si.seart.treesitter.LibraryLoader; import lombok.extern.slf4j.Slf4j; diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/component/CodeCrawler.java similarity index 92% rename from dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java rename to dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/component/CodeCrawler.java index cd1b332d..7b587215 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/CodeCrawler.java +++ b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/component/CodeCrawler.java @@ -1,5 +1,20 @@ -package usi.si.seart.crawler.component; +package ch.usi.si.seart.crawler.component; +import ch.usi.si.seart.analyzer.Analyzer; +import ch.usi.si.seart.analyzer.LocalClone; +import ch.usi.si.seart.crawler.config.CrawlerConfig; +import ch.usi.si.seart.crawler.dto.SearchResultDto; +import ch.usi.si.seart.crawler.git.Git; +import ch.usi.si.seart.crawler.git.GitException; +import ch.usi.si.seart.crawler.io.ExtensionBasedFileVisitor; +import ch.usi.si.seart.crawler.service.CrawlJobService; +import ch.usi.si.seart.crawler.service.FileService; +import ch.usi.si.seart.crawler.service.GitRepoService; +import ch.usi.si.seart.crawler.service.LanguageService; +import ch.usi.si.seart.model.GitRepo; +import ch.usi.si.seart.model.Language; +import ch.usi.si.seart.model.code.File; +import ch.usi.si.seart.model.code.Function; import com.google.api.client.http.GenericUrl; import com.google.api.client.http.HttpResponse; import com.google.common.base.Strings; @@ -17,21 +32,6 @@ import org.springframework.core.convert.ConversionService; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; -import usi.si.seart.analyzer.Analyzer; -import usi.si.seart.analyzer.LocalClone; -import usi.si.seart.crawler.config.CrawlerConfig; -import usi.si.seart.crawler.dto.SearchResultDto; -import usi.si.seart.crawler.git.Git; -import usi.si.seart.crawler.git.GitException; -import usi.si.seart.crawler.io.ExtensionBasedFileVisitor; -import usi.si.seart.crawler.service.CrawlJobService; -import usi.si.seart.crawler.service.FileService; -import usi.si.seart.crawler.service.GitRepoService; -import usi.si.seart.crawler.service.LanguageService; -import usi.si.seart.model.GitRepo; -import usi.si.seart.model.Language; -import usi.si.seart.model.code.File; -import usi.si.seart.model.code.Function; import javax.annotation.PostConstruct; import javax.persistence.EntityNotFoundException; @@ -56,7 +56,7 @@ @Slf4j @Component @ConditionalOnExpression( - "#{T(usi.si.seart.model.job.Job).valueOf('${app.crawl-job.type}') == T(usi.si.seart.model.job.Job).CODE}" + "#{T(ch.usi.si.seart.model.job.Job).valueOf('${app.crawl-job.type}') == T(ch.usi.si.seart.model.job.Job).CODE}" ) @RequiredArgsConstructor(onConstructor_ = @Autowired) @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/HttpClient.java b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/component/HttpClient.java similarity index 95% rename from dl4se-crawler/src/main/java/usi/si/seart/crawler/component/HttpClient.java rename to dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/component/HttpClient.java index e6027f98..20cf9b1b 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/component/HttpClient.java +++ b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/component/HttpClient.java @@ -1,5 +1,6 @@ -package usi.si.seart.crawler.component; +package ch.usi.si.seart.crawler.component; +import ch.usi.si.seart.crawler.dto.SearchResultDto; import com.google.api.client.http.GenericUrl; import com.google.api.client.http.HttpRequest; import com.google.api.client.http.HttpRequestFactory; @@ -13,7 +14,6 @@ import lombok.experimental.FieldDefaults; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import usi.si.seart.crawler.dto.SearchResultDto; import java.io.IOException; import java.util.HashMap; diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/ConverterConfig.java b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/config/ConverterConfig.java similarity index 84% rename from dl4se-crawler/src/main/java/usi/si/seart/crawler/config/ConverterConfig.java rename to dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/config/ConverterConfig.java index 2b75cfe6..f7e78fa1 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/ConverterConfig.java +++ b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/config/ConverterConfig.java @@ -1,12 +1,12 @@ -package usi.si.seart.crawler.config; +package ch.usi.si.seart.crawler.config; +import ch.usi.si.seart.crawler.converter.DateToLocalDateTimeConverter; +import ch.usi.si.seart.crawler.converter.SearchResultDtoToGitRepoConverter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.support.ConversionServiceFactoryBean; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.converter.Converter; -import usi.si.seart.crawler.converter.DateToLocalDateTimeConverter; -import usi.si.seart.crawler.converter.SearchResultDtoToGitRepoConverter; import java.util.Set; diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/CrawlerConfig.java b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/config/CrawlerConfig.java similarity index 98% rename from dl4se-crawler/src/main/java/usi/si/seart/crawler/config/CrawlerConfig.java rename to dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/config/CrawlerConfig.java index 58e09bad..a1f127d5 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/CrawlerConfig.java +++ b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/config/CrawlerConfig.java @@ -1,5 +1,6 @@ -package usi.si.seart.crawler.config; +package ch.usi.si.seart.crawler.config; +import ch.usi.si.seart.model.job.Job; import com.google.api.client.http.GenericUrl; import lombok.AccessLevel; import lombok.Getter; @@ -11,7 +12,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.util.unit.DataSize; -import usi.si.seart.model.job.Job; import java.io.BufferedReader; import java.io.FileNotFoundException; diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/HttpConfig.java b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/config/HttpConfig.java similarity index 98% rename from dl4se-crawler/src/main/java/usi/si/seart/crawler/config/HttpConfig.java rename to dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/config/HttpConfig.java index 906b9e04..7cfff8e2 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/HttpConfig.java +++ b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/config/HttpConfig.java @@ -1,4 +1,4 @@ -package usi.si.seart.crawler.config; +package ch.usi.si.seart.crawler.config; import com.google.api.client.http.HttpIOExceptionHandler; import com.google.api.client.http.HttpRequestFactory; diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/JpaConfig.java b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/config/JpaConfig.java similarity index 64% rename from dl4se-crawler/src/main/java/usi/si/seart/crawler/config/JpaConfig.java rename to dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/config/JpaConfig.java index ff6c1fa2..d587a1f9 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/JpaConfig.java +++ b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/config/JpaConfig.java @@ -1,9 +1,9 @@ -package usi.si.seart.crawler.config; +package ch.usi.si.seart.crawler.config; import org.springframework.boot.autoconfigure.domain.EntityScan; import org.springframework.context.annotation.Configuration; @Configuration -@EntityScan(basePackages = "usi.si.seart.model") +@EntityScan(basePackages = "ch.usi.si.seart.model") public class JpaConfig { } diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/SchedulerConfig.java b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/config/SchedulerConfig.java similarity index 95% rename from dl4se-crawler/src/main/java/usi/si/seart/crawler/config/SchedulerConfig.java rename to dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/config/SchedulerConfig.java index 184298b4..97ed2cf5 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/config/SchedulerConfig.java +++ b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/config/SchedulerConfig.java @@ -1,4 +1,4 @@ -package usi.si.seart.crawler.config; +package ch.usi.si.seart.crawler.config; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.task.TaskSchedulerCustomizer; diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/converter/DateToLocalDateTimeConverter.java b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/converter/DateToLocalDateTimeConverter.java similarity index 89% rename from dl4se-crawler/src/main/java/usi/si/seart/crawler/converter/DateToLocalDateTimeConverter.java rename to dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/converter/DateToLocalDateTimeConverter.java index 84378879..bb4a48d2 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/converter/DateToLocalDateTimeConverter.java +++ b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/converter/DateToLocalDateTimeConverter.java @@ -1,4 +1,4 @@ -package usi.si.seart.crawler.converter; +package ch.usi.si.seart.crawler.converter; import org.springframework.core.convert.converter.Converter; diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/converter/SearchResultDtoToGitRepoConverter.java b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/converter/SearchResultDtoToGitRepoConverter.java similarity index 90% rename from dl4se-crawler/src/main/java/usi/si/seart/crawler/converter/SearchResultDtoToGitRepoConverter.java rename to dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/converter/SearchResultDtoToGitRepoConverter.java index 6ce7dcd8..1ecb8d71 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/converter/SearchResultDtoToGitRepoConverter.java +++ b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/converter/SearchResultDtoToGitRepoConverter.java @@ -1,9 +1,9 @@ -package usi.si.seart.crawler.converter; +package ch.usi.si.seart.crawler.converter; +import ch.usi.si.seart.crawler.dto.SearchResultDto; +import ch.usi.si.seart.model.GitRepo; import lombok.AllArgsConstructor; import org.springframework.core.convert.converter.Converter; -import usi.si.seart.crawler.dto.SearchResultDto; -import usi.si.seart.model.GitRepo; import java.util.Date; diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/dto/SearchResultDto.java b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/dto/SearchResultDto.java similarity index 96% rename from dl4se-crawler/src/main/java/usi/si/seart/crawler/dto/SearchResultDto.java rename to dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/dto/SearchResultDto.java index b612d694..40fe00e7 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/dto/SearchResultDto.java +++ b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/dto/SearchResultDto.java @@ -1,12 +1,12 @@ -package usi.si.seart.crawler.dto; +package ch.usi.si.seart.crawler.dto; +import ch.usi.si.seart.model.GitRepo; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import lombok.experimental.FieldDefaults; -import usi.si.seart.model.GitRepo; import java.util.Date; import java.util.List; diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/git/Git.java b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/git/Git.java similarity index 99% rename from dl4se-crawler/src/main/java/usi/si/seart/crawler/git/Git.java rename to dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/git/Git.java index 0e8b3e31..fa73d613 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/git/Git.java +++ b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/git/Git.java @@ -1,12 +1,12 @@ -package usi.si.seart.crawler.git; +package ch.usi.si.seart.crawler.git; +import ch.usi.si.seart.model.Language; import com.google.common.collect.ObjectArrays; import com.google.common.io.CharStreams; import lombok.AccessLevel; import lombok.Getter; import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; -import usi.si.seart.model.Language; import java.io.IOException; import java.io.InputStream; diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/git/GitException.java b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/git/GitException.java similarity index 75% rename from dl4se-crawler/src/main/java/usi/si/seart/crawler/git/GitException.java rename to dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/git/GitException.java index e6e4294c..0879abf7 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/git/GitException.java +++ b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/git/GitException.java @@ -1,4 +1,4 @@ -package usi.si.seart.crawler.git; +package ch.usi.si.seart.crawler.git; import lombok.experimental.StandardException; diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/io/ExtensionBasedFileVisitor.java b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/io/ExtensionBasedFileVisitor.java similarity index 99% rename from dl4se-crawler/src/main/java/usi/si/seart/crawler/io/ExtensionBasedFileVisitor.java rename to dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/io/ExtensionBasedFileVisitor.java index 6b2711b2..3cb76331 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/io/ExtensionBasedFileVisitor.java +++ b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/io/ExtensionBasedFileVisitor.java @@ -1,4 +1,4 @@ -package usi.si.seart.crawler.io; +package ch.usi.si.seart.crawler.io; import lombok.AccessLevel; import lombok.Getter; diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/CrawlJobRepository.java b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/repository/CrawlJobRepository.java similarity index 68% rename from dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/CrawlJobRepository.java rename to dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/repository/CrawlJobRepository.java index bfa02c4e..ec4f17de 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/CrawlJobRepository.java +++ b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/repository/CrawlJobRepository.java @@ -1,8 +1,8 @@ -package usi.si.seart.crawler.repository; +package ch.usi.si.seart.crawler.repository; +import ch.usi.si.seart.model.job.CrawlJob; +import ch.usi.si.seart.model.job.Job; import org.springframework.data.jpa.repository.JpaRepository; -import usi.si.seart.model.job.CrawlJob; -import usi.si.seart.model.job.Job; import javax.validation.constraints.NotNull; import java.util.Optional; diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/FileRepository.java b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/repository/FileRepository.java similarity index 87% rename from dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/FileRepository.java rename to dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/repository/FileRepository.java index f45182dc..8ba22950 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/FileRepository.java +++ b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/repository/FileRepository.java @@ -1,11 +1,11 @@ -package usi.si.seart.crawler.repository; +package ch.usi.si.seart.crawler.repository; +import ch.usi.si.seart.model.GitRepo; +import ch.usi.si.seart.model.code.File; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import usi.si.seart.model.GitRepo; -import usi.si.seart.model.code.File; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/GitRepoRepository.java b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/repository/GitRepoRepository.java similarity index 89% rename from dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/GitRepoRepository.java rename to dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/repository/GitRepoRepository.java index 11576076..746dbf4e 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/GitRepoRepository.java +++ b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/repository/GitRepoRepository.java @@ -1,10 +1,10 @@ -package usi.si.seart.crawler.repository; +package ch.usi.si.seart.crawler.repository; +import ch.usi.si.seart.model.GitRepo; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import usi.si.seart.model.GitRepo; import javax.validation.constraints.NotNull; import java.util.Optional; diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/LanguageRepository.java b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/repository/LanguageRepository.java similarity index 77% rename from dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/LanguageRepository.java rename to dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/repository/LanguageRepository.java index 8b04e282..1fb1cb06 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/repository/LanguageRepository.java +++ b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/repository/LanguageRepository.java @@ -1,7 +1,7 @@ -package usi.si.seart.crawler.repository; +package ch.usi.si.seart.crawler.repository; +import ch.usi.si.seart.model.Language; import org.springframework.data.jpa.repository.JpaRepository; -import usi.si.seart.model.Language; import javax.validation.constraints.NotBlank; import java.util.Optional; diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/CrawlJobService.java b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/service/CrawlJobService.java similarity index 87% rename from dl4se-crawler/src/main/java/usi/si/seart/crawler/service/CrawlJobService.java rename to dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/service/CrawlJobService.java index bbe1812c..77396564 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/CrawlJobService.java +++ b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/service/CrawlJobService.java @@ -1,13 +1,13 @@ -package usi.si.seart.crawler.service; +package ch.usi.si.seart.crawler.service; +import ch.usi.si.seart.crawler.repository.CrawlJobRepository; +import ch.usi.si.seart.model.job.CrawlJob; +import ch.usi.si.seart.model.job.Job; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.experimental.FieldDefaults; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import usi.si.seart.crawler.repository.CrawlJobRepository; -import usi.si.seart.model.job.CrawlJob; -import usi.si.seart.model.job.Job; import java.time.LocalDateTime; import java.util.Optional; diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/FileService.java b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/service/FileService.java similarity index 88% rename from dl4se-crawler/src/main/java/usi/si/seart/crawler/service/FileService.java rename to dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/service/FileService.java index 3291ec6b..032a8590 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/FileService.java +++ b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/service/FileService.java @@ -1,14 +1,14 @@ -package usi.si.seart.crawler.service; +package ch.usi.si.seart.crawler.service; +import ch.usi.si.seart.crawler.repository.FileRepository; +import ch.usi.si.seart.model.GitRepo; +import ch.usi.si.seart.model.code.File; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.experimental.FieldDefaults; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import usi.si.seart.crawler.repository.FileRepository; -import usi.si.seart.model.GitRepo; -import usi.si.seart.model.code.File; import java.nio.file.Path; import java.util.List; diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/GitRepoService.java b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/service/GitRepoService.java similarity index 87% rename from dl4se-crawler/src/main/java/usi/si/seart/crawler/service/GitRepoService.java rename to dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/service/GitRepoService.java index 1f83a833..89a28b3f 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/GitRepoService.java +++ b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/service/GitRepoService.java @@ -1,12 +1,12 @@ -package usi.si.seart.crawler.service; +package ch.usi.si.seart.crawler.service; +import ch.usi.si.seart.crawler.repository.GitRepoRepository; +import ch.usi.si.seart.model.GitRepo; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.experimental.FieldDefaults; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import usi.si.seart.crawler.repository.GitRepoRepository; -import usi.si.seart.model.GitRepo; import javax.persistence.EntityNotFoundException; diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/LanguageService.java b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/service/LanguageService.java similarity index 82% rename from dl4se-crawler/src/main/java/usi/si/seart/crawler/service/LanguageService.java rename to dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/service/LanguageService.java index 2f0e597c..3950f53b 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/service/LanguageService.java +++ b/dl4se-crawler/src/main/java/ch/usi/si/seart/crawler/service/LanguageService.java @@ -1,12 +1,12 @@ -package usi.si.seart.crawler.service; +package ch.usi.si.seart.crawler.service; +import ch.usi.si.seart.crawler.repository.LanguageRepository; +import ch.usi.si.seart.model.Language; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.experimental.FieldDefaults; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import usi.si.seart.crawler.repository.LanguageRepository; -import usi.si.seart.model.Language; import java.util.List; diff --git a/dl4se-crawler/src/main/resources/application.properties b/dl4se-crawler/src/main/resources/application.properties index 39c36184..46f2d88c 100644 --- a/dl4se-crawler/src/main/resources/application.properties +++ b/dl4se-crawler/src/main/resources/application.properties @@ -13,7 +13,7 @@ spring.task.scheduling.pool.size=1 # Logging Configuration logging.level.root=INFO -logging.level.usi.si.seart.crawler=INFO +logging.level.ch.usi.si.seart.crawler=INFO logging.file.path=logs logging.file.name=${logging.file.path}/crawler.log logging.logback.rollingpolicy.max-history=180 diff --git a/dl4se-crawler/src/test/java/usi/si/seart/git/GitTest.java b/dl4se-crawler/src/test/java/ch/usi/si/seart/git/GitTest.java similarity index 98% rename from dl4se-crawler/src/test/java/usi/si/seart/git/GitTest.java rename to dl4se-crawler/src/test/java/ch/usi/si/seart/git/GitTest.java index 1edc41cf..7de52259 100644 --- a/dl4se-crawler/src/test/java/usi/si/seart/git/GitTest.java +++ b/dl4se-crawler/src/test/java/ch/usi/si/seart/git/GitTest.java @@ -1,5 +1,8 @@ -package usi.si.seart.git; +package ch.usi.si.seart.git; +import ch.usi.si.seart.crawler.git.Git; +import ch.usi.si.seart.crawler.git.GitException; +import ch.usi.si.seart.model.Language; import lombok.AccessLevel; import lombok.experimental.FieldDefaults; import lombok.experimental.NonFinal; @@ -9,9 +12,6 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EmptySource; import org.junit.jupiter.params.provider.ValueSource; -import usi.si.seart.crawler.git.Git; -import usi.si.seart.crawler.git.GitException; -import usi.si.seart.model.Language; import java.io.File; import java.io.IOException; @@ -261,4 +261,4 @@ void invalidShallowDateTest() { GitException.class, () -> new Git(testRepoName, tmp, LocalDateTime.of(2022, 2, 14, 0, 0)) ); } -} \ No newline at end of file +} diff --git a/dl4se-crawler/src/test/java/usi/si/seart/io/ExtensionBasedFileVisitorTest.java b/dl4se-crawler/src/test/java/ch/usi/si/seart/io/ExtensionBasedFileVisitorTest.java similarity index 96% rename from dl4se-crawler/src/test/java/usi/si/seart/io/ExtensionBasedFileVisitorTest.java rename to dl4se-crawler/src/test/java/ch/usi/si/seart/io/ExtensionBasedFileVisitorTest.java index aab70028..8b481885 100644 --- a/dl4se-crawler/src/test/java/usi/si/seart/io/ExtensionBasedFileVisitorTest.java +++ b/dl4se-crawler/src/test/java/ch/usi/si/seart/io/ExtensionBasedFileVisitorTest.java @@ -1,5 +1,6 @@ -package usi.si.seart.io; +package ch.usi.si.seart.io; +import ch.usi.si.seart.crawler.io.ExtensionBasedFileVisitor; import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -8,7 +9,6 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.ArgumentsProvider; import org.junit.jupiter.params.provider.ArgumentsSource; -import usi.si.seart.crawler.io.ExtensionBasedFileVisitor; import java.io.IOException; import java.nio.file.Files; @@ -75,4 +75,4 @@ void nullExtensionsTest() { String[] invalid = null; Assertions.assertThrows(NullPointerException.class, () -> ExtensionBasedFileVisitor.forExtensions(invalid)); } -} \ No newline at end of file +} diff --git a/dl4se-model/pom.xml b/dl4se-model/pom.xml index 3581a2cb..ca38d2cc 100644 --- a/dl4se-model/pom.xml +++ b/dl4se-model/pom.xml @@ -3,7 +3,7 @@ 4.0.0 dl4se - usi.si.seart + ch.usi.si.seart ${revision} ../pom.xml diff --git a/dl4se-model/src/main/java/usi/si/seart/model/Configuration.java b/dl4se-model/src/main/java/ch/usi/si/seart/model/Configuration.java similarity index 95% rename from dl4se-model/src/main/java/usi/si/seart/model/Configuration.java rename to dl4se-model/src/main/java/ch/usi/si/seart/model/Configuration.java index 95eb5240..fefa694f 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/Configuration.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/model/Configuration.java @@ -1,4 +1,4 @@ -package usi.si.seart.model; +package ch.usi.si.seart.model; import lombok.AccessLevel; import lombok.AllArgsConstructor; diff --git a/dl4se-model/src/main/java/usi/si/seart/model/GitRepo.java b/dl4se-model/src/main/java/ch/usi/si/seart/model/GitRepo.java similarity index 94% rename from dl4se-model/src/main/java/usi/si/seart/model/GitRepo.java rename to dl4se-model/src/main/java/ch/usi/si/seart/model/GitRepo.java index 34504bb3..ed309935 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/GitRepo.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/model/GitRepo.java @@ -1,5 +1,8 @@ -package usi.si.seart.model; +package ch.usi.si.seart.model; +import ch.usi.si.seart.model.code.File; +import ch.usi.si.seart.model.code.Function; +import ch.usi.si.seart.validation.constraints.NullOrNotBlank; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AccessLevel; @@ -11,9 +14,6 @@ import lombok.ToString; import lombok.experimental.FieldDefaults; import org.hibernate.annotations.DynamicUpdate; -import usi.si.seart.model.code.File; -import usi.si.seart.model.code.Function; -import usi.si.seart.validation.constraints.NullOrNotBlank; import javax.persistence.Column; import javax.persistence.Entity; diff --git a/dl4se-model/src/main/java/usi/si/seart/model/Language.java b/dl4se-model/src/main/java/ch/usi/si/seart/model/Language.java similarity index 98% rename from dl4se-model/src/main/java/usi/si/seart/model/Language.java rename to dl4se-model/src/main/java/ch/usi/si/seart/model/Language.java index ce7bb675..c7895c9d 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/Language.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/model/Language.java @@ -1,4 +1,4 @@ -package usi.si.seart.model; +package ch.usi.si.seart.model; import com.fasterxml.jackson.annotation.JsonIgnore; import io.hypersistence.utils.hibernate.type.array.ListArrayType; diff --git a/dl4se-model/src/main/java/usi/si/seart/model/code/Boilerplate.java b/dl4se-model/src/main/java/ch/usi/si/seart/model/code/Boilerplate.java similarity index 98% rename from dl4se-model/src/main/java/usi/si/seart/model/code/Boilerplate.java rename to dl4se-model/src/main/java/ch/usi/si/seart/model/code/Boilerplate.java index bdf37ae3..7ad02bec 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/code/Boilerplate.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/model/code/Boilerplate.java @@ -1,4 +1,4 @@ -package usi.si.seart.model.code; +package ch.usi.si.seart.model.code; /** * @see Comparable#compareTo(Object) diff --git a/dl4se-model/src/main/java/usi/si/seart/model/code/Code.java b/dl4se-model/src/main/java/ch/usi/si/seart/model/code/Code.java similarity index 93% rename from dl4se-model/src/main/java/usi/si/seart/model/code/Code.java rename to dl4se-model/src/main/java/ch/usi/si/seart/model/code/Code.java index 63fd4b91..60b111cd 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/code/Code.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/model/code/Code.java @@ -1,5 +1,8 @@ -package usi.si.seart.model.code; +package ch.usi.si.seart.model.code; +import ch.usi.si.seart.model.GitRepo; +import ch.usi.si.seart.model.Language; +import ch.usi.si.seart.validation.constraints.Hash; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonUnwrapped; import lombok.AccessLevel; @@ -10,9 +13,6 @@ import lombok.Setter; import lombok.experimental.FieldDefaults; import lombok.experimental.SuperBuilder; -import usi.si.seart.model.GitRepo; -import usi.si.seart.model.Language; -import usi.si.seart.validation.constraints.Hash; import javax.persistence.Column; import javax.persistence.Entity; diff --git a/dl4se-model/src/main/java/usi/si/seart/model/code/File.java b/dl4se-model/src/main/java/ch/usi/si/seart/model/code/File.java similarity index 97% rename from dl4se-model/src/main/java/usi/si/seart/model/code/File.java rename to dl4se-model/src/main/java/ch/usi/si/seart/model/code/File.java index db186971..93725d7a 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/code/File.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/model/code/File.java @@ -1,4 +1,4 @@ -package usi.si.seart.model.code; +package ch.usi.si.seart.model.code; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.AccessLevel; diff --git a/dl4se-model/src/main/java/usi/si/seart/model/code/Function.java b/dl4se-model/src/main/java/ch/usi/si/seart/model/code/Function.java similarity index 96% rename from dl4se-model/src/main/java/usi/si/seart/model/code/Function.java rename to dl4se-model/src/main/java/ch/usi/si/seart/model/code/Function.java index d9aaf445..9cbc69cd 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/code/Function.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/model/code/Function.java @@ -1,5 +1,6 @@ -package usi.si.seart.model.code; +package ch.usi.si.seart.model.code; +import ch.usi.si.seart.model.type.StringEnumType; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AccessLevel; @@ -11,7 +12,6 @@ import org.hibernate.annotations.Type; import org.hibernate.annotations.TypeDef; import org.hibernate.annotations.TypeDefs; -import usi.si.seart.model.type.StringEnumType; import javax.persistence.Basic; import javax.persistence.Column; diff --git a/dl4se-model/src/main/java/usi/si/seart/model/job/CrawlJob.java b/dl4se-model/src/main/java/ch/usi/si/seart/model/job/CrawlJob.java similarity index 93% rename from dl4se-model/src/main/java/usi/si/seart/model/job/CrawlJob.java rename to dl4se-model/src/main/java/ch/usi/si/seart/model/job/CrawlJob.java index e44e317c..e180ded1 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/job/CrawlJob.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/model/job/CrawlJob.java @@ -1,5 +1,6 @@ -package usi.si.seart.model.job; +package ch.usi.si.seart.model.job; +import ch.usi.si.seart.model.type.StringEnumType; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -12,7 +13,6 @@ import org.hibernate.annotations.Type; import org.hibernate.annotations.TypeDef; import org.hibernate.annotations.TypeDefs; -import usi.si.seart.model.type.StringEnumType; import javax.persistence.Basic; import javax.persistence.Column; diff --git a/dl4se-model/src/main/java/usi/si/seart/model/job/Job.java b/dl4se-model/src/main/java/ch/usi/si/seart/model/job/Job.java similarity index 55% rename from dl4se-model/src/main/java/usi/si/seart/model/job/Job.java rename to dl4se-model/src/main/java/ch/usi/si/seart/model/job/Job.java index 1170ff85..9452869c 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/job/Job.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/model/job/Job.java @@ -1,4 +1,4 @@ -package usi.si.seart.model.job; +package ch.usi.si.seart.model.job; public enum Job { CODE, REVIEW, BUG diff --git a/dl4se-model/src/main/java/usi/si/seart/model/task/Status.java b/dl4se-model/src/main/java/ch/usi/si/seart/model/task/Status.java similarity index 92% rename from dl4se-model/src/main/java/usi/si/seart/model/task/Status.java rename to dl4se-model/src/main/java/ch/usi/si/seart/model/task/Status.java index 8c256355..d1f2e363 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/task/Status.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/model/task/Status.java @@ -1,4 +1,4 @@ -package usi.si.seart.model.task; +package ch.usi.si.seart.model.task; import lombok.AccessLevel; import lombok.NoArgsConstructor; diff --git a/dl4se-model/src/main/java/usi/si/seart/model/task/Task.java b/dl4se-model/src/main/java/ch/usi/si/seart/model/task/Task.java similarity index 95% rename from dl4se-model/src/main/java/usi/si/seart/model/task/Task.java rename to dl4se-model/src/main/java/ch/usi/si/seart/model/task/Task.java index 01a2828b..a0285018 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/task/Task.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/model/task/Task.java @@ -1,5 +1,8 @@ -package usi.si.seart.model.task; +package ch.usi.si.seart.model.task; +import ch.usi.si.seart.model.job.Job; +import ch.usi.si.seart.model.type.StringEnumType; +import ch.usi.si.seart.model.user.User; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.JsonNode; @@ -16,9 +19,6 @@ import org.hibernate.annotations.Type; import org.hibernate.annotations.TypeDef; import org.hibernate.annotations.TypeDefs; -import usi.si.seart.model.job.Job; -import usi.si.seart.model.type.StringEnumType; -import usi.si.seart.model.user.User; import javax.persistence.Basic; import javax.persistence.Column; diff --git a/dl4se-model/src/main/java/usi/si/seart/model/type/StringEnumType.java b/dl4se-model/src/main/java/ch/usi/si/seart/model/type/StringEnumType.java similarity index 95% rename from dl4se-model/src/main/java/usi/si/seart/model/type/StringEnumType.java rename to dl4se-model/src/main/java/ch/usi/si/seart/model/type/StringEnumType.java index f9639396..c021a5fb 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/type/StringEnumType.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/model/type/StringEnumType.java @@ -1,4 +1,4 @@ -package usi.si.seart.model.type; +package ch.usi.si.seart.model.type; import org.hibernate.HibernateException; import org.hibernate.engine.spi.SharedSessionContractImplementor; diff --git a/dl4se-model/src/main/java/usi/si/seart/model/user/Role.java b/dl4se-model/src/main/java/ch/usi/si/seart/model/user/Role.java similarity index 51% rename from dl4se-model/src/main/java/usi/si/seart/model/user/Role.java rename to dl4se-model/src/main/java/ch/usi/si/seart/model/user/Role.java index ffc19996..5fad5ef8 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/user/Role.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/model/user/Role.java @@ -1,4 +1,4 @@ -package usi.si.seart.model.user; +package ch.usi.si.seart.model.user; public enum Role { ADMIN, USER diff --git a/dl4se-model/src/main/java/usi/si/seart/model/user/User.java b/dl4se-model/src/main/java/ch/usi/si/seart/model/user/User.java similarity index 93% rename from dl4se-model/src/main/java/usi/si/seart/model/user/User.java rename to dl4se-model/src/main/java/ch/usi/si/seart/model/user/User.java index 717728bb..8140f5fa 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/user/User.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/model/user/User.java @@ -1,5 +1,8 @@ -package usi.si.seart.model.user; +package ch.usi.si.seart.model.user; +import ch.usi.si.seart.model.task.Task; +import ch.usi.si.seart.model.type.StringEnumType; +import ch.usi.si.seart.validation.constraints.OWASPEmail; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -14,9 +17,6 @@ import org.hibernate.annotations.Type; import org.hibernate.annotations.TypeDef; import org.hibernate.annotations.TypeDefs; -import usi.si.seart.model.task.Task; -import usi.si.seart.model.type.StringEnumType; -import usi.si.seart.validation.constraints.OWASPEmail; import javax.persistence.Basic; import javax.persistence.CascadeType; diff --git a/dl4se-model/src/main/java/usi/si/seart/model/user/token/DownloadToken.java b/dl4se-model/src/main/java/ch/usi/si/seart/model/user/token/DownloadToken.java similarity index 94% rename from dl4se-model/src/main/java/usi/si/seart/model/user/token/DownloadToken.java rename to dl4se-model/src/main/java/ch/usi/si/seart/model/user/token/DownloadToken.java index f5ec59bd..62304981 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/user/token/DownloadToken.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/model/user/token/DownloadToken.java @@ -1,4 +1,4 @@ -package usi.si.seart.model.user.token; +package ch.usi.si.seart.model.user.token; import lombok.AccessLevel; import lombok.Getter; diff --git a/dl4se-model/src/main/java/usi/si/seart/model/user/token/PasswordResetToken.java b/dl4se-model/src/main/java/ch/usi/si/seart/model/user/token/PasswordResetToken.java similarity index 94% rename from dl4se-model/src/main/java/usi/si/seart/model/user/token/PasswordResetToken.java rename to dl4se-model/src/main/java/ch/usi/si/seart/model/user/token/PasswordResetToken.java index a73ea0ac..fda4d484 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/user/token/PasswordResetToken.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/model/user/token/PasswordResetToken.java @@ -1,4 +1,4 @@ -package usi.si.seart.model.user.token; +package ch.usi.si.seart.model.user.token; import lombok.AccessLevel; import lombok.Getter; diff --git a/dl4se-model/src/main/java/usi/si/seart/model/user/token/Token.java b/dl4se-model/src/main/java/ch/usi/si/seart/model/user/token/Token.java similarity index 95% rename from dl4se-model/src/main/java/usi/si/seart/model/user/token/Token.java rename to dl4se-model/src/main/java/ch/usi/si/seart/model/user/token/Token.java index 378f6d9e..4545a138 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/user/token/Token.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/model/user/token/Token.java @@ -1,5 +1,6 @@ -package usi.si.seart.model.user.token; +package ch.usi.si.seart.model.user.token; +import ch.usi.si.seart.model.user.User; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -8,7 +9,6 @@ import lombok.Setter; import lombok.experimental.FieldDefaults; import lombok.experimental.SuperBuilder; -import usi.si.seart.model.user.User; import javax.persistence.Column; import javax.persistence.DiscriminatorColumn; diff --git a/dl4se-model/src/main/java/usi/si/seart/model/user/token/VerificationToken.java b/dl4se-model/src/main/java/ch/usi/si/seart/model/user/token/VerificationToken.java similarity index 94% rename from dl4se-model/src/main/java/usi/si/seart/model/user/token/VerificationToken.java rename to dl4se-model/src/main/java/ch/usi/si/seart/model/user/token/VerificationToken.java index 9aa1cd81..499d1216 100644 --- a/dl4se-model/src/main/java/usi/si/seart/model/user/token/VerificationToken.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/model/user/token/VerificationToken.java @@ -1,4 +1,4 @@ -package usi.si.seart.model.user.token; +package ch.usi.si.seart.model.user.token; import lombok.AccessLevel; import lombok.Getter; diff --git a/dl4se-model/src/main/java/usi/si/seart/validation/constraints/Hash.java b/dl4se-model/src/main/java/ch/usi/si/seart/validation/constraints/Hash.java similarity index 90% rename from dl4se-model/src/main/java/usi/si/seart/validation/constraints/Hash.java rename to dl4se-model/src/main/java/ch/usi/si/seart/validation/constraints/Hash.java index f24e2d85..b8582b2c 100644 --- a/dl4se-model/src/main/java/usi/si/seart/validation/constraints/Hash.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/validation/constraints/Hash.java @@ -1,4 +1,4 @@ -package usi.si.seart.validation.constraints; +package ch.usi.si.seart.validation.constraints; import org.hibernate.validator.constraints.CompositionType; import org.hibernate.validator.constraints.ConstraintComposition; @@ -32,7 +32,7 @@ @ReportAsSingleViolation public @interface Hash { - String message() default "{usi.si.seart.validation.constraints.Hash.message}"; + String message() default "{ch.usi.si.seart.validation.constraints.Hash.message}"; Class[] groups() default { }; diff --git a/dl4se-model/src/main/java/usi/si/seart/validation/constraints/NullOrNotBlank.java b/dl4se-model/src/main/java/ch/usi/si/seart/validation/constraints/NullOrNotBlank.java similarity index 89% rename from dl4se-model/src/main/java/usi/si/seart/validation/constraints/NullOrNotBlank.java rename to dl4se-model/src/main/java/ch/usi/si/seart/validation/constraints/NullOrNotBlank.java index 788c4b74..330699cf 100644 --- a/dl4se-model/src/main/java/usi/si/seart/validation/constraints/NullOrNotBlank.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/validation/constraints/NullOrNotBlank.java @@ -1,4 +1,4 @@ -package usi.si.seart.validation.constraints; +package ch.usi.si.seart.validation.constraints; import org.hibernate.validator.constraints.CompositionType; import org.hibernate.validator.constraints.ConstraintComposition; @@ -30,7 +30,7 @@ @ReportAsSingleViolation public @interface NullOrNotBlank { - String message() default "{usi.si.seart.validation.constraints.NullOrNotBlank.message}"; + String message() default "{ch.usi.si.seart.validation.constraints.NullOrNotBlank.message}"; Class[] groups() default { }; diff --git a/dl4se-model/src/main/java/usi/si/seart/validation/constraints/OWASPEmail.java b/dl4se-model/src/main/java/ch/usi/si/seart/validation/constraints/OWASPEmail.java similarity index 92% rename from dl4se-model/src/main/java/usi/si/seart/validation/constraints/OWASPEmail.java rename to dl4se-model/src/main/java/ch/usi/si/seart/validation/constraints/OWASPEmail.java index 39e29e64..c31030ed 100644 --- a/dl4se-model/src/main/java/usi/si/seart/validation/constraints/OWASPEmail.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/validation/constraints/OWASPEmail.java @@ -1,4 +1,4 @@ -package usi.si.seart.validation.constraints; +package ch.usi.si.seart.validation.constraints; import org.hibernate.validator.constraints.CompositionType; import org.hibernate.validator.constraints.ConstraintComposition; @@ -37,7 +37,7 @@ @ReportAsSingleViolation public @interface OWASPEmail { - String message() default "{usi.si.seart.validation.constraints.OWASPEmail.message}"; + String message() default "{ch.usi.si.seart.validation.constraints.OWASPEmail.message}"; Class[] groups() default { }; diff --git a/dl4se-model/src/main/java/usi/si/seart/validation/constraints/Password.java b/dl4se-model/src/main/java/ch/usi/si/seart/validation/constraints/Password.java similarity index 91% rename from dl4se-model/src/main/java/usi/si/seart/validation/constraints/Password.java rename to dl4se-model/src/main/java/ch/usi/si/seart/validation/constraints/Password.java index e974d871..0e7aaefc 100644 --- a/dl4se-model/src/main/java/usi/si/seart/validation/constraints/Password.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/validation/constraints/Password.java @@ -1,4 +1,4 @@ -package usi.si.seart.validation.constraints; +package ch.usi.si.seart.validation.constraints; import org.hibernate.validator.constraints.CompositionType; import org.hibernate.validator.constraints.ConstraintComposition; @@ -38,7 +38,7 @@ @OverridesAttribute(constraint = Pattern.class, name = "regexp") String regexp() default "^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?\\d).{6,20}$"; - String message() default "{usi.si.seart.validation.constraints.Password.message}"; + String message() default "{ch.usi.si.seart.validation.constraints.Password.message}"; Class[] groups() default { }; diff --git a/dl4se-model/src/main/java/usi/si/seart/views/GroupedCount.java b/dl4se-model/src/main/java/ch/usi/si/seart/views/GroupedCount.java similarity index 91% rename from dl4se-model/src/main/java/usi/si/seart/views/GroupedCount.java rename to dl4se-model/src/main/java/ch/usi/si/seart/views/GroupedCount.java index 3d942d72..5c299bd2 100644 --- a/dl4se-model/src/main/java/usi/si/seart/views/GroupedCount.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/views/GroupedCount.java @@ -1,4 +1,4 @@ -package usi.si.seart.views; +package ch.usi.si.seart.views; import java.util.Map; diff --git a/dl4se-model/src/main/java/usi/si/seart/views/TableRowCount.java b/dl4se-model/src/main/java/ch/usi/si/seart/views/TableRowCount.java similarity index 97% rename from dl4se-model/src/main/java/usi/si/seart/views/TableRowCount.java rename to dl4se-model/src/main/java/ch/usi/si/seart/views/TableRowCount.java index d58b3adf..d0f0b686 100644 --- a/dl4se-model/src/main/java/usi/si/seart/views/TableRowCount.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/views/TableRowCount.java @@ -1,4 +1,4 @@ -package usi.si.seart.views; +package ch.usi.si.seart.views; import lombok.AccessLevel; import lombok.AllArgsConstructor; diff --git a/dl4se-model/src/main/java/usi/si/seart/views/code/FileAstHashDistinct.java b/dl4se-model/src/main/java/ch/usi/si/seart/views/code/FileAstHashDistinct.java similarity index 82% rename from dl4se-model/src/main/java/usi/si/seart/views/code/FileAstHashDistinct.java rename to dl4se-model/src/main/java/ch/usi/si/seart/views/code/FileAstHashDistinct.java index ed2b23cf..5592bcd7 100644 --- a/dl4se-model/src/main/java/usi/si/seart/views/code/FileAstHashDistinct.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/views/code/FileAstHashDistinct.java @@ -1,4 +1,4 @@ -package usi.si.seart.views.code; +package ch.usi.si.seart.views.code; import javax.persistence.Entity; import javax.persistence.Table; diff --git a/dl4se-model/src/main/java/usi/si/seart/views/code/FileContentHashDistinct.java b/dl4se-model/src/main/java/ch/usi/si/seart/views/code/FileContentHashDistinct.java similarity index 83% rename from dl4se-model/src/main/java/usi/si/seart/views/code/FileContentHashDistinct.java rename to dl4se-model/src/main/java/ch/usi/si/seart/views/code/FileContentHashDistinct.java index 88316356..975731db 100644 --- a/dl4se-model/src/main/java/usi/si/seart/views/code/FileContentHashDistinct.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/views/code/FileContentHashDistinct.java @@ -1,4 +1,4 @@ -package usi.si.seart.views.code; +package ch.usi.si.seart.views.code; import javax.persistence.Entity; import javax.persistence.Table; diff --git a/dl4se-model/src/main/java/usi/si/seart/views/code/FunctionAstHashDistinct.java b/dl4se-model/src/main/java/ch/usi/si/seart/views/code/FunctionAstHashDistinct.java similarity index 83% rename from dl4se-model/src/main/java/usi/si/seart/views/code/FunctionAstHashDistinct.java rename to dl4se-model/src/main/java/ch/usi/si/seart/views/code/FunctionAstHashDistinct.java index 5cb70c69..5872e120 100644 --- a/dl4se-model/src/main/java/usi/si/seart/views/code/FunctionAstHashDistinct.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/views/code/FunctionAstHashDistinct.java @@ -1,4 +1,4 @@ -package usi.si.seart.views.code; +package ch.usi.si.seart.views.code; import javax.persistence.Entity; import javax.persistence.Table; diff --git a/dl4se-model/src/main/java/usi/si/seart/views/code/FunctionContentHashDistinct.java b/dl4se-model/src/main/java/ch/usi/si/seart/views/code/FunctionContentHashDistinct.java similarity index 84% rename from dl4se-model/src/main/java/usi/si/seart/views/code/FunctionContentHashDistinct.java rename to dl4se-model/src/main/java/ch/usi/si/seart/views/code/FunctionContentHashDistinct.java index 18e452cd..90b4d2d8 100644 --- a/dl4se-model/src/main/java/usi/si/seart/views/code/FunctionContentHashDistinct.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/views/code/FunctionContentHashDistinct.java @@ -1,4 +1,4 @@ -package usi.si.seart.views.code; +package ch.usi.si.seart.views.code; import javax.persistence.Entity; import javax.persistence.Table; diff --git a/dl4se-model/src/main/java/usi/si/seart/views/code/HashDistinct.java b/dl4se-model/src/main/java/ch/usi/si/seart/views/code/HashDistinct.java similarity index 92% rename from dl4se-model/src/main/java/usi/si/seart/views/code/HashDistinct.java rename to dl4se-model/src/main/java/ch/usi/si/seart/views/code/HashDistinct.java index 72688b48..6ce0622b 100644 --- a/dl4se-model/src/main/java/usi/si/seart/views/code/HashDistinct.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/views/code/HashDistinct.java @@ -1,12 +1,12 @@ -package usi.si.seart.views.code; +package ch.usi.si.seart.views.code; +import ch.usi.si.seart.validation.constraints.Hash; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.experimental.FieldDefaults; import org.hibernate.annotations.Immutable; -import usi.si.seart.validation.constraints.Hash; import javax.persistence.Entity; import javax.persistence.Id; diff --git a/dl4se-model/src/main/java/usi/si/seart/views/language/CountByLanguage.java b/dl4se-model/src/main/java/ch/usi/si/seart/views/language/CountByLanguage.java similarity index 92% rename from dl4se-model/src/main/java/usi/si/seart/views/language/CountByLanguage.java rename to dl4se-model/src/main/java/ch/usi/si/seart/views/language/CountByLanguage.java index cb9baf50..33cd6d56 100644 --- a/dl4se-model/src/main/java/usi/si/seart/views/language/CountByLanguage.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/views/language/CountByLanguage.java @@ -1,13 +1,13 @@ -package usi.si.seart.views.language; +package ch.usi.si.seart.views.language; +import ch.usi.si.seart.model.Language; +import ch.usi.si.seart.views.GroupedCount; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.experimental.FieldDefaults; import org.hibernate.annotations.Immutable; -import usi.si.seart.model.Language; -import usi.si.seart.views.GroupedCount; import javax.persistence.Column; import javax.persistence.Entity; diff --git a/dl4se-model/src/main/java/usi/si/seart/views/language/FileCountByLanguage.java b/dl4se-model/src/main/java/ch/usi/si/seart/views/language/FileCountByLanguage.java similarity index 81% rename from dl4se-model/src/main/java/usi/si/seart/views/language/FileCountByLanguage.java rename to dl4se-model/src/main/java/ch/usi/si/seart/views/language/FileCountByLanguage.java index 341e0c8a..f4fe5da6 100644 --- a/dl4se-model/src/main/java/usi/si/seart/views/language/FileCountByLanguage.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/views/language/FileCountByLanguage.java @@ -1,4 +1,4 @@ -package usi.si.seart.views.language; +package ch.usi.si.seart.views.language; import javax.persistence.Entity; import javax.persistence.Table; diff --git a/dl4se-model/src/main/java/usi/si/seart/views/language/FunctionCountByLanguage.java b/dl4se-model/src/main/java/ch/usi/si/seart/views/language/FunctionCountByLanguage.java similarity index 82% rename from dl4se-model/src/main/java/usi/si/seart/views/language/FunctionCountByLanguage.java rename to dl4se-model/src/main/java/ch/usi/si/seart/views/language/FunctionCountByLanguage.java index 6afead33..401e63ea 100644 --- a/dl4se-model/src/main/java/usi/si/seart/views/language/FunctionCountByLanguage.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/views/language/FunctionCountByLanguage.java @@ -1,4 +1,4 @@ -package usi.si.seart.views.language; +package ch.usi.si.seart.views.language; import javax.persistence.Entity; import javax.persistence.Table; diff --git a/dl4se-model/src/main/java/usi/si/seart/views/language/GitRepoCountByLanguage.java b/dl4se-model/src/main/java/ch/usi/si/seart/views/language/GitRepoCountByLanguage.java similarity index 82% rename from dl4se-model/src/main/java/usi/si/seart/views/language/GitRepoCountByLanguage.java rename to dl4se-model/src/main/java/ch/usi/si/seart/views/language/GitRepoCountByLanguage.java index 4970674f..a55e49dd 100644 --- a/dl4se-model/src/main/java/usi/si/seart/views/language/GitRepoCountByLanguage.java +++ b/dl4se-model/src/main/java/ch/usi/si/seart/views/language/GitRepoCountByLanguage.java @@ -1,4 +1,4 @@ -package usi.si.seart.views.language; +package ch.usi.si.seart.views.language; import javax.persistence.Entity; import javax.persistence.Table; diff --git a/dl4se-model/src/main/resources/ValidationMessages.properties b/dl4se-model/src/main/resources/ValidationMessages.properties index 3254b689..f1f05dc6 100644 --- a/dl4se-model/src/main/resources/ValidationMessages.properties +++ b/dl4se-model/src/main/resources/ValidationMessages.properties @@ -1,4 +1,4 @@ -usi.si.seart.validation.constraints.Hash.message=Not a valid hash -usi.si.seart.validation.constraints.NullOrNotBlank.message=Value is neither unset, nor does it contain a single non-whitespace character -usi.si.seart.validation.constraints.OWASPEmail.message=Not an OWASP-compliant email address -usi.si.seart.validation.constraints.Password.message=Not a valid password +ch.usi.si.seart.validation.constraints.Hash.message=Not a valid hash +ch.usi.si.seart.validation.constraints.NullOrNotBlank.message=Value is neither unset, nor does it contain a single non-whitespace character +ch.usi.si.seart.validation.constraints.OWASPEmail.message=Not an OWASP-compliant email address +ch.usi.si.seart.validation.constraints.Password.message=Not a valid password diff --git a/dl4se-model/src/test/java/usi/si/seart/model/code/CodeTest.java b/dl4se-model/src/test/java/ch/usi/si/seart/model/code/CodeTest.java similarity index 93% rename from dl4se-model/src/test/java/usi/si/seart/model/code/CodeTest.java rename to dl4se-model/src/test/java/ch/usi/si/seart/model/code/CodeTest.java index 204ab52f..ad8cfce8 100644 --- a/dl4se-model/src/test/java/usi/si/seart/model/code/CodeTest.java +++ b/dl4se-model/src/test/java/ch/usi/si/seart/model/code/CodeTest.java @@ -1,4 +1,4 @@ -package usi.si.seart.model.code; +package ch.usi.si.seart.model.code; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -19,4 +19,4 @@ void toStringTest() { strings.get(1).startsWith("Function") ); } -} \ No newline at end of file +} diff --git a/dl4se-model/src/test/java/usi/si/seart/validation/constraints/HashTest.java b/dl4se-model/src/test/java/ch/usi/si/seart/validation/constraints/HashTest.java similarity index 97% rename from dl4se-model/src/test/java/usi/si/seart/validation/constraints/HashTest.java rename to dl4se-model/src/test/java/ch/usi/si/seart/validation/constraints/HashTest.java index c918cb38..db4d5e9a 100644 --- a/dl4se-model/src/test/java/usi/si/seart/validation/constraints/HashTest.java +++ b/dl4se-model/src/test/java/ch/usi/si/seart/validation/constraints/HashTest.java @@ -1,4 +1,4 @@ -package usi.si.seart.validation.constraints; +package ch.usi.si.seart.validation.constraints; import lombok.AllArgsConstructor; import lombok.Cleanup; diff --git a/dl4se-model/src/test/java/usi/si/seart/validation/constraints/NullOrNotBlankTest.java b/dl4se-model/src/test/java/ch/usi/si/seart/validation/constraints/NullOrNotBlankTest.java similarity index 97% rename from dl4se-model/src/test/java/usi/si/seart/validation/constraints/NullOrNotBlankTest.java rename to dl4se-model/src/test/java/ch/usi/si/seart/validation/constraints/NullOrNotBlankTest.java index e0733a4b..24fbdcf0 100644 --- a/dl4se-model/src/test/java/usi/si/seart/validation/constraints/NullOrNotBlankTest.java +++ b/dl4se-model/src/test/java/ch/usi/si/seart/validation/constraints/NullOrNotBlankTest.java @@ -1,4 +1,4 @@ -package usi.si.seart.validation.constraints; +package ch.usi.si.seart.validation.constraints; import lombok.AllArgsConstructor; import lombok.Cleanup; diff --git a/dl4se-model/src/test/java/usi/si/seart/validation/constraints/OWASPEmailTest.java b/dl4se-model/src/test/java/ch/usi/si/seart/validation/constraints/OWASPEmailTest.java similarity index 97% rename from dl4se-model/src/test/java/usi/si/seart/validation/constraints/OWASPEmailTest.java rename to dl4se-model/src/test/java/ch/usi/si/seart/validation/constraints/OWASPEmailTest.java index fe15f906..33f5c323 100644 --- a/dl4se-model/src/test/java/usi/si/seart/validation/constraints/OWASPEmailTest.java +++ b/dl4se-model/src/test/java/ch/usi/si/seart/validation/constraints/OWASPEmailTest.java @@ -1,4 +1,4 @@ -package usi.si.seart.validation.constraints; +package ch.usi.si.seart.validation.constraints; import lombok.AllArgsConstructor; import lombok.Cleanup; diff --git a/dl4se-model/src/test/java/usi/si/seart/validation/constraints/PasswordTest.java b/dl4se-model/src/test/java/ch/usi/si/seart/validation/constraints/PasswordTest.java similarity index 97% rename from dl4se-model/src/test/java/usi/si/seart/validation/constraints/PasswordTest.java rename to dl4se-model/src/test/java/ch/usi/si/seart/validation/constraints/PasswordTest.java index 6c222720..ddc14827 100644 --- a/dl4se-model/src/test/java/usi/si/seart/validation/constraints/PasswordTest.java +++ b/dl4se-model/src/test/java/ch/usi/si/seart/validation/constraints/PasswordTest.java @@ -1,4 +1,4 @@ -package usi.si.seart.validation.constraints; +package ch.usi.si.seart.validation.constraints; import lombok.AllArgsConstructor; import lombok.Cleanup; diff --git a/dl4se-server/pom.xml b/dl4se-server/pom.xml index 4814601b..c5a6e987 100644 --- a/dl4se-server/pom.xml +++ b/dl4se-server/pom.xml @@ -3,7 +3,7 @@ 4.0.0 dl4se - usi.si.seart + ch.usi.si.seart ${revision} ../pom.xml @@ -14,12 +14,12 @@ UTF-8 - usi.si.seart.server.Application + ch.usi.si.seart.server.Application - usi.si.seart + ch.usi.si.seart dl4se-model ${project.version} diff --git a/dl4se-crawler/src/main/java/usi/si/seart/crawler/Application.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/Application.java similarity index 89% rename from dl4se-crawler/src/main/java/usi/si/seart/crawler/Application.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/Application.java index 29f6972e..159d11f7 100644 --- a/dl4se-crawler/src/main/java/usi/si/seart/crawler/Application.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/Application.java @@ -1,4 +1,4 @@ -package usi.si.seart.crawler; +package ch.usi.si.seart.server; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/bean/ConfigurationInitializingBean.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/bean/ConfigurationInitializingBean.java similarity index 91% rename from dl4se-server/src/main/java/usi/si/seart/server/bean/ConfigurationInitializingBean.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/bean/ConfigurationInitializingBean.java index ace17e9b..2d469541 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/bean/ConfigurationInitializingBean.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/bean/ConfigurationInitializingBean.java @@ -1,5 +1,7 @@ -package usi.si.seart.server.bean; +package ch.usi.si.seart.server.bean; +import ch.usi.si.seart.model.Configuration; +import ch.usi.si.seart.server.repository.ConfigurationRepository; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.experimental.FieldDefaults; @@ -9,8 +11,6 @@ import org.springframework.core.io.Resource; import org.springframework.core.io.support.PropertiesLoaderUtils; import org.springframework.stereotype.Component; -import usi.si.seart.model.Configuration; -import usi.si.seart.server.repository.ConfigurationRepository; import java.util.Map; import java.util.Properties; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/bean/DirectoryInitializationBean.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/bean/DirectoryInitializationBean.java similarity index 96% rename from dl4se-server/src/main/java/usi/si/seart/server/bean/DirectoryInitializationBean.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/bean/DirectoryInitializationBean.java index b2bbf2b5..207a1e36 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/bean/DirectoryInitializationBean.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/bean/DirectoryInitializationBean.java @@ -1,4 +1,4 @@ -package usi.si.seart.server.bean; +package ch.usi.si.seart.server.bean; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/bean/TaskRunnerRecoveryBean.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/bean/TaskRunnerRecoveryBean.java similarity index 82% rename from dl4se-server/src/main/java/usi/si/seart/server/bean/TaskRunnerRecoveryBean.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/bean/TaskRunnerRecoveryBean.java index 4ce79bb0..a29ba133 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/bean/TaskRunnerRecoveryBean.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/bean/TaskRunnerRecoveryBean.java @@ -1,13 +1,13 @@ -package usi.si.seart.server.bean; +package ch.usi.si.seart.server.bean; +import ch.usi.si.seart.model.task.Status; +import ch.usi.si.seart.server.service.StatisticsService; +import ch.usi.si.seart.server.service.TaskService; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import usi.si.seart.model.task.Status; -import usi.si.seart.server.service.StatisticsService; -import usi.si.seart.server.service.TaskService; @Slf4j @Component("TaskRunnerRecoveryBean") diff --git a/dl4se-server/src/main/java/usi/si/seart/server/config/JpaConfig.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/config/JpaConfig.java similarity index 65% rename from dl4se-server/src/main/java/usi/si/seart/server/config/JpaConfig.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/config/JpaConfig.java index ec580890..140fa0cf 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/config/JpaConfig.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/config/JpaConfig.java @@ -1,12 +1,12 @@ -package usi.si.seart.server.config; +package ch.usi.si.seart.server.config; import org.springframework.boot.autoconfigure.domain.EntityScan; import org.springframework.context.annotation.Configuration; @Configuration @EntityScan(basePackages = { - "usi.si.seart.model", - "usi.si.seart.views", + "ch.usi.si.seart.model", + "ch.usi.si.seart.views", }) public class JpaConfig { } diff --git a/dl4se-server/src/main/java/usi/si/seart/server/config/JwtConfig.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/config/JwtConfig.java similarity index 83% rename from dl4se-server/src/main/java/usi/si/seart/server/config/JwtConfig.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/config/JwtConfig.java index 5c525906..9200a8b2 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/config/JwtConfig.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/config/JwtConfig.java @@ -1,5 +1,11 @@ -package usi.si.seart.server.config; +package ch.usi.si.seart.server.config; +import ch.usi.si.seart.model.user.User; +import ch.usi.si.seart.server.exception.UserNotFoundException; +import ch.usi.si.seart.server.security.UserPrincipal; +import ch.usi.si.seart.server.security.jwt.JwtRequestFilter; +import ch.usi.si.seart.server.security.jwt.JwtTokenProvider; +import ch.usi.si.seart.server.service.UserService; import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.JwtParser; import io.jsonwebtoken.Jwts; @@ -10,12 +16,6 @@ import org.springframework.core.convert.ConversionService; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; -import usi.si.seart.model.user.User; -import usi.si.seart.server.exception.UserNotFoundException; -import usi.si.seart.server.security.UserPrincipal; -import usi.si.seart.server.security.jwt.JwtRequestFilter; -import usi.si.seart.server.security.jwt.JwtTokenProvider; -import usi.si.seart.server.service.UserService; import javax.crypto.SecretKey; import java.time.Duration; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/config/MainConfig.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/config/MainConfig.java similarity index 91% rename from dl4se-server/src/main/java/usi/si/seart/server/config/MainConfig.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/config/MainConfig.java index ea30328c..1ab0435b 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/config/MainConfig.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/config/MainConfig.java @@ -1,11 +1,11 @@ -package usi.si.seart.server.config; +package ch.usi.si.seart.server.config; +import ch.usi.si.seart.server.jackson.PaginationModule; import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import usi.si.seart.server.jackson.PaginationModule; import java.nio.file.Path; import java.text.DateFormat; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/config/SchedulerConfig.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/config/SchedulerConfig.java similarity index 89% rename from dl4se-server/src/main/java/usi/si/seart/server/config/SchedulerConfig.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/config/SchedulerConfig.java index 5dee8fd5..0f99ee2b 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/config/SchedulerConfig.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/config/SchedulerConfig.java @@ -1,5 +1,15 @@ -package usi.si.seart.server.config; +package ch.usi.si.seart.server.config; +import ch.usi.si.seart.model.task.Task; +import ch.usi.si.seart.server.exception.TaskFailedException; +import ch.usi.si.seart.server.scheduling.RepoMaintainer; +import ch.usi.si.seart.server.scheduling.TaskCleaner; +import ch.usi.si.seart.server.scheduling.TaskRunner; +import ch.usi.si.seart.server.scheduling.ViewMaintainer; +import ch.usi.si.seart.server.service.ConfigurationService; +import ch.usi.si.seart.server.service.EmailService; +import ch.usi.si.seart.server.service.FileSystemService; +import ch.usi.si.seart.server.service.TaskService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; @@ -13,16 +23,6 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.scheduling.support.CronTrigger; import org.springframework.util.ErrorHandler; -import usi.si.seart.model.task.Task; -import usi.si.seart.server.exception.TaskFailedException; -import usi.si.seart.server.scheduling.RepoMaintainer; -import usi.si.seart.server.scheduling.TaskCleaner; -import usi.si.seart.server.scheduling.TaskRunner; -import usi.si.seart.server.scheduling.ViewMaintainer; -import usi.si.seart.server.service.ConfigurationService; -import usi.si.seart.server.service.EmailService; -import usi.si.seart.server.service.FileSystemService; -import usi.si.seart.server.service.TaskService; import java.time.Clock; import java.util.HashSet; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/config/SecurityConfig.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/config/SecurityConfig.java similarity index 95% rename from dl4se-server/src/main/java/usi/si/seart/server/config/SecurityConfig.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/config/SecurityConfig.java index 9ff14144..1100b2f1 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/config/SecurityConfig.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/config/SecurityConfig.java @@ -1,5 +1,10 @@ -package usi.si.seart.server.config; +package ch.usi.si.seart.server.config; +import ch.usi.si.seart.model.user.User; +import ch.usi.si.seart.server.exception.UserNotFoundException; +import ch.usi.si.seart.server.security.UserPrincipal; +import ch.usi.si.seart.server.security.jwt.JwtRequestFilter; +import ch.usi.si.seart.server.service.UserService; import org.owasp.encoder.Encode; import org.springframework.context.annotation.Bean; import org.springframework.core.convert.ConversionService; @@ -20,11 +25,6 @@ import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -import usi.si.seart.model.user.User; -import usi.si.seart.server.exception.UserNotFoundException; -import usi.si.seart.server.security.UserPrincipal; -import usi.si.seart.server.security.jwt.JwtRequestFilter; -import usi.si.seart.server.service.UserService; import javax.servlet.http.HttpServletResponse; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/config/WebConfig.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/config/WebConfig.java similarity index 74% rename from dl4se-server/src/main/java/usi/si/seart/server/config/WebConfig.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/config/WebConfig.java index 1c160651..c60d1af6 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/config/WebConfig.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/config/WebConfig.java @@ -1,15 +1,15 @@ -package usi.si.seart.server.config; +package ch.usi.si.seart.server.config; +import ch.usi.si.seart.server.converter.DtoToConfigurationConverter; +import ch.usi.si.seart.server.converter.DtoToUserConverter; +import ch.usi.si.seart.server.converter.TaskSearchDtoToSpecificationConverter; +import ch.usi.si.seart.server.converter.UserSearchDtoToSpecificationConverter; +import ch.usi.si.seart.server.converter.UserToUserPrincipalConverter; import org.springframework.context.annotation.Configuration; import org.springframework.data.web.config.EnableSpringDataWebSupport; import org.springframework.format.FormatterRegistry; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import usi.si.seart.server.converter.DtoToConfigurationConverter; -import usi.si.seart.server.converter.DtoToUserConverter; -import usi.si.seart.server.converter.TaskSearchDtoToSpecificationConverter; -import usi.si.seart.server.converter.UserSearchDtoToSpecificationConverter; -import usi.si.seart.server.converter.UserToUserPrincipalConverter; @Configuration @EnableSpringDataWebSupport diff --git a/dl4se-server/src/main/java/usi/si/seart/server/context/ConfigurationEnvironment.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/context/ConfigurationEnvironment.java similarity index 90% rename from dl4se-server/src/main/java/usi/si/seart/server/context/ConfigurationEnvironment.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/context/ConfigurationEnvironment.java index af0b4ee0..1b1e7240 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/context/ConfigurationEnvironment.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/context/ConfigurationEnvironment.java @@ -1,5 +1,6 @@ -package usi.si.seart.server.context; +package ch.usi.si.seart.server.context; +import ch.usi.si.seart.server.service.ConfigurationService; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.experimental.FieldDefaults; @@ -8,7 +9,6 @@ import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; -import usi.si.seart.server.service.ConfigurationService; @Component @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) diff --git a/dl4se-server/src/main/java/usi/si/seart/server/controller/AdminController.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/AdminController.java similarity index 86% rename from dl4se-server/src/main/java/usi/si/seart/server/controller/AdminController.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/controller/AdminController.java index d4099bbc..941bf03e 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/controller/AdminController.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/AdminController.java @@ -1,5 +1,19 @@ -package usi.si.seart.server.controller; - +package ch.usi.si.seart.server.controller; + +import ch.usi.si.seart.model.Configuration; +import ch.usi.si.seart.model.Configuration_; +import ch.usi.si.seart.model.task.Task; +import ch.usi.si.seart.model.task.Task_; +import ch.usi.si.seart.model.user.Role; +import ch.usi.si.seart.model.user.User; +import ch.usi.si.seart.model.user.User_; +import ch.usi.si.seart.server.dto.task.TaskSearchDto; +import ch.usi.si.seart.server.dto.user.UserSearchDto; +import ch.usi.si.seart.server.exception.ConfigurationNotFoundException; +import ch.usi.si.seart.server.security.annotation.AdminRestController; +import ch.usi.si.seart.server.service.ConfigurationService; +import ch.usi.si.seart.server.service.TaskService; +import ch.usi.si.seart.server.service.UserService; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.experimental.FieldDefaults; @@ -16,20 +30,6 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; -import usi.si.seart.model.Configuration; -import usi.si.seart.model.Configuration_; -import usi.si.seart.model.task.Task; -import usi.si.seart.model.task.Task_; -import usi.si.seart.model.user.Role; -import usi.si.seart.model.user.User; -import usi.si.seart.model.user.User_; -import usi.si.seart.server.dto.task.TaskSearchDto; -import usi.si.seart.server.dto.user.UserSearchDto; -import usi.si.seart.server.exception.ConfigurationNotFoundException; -import usi.si.seart.server.security.annotation.AdminRestController; -import usi.si.seart.server.service.ConfigurationService; -import usi.si.seart.server.service.TaskService; -import usi.si.seart.server.service.UserService; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/controller/ExceptionHandlerController.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/ExceptionHandlerController.java similarity index 93% rename from dl4se-server/src/main/java/usi/si/seart/server/controller/ExceptionHandlerController.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/controller/ExceptionHandlerController.java index c1e4c88d..0a370511 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/controller/ExceptionHandlerController.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/ExceptionHandlerController.java @@ -1,5 +1,7 @@ -package usi.si.seart.server.controller; +package ch.usi.si.seart.server.controller; +import ch.usi.si.seart.server.exception.EntityNotFoundException; +import ch.usi.si.seart.server.exception.TokenExpiredException; import lombok.extern.slf4j.Slf4j; import org.hibernate.exception.ConstraintViolationException; import org.springframework.dao.DataAccessException; @@ -11,8 +13,6 @@ import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; -import usi.si.seart.server.exception.EntityNotFoundException; -import usi.si.seart.server.exception.TokenExpiredException; import java.io.FileNotFoundException; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/controller/LanguageController.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/LanguageController.java similarity index 87% rename from dl4se-server/src/main/java/usi/si/seart/server/controller/LanguageController.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/controller/LanguageController.java index 5289d710..2321e060 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/controller/LanguageController.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/LanguageController.java @@ -1,5 +1,7 @@ -package usi.si.seart.server.controller; +package ch.usi.si.seart.server.controller; +import ch.usi.si.seart.model.Language; +import ch.usi.si.seart.server.service.LanguageService; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.experimental.FieldDefaults; @@ -8,8 +10,6 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import usi.si.seart.model.Language; -import usi.si.seart.server.service.LanguageService; import java.util.List; import java.util.stream.Collectors; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/controller/RootController.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/RootController.java similarity index 88% rename from dl4se-server/src/main/java/usi/si/seart/server/controller/RootController.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/controller/RootController.java index 45b69dbb..3b9a7a5c 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/controller/RootController.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/RootController.java @@ -1,4 +1,4 @@ -package usi.si.seart.server.controller; +package ch.usi.si.seart.server.controller; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/controller/StatisticsController.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/StatisticsController.java similarity index 93% rename from dl4se-server/src/main/java/usi/si/seart/server/controller/StatisticsController.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/controller/StatisticsController.java index badae016..7e0d2de1 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/controller/StatisticsController.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/StatisticsController.java @@ -1,5 +1,10 @@ -package usi.si.seart.server.controller; +package ch.usi.si.seart.server.controller; +import ch.usi.si.seart.model.Language; +import ch.usi.si.seart.model.user.User; +import ch.usi.si.seart.server.security.UserPrincipal; +import ch.usi.si.seart.server.service.StatisticsService; +import ch.usi.si.seart.server.service.UserService; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.experimental.FieldDefaults; @@ -9,11 +14,6 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import usi.si.seart.model.Language; -import usi.si.seart.model.user.User; -import usi.si.seart.server.security.UserPrincipal; -import usi.si.seart.server.service.StatisticsService; -import usi.si.seart.server.service.UserService; import java.util.Map; import java.util.TreeMap; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/controller/TaskController.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/TaskController.java similarity index 89% rename from dl4se-server/src/main/java/usi/si/seart/server/controller/TaskController.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/controller/TaskController.java index 96a10113..e8f6d10c 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/controller/TaskController.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/TaskController.java @@ -1,5 +1,21 @@ -package usi.si.seart.server.controller; - +package ch.usi.si.seart.server.controller; + +import ch.usi.si.seart.model.job.Job; +import ch.usi.si.seart.model.task.Status; +import ch.usi.si.seart.model.task.Task; +import ch.usi.si.seart.model.task.Task_; +import ch.usi.si.seart.model.user.Role; +import ch.usi.si.seart.model.user.User; +import ch.usi.si.seart.model.user.User_; +import ch.usi.si.seart.model.user.token.Token; +import ch.usi.si.seart.server.dto.task.TaskDto; +import ch.usi.si.seart.server.dto.task.TaskSearchDto; +import ch.usi.si.seart.server.security.UserPrincipal; +import ch.usi.si.seart.server.service.ConfigurationService; +import ch.usi.si.seart.server.service.DownloadService; +import ch.usi.si.seart.server.service.FileSystemService; +import ch.usi.si.seart.server.service.TaskService; +import ch.usi.si.seart.server.service.UserService; import com.fasterxml.jackson.databind.JsonNode; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -26,22 +42,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import usi.si.seart.model.job.Job; -import usi.si.seart.model.task.Status; -import usi.si.seart.model.task.Task; -import usi.si.seart.model.task.Task_; -import usi.si.seart.model.user.Role; -import usi.si.seart.model.user.User; -import usi.si.seart.model.user.User_; -import usi.si.seart.model.user.token.Token; -import usi.si.seart.server.dto.task.TaskDto; -import usi.si.seart.server.dto.task.TaskSearchDto; -import usi.si.seart.server.security.UserPrincipal; -import usi.si.seart.server.service.ConfigurationService; -import usi.si.seart.server.service.DownloadService; -import usi.si.seart.server.service.FileSystemService; -import usi.si.seart.server.service.TaskService; -import usi.si.seart.server.service.UserService; import javax.validation.Valid; import javax.validation.constraints.NotBlank; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/controller/UserController.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/UserController.java similarity index 89% rename from dl4se-server/src/main/java/usi/si/seart/server/controller/UserController.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/controller/UserController.java index cb935e67..0adba5bb 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/controller/UserController.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/UserController.java @@ -1,5 +1,17 @@ -package usi.si.seart.server.controller; - +package ch.usi.si.seart.server.controller; + +import ch.usi.si.seart.model.user.User; +import ch.usi.si.seart.model.user.token.Token; +import ch.usi.si.seart.server.dto.LoginDto; +import ch.usi.si.seart.server.dto.RegisterDto; +import ch.usi.si.seart.server.dto.user.EmailDto; +import ch.usi.si.seart.server.dto.user.PasswordDto; +import ch.usi.si.seart.server.security.UserPrincipal; +import ch.usi.si.seart.server.security.jwt.JwtTokenProvider; +import ch.usi.si.seart.server.service.EmailService; +import ch.usi.si.seart.server.service.PasswordResetService; +import ch.usi.si.seart.server.service.UserService; +import ch.usi.si.seart.server.service.VerificationService; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; @@ -25,18 +37,6 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.util.UriComponentsBuilder; -import usi.si.seart.model.user.User; -import usi.si.seart.model.user.token.Token; -import usi.si.seart.server.dto.LoginDto; -import usi.si.seart.server.dto.RegisterDto; -import usi.si.seart.server.dto.user.EmailDto; -import usi.si.seart.server.dto.user.PasswordDto; -import usi.si.seart.server.security.UserPrincipal; -import usi.si.seart.server.security.jwt.JwtTokenProvider; -import usi.si.seart.server.service.EmailService; -import usi.si.seart.server.service.PasswordResetService; -import usi.si.seart.server.service.UserService; -import usi.si.seart.server.service.VerificationService; import javax.validation.Valid; import javax.validation.constraints.NotBlank; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/converter/DtoToConfigurationConverter.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/converter/DtoToConfigurationConverter.java similarity index 76% rename from dl4se-server/src/main/java/usi/si/seart/server/converter/DtoToConfigurationConverter.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/converter/DtoToConfigurationConverter.java index e92bb84c..35d5005f 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/converter/DtoToConfigurationConverter.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/converter/DtoToConfigurationConverter.java @@ -1,9 +1,9 @@ -package usi.si.seart.server.converter; +package ch.usi.si.seart.server.converter; +import ch.usi.si.seart.model.Configuration; +import ch.usi.si.seart.server.dto.ConfigurationDto; import org.springframework.core.convert.converter.Converter; import org.springframework.lang.NonNull; -import usi.si.seart.model.Configuration; -import usi.si.seart.server.dto.ConfigurationDto; public class DtoToConfigurationConverter implements Converter { diff --git a/dl4se-server/src/main/java/usi/si/seart/server/converter/DtoToUserConverter.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/converter/DtoToUserConverter.java similarity index 78% rename from dl4se-server/src/main/java/usi/si/seart/server/converter/DtoToUserConverter.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/converter/DtoToUserConverter.java index 23a1951f..8bf1d24e 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/converter/DtoToUserConverter.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/converter/DtoToUserConverter.java @@ -1,9 +1,9 @@ -package usi.si.seart.server.converter; +package ch.usi.si.seart.server.converter; +import ch.usi.si.seart.model.user.User; +import ch.usi.si.seart.server.dto.RegisterDto; import org.springframework.core.convert.converter.Converter; import org.springframework.lang.NonNull; -import usi.si.seart.model.user.User; -import usi.si.seart.server.dto.RegisterDto; public class DtoToUserConverter implements Converter { diff --git a/dl4se-server/src/main/java/usi/si/seart/server/converter/TaskSearchDtoToSpecificationConverter.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/converter/TaskSearchDtoToSpecificationConverter.java similarity index 82% rename from dl4se-server/src/main/java/usi/si/seart/server/converter/TaskSearchDtoToSpecificationConverter.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/converter/TaskSearchDtoToSpecificationConverter.java index 25695b9c..d34bb9d1 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/converter/TaskSearchDtoToSpecificationConverter.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/converter/TaskSearchDtoToSpecificationConverter.java @@ -1,11 +1,11 @@ -package usi.si.seart.server.converter; +package ch.usi.si.seart.server.converter; +import ch.usi.si.seart.model.task.Task; +import ch.usi.si.seart.model.task.Task_; +import ch.usi.si.seart.server.dto.task.TaskSearchDto; import org.springframework.core.convert.converter.Converter; import org.springframework.data.jpa.domain.Specification; import org.springframework.lang.NonNull; -import usi.si.seart.model.task.Task; -import usi.si.seart.model.task.Task_; -import usi.si.seart.server.dto.task.TaskSearchDto; public class TaskSearchDtoToSpecificationConverter implements Converter> { diff --git a/dl4se-server/src/main/java/usi/si/seart/server/converter/TaskToCodeSpecificationConverter.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/converter/TaskToCodeSpecificationConverter.java similarity index 96% rename from dl4se-server/src/main/java/usi/si/seart/server/converter/TaskToCodeSpecificationConverter.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/converter/TaskToCodeSpecificationConverter.java index 7bc19766..913c1239 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/converter/TaskToCodeSpecificationConverter.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/converter/TaskToCodeSpecificationConverter.java @@ -1,5 +1,17 @@ -package usi.si.seart.server.converter; +package ch.usi.si.seart.server.converter; +import ch.usi.si.seart.model.GitRepo_; +import ch.usi.si.seart.model.Language_; +import ch.usi.si.seart.model.code.Boilerplate; +import ch.usi.si.seart.model.code.Code; +import ch.usi.si.seart.model.code.Code_; +import ch.usi.si.seart.model.code.File; +import ch.usi.si.seart.model.code.Function; +import ch.usi.si.seart.model.code.Function_; +import ch.usi.si.seart.model.job.Job; +import ch.usi.si.seart.model.task.Task; +import ch.usi.si.seart.views.code.HashDistinct; +import ch.usi.si.seart.views.code.HashDistinct_; import com.fasterxml.jackson.databind.JsonNode; import org.springframework.core.convert.converter.Converter; import org.springframework.data.jpa.domain.Specification; @@ -7,18 +19,6 @@ import org.springframework.stereotype.Component; import org.springframework.util.Assert; import org.springframework.util.StringUtils; -import usi.si.seart.model.GitRepo_; -import usi.si.seart.model.Language_; -import usi.si.seart.model.code.Boilerplate; -import usi.si.seart.model.code.Code; -import usi.si.seart.model.code.Code_; -import usi.si.seart.model.code.File; -import usi.si.seart.model.code.Function; -import usi.si.seart.model.code.Function_; -import usi.si.seart.model.job.Job; -import usi.si.seart.model.task.Task; -import usi.si.seart.views.code.HashDistinct; -import usi.si.seart.views.code.HashDistinct_; import javax.persistence.criteria.Expression; import javax.persistence.criteria.Path; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/converter/UserSearchDtoToSpecificationConverter.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/converter/UserSearchDtoToSpecificationConverter.java similarity index 90% rename from dl4se-server/src/main/java/usi/si/seart/server/converter/UserSearchDtoToSpecificationConverter.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/converter/UserSearchDtoToSpecificationConverter.java index 779836ba..72d08315 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/converter/UserSearchDtoToSpecificationConverter.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/converter/UserSearchDtoToSpecificationConverter.java @@ -1,11 +1,11 @@ -package usi.si.seart.server.converter; +package ch.usi.si.seart.server.converter; +import ch.usi.si.seart.model.user.User; +import ch.usi.si.seart.model.user.User_; +import ch.usi.si.seart.server.dto.user.UserSearchDto; import org.springframework.core.convert.converter.Converter; import org.springframework.data.jpa.domain.Specification; import org.springframework.lang.NonNull; -import usi.si.seart.model.user.User; -import usi.si.seart.model.user.User_; -import usi.si.seart.server.dto.user.UserSearchDto; public class UserSearchDtoToSpecificationConverter implements Converter> { diff --git a/dl4se-server/src/main/java/usi/si/seart/server/converter/UserToUserPrincipalConverter.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/converter/UserToUserPrincipalConverter.java similarity index 81% rename from dl4se-server/src/main/java/usi/si/seart/server/converter/UserToUserPrincipalConverter.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/converter/UserToUserPrincipalConverter.java index 17a78fd8..e3b877f3 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/converter/UserToUserPrincipalConverter.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/converter/UserToUserPrincipalConverter.java @@ -1,8 +1,8 @@ -package usi.si.seart.server.converter; +package ch.usi.si.seart.server.converter; +import ch.usi.si.seart.model.user.User; +import ch.usi.si.seart.server.security.UserPrincipal; import org.springframework.core.convert.converter.Converter; -import usi.si.seart.model.user.User; -import usi.si.seart.server.security.UserPrincipal; public class UserToUserPrincipalConverter implements Converter { diff --git a/dl4se-server/src/main/java/usi/si/seart/server/dto/ConfigurationDto.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/dto/ConfigurationDto.java similarity index 92% rename from dl4se-server/src/main/java/usi/si/seart/server/dto/ConfigurationDto.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/dto/ConfigurationDto.java index 826d50c3..49479618 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/dto/ConfigurationDto.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/dto/ConfigurationDto.java @@ -1,4 +1,4 @@ -package usi.si.seart.server.dto; +package ch.usi.si.seart.server.dto; import lombok.AccessLevel; import lombok.AllArgsConstructor; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/dto/LoginDto.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/dto/LoginDto.java similarity index 71% rename from dl4se-server/src/main/java/usi/si/seart/server/dto/LoginDto.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/dto/LoginDto.java index 9c8daa39..ca1033fe 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/dto/LoginDto.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/dto/LoginDto.java @@ -1,13 +1,13 @@ -package usi.si.seart.server.dto; +package ch.usi.si.seart.server.dto; +import ch.usi.si.seart.validation.constraints.OWASPEmail; +import ch.usi.si.seart.validation.constraints.Password; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.experimental.FieldDefaults; -import usi.si.seart.validation.constraints.OWASPEmail; -import usi.si.seart.validation.constraints.Password; @Getter @Builder diff --git a/dl4se-server/src/main/java/usi/si/seart/server/dto/RegisterDto.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/dto/RegisterDto.java similarity index 77% rename from dl4se-server/src/main/java/usi/si/seart/server/dto/RegisterDto.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/dto/RegisterDto.java index b793221a..f0cf4e8a 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/dto/RegisterDto.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/dto/RegisterDto.java @@ -1,13 +1,13 @@ -package usi.si.seart.server.dto; +package ch.usi.si.seart.server.dto; +import ch.usi.si.seart.validation.constraints.OWASPEmail; +import ch.usi.si.seart.validation.constraints.Password; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.experimental.FieldDefaults; -import usi.si.seart.validation.constraints.OWASPEmail; -import usi.si.seart.validation.constraints.Password; import javax.validation.constraints.NotBlank; import java.io.Serializable; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/dto/task/TaskDto.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/dto/task/TaskDto.java similarity index 95% rename from dl4se-server/src/main/java/usi/si/seart/server/dto/task/TaskDto.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/dto/task/TaskDto.java index c85205a5..9ed9ccab 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/dto/task/TaskDto.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/dto/task/TaskDto.java @@ -1,4 +1,4 @@ -package usi.si.seart.server.dto.task; +package ch.usi.si.seart.server.dto.task; import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.annotation.Nulls; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/dto/task/TaskSearchDto.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/dto/task/TaskSearchDto.java similarity index 94% rename from dl4se-server/src/main/java/usi/si/seart/server/dto/task/TaskSearchDto.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/dto/task/TaskSearchDto.java index 9567cdb4..a076473b 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/dto/task/TaskSearchDto.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/dto/task/TaskSearchDto.java @@ -1,4 +1,4 @@ -package usi.si.seart.server.dto.task; +package ch.usi.si.seart.server.dto.task; import lombok.AccessLevel; import lombok.AllArgsConstructor; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/dto/user/EmailDto.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/dto/user/EmailDto.java similarity index 77% rename from dl4se-server/src/main/java/usi/si/seart/server/dto/user/EmailDto.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/dto/user/EmailDto.java index d8b3fe3b..777e20aa 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/dto/user/EmailDto.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/dto/user/EmailDto.java @@ -1,12 +1,12 @@ -package usi.si.seart.server.dto.user; +package ch.usi.si.seart.server.dto.user; +import ch.usi.si.seart.validation.constraints.OWASPEmail; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.experimental.FieldDefaults; -import usi.si.seart.validation.constraints.OWASPEmail; @Getter @Builder diff --git a/dl4se-server/src/main/java/usi/si/seart/server/dto/user/PasswordDto.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/dto/user/PasswordDto.java similarity index 78% rename from dl4se-server/src/main/java/usi/si/seart/server/dto/user/PasswordDto.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/dto/user/PasswordDto.java index 0d248839..4f435adb 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/dto/user/PasswordDto.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/dto/user/PasswordDto.java @@ -1,12 +1,12 @@ -package usi.si.seart.server.dto.user; +package ch.usi.si.seart.server.dto.user; +import ch.usi.si.seart.validation.constraints.Password; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.experimental.FieldDefaults; -import usi.si.seart.validation.constraints.Password; @Getter @Builder diff --git a/dl4se-server/src/main/java/usi/si/seart/server/dto/user/UserSearchDto.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/dto/user/UserSearchDto.java similarity index 95% rename from dl4se-server/src/main/java/usi/si/seart/server/dto/user/UserSearchDto.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/dto/user/UserSearchDto.java index eea511c6..83999869 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/dto/user/UserSearchDto.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/dto/user/UserSearchDto.java @@ -1,4 +1,4 @@ -package usi.si.seart.server.dto.user; +package ch.usi.si.seart.server.dto.user; import lombok.AccessLevel; import lombok.AllArgsConstructor; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/exception/ConfigurationNotFoundException.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/exception/ConfigurationNotFoundException.java similarity index 76% rename from dl4se-server/src/main/java/usi/si/seart/server/exception/ConfigurationNotFoundException.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/exception/ConfigurationNotFoundException.java index 1daa0229..f217d1fd 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/exception/ConfigurationNotFoundException.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/exception/ConfigurationNotFoundException.java @@ -1,6 +1,6 @@ -package usi.si.seart.server.exception; +package ch.usi.si.seart.server.exception; -import usi.si.seart.model.Configuration; +import ch.usi.si.seart.model.Configuration; import javax.persistence.metamodel.Attribute; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/exception/EntityNotFoundException.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/exception/EntityNotFoundException.java similarity index 94% rename from dl4se-server/src/main/java/usi/si/seart/server/exception/EntityNotFoundException.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/exception/EntityNotFoundException.java index 22bfa776..d687797e 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/exception/EntityNotFoundException.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/exception/EntityNotFoundException.java @@ -1,4 +1,4 @@ -package usi.si.seart.server.exception; +package ch.usi.si.seart.server.exception; import lombok.AccessLevel; import lombok.experimental.StandardException; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/exception/LanguageNotFoundException.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/exception/LanguageNotFoundException.java similarity index 76% rename from dl4se-server/src/main/java/usi/si/seart/server/exception/LanguageNotFoundException.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/exception/LanguageNotFoundException.java index 82140f99..430534cd 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/exception/LanguageNotFoundException.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/exception/LanguageNotFoundException.java @@ -1,6 +1,6 @@ -package usi.si.seart.server.exception; +package ch.usi.si.seart.server.exception; -import usi.si.seart.model.Language; +import ch.usi.si.seart.model.Language; import javax.persistence.metamodel.Attribute; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/exception/TaskFailedException.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/exception/TaskFailedException.java similarity index 91% rename from dl4se-server/src/main/java/usi/si/seart/server/exception/TaskFailedException.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/exception/TaskFailedException.java index 7d48bffa..8eadbbf6 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/exception/TaskFailedException.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/exception/TaskFailedException.java @@ -1,7 +1,7 @@ -package usi.si.seart.server.exception; +package ch.usi.si.seart.server.exception; +import ch.usi.si.seart.model.task.Task; import lombok.Getter; -import usi.si.seart.model.task.Task; import javax.validation.constraints.NotNull; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/exception/TaskNotFoundException.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/exception/TaskNotFoundException.java similarity index 75% rename from dl4se-server/src/main/java/usi/si/seart/server/exception/TaskNotFoundException.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/exception/TaskNotFoundException.java index 56e8ef79..e1ff41d3 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/exception/TaskNotFoundException.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/exception/TaskNotFoundException.java @@ -1,6 +1,6 @@ -package usi.si.seart.server.exception; +package ch.usi.si.seart.server.exception; -import usi.si.seart.model.task.Task; +import ch.usi.si.seart.model.task.Task; import javax.persistence.metamodel.Attribute; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/exception/TokenExpiredException.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/exception/TokenExpiredException.java similarity index 73% rename from dl4se-server/src/main/java/usi/si/seart/server/exception/TokenExpiredException.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/exception/TokenExpiredException.java index 5b8b40b1..e77058bf 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/exception/TokenExpiredException.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/exception/TokenExpiredException.java @@ -1,6 +1,6 @@ -package usi.si.seart.server.exception; +package ch.usi.si.seart.server.exception; -import usi.si.seart.model.user.token.Token; +import ch.usi.si.seart.model.user.token.Token; public class TokenExpiredException extends RuntimeException { diff --git a/dl4se-server/src/main/java/usi/si/seart/server/exception/TokenNotFoundException.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/exception/TokenNotFoundException.java similarity index 74% rename from dl4se-server/src/main/java/usi/si/seart/server/exception/TokenNotFoundException.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/exception/TokenNotFoundException.java index e45bbacd..fd5ccc66 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/exception/TokenNotFoundException.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/exception/TokenNotFoundException.java @@ -1,6 +1,6 @@ -package usi.si.seart.server.exception; +package ch.usi.si.seart.server.exception; -import usi.si.seart.model.user.token.Token; +import ch.usi.si.seart.model.user.token.Token; import javax.persistence.metamodel.Attribute; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/exception/UserNotFoundException.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/exception/UserNotFoundException.java similarity index 75% rename from dl4se-server/src/main/java/usi/si/seart/server/exception/UserNotFoundException.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/exception/UserNotFoundException.java index d6411f73..b871a406 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/exception/UserNotFoundException.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/exception/UserNotFoundException.java @@ -1,6 +1,6 @@ -package usi.si.seart.server.exception; +package ch.usi.si.seart.server.exception; -import usi.si.seart.model.user.User; +import ch.usi.si.seart.model.user.User; import javax.persistence.metamodel.Attribute; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/jackson/PageSerializer.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/jackson/PageSerializer.java similarity index 96% rename from dl4se-server/src/main/java/usi/si/seart/server/jackson/PageSerializer.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/jackson/PageSerializer.java index a8a7ab01..407fade5 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/jackson/PageSerializer.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/jackson/PageSerializer.java @@ -1,4 +1,4 @@ -package usi.si.seart.server.jackson; +package ch.usi.si.seart.server.jackson; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.SerializerProvider; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/jackson/PaginationModule.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/jackson/PaginationModule.java similarity index 88% rename from dl4se-server/src/main/java/usi/si/seart/server/jackson/PaginationModule.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/jackson/PaginationModule.java index aa881da3..793446db 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/jackson/PaginationModule.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/jackson/PaginationModule.java @@ -1,4 +1,4 @@ -package usi.si.seart.server.jackson; +package ch.usi.si.seart.server.jackson; import com.fasterxml.jackson.databind.module.SimpleModule; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/jackson/SortSerializer.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/jackson/SortSerializer.java similarity index 96% rename from dl4se-server/src/main/java/usi/si/seart/server/jackson/SortSerializer.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/jackson/SortSerializer.java index 68480dd2..edd28680 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/jackson/SortSerializer.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/jackson/SortSerializer.java @@ -1,4 +1,4 @@ -package usi.si.seart.server.jackson; +package ch.usi.si.seart.server.jackson; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.SerializerProvider; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/repository/CodeRepository.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/repository/CodeRepository.java similarity index 72% rename from dl4se-server/src/main/java/usi/si/seart/server/repository/CodeRepository.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/repository/CodeRepository.java index a50d8dbe..3280a809 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/repository/CodeRepository.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/repository/CodeRepository.java @@ -1,10 +1,10 @@ -package usi.si.seart.server.repository; +package ch.usi.si.seart.server.repository; +import ch.usi.si.seart.model.code.Code; +import ch.usi.si.seart.server.repository.specification.JpaStreamableSpecificationRepository; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; -import usi.si.seart.model.code.Code; -import usi.si.seart.server.repository.specification.JpaStreamableSpecificationRepository; public interface CodeRepository extends JpaRepository, diff --git a/dl4se-server/src/main/java/usi/si/seart/server/repository/ConfigurationRepository.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/repository/ConfigurationRepository.java similarity index 63% rename from dl4se-server/src/main/java/usi/si/seart/server/repository/ConfigurationRepository.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/repository/ConfigurationRepository.java index 9f8a3229..bed58ebc 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/repository/ConfigurationRepository.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/repository/ConfigurationRepository.java @@ -1,7 +1,7 @@ -package usi.si.seart.server.repository; +package ch.usi.si.seart.server.repository; +import ch.usi.si.seart.model.Configuration; import org.springframework.data.jpa.repository.JpaRepository; -import usi.si.seart.model.Configuration; public interface ConfigurationRepository extends JpaRepository { } diff --git a/dl4se-server/src/main/java/usi/si/seart/server/repository/FileRepository.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/repository/FileRepository.java similarity index 66% rename from dl4se-server/src/main/java/usi/si/seart/server/repository/FileRepository.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/repository/FileRepository.java index 78ad3876..d5a5e4df 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/repository/FileRepository.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/repository/FileRepository.java @@ -1,10 +1,10 @@ -package usi.si.seart.server.repository; +package ch.usi.si.seart.server.repository; +import ch.usi.si.seart.model.Language; +import ch.usi.si.seart.model.code.File; +import ch.usi.si.seart.views.GroupedCount; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; -import usi.si.seart.model.Language; -import usi.si.seart.model.code.File; -import usi.si.seart.views.GroupedCount; import java.util.Collection; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/repository/FunctionRepository.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/repository/FunctionRepository.java similarity index 66% rename from dl4se-server/src/main/java/usi/si/seart/server/repository/FunctionRepository.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/repository/FunctionRepository.java index 95824b54..92ff26f3 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/repository/FunctionRepository.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/repository/FunctionRepository.java @@ -1,10 +1,10 @@ -package usi.si.seart.server.repository; +package ch.usi.si.seart.server.repository; +import ch.usi.si.seart.model.Language; +import ch.usi.si.seart.model.code.Function; +import ch.usi.si.seart.views.GroupedCount; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; -import usi.si.seart.model.Language; -import usi.si.seart.model.code.Function; -import usi.si.seart.views.GroupedCount; import java.util.Collection; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/repository/GitRepoRepository.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/repository/GitRepoRepository.java similarity index 71% rename from dl4se-server/src/main/java/usi/si/seart/server/repository/GitRepoRepository.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/repository/GitRepoRepository.java index d8e50f42..80faf3a6 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/repository/GitRepoRepository.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/repository/GitRepoRepository.java @@ -1,10 +1,10 @@ -package usi.si.seart.server.repository; +package ch.usi.si.seart.server.repository; +import ch.usi.si.seart.model.GitRepo; +import ch.usi.si.seart.model.Language; +import ch.usi.si.seart.views.GroupedCount; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; -import usi.si.seart.model.GitRepo; -import usi.si.seart.model.Language; -import usi.si.seart.views.GroupedCount; import java.util.Collection; import java.util.stream.Stream; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/repository/LanguageRepository.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/repository/LanguageRepository.java similarity index 72% rename from dl4se-server/src/main/java/usi/si/seart/server/repository/LanguageRepository.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/repository/LanguageRepository.java index 6dd087d2..cda22667 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/repository/LanguageRepository.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/repository/LanguageRepository.java @@ -1,7 +1,7 @@ -package usi.si.seart.server.repository; +package ch.usi.si.seart.server.repository; +import ch.usi.si.seart.model.Language; import org.springframework.data.jpa.repository.JpaRepository; -import usi.si.seart.model.Language; import java.util.Optional; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/repository/TableRowCountRepository.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/repository/TableRowCountRepository.java similarity index 63% rename from dl4se-server/src/main/java/usi/si/seart/server/repository/TableRowCountRepository.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/repository/TableRowCountRepository.java index 8eec89ea..36f3eb85 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/repository/TableRowCountRepository.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/repository/TableRowCountRepository.java @@ -1,7 +1,7 @@ -package usi.si.seart.server.repository; +package ch.usi.si.seart.server.repository; +import ch.usi.si.seart.views.TableRowCount; import org.springframework.data.jpa.repository.JpaRepository; -import usi.si.seart.views.TableRowCount; public interface TableRowCountRepository extends JpaRepository { } diff --git a/dl4se-server/src/main/java/usi/si/seart/server/repository/TaskRepository.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/repository/TaskRepository.java similarity index 89% rename from dl4se-server/src/main/java/usi/si/seart/server/repository/TaskRepository.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/repository/TaskRepository.java index 2b99d525..d5478d94 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/repository/TaskRepository.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/repository/TaskRepository.java @@ -1,5 +1,8 @@ -package usi.si.seart.server.repository; +package ch.usi.si.seart.server.repository; +import ch.usi.si.seart.model.task.Status; +import ch.usi.si.seart.model.task.Task; +import ch.usi.si.seart.model.user.User; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; @@ -7,9 +10,6 @@ import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import usi.si.seart.model.task.Status; -import usi.si.seart.model.task.Task; -import usi.si.seart.model.user.User; import javax.persistence.Tuple; import javax.validation.constraints.NotNull; @@ -38,7 +38,7 @@ public interface TaskRepository extends JpaRepository, JpaSpecificat @Modifying @Query( value = "UPDATE Task SET " + - "status = usi.si.seart.model.task.Status.CANCELLED, " + + "status = ch.usi.si.seart.model.task.Status.CANCELLED, " + "finished = current_timestamp, " + "version = version + 1, " + "expired = true " + diff --git a/dl4se-server/src/main/java/usi/si/seart/server/repository/TokenRepository.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/repository/TokenRepository.java similarity index 67% rename from dl4se-server/src/main/java/usi/si/seart/server/repository/TokenRepository.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/repository/TokenRepository.java index 7499963a..97fb31b5 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/repository/TokenRepository.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/repository/TokenRepository.java @@ -1,8 +1,8 @@ -package usi.si.seart.server.repository; +package ch.usi.si.seart.server.repository; +import ch.usi.si.seart.model.user.User; +import ch.usi.si.seart.model.user.token.Token; import org.springframework.data.jpa.repository.JpaRepository; -import usi.si.seart.model.user.User; -import usi.si.seart.model.user.token.Token; import java.util.List; import java.util.Optional; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/repository/UserRepository.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/repository/UserRepository.java similarity index 83% rename from dl4se-server/src/main/java/usi/si/seart/server/repository/UserRepository.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/repository/UserRepository.java index 80ab063e..6739e1b8 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/repository/UserRepository.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/repository/UserRepository.java @@ -1,8 +1,8 @@ -package usi.si.seart.server.repository; +package ch.usi.si.seart.server.repository; +import ch.usi.si.seart.model.user.User; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; -import usi.si.seart.model.user.User; import javax.validation.constraints.NotBlank; import java.util.Optional; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/repository/specification/JpaStreamableSpecificationRepository.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/repository/specification/JpaStreamableSpecificationRepository.java similarity index 86% rename from dl4se-server/src/main/java/usi/si/seart/server/repository/specification/JpaStreamableSpecificationRepository.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/repository/specification/JpaStreamableSpecificationRepository.java index 7337c760..a3ef904c 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/repository/specification/JpaStreamableSpecificationRepository.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/repository/specification/JpaStreamableSpecificationRepository.java @@ -1,4 +1,4 @@ -package usi.si.seart.server.repository.specification; +package ch.usi.si.seart.server.repository.specification; import org.springframework.data.domain.Sort; import org.springframework.data.jpa.domain.Specification; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/repository/specification/JpaStreamableSpecificationRepositoryImpl.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/repository/specification/JpaStreamableSpecificationRepositoryImpl.java similarity index 97% rename from dl4se-server/src/main/java/usi/si/seart/server/repository/specification/JpaStreamableSpecificationRepositoryImpl.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/repository/specification/JpaStreamableSpecificationRepositoryImpl.java index c08628e4..c31add19 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/repository/specification/JpaStreamableSpecificationRepositoryImpl.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/repository/specification/JpaStreamableSpecificationRepositoryImpl.java @@ -1,4 +1,4 @@ -package usi.si.seart.server.repository.specification; +package ch.usi.si.seart.server.repository.specification; import lombok.AllArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/scheduling/RepoMaintainer.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/scheduling/RepoMaintainer.java similarity index 92% rename from dl4se-server/src/main/java/usi/si/seart/server/scheduling/RepoMaintainer.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/scheduling/RepoMaintainer.java index 7c6b218a..da5f7ffb 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/scheduling/RepoMaintainer.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/scheduling/RepoMaintainer.java @@ -1,5 +1,7 @@ -package usi.si.seart.server.scheduling; +package ch.usi.si.seart.server.scheduling; +import ch.usi.si.seart.model.GitRepo; +import ch.usi.si.seart.server.service.GitRepoService; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.SneakyThrows; @@ -7,8 +9,6 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import usi.si.seart.model.GitRepo; -import usi.si.seart.server.service.GitRepoService; import java.io.IOException; import java.util.concurrent.TimeUnit; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/scheduling/TaskCleaner.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/scheduling/TaskCleaner.java similarity index 82% rename from dl4se-server/src/main/java/usi/si/seart/server/scheduling/TaskCleaner.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/scheduling/TaskCleaner.java index bc7d3917..8c323fb9 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/scheduling/TaskCleaner.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/scheduling/TaskCleaner.java @@ -1,14 +1,14 @@ -package usi.si.seart.server.scheduling; +package ch.usi.si.seart.server.scheduling; +import ch.usi.si.seart.model.task.Task; +import ch.usi.si.seart.server.service.FileSystemService; +import ch.usi.si.seart.server.service.TaskService; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.experimental.FieldDefaults; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import usi.si.seart.model.task.Task; -import usi.si.seart.server.service.FileSystemService; -import usi.si.seart.server.service.TaskService; @Slf4j @Component diff --git a/dl4se-server/src/main/java/usi/si/seart/server/scheduling/TaskRunner.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/scheduling/TaskRunner.java similarity index 94% rename from dl4se-server/src/main/java/usi/si/seart/server/scheduling/TaskRunner.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/scheduling/TaskRunner.java index 474a6819..25c5917d 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/scheduling/TaskRunner.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/scheduling/TaskRunner.java @@ -1,5 +1,14 @@ -package usi.si.seart.server.scheduling; - +package ch.usi.si.seart.server.scheduling; + +import ch.usi.si.seart.model.code.Code; +import ch.usi.si.seart.model.job.Job; +import ch.usi.si.seart.model.task.Status; +import ch.usi.si.seart.model.task.Task; +import ch.usi.si.seart.server.exception.TaskFailedException; +import ch.usi.si.seart.server.service.CodeService; +import ch.usi.si.seart.server.service.EmailService; +import ch.usi.si.seart.server.service.FileSystemService; +import ch.usi.si.seart.server.service.TaskService; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -20,15 +29,6 @@ import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; -import usi.si.seart.model.code.Code; -import usi.si.seart.model.job.Job; -import usi.si.seart.model.task.Status; -import usi.si.seart.model.task.Task; -import usi.si.seart.server.exception.TaskFailedException; -import usi.si.seart.server.service.CodeService; -import usi.si.seart.server.service.EmailService; -import usi.si.seart.server.service.FileSystemService; -import usi.si.seart.server.service.TaskService; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/scheduling/ViewMaintainer.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/scheduling/ViewMaintainer.java similarity index 87% rename from dl4se-server/src/main/java/usi/si/seart/server/scheduling/ViewMaintainer.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/scheduling/ViewMaintainer.java index 8150626b..9558966c 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/scheduling/ViewMaintainer.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/scheduling/ViewMaintainer.java @@ -1,12 +1,12 @@ -package usi.si.seart.server.scheduling; +package ch.usi.si.seart.server.scheduling; +import ch.usi.si.seart.server.service.DatabaseService; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.experimental.FieldDefaults; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import usi.si.seart.server.service.DatabaseService; @Slf4j @Component diff --git a/dl4se-server/src/main/java/usi/si/seart/server/security/UserPrincipal.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/security/UserPrincipal.java similarity index 94% rename from dl4se-server/src/main/java/usi/si/seart/server/security/UserPrincipal.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/security/UserPrincipal.java index 350e4527..ecd9360d 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/security/UserPrincipal.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/security/UserPrincipal.java @@ -1,5 +1,6 @@ -package usi.si.seart.server.security; +package ch.usi.si.seart.server.security; +import ch.usi.si.seart.model.user.Role; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; @@ -8,7 +9,6 @@ import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; -import usi.si.seart.model.user.Role; import java.util.Collection; import java.util.List; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/security/annotation/AdminRestController.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/security/annotation/AdminRestController.java similarity index 89% rename from dl4se-server/src/main/java/usi/si/seart/server/security/annotation/AdminRestController.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/security/annotation/AdminRestController.java index ac1e2e39..775cf0fc 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/security/annotation/AdminRestController.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/security/annotation/AdminRestController.java @@ -1,4 +1,4 @@ -package usi.si.seart.server.security.annotation; +package ch.usi.si.seart.server.security.annotation; import org.springframework.security.access.annotation.Secured; import org.springframework.web.bind.annotation.RestController; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/security/jwt/JwtRequestFilter.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/security/jwt/JwtRequestFilter.java similarity index 98% rename from dl4se-server/src/main/java/usi/si/seart/server/security/jwt/JwtRequestFilter.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/security/jwt/JwtRequestFilter.java index 58adbdd6..47282850 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/security/jwt/JwtRequestFilter.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/security/jwt/JwtRequestFilter.java @@ -1,4 +1,4 @@ -package usi.si.seart.server.security.jwt; +package ch.usi.si.seart.server.security.jwt; import lombok.AccessLevel; import lombok.AllArgsConstructor; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/security/jwt/JwtTokenProvider.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/security/jwt/JwtTokenProvider.java similarity index 93% rename from dl4se-server/src/main/java/usi/si/seart/server/security/jwt/JwtTokenProvider.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/security/jwt/JwtTokenProvider.java index 04485ac3..b63a2140 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/security/jwt/JwtTokenProvider.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/security/jwt/JwtTokenProvider.java @@ -1,5 +1,6 @@ -package usi.si.seart.server.security.jwt; +package ch.usi.si.seart.server.security.jwt; +import ch.usi.si.seart.server.security.UserPrincipal; import io.jsonwebtoken.Claims; import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.JwtParser; @@ -7,7 +8,6 @@ import lombok.AllArgsConstructor; import lombok.experimental.FieldDefaults; import org.springframework.security.core.Authentication; -import usi.si.seart.server.security.UserPrincipal; import java.time.Duration; import java.time.Instant; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/service/CodeService.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/service/CodeService.java similarity index 88% rename from dl4se-server/src/main/java/usi/si/seart/server/service/CodeService.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/service/CodeService.java index b67c6516..e16fc8e2 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/service/CodeService.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/service/CodeService.java @@ -1,13 +1,13 @@ -package usi.si.seart.server.service; +package ch.usi.si.seart.server.service; +import ch.usi.si.seart.model.code.Code; +import ch.usi.si.seart.server.repository.CodeRepository; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.experimental.FieldDefaults; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; -import usi.si.seart.model.code.Code; -import usi.si.seart.server.repository.CodeRepository; import java.util.stream.Stream; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/service/ConfigurationService.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/service/ConfigurationService.java similarity index 96% rename from dl4se-server/src/main/java/usi/si/seart/server/service/ConfigurationService.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/service/ConfigurationService.java index 128472ed..a741ccc5 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/service/ConfigurationService.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/service/ConfigurationService.java @@ -1,5 +1,7 @@ -package usi.si.seart.server.service; +package ch.usi.si.seart.server.service; +import ch.usi.si.seart.model.Configuration; +import ch.usi.si.seart.server.repository.ConfigurationRepository; import lombok.AccessLevel; import lombok.experimental.FieldDefaults; import org.springframework.beans.factory.annotation.Autowired; @@ -7,8 +9,6 @@ import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.PropertySource; import org.springframework.stereotype.Service; -import usi.si.seart.model.Configuration; -import usi.si.seart.server.repository.ConfigurationRepository; import java.util.Collection; import java.util.Map; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/service/DatabaseService.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/service/DatabaseService.java similarity index 98% rename from dl4se-server/src/main/java/usi/si/seart/server/service/DatabaseService.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/service/DatabaseService.java index f8e00b14..ae847ec4 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/service/DatabaseService.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/service/DatabaseService.java @@ -1,4 +1,4 @@ -package usi.si.seart.server.service; +package ch.usi.si.seart.server.service; import lombok.AccessLevel; import lombok.AllArgsConstructor; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/service/DownloadService.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/service/DownloadService.java similarity index 77% rename from dl4se-server/src/main/java/usi/si/seart/server/service/DownloadService.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/service/DownloadService.java index b751d6d2..8917b160 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/service/DownloadService.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/service/DownloadService.java @@ -1,17 +1,17 @@ -package usi.si.seart.server.service; - +package ch.usi.si.seart.server.service; + +import ch.usi.si.seart.model.user.User; +import ch.usi.si.seart.model.user.token.DownloadToken; +import ch.usi.si.seart.model.user.token.Token; +import ch.usi.si.seart.model.user.token.Token_; +import ch.usi.si.seart.server.exception.TokenExpiredException; +import ch.usi.si.seart.server.exception.TokenNotFoundException; +import ch.usi.si.seart.server.repository.TokenRepository; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import lombok.experimental.FieldDefaults; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import usi.si.seart.model.user.User; -import usi.si.seart.model.user.token.DownloadToken; -import usi.si.seart.model.user.token.Token; -import usi.si.seart.model.user.token.Token_; -import usi.si.seart.server.exception.TokenExpiredException; -import usi.si.seart.server.exception.TokenNotFoundException; -import usi.si.seart.server.repository.TokenRepository; import java.util.UUID; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/service/EmailService.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/service/EmailService.java similarity index 96% rename from dl4se-server/src/main/java/usi/si/seart/server/service/EmailService.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/service/EmailService.java index d1b5387e..77ae1587 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/service/EmailService.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/service/EmailService.java @@ -1,5 +1,7 @@ -package usi.si.seart.server.service; +package ch.usi.si.seart.server.service; +import ch.usi.si.seart.model.task.Task; +import ch.usi.si.seart.server.util.unit.ReadableFileSize; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; @@ -13,8 +15,6 @@ import org.springframework.stereotype.Service; import org.thymeleaf.context.Context; import org.thymeleaf.spring5.SpringTemplateEngine; -import usi.si.seart.model.task.Task; -import usi.si.seart.server.util.unit.ReadableFileSize; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/service/FileSystemService.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/service/FileSystemService.java similarity index 96% rename from dl4se-server/src/main/java/usi/si/seart/server/service/FileSystemService.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/service/FileSystemService.java index 0dc1d353..900d1825 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/service/FileSystemService.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/service/FileSystemService.java @@ -1,12 +1,12 @@ -package usi.si.seart.server.service; +package ch.usi.si.seart.server.service; +import ch.usi.si.seart.model.task.Task; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.experimental.FieldDefaults; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import usi.si.seart.model.task.Task; import java.io.File; import java.io.IOException; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/service/GitRepoService.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/service/GitRepoService.java similarity index 88% rename from dl4se-server/src/main/java/usi/si/seart/server/service/GitRepoService.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/service/GitRepoService.java index 99ab9d1e..79efcd2d 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/service/GitRepoService.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/service/GitRepoService.java @@ -1,5 +1,7 @@ -package usi.si.seart.server.service; +package ch.usi.si.seart.server.service; +import ch.usi.si.seart.model.GitRepo; +import ch.usi.si.seart.server.repository.GitRepoRepository; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Cleanup; @@ -8,8 +10,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; -import usi.si.seart.model.GitRepo; -import usi.si.seart.server.repository.GitRepoRepository; import java.util.function.Consumer; import java.util.stream.Stream; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/service/LanguageService.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/service/LanguageService.java similarity index 79% rename from dl4se-server/src/main/java/usi/si/seart/server/service/LanguageService.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/service/LanguageService.java index 28c65b1c..671635ae 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/service/LanguageService.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/service/LanguageService.java @@ -1,14 +1,14 @@ -package usi.si.seart.server.service; +package ch.usi.si.seart.server.service; +import ch.usi.si.seart.model.Language; +import ch.usi.si.seart.model.Language_; +import ch.usi.si.seart.server.exception.LanguageNotFoundException; +import ch.usi.si.seart.server.repository.LanguageRepository; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.experimental.FieldDefaults; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import usi.si.seart.model.Language; -import usi.si.seart.model.Language_; -import usi.si.seart.server.exception.LanguageNotFoundException; -import usi.si.seart.server.repository.LanguageRepository; import java.util.List; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/service/PasswordResetService.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/service/PasswordResetService.java similarity index 82% rename from dl4se-server/src/main/java/usi/si/seart/server/service/PasswordResetService.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/service/PasswordResetService.java index b6e80ba8..fc1d3c0b 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/service/PasswordResetService.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/service/PasswordResetService.java @@ -1,19 +1,19 @@ -package usi.si.seart.server.service; +package ch.usi.si.seart.server.service; +import ch.usi.si.seart.model.user.User; +import ch.usi.si.seart.model.user.token.PasswordResetToken; +import ch.usi.si.seart.model.user.token.Token; +import ch.usi.si.seart.model.user.token.Token_; +import ch.usi.si.seart.server.exception.TokenExpiredException; +import ch.usi.si.seart.server.exception.TokenNotFoundException; +import ch.usi.si.seart.server.repository.TokenRepository; +import ch.usi.si.seart.server.repository.UserRepository; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import lombok.experimental.FieldDefaults; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; -import usi.si.seart.model.user.User; -import usi.si.seart.model.user.token.PasswordResetToken; -import usi.si.seart.model.user.token.Token; -import usi.si.seart.model.user.token.Token_; -import usi.si.seart.server.exception.TokenExpiredException; -import usi.si.seart.server.exception.TokenNotFoundException; -import usi.si.seart.server.repository.TokenRepository; -import usi.si.seart.server.repository.UserRepository; import java.util.UUID; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/service/StatisticsService.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/service/StatisticsService.java similarity index 86% rename from dl4se-server/src/main/java/usi/si/seart/server/service/StatisticsService.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/service/StatisticsService.java index 763ca801..6d433933 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/service/StatisticsService.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/service/StatisticsService.java @@ -1,24 +1,24 @@ -package usi.si.seart.server.service; - +package ch.usi.si.seart.server.service; + +import ch.usi.si.seart.model.GitRepo; +import ch.usi.si.seart.model.Language; +import ch.usi.si.seart.model.code.File; +import ch.usi.si.seart.model.code.Function; +import ch.usi.si.seart.model.task.Status; +import ch.usi.si.seart.model.user.User; +import ch.usi.si.seart.server.repository.CodeRepository; +import ch.usi.si.seart.server.repository.FileRepository; +import ch.usi.si.seart.server.repository.FunctionRepository; +import ch.usi.si.seart.server.repository.GitRepoRepository; +import ch.usi.si.seart.server.repository.TableRowCountRepository; +import ch.usi.si.seart.server.repository.TaskRepository; +import ch.usi.si.seart.views.GroupedCount; +import ch.usi.si.seart.views.TableRowCount; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.experimental.FieldDefaults; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import usi.si.seart.model.GitRepo; -import usi.si.seart.model.Language; -import usi.si.seart.model.code.File; -import usi.si.seart.model.code.Function; -import usi.si.seart.model.task.Status; -import usi.si.seart.model.user.User; -import usi.si.seart.server.repository.CodeRepository; -import usi.si.seart.server.repository.FileRepository; -import usi.si.seart.server.repository.FunctionRepository; -import usi.si.seart.server.repository.GitRepoRepository; -import usi.si.seart.server.repository.TableRowCountRepository; -import usi.si.seart.server.repository.TaskRepository; -import usi.si.seart.views.GroupedCount; -import usi.si.seart.views.TableRowCount; import javax.persistence.Table; import javax.persistence.Tuple; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/service/TaskService.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/service/TaskService.java similarity index 93% rename from dl4se-server/src/main/java/usi/si/seart/server/service/TaskService.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/service/TaskService.java index 3609dcf8..d18794a1 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/service/TaskService.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/service/TaskService.java @@ -1,5 +1,13 @@ -package usi.si.seart.server.service; - +package ch.usi.si.seart.server.service; + +import ch.usi.si.seart.model.job.Job; +import ch.usi.si.seart.model.task.Status; +import ch.usi.si.seart.model.task.Task; +import ch.usi.si.seart.model.task.Task_; +import ch.usi.si.seart.model.user.User; +import ch.usi.si.seart.server.exception.TaskFailedException; +import ch.usi.si.seart.server.exception.TaskNotFoundException; +import ch.usi.si.seart.server.repository.TaskRepository; import com.fasterxml.jackson.databind.JsonNode; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -13,14 +21,6 @@ import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.ConcurrentReferenceHashMap; -import usi.si.seart.model.job.Job; -import usi.si.seart.model.task.Status; -import usi.si.seart.model.task.Task; -import usi.si.seart.model.task.Task_; -import usi.si.seart.model.user.User; -import usi.si.seart.server.exception.TaskFailedException; -import usi.si.seart.server.exception.TaskNotFoundException; -import usi.si.seart.server.repository.TaskRepository; import java.io.PrintWriter; import java.io.StringWriter; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/service/UserService.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/service/UserService.java similarity index 88% rename from dl4se-server/src/main/java/usi/si/seart/server/service/UserService.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/service/UserService.java index 3aa925d1..871da952 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/service/UserService.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/service/UserService.java @@ -1,5 +1,10 @@ -package usi.si.seart.server.service; +package ch.usi.si.seart.server.service; +import ch.usi.si.seart.model.user.Role; +import ch.usi.si.seart.model.user.User; +import ch.usi.si.seart.model.user.User_; +import ch.usi.si.seart.server.exception.UserNotFoundException; +import ch.usi.si.seart.server.repository.UserRepository; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.experimental.FieldDefaults; @@ -9,11 +14,6 @@ import org.springframework.data.jpa.domain.Specification; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; -import usi.si.seart.model.user.Role; -import usi.si.seart.model.user.User; -import usi.si.seart.model.user.User_; -import usi.si.seart.server.exception.UserNotFoundException; -import usi.si.seart.server.repository.UserRepository; public interface UserService { diff --git a/dl4se-server/src/main/java/usi/si/seart/server/service/VerificationService.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/service/VerificationService.java similarity index 80% rename from dl4se-server/src/main/java/usi/si/seart/server/service/VerificationService.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/service/VerificationService.java index bb533649..f6fddd33 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/service/VerificationService.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/service/VerificationService.java @@ -1,18 +1,18 @@ -package usi.si.seart.server.service; +package ch.usi.si.seart.server.service; +import ch.usi.si.seart.model.user.User; +import ch.usi.si.seart.model.user.token.Token; +import ch.usi.si.seart.model.user.token.Token_; +import ch.usi.si.seart.model.user.token.VerificationToken; +import ch.usi.si.seart.server.exception.TokenExpiredException; +import ch.usi.si.seart.server.exception.TokenNotFoundException; +import ch.usi.si.seart.server.repository.TokenRepository; +import ch.usi.si.seart.server.repository.UserRepository; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import lombok.experimental.FieldDefaults; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import usi.si.seart.model.user.User; -import usi.si.seart.model.user.token.Token; -import usi.si.seart.model.user.token.Token_; -import usi.si.seart.model.user.token.VerificationToken; -import usi.si.seart.server.exception.TokenExpiredException; -import usi.si.seart.server.exception.TokenNotFoundException; -import usi.si.seart.server.repository.TokenRepository; -import usi.si.seart.server.repository.UserRepository; import java.util.UUID; diff --git a/dl4se-server/src/main/java/usi/si/seart/server/util/unit/ReadableFileSize.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/util/unit/ReadableFileSize.java similarity index 95% rename from dl4se-server/src/main/java/usi/si/seart/server/util/unit/ReadableFileSize.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/util/unit/ReadableFileSize.java index 27102a2d..641ebcbd 100644 --- a/dl4se-server/src/main/java/usi/si/seart/server/util/unit/ReadableFileSize.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/util/unit/ReadableFileSize.java @@ -1,4 +1,4 @@ -package usi.si.seart.server.util.unit; +package ch.usi.si.seart.server.util.unit; import lombok.AccessLevel; import lombok.AllArgsConstructor; diff --git a/dl4se-server/src/main/resources/application.properties b/dl4se-server/src/main/resources/application.properties index 960f3758..e391cc78 100644 --- a/dl4se-server/src/main/resources/application.properties +++ b/dl4se-server/src/main/resources/application.properties @@ -50,7 +50,8 @@ spring.data.web.pageable.max-page-size=100 spring.data.web.pageable.one-indexed-parameters=true # Logging Configuration -logging.level.usi.si.seart=INFO +logging.level.root=INFO +logging.level.ch.usi.si.seart.server=INFO # JPA Configuration spring.jpa.database=postgresql diff --git a/pom.xml b/pom.xml index 66d632ec..d55c53a9 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 - usi.si.seart + ch.usi.si.seart dl4se ${revision} pom From 1cecb61ad42b7bdb8bb31376d6bfdb55d3bc2395 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 18 Oct 2023 16:18:29 +0200 Subject: [PATCH 0443/1089] Minor refactoring for readability --- .../converter/TaskSearchDtoToSpecificationConverter.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dl4se-server/src/main/java/ch/usi/si/seart/server/converter/TaskSearchDtoToSpecificationConverter.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/converter/TaskSearchDtoToSpecificationConverter.java index d34bb9d1..af7e6207 100644 --- a/dl4se-server/src/main/java/ch/usi/si/seart/server/converter/TaskSearchDtoToSpecificationConverter.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/converter/TaskSearchDtoToSpecificationConverter.java @@ -7,6 +7,8 @@ import org.springframework.data.jpa.domain.Specification; import org.springframework.lang.NonNull; +import javax.persistence.criteria.Expression; + public class TaskSearchDtoToSpecificationConverter implements Converter> { @Override @@ -21,6 +23,9 @@ public Specification convert(TaskSearchDto source) { } private Specification withUuidContaining(String pattern) { - return (root, query, criteriaBuilder) -> criteriaBuilder.like(root.get(Task_.UUID).as(String.class), "%" + pattern + "%"); + return (root, query, criteriaBuilder) -> { + Expression expression = root.get(Task_.UUID).as(String.class); + return criteriaBuilder.like(expression, "%" + pattern + "%"); + }; } } From 5e5e07a9a06b1e6d695769970342f6f3aa467bd1 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 18 Oct 2023 16:26:17 +0200 Subject: [PATCH 0444/1089] Removing casts --- .../ch/usi/si/seart/server/controller/AdminController.java | 4 ++-- .../ch/usi/si/seart/server/controller/TaskController.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/AdminController.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/AdminController.java index 941bf03e..d6b98984 100644 --- a/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/AdminController.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/AdminController.java @@ -59,7 +59,7 @@ public ResponseEntity listUsers( UserSearchDto userSearchDto, @SortDefault(sort = User_.REGISTERED, direction = Sort.Direction.DESC) Pageable pageable ) { - Specification specification = (Specification) conversionService.convert(userSearchDto, Specification.class); + Specification specification = conversionService.convert(userSearchDto, Specification.class); Page users = userService.getAll(specification, pageable); return ResponseEntity.ok(users); } @@ -108,7 +108,7 @@ public ResponseEntity listTasks( TaskSearchDto taskSearchDto, @SortDefault(sort = Task_.SUBMITTED, direction = Sort.Direction.DESC) Pageable pageable ) { - Specification specification = (Specification) conversionService.convert(taskSearchDto, Specification.class); + Specification specification = conversionService.convert(taskSearchDto, Specification.class); Page tasks = taskService.getAll(specification, pageable); return ResponseEntity.ok(tasks); } diff --git a/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/TaskController.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/TaskController.java index e8f6d10c..2e38db2f 100644 --- a/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/TaskController.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/TaskController.java @@ -78,7 +78,7 @@ public ResponseEntity tasks( @SortDefault(sort = Task_.SUBMITTED, direction = Sort.Direction.DESC) Pageable pageable, @AuthenticationPrincipal UserPrincipal principal ) { - Specification specification = (Specification) conversionService.convert(taskSearchDto, Specification.class); + Specification specification = conversionService.convert(taskSearchDto, Specification.class); specification = specification.and( (root, query, criteriaBuilder) -> criteriaBuilder.equal(root.join(Task_.USER).get(User_.ID), principal.getId()) ); From 78fdc7f8d0c07655547b6ed199d5208535cd4a26 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 18 Oct 2023 16:28:12 +0200 Subject: [PATCH 0445/1089] Using better typing for specification --- .../java/ch/usi/si/seart/server/controller/TaskController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/TaskController.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/TaskController.java index 2e38db2f..591884ac 100644 --- a/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/TaskController.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/TaskController.java @@ -80,7 +80,7 @@ public ResponseEntity tasks( ) { Specification specification = conversionService.convert(taskSearchDto, Specification.class); specification = specification.and( - (root, query, criteriaBuilder) -> criteriaBuilder.equal(root.join(Task_.USER).get(User_.ID), principal.getId()) + (root, query, criteriaBuilder) -> criteriaBuilder.equal(root.join(Task_.user).get(User_.id), principal.getId()) ); Page tasks = taskService.getAll(specification, pageable); return ResponseEntity.ok(tasks); From ff27876aa6d0ec0a780633bf271f55146e19e9b1 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 18 Oct 2023 16:28:51 +0200 Subject: [PATCH 0446/1089] Renaming converter in favor of something more explicit --- .../main/java/ch/usi/si/seart/server/config/WebConfig.java | 4 ++-- ...toToUserConverter.java => RegisterDtoToUserConverter.java} | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename dl4se-server/src/main/java/ch/usi/si/seart/server/converter/{DtoToUserConverter.java => RegisterDtoToUserConverter.java} (86%) diff --git a/dl4se-server/src/main/java/ch/usi/si/seart/server/config/WebConfig.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/config/WebConfig.java index c60d1af6..5b539ad3 100644 --- a/dl4se-server/src/main/java/ch/usi/si/seart/server/config/WebConfig.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/config/WebConfig.java @@ -1,7 +1,7 @@ package ch.usi.si.seart.server.config; import ch.usi.si.seart.server.converter.DtoToConfigurationConverter; -import ch.usi.si.seart.server.converter.DtoToUserConverter; +import ch.usi.si.seart.server.converter.RegisterDtoToUserConverter; import ch.usi.si.seart.server.converter.TaskSearchDtoToSpecificationConverter; import ch.usi.si.seart.server.converter.UserSearchDtoToSpecificationConverter; import ch.usi.si.seart.server.converter.UserToUserPrincipalConverter; @@ -25,8 +25,8 @@ public void addCorsMappings(CorsRegistry registry) { @Override public void addFormatters(FormatterRegistry registry) { - registry.addConverter(new DtoToUserConverter()); registry.addConverter(new DtoToConfigurationConverter()); + registry.addConverter(new RegisterDtoToUserConverter()); registry.addConverter(new TaskSearchDtoToSpecificationConverter()); registry.addConverter(new UserSearchDtoToSpecificationConverter()); registry.addConverter(new UserToUserPrincipalConverter()); diff --git a/dl4se-server/src/main/java/ch/usi/si/seart/server/converter/DtoToUserConverter.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/converter/RegisterDtoToUserConverter.java similarity index 86% rename from dl4se-server/src/main/java/ch/usi/si/seart/server/converter/DtoToUserConverter.java rename to dl4se-server/src/main/java/ch/usi/si/seart/server/converter/RegisterDtoToUserConverter.java index 8bf1d24e..0bbf2082 100644 --- a/dl4se-server/src/main/java/ch/usi/si/seart/server/converter/DtoToUserConverter.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/converter/RegisterDtoToUserConverter.java @@ -5,7 +5,7 @@ import org.springframework.core.convert.converter.Converter; import org.springframework.lang.NonNull; -public class DtoToUserConverter implements Converter { +public class RegisterDtoToUserConverter implements Converter { @Override @NonNull From aa2a7b69cffa3543dff3331f6522b96a13e72a12 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 18 Oct 2023 16:30:16 +0200 Subject: [PATCH 0447/1089] Removing DTO and unused converter --- .../usi/si/seart/server/config/WebConfig.java | 2 -- .../DtoToConfigurationConverter.java | 18 ------------- .../si/seart/server/dto/ConfigurationDto.java | 25 ------------------- 3 files changed, 45 deletions(-) delete mode 100644 dl4se-server/src/main/java/ch/usi/si/seart/server/converter/DtoToConfigurationConverter.java delete mode 100644 dl4se-server/src/main/java/ch/usi/si/seart/server/dto/ConfigurationDto.java diff --git a/dl4se-server/src/main/java/ch/usi/si/seart/server/config/WebConfig.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/config/WebConfig.java index 5b539ad3..2ab9f3f4 100644 --- a/dl4se-server/src/main/java/ch/usi/si/seart/server/config/WebConfig.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/config/WebConfig.java @@ -1,6 +1,5 @@ package ch.usi.si.seart.server.config; -import ch.usi.si.seart.server.converter.DtoToConfigurationConverter; import ch.usi.si.seart.server.converter.RegisterDtoToUserConverter; import ch.usi.si.seart.server.converter.TaskSearchDtoToSpecificationConverter; import ch.usi.si.seart.server.converter.UserSearchDtoToSpecificationConverter; @@ -25,7 +24,6 @@ public void addCorsMappings(CorsRegistry registry) { @Override public void addFormatters(FormatterRegistry registry) { - registry.addConverter(new DtoToConfigurationConverter()); registry.addConverter(new RegisterDtoToUserConverter()); registry.addConverter(new TaskSearchDtoToSpecificationConverter()); registry.addConverter(new UserSearchDtoToSpecificationConverter()); diff --git a/dl4se-server/src/main/java/ch/usi/si/seart/server/converter/DtoToConfigurationConverter.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/converter/DtoToConfigurationConverter.java deleted file mode 100644 index 35d5005f..00000000 --- a/dl4se-server/src/main/java/ch/usi/si/seart/server/converter/DtoToConfigurationConverter.java +++ /dev/null @@ -1,18 +0,0 @@ -package ch.usi.si.seart.server.converter; - -import ch.usi.si.seart.model.Configuration; -import ch.usi.si.seart.server.dto.ConfigurationDto; -import org.springframework.core.convert.converter.Converter; -import org.springframework.lang.NonNull; - -public class DtoToConfigurationConverter implements Converter { - - @Override - @NonNull - public Configuration convert(@NonNull ConfigurationDto source) { - return Configuration.builder() - .key(source.getKey()) - .value(source.getValue()) - .build(); - } -} diff --git a/dl4se-server/src/main/java/ch/usi/si/seart/server/dto/ConfigurationDto.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/dto/ConfigurationDto.java deleted file mode 100644 index 49479618..00000000 --- a/dl4se-server/src/main/java/ch/usi/si/seart/server/dto/ConfigurationDto.java +++ /dev/null @@ -1,25 +0,0 @@ -package ch.usi.si.seart.server.dto; - -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.experimental.FieldDefaults; - -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; - -@Getter -@Builder -@FieldDefaults(level = AccessLevel.PRIVATE) -@NoArgsConstructor -@AllArgsConstructor -public class ConfigurationDto { - - @NotBlank - String key; - - @NotNull - String value; -} From 5feaabbeddaffd7b43e2b0880372ab2875c10c03 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 18 Oct 2023 16:39:00 +0200 Subject: [PATCH 0448/1089] Server logging config now similar to crawler --- dl4se-server/src/main/resources/application.properties | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/dl4se-server/src/main/resources/application.properties b/dl4se-server/src/main/resources/application.properties index e391cc78..72dbd04b 100644 --- a/dl4se-server/src/main/resources/application.properties +++ b/dl4se-server/src/main/resources/application.properties @@ -52,6 +52,12 @@ spring.data.web.pageable.one-indexed-parameters=true # Logging Configuration logging.level.root=INFO logging.level.ch.usi.si.seart.server=INFO +logging.file.path=logs +logging.file.name=${logging.file.path}/server.log +logging.logback.rollingpolicy.max-history=180 +logging.logback.rollingpolicy.max-file-size=100MB +logging.logback.rollingpolicy.total-size-cap=5GB +logging.logback.rollingpolicy.file-name-pattern=${logging.file.path}/server_%d{yyyy-MM-dd}_%i.log.gz # JPA Configuration spring.jpa.database=postgresql @@ -64,10 +70,6 @@ spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL10Dialec # JPA Debugging Configuration spring.jpa.properties.hibernate.format_sql=false logging.level.org.hibernate.SQL=OFF -logging.file.name=logs/platform.log -logging.logback.rollingpolicy.file-name-pattern=${LOG_FILE}_%d{yyyy-MM-dd}_%i.log.gz -logging.logback.rollingpolicy.max-file-size=100MB -logging.logback.rollingpolicy.max-history=180 # Spring Datasource Configuration spring.datasource.url=jdbc:postgresql://${DATABASE_HOST}:${DATABASE_PORT}/${DATABASE_NAME} From c80aed81e565e8070d3c986a198fff3254273d78 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 18 Oct 2023 16:40:32 +0200 Subject: [PATCH 0449/1089] Datasource configurations now have defaults just like in the crawler --- dl4se-server/src/main/resources/application.properties | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dl4se-server/src/main/resources/application.properties b/dl4se-server/src/main/resources/application.properties index 72dbd04b..021001a6 100644 --- a/dl4se-server/src/main/resources/application.properties +++ b/dl4se-server/src/main/resources/application.properties @@ -72,9 +72,9 @@ spring.jpa.properties.hibernate.format_sql=false logging.level.org.hibernate.SQL=OFF # Spring Datasource Configuration -spring.datasource.url=jdbc:postgresql://${DATABASE_HOST}:${DATABASE_PORT}/${DATABASE_NAME} -spring.datasource.username=${DATABASE_USER} -spring.datasource.password=${DATABASE_PASS} +spring.datasource.url=jdbc:postgresql://${DATABASE_HOST:localhost}:${DATABASE_PORT:5432}/${DATABASE_NAME:dl4se} +spring.datasource.username=${DATABASE_USER:dl4se_admin} +spring.datasource.password=${DATABASE_PASS:Lugano2022} spring.datasource.driver-class-name=org.postgresql.Driver website.host=${WEBSITE_HOST:localhost} From e7de66fa418da27c33e3e9829674d98952b9f6b4 Mon Sep 17 00:00:00 2001 From: dabico Date: Wed, 18 Oct 2023 16:46:24 +0200 Subject: [PATCH 0450/1089] Upgrading Postgres dialect for crawler --- dl4se-crawler/src/main/resources/application.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dl4se-crawler/src/main/resources/application.properties b/dl4se-crawler/src/main/resources/application.properties index 46f2d88c..02124878 100644 --- a/dl4se-crawler/src/main/resources/application.properties +++ b/dl4se-crawler/src/main/resources/application.properties @@ -27,7 +27,7 @@ spring.jpa.open-in-view=false spring.jpa.hibernate.ddl-auto=none spring.jpa.properties.hibernate.jdbc.time_zone=UTC spring.jpa.properties.hibernate.jdbc.fetch_size=500 -spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL95Dialect +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL10Dialect # Spring Datasource Configuration spring.datasource.url=jdbc:postgresql://${DATABASE_HOST:localhost}:${DATABASE_PORT:5432}/${DATABASE_NAME:dl4se} From 56e8984f0a90827265523b9a731d9d056e71e31f Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 19 Oct 2023 10:38:42 +0200 Subject: [PATCH 0451/1089] Changing the `name` attribute an all pom files --- dl4se-analyzer/pom.xml | 2 +- dl4se-crawler/pom.xml | 2 +- dl4se-model/pom.xml | 2 +- dl4se-server/pom.xml | 2 +- pom.xml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dl4se-analyzer/pom.xml b/dl4se-analyzer/pom.xml index 7076b0e9..7839d548 100644 --- a/dl4se-analyzer/pom.xml +++ b/dl4se-analyzer/pom.xml @@ -10,7 +10,7 @@ dl4se-analyzer - dl4se-analyzer + ${project.groupId}:${project.artifactId} UTF-8 diff --git a/dl4se-crawler/pom.xml b/dl4se-crawler/pom.xml index a61f41dc..b88c4519 100644 --- a/dl4se-crawler/pom.xml +++ b/dl4se-crawler/pom.xml @@ -10,7 +10,7 @@ dl4se-crawler - dl4se-crawler + ${project.groupId}:${project.artifactId} UTF-8 diff --git a/dl4se-model/pom.xml b/dl4se-model/pom.xml index ca38d2cc..fb6a9e6c 100644 --- a/dl4se-model/pom.xml +++ b/dl4se-model/pom.xml @@ -10,7 +10,7 @@ dl4se-model - dl4se-model + ${project.groupId}:${project.artifactId} UTF-8 diff --git a/dl4se-server/pom.xml b/dl4se-server/pom.xml index c5a6e987..bbd42908 100644 --- a/dl4se-server/pom.xml +++ b/dl4se-server/pom.xml @@ -10,7 +10,7 @@ dl4se-server - dl4se-server + ${project.groupId}:${project.artifactId} UTF-8 diff --git a/pom.xml b/pom.xml index d55c53a9..c38a63f2 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ ${revision} pom - DL4SE Dataset Hub + ${project.groupId}:${project.artifactId} Building Training Datasets for Deep Learning Models in Software Engineering. From 70fd92821500bafaff56b71f7361dbdb98921cea Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 19 Oct 2023 10:43:00 +0200 Subject: [PATCH 0452/1089] Compartmentalizing module definitions into different profiles --- .idea/misc.xml | 6 +++++- pom.xml | 35 +++++++++++++++++++++++++++++------ 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 5a77f618..28cffce3 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -10,6 +10,10 @@ @@ -17,4 +21,4 @@ - \ No newline at end of file + diff --git a/pom.xml b/pom.xml index c38a63f2..cfd886a5 100644 --- a/pom.xml +++ b/pom.xml @@ -23,12 +23,35 @@ - - dl4se-crawler - dl4se-model - dl4se-server - dl4se-analyzer - + + + crawler + + dl4se-model + dl4se-analyzer + dl4se-crawler + + + + server + + dl4se-model + dl4se-server + + + + default + + true + + + dl4se-model + dl4se-analyzer + dl4se-crawler + dl4se-server + + + 1.0.0 From 51f4d8f1acca5c485f41aa0df368db5f558353df Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 19 Oct 2023 10:56:42 +0200 Subject: [PATCH 0453/1089] Simplifying docker build to only copy required modules and use profiles --- deployment/crawler/Dockerfile | 4 +--- deployment/server/Dockerfile | 5 +---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/deployment/crawler/Dockerfile b/deployment/crawler/Dockerfile index 0efa2c08..9b6343b5 100644 --- a/deployment/crawler/Dockerfile +++ b/deployment/crawler/Dockerfile @@ -4,13 +4,11 @@ COPY ./pom.xml /pom.xml COPY ./dl4se-analyzer /dl4se-analyzer COPY ./dl4se-crawler /dl4se-crawler COPY ./dl4se-model /dl4se-model -COPY ./dl4se-server /dl4se-server RUN mvn -e \ --no-transfer-progress \ - clean \ package \ - -pl dl4se-crawler \ + -Pcrawler \ -am -DskipTests FROM eclipse-temurin:11.0.20_8-jre-alpine diff --git a/deployment/server/Dockerfile b/deployment/server/Dockerfile index 5d1409e6..2a56b876 100644 --- a/deployment/server/Dockerfile +++ b/deployment/server/Dockerfile @@ -1,16 +1,13 @@ FROM maven:3.9.3-eclipse-temurin-11-alpine AS build COPY ./pom.xml /pom.xml -COPY ./dl4se-analyzer /dl4se-analyzer -COPY ./dl4se-crawler /dl4se-crawler COPY ./dl4se-model /dl4se-model COPY ./dl4se-server /dl4se-server RUN mvn -e \ --no-transfer-progress \ - clean \ package \ - -pl dl4se-server \ + -Pserver \ -am -DskipTests FROM eclipse-temurin:11.0.20_8-jre-alpine From 88a1311114c7b28f188b3dda9accfd2f80d0cb22 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 19 Oct 2023 10:58:40 +0200 Subject: [PATCH 0454/1089] Removing JAR run configurations which are no longer used --- .idea/runConfigurations/Crawler.xml | 11 ----------- .idea/runConfigurations/Server.xml | 10 ---------- 2 files changed, 21 deletions(-) delete mode 100644 .idea/runConfigurations/Crawler.xml delete mode 100644 .idea/runConfigurations/Server.xml diff --git a/.idea/runConfigurations/Crawler.xml b/.idea/runConfigurations/Crawler.xml deleted file mode 100644 index 7138e42a..00000000 --- a/.idea/runConfigurations/Crawler.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/runConfigurations/Server.xml b/.idea/runConfigurations/Server.xml deleted file mode 100644 index afba5796..00000000 --- a/.idea/runConfigurations/Server.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - \ No newline at end of file From 24bcfc2370f1e92718a9b5f737a51627b49b11cb Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 19 Oct 2023 11:12:38 +0200 Subject: [PATCH 0455/1089] Bumping patch version of Spring Boot `2.7.16` -> `2.7.17` --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index cfd886a5..72c4b7d3 100644 --- a/pom.xml +++ b/pom.xml @@ -65,7 +65,7 @@ 42.6.0 0.12.3 2.15.2 - 2.7.16 + 2.7.17 2021.0.8 From 47f0a991dbea7a33095cdfbe98b6688034071d5c Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 19 Oct 2023 11:18:05 +0200 Subject: [PATCH 0456/1089] Bumping patch version of Jackson `2.15.2` -> `2.15.3` --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 72c4b7d3..5decb35a 100644 --- a/pom.xml +++ b/pom.xml @@ -64,7 +64,7 @@ 3.1.10 42.6.0 0.12.3 - 2.15.2 + 2.15.3 2.7.17 2021.0.8 From 6c1b0f2b54c9d665816e64b4b52443b78f8a6ae7 Mon Sep 17 00:00:00 2001 From: dabico Date: Thu, 19 Oct 2023 11:22:19 +0200 Subject: [PATCH 0457/1089] Bumping patch version of Guava `32.1.2-jre` -> `32.1.3-jre` --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5decb35a..165a01e7 100644 --- a/pom.xml +++ b/pom.xml @@ -59,7 +59,7 @@ 5.10.0 1.7.0 1.18.30 - 32.1.2-jre + 32.1.3-jre 1.43.3 3.1.10 42.6.0 From d60bd879573679f8090e29198da59d4a98cfb842 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 20 Oct 2023 10:54:54 +0200 Subject: [PATCH 0458/1089] Renaming static variable field in `TaskFailedException` --- .../ch/usi/si/seart/server/exception/TaskFailedException.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dl4se-server/src/main/java/ch/usi/si/seart/server/exception/TaskFailedException.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/exception/TaskFailedException.java index 8eadbbf6..179b72e0 100644 --- a/dl4se-server/src/main/java/ch/usi/si/seart/server/exception/TaskFailedException.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/exception/TaskFailedException.java @@ -14,13 +14,13 @@ */ public class TaskFailedException extends RuntimeException { - private static final String format = "%s occurred while executing task [%s]"; + private static final String TEMPLATE = "%s occurred while executing task [%s]"; @Getter private final transient Task task; public TaskFailedException(@NotNull Task task, @NotNull Throwable cause) { - super(String.format(format, cause.getClass().getSimpleName(), task.getUuid()), cause); + super(String.format(TEMPLATE, cause.getClass().getSimpleName(), task.getUuid()), cause); this.task = task; } } From e70f804d3a1ca424d15985af142832a2076ff8ad Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 20 Oct 2023 10:55:07 +0200 Subject: [PATCH 0459/1089] Using class-level getter for `TaskFailedException` --- .../ch/usi/si/seart/server/exception/TaskFailedException.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dl4se-server/src/main/java/ch/usi/si/seart/server/exception/TaskFailedException.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/exception/TaskFailedException.java index 179b72e0..adbf802b 100644 --- a/dl4se-server/src/main/java/ch/usi/si/seart/server/exception/TaskFailedException.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/exception/TaskFailedException.java @@ -12,11 +12,11 @@ * * @author dabico */ +@Getter public class TaskFailedException extends RuntimeException { private static final String TEMPLATE = "%s occurred while executing task [%s]"; - @Getter private final transient Task task; public TaskFailedException(@NotNull Task task, @NotNull Throwable cause) { From 7d42c62f074ae868bd7e323b8ab8e66a08b49c2c Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 20 Oct 2023 10:57:09 +0200 Subject: [PATCH 0460/1089] Replacing general suppression with something more specific --- .../java/ch/usi/si/seart/server/controller/TaskController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/TaskController.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/TaskController.java index 591884ac..59632409 100644 --- a/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/TaskController.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/TaskController.java @@ -71,7 +71,7 @@ public ResponseEntity task(@PathVariable UUID uuid) { return ResponseEntity.ok(task); } - @SuppressWarnings({"unchecked", "ConstantConditions"}) + @SuppressWarnings({"unchecked", "DataFlowIssue"}) @GetMapping public ResponseEntity tasks( TaskSearchDto taskSearchDto, From 191398bd33f8fdd67f6f60b82ac6b039f010abd4 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 20 Oct 2023 10:57:18 +0200 Subject: [PATCH 0461/1089] Removing redundant suppression --- .../java/ch/usi/si/seart/server/controller/TaskController.java | 1 - 1 file changed, 1 deletion(-) diff --git a/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/TaskController.java b/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/TaskController.java index 59632409..615e0520 100644 --- a/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/TaskController.java +++ b/dl4se-server/src/main/java/ch/usi/si/seart/server/controller/TaskController.java @@ -86,7 +86,6 @@ public ResponseEntity tasks( return ResponseEntity.ok(tasks); } - @SuppressWarnings("ConstantConditions") @PostMapping("/{dataset}/create") public ResponseEntity create( @PathVariable String dataset, From 33eb8e0e764516662898059002c98b6d7d38fb8e Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 20 Oct 2023 15:58:31 +0200 Subject: [PATCH 0462/1089] Adding missing blank line to EOF --- http/UserController.http | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/http/UserController.http b/http/UserController.http index 061b1c14..1042e7cd 100644 --- a/http/UserController.http +++ b/http/UserController.http @@ -42,4 +42,4 @@ Content-Type: application/json { "password": "22022onaguL" -} \ No newline at end of file +} From c9ebdf5a9808af7ec5bf5de24c209ad3a0862df7 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 20 Oct 2023 15:58:54 +0200 Subject: [PATCH 0463/1089] Removing non-functional run configuration --- .../runConfigurations/dl4se_crawler__run_.xml | 53 ------------------- 1 file changed, 53 deletions(-) delete mode 100644 .idea/runConfigurations/dl4se_crawler__run_.xml diff --git a/.idea/runConfigurations/dl4se_crawler__run_.xml b/.idea/runConfigurations/dl4se_crawler__run_.xml deleted file mode 100644 index dc9a41e9..00000000 --- a/.idea/runConfigurations/dl4se_crawler__run_.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - \ No newline at end of file From acec75319b7e7f3cd0e0d3b4029693b3838bcf24 Mon Sep 17 00:00:00 2001 From: dabico Date: Fri, 20 Oct 2023 15:59:15 +0200 Subject: [PATCH 0464/1089] Renaming existing Maven run configurations --- .../dl4se__clean_install_.xml | 28 ---------------- .idea/runConfigurations/install.xml | 33 ++++++++++++++++--- .../{dl4se__test_.xml => test.xml} | 7 ++-- 3 files changed, 33 insertions(+), 35 deletions(-) delete mode 100644 .idea/runConfigurations/dl4se__clean_install_.xml rename .idea/runConfigurations/{dl4se__test_.xml => test.xml} (78%) diff --git a/.idea/runConfigurations/dl4se__clean_install_.xml b/.idea/runConfigurations/dl4se__clean_install_.xml deleted file mode 100644 index a3aba018..00000000 --- a/.idea/runConfigurations/dl4se__clean_install_.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/runConfigurations/install.xml b/.idea/runConfigurations/install.xml index b5499c57..9193b587 100644 --- a/.idea/runConfigurations/install.xml +++ b/.idea/runConfigurations/install.xml @@ -1,9 +1,32 @@ - - - - - + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/dl4se__test_.xml b/.idea/runConfigurations/test.xml similarity index 78% rename from .idea/runConfigurations/dl4se__test_.xml rename to .idea/runConfigurations/test.xml index efb52bb5..acc14b08 100644 --- a/.idea/runConfigurations/dl4se__test_.xml +++ b/.idea/runConfigurations/test.xml @@ -1,17 +1,17 @@ - +