Add context locator for Kotlin function definitions
Implemented Kotlin-specific context locator to handle function
definition requests in Java projects.
Change-Id: I86a3baae574870b197dc5f2e674e8e3fde8ae22b
Signed-off-by: Patrizio <patrizio.gelosi@amarulasolutions.com>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/code/context/ondemand/locator/CallableLocatorBase.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/code/context/ondemand/locator/CallableLocatorBase.java
index 637b3e8..7fde3d5 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/code/context/ondemand/locator/CallableLocatorBase.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/code/context/ondemand/locator/CallableLocatorBase.java
@@ -28,6 +28,7 @@
protected final List<String> importModules = new ArrayList<>();
protected final CodeFileFetcher codeFileFetcher;
+ protected Pattern importPattern;
protected String languageModuleExtension;
protected String rootFileDir;
@@ -52,7 +53,9 @@
protected abstract String getFunctionRegex(String functionName);
- protected abstract String findImportedFunctionDefinition(String functionName, String content);
+ protected abstract void parseImportStatements(String content);
+
+ protected abstract String findInImportModules(String functionName);
protected String getFunctionFromModule(String functionName, String module) {
String modulePath = convertDotNotationToPath(module) + languageModuleExtension;
@@ -77,9 +80,16 @@
return null;
}
+ private String findImportedFunctionDefinition(String functionName, String content) {
+ parseImportStatements(content);
+
+ return findInImportModules(functionName);
+ }
+
private String findFunctionInFile(String filename, String functionName) {
log.debug("Finding function {} in file {}", functionName, filename);
if (visitedFiles.contains(filename)) {
+ log.debug("File {} already visited", filename);
return null;
}
visitedFiles.add(filename);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/code/context/ondemand/locator/CallableLocatorJVM.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/code/context/ondemand/locator/CallableLocatorJVM.java
new file mode 100644
index 0000000..78cdac5
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/code/context/ondemand/locator/CallableLocatorJVM.java
@@ -0,0 +1,51 @@
+package com.googlesource.gerrit.plugins.chatgpt.mode.stateful.client.code.context.ondemand.locator;
+
+import com.googlesource.gerrit.plugins.chatgpt.config.Configuration;
+import com.googlesource.gerrit.plugins.chatgpt.interfaces.mode.stateful.client.code.context.ondemand.IEntityLocator;
+import com.googlesource.gerrit.plugins.chatgpt.mode.common.client.api.gerrit.GerritChange;
+import com.googlesource.gerrit.plugins.chatgpt.mode.stateful.client.api.git.GitRepoFiles;
+import com.googlesource.gerrit.plugins.chatgpt.utils.FileUtils;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.List;
+import java.util.regex.Matcher;
+
+@Slf4j
+public abstract class CallableLocatorJVM extends CallableLocatorBase implements IEntityLocator {
+ public CallableLocatorJVM(Configuration config, GerritChange change, GitRepoFiles gitRepoFiles) {
+ super(config, change, gitRepoFiles);
+ log.debug("Initializing JVM CallableLocator");
+ }
+
+ @Override
+ protected void parseImportStatements(String content) {
+ parseDirectImportStatements(content, importModules);
+ retrievePackageModules();
+ }
+
+ @Override
+ protected String findInImportModules(String functionName) {
+ return findInModules(functionName);
+ }
+
+ protected void parseDirectImportStatements(String content, List<String> importModules) {
+ log.debug("Parsing import statements");
+ Matcher importMatcher = importPattern.matcher(content);
+ while (importMatcher.find()) {
+ String importModulesGroup = importMatcher.group(1);
+ log.debug("Parsing import module: `{}`", importModulesGroup);
+ importModules.add(importModulesGroup);
+ }
+ log.debug("Found import modules from import statements: {}", importModules);
+ }
+
+ protected void retrievePackageModules() {
+ log.debug("Retrieving modules from current package");
+ List<String> packageModules = codeFileFetcher.getFilesInDir(rootFileDir)
+ .stream()
+ .map(FileUtils::removeExtension)
+ .toList();
+ log.debug("Modules retrieved from current package: {}", packageModules);
+ importModules.addAll(packageModules);
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/code/context/ondemand/locator/CodeLocatorFactory.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/code/context/ondemand/locator/CodeLocatorFactory.java
index 53b3778..a4e40d2 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/code/context/ondemand/locator/CodeLocatorFactory.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/code/context/ondemand/locator/CodeLocatorFactory.java
@@ -28,6 +28,7 @@
private static final Map<String, String> MAP_EXTENSION = Map.of(
"py", "python",
"java", "java",
+ "kt", "kotlin",
"c", "c",
"h", "c"
);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/code/context/ondemand/locator/language/java/CallableLocator.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/code/context/ondemand/locator/language/java/CallableLocator.java
index b02aec6..b0f7715 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/code/context/ondemand/locator/language/java/CallableLocator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/code/context/ondemand/locator/language/java/CallableLocator.java
@@ -4,26 +4,23 @@
import com.googlesource.gerrit.plugins.chatgpt.interfaces.mode.stateful.client.code.context.ondemand.IEntityLocator;
import com.googlesource.gerrit.plugins.chatgpt.mode.common.client.api.gerrit.GerritChange;
import com.googlesource.gerrit.plugins.chatgpt.mode.stateful.client.api.git.GitRepoFiles;
-import com.googlesource.gerrit.plugins.chatgpt.mode.stateful.client.code.context.ondemand.locator.CallableLocatorBase;
-import com.googlesource.gerrit.plugins.chatgpt.utils.FileUtils;
+import com.googlesource.gerrit.plugins.chatgpt.mode.stateful.client.code.context.ondemand.locator.CallableLocatorJVM;
import lombok.extern.slf4j.Slf4j;
-import java.util.List;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j
-public class CallableLocator extends CallableLocatorBase implements IEntityLocator {
+public class CallableLocator extends CallableLocatorJVM implements IEntityLocator {
private static final String JAVA_MODULE_EXTENSION = ".java";
- private static final Pattern IMPORT_PATTERN = Pattern.compile(
- String.format("^import\\s+(?:static\\s+)?(%s)", DOT_NOTATION_REGEX),
- Pattern.MULTILINE
- );
public CallableLocator(Configuration config, GerritChange change, GitRepoFiles gitRepoFiles) {
super(config, change, gitRepoFiles);
- log.debug("Initializing FunctionLocator");
+ log.debug("Initializing CallableLocator for Java projects");
languageModuleExtension = JAVA_MODULE_EXTENSION;
+ importPattern = Pattern.compile(
+ String.format("^import\\s+(?:static\\s+)?(%s)", DOT_NOTATION_REGEX),
+ Pattern.MULTILINE
+ );
}
@Override
@@ -36,33 +33,4 @@
"\\s*\\(.*?\\)" + // Parameters
"(?:\\s*throws\\s+[^\\{;]+)?"; // Optional throws clause
}
-
- @Override
- protected String findImportedFunctionDefinition(String functionName, String content) {
- parseImportStatements(content);
- retrievePackageModules();
-
- return findInModules(functionName);
- }
-
- private void retrievePackageModules() {
- log.debug("Retrieving modules from current Package");
- List<String> packageModules = codeFileFetcher.getFilesInDir(rootFileDir)
- .stream()
- .map(FileUtils::removeExtension)
- .toList();
- log.debug("Modules retrieved from current Package: {}", packageModules);
- importModules.addAll(packageModules);
- }
-
- private void parseImportStatements(String content) {
- log.debug("Parsing import statements");
- Matcher importMatcher = IMPORT_PATTERN.matcher(content);
- while (importMatcher.find()) {
- String importModulesGroup = importMatcher.group(1);
- log.debug("Parsing IMPORT module: `{}`", importModulesGroup);
- importModules.add(importModulesGroup);
- }
- log.debug("Found importModules from import statements: {}", importModules);
- }
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/code/context/ondemand/locator/language/kotlin/CallableLocator.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/code/context/ondemand/locator/language/kotlin/CallableLocator.java
new file mode 100644
index 0000000..384d6f2
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/code/context/ondemand/locator/language/kotlin/CallableLocator.java
@@ -0,0 +1,48 @@
+package com.googlesource.gerrit.plugins.chatgpt.mode.stateful.client.code.context.ondemand.locator.language.kotlin;
+
+import com.googlesource.gerrit.plugins.chatgpt.config.Configuration;
+import com.googlesource.gerrit.plugins.chatgpt.interfaces.mode.stateful.client.code.context.ondemand.IEntityLocator;
+import com.googlesource.gerrit.plugins.chatgpt.mode.common.client.api.gerrit.GerritChange;
+import com.googlesource.gerrit.plugins.chatgpt.mode.stateful.client.api.git.GitRepoFiles;
+import com.googlesource.gerrit.plugins.chatgpt.mode.stateful.client.code.context.ondemand.locator.CallableLocatorJVM;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.regex.Pattern;
+
+@Slf4j
+public class CallableLocator extends CallableLocatorJVM implements IEntityLocator {
+ private static final String KOTLIN_MODULE_EXTENSION = ".kt";
+ private static final String ALTERNATIVE_BASE_PATH = "app/src/main/kotlin/";
+ private static final String NON_MODIFIABLE_BASE_PATH = "app/src/";
+
+ public CallableLocator(Configuration config, GerritChange change, GitRepoFiles gitRepoFiles) {
+ super(config, change, gitRepoFiles);
+ log.debug("Initializing CallableLocator for Kotlin projects");
+ languageModuleExtension = KOTLIN_MODULE_EXTENSION;
+ importPattern = Pattern.compile(
+ String.format("^import\\s+(%s)", DOT_NOTATION_REGEX),
+ Pattern.MULTILINE
+ );
+ }
+
+ @Override
+ protected String getFunctionRegex(String functionName) {
+ return "^\\s*(?:@\\w+(?:\\(.*?\\))?\\s*)*" + // Optional annotations
+ "(?:\\w+\\s+)*" + // Optional modifiers
+ "fun\\s+" + // 'fun' keyword
+ Pattern.quote(functionName) + // Function name
+ "\\s*\\(.*?\\)" + // Parameters
+ "(?:\\s*:\\s*\\S+)?"; // Optional return type
+ }
+
+ @Override
+ protected void parseImportStatements(String content) {
+ parseDirectImportStatements(content, importModules);
+ importModules.addAll(importModules.stream()
+ .filter(s -> !s.startsWith(NON_MODIFIABLE_BASE_PATH))
+ .map(s -> ALTERNATIVE_BASE_PATH + s)
+ .toList()
+ );
+ retrievePackageModules();
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/code/context/ondemand/locator/language/python/CallableLocator.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/code/context/ondemand/locator/language/python/CallableLocator.java
index 6766deb..276aacd 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/code/context/ondemand/locator/language/python/CallableLocator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/code/context/ondemand/locator/language/python/CallableLocator.java
@@ -17,14 +17,6 @@
@Slf4j
public class CallableLocator extends CallableLocatorBase implements IEntityLocator {
private static final String PYTHON_MODULE_EXTENSION = ".py";
- private static final Pattern IMPORT_PATTERN = Pattern.compile(
- String.format(
- "^(?:from\\s+(%1$s)\\s+import\\s+(\\*|\\w+(?:%2$s\\w+)*)|import\\s+(%1$s(?:%2$s%1$s))*)",
- DOT_NOTATION_REGEX,
- ITEM_COMMA_DELIMITED_REGEX
- ),
- Pattern.MULTILINE
- );
private final Map<String, String> fromModuleMap = new HashMap<>();
@@ -32,6 +24,14 @@
super(config, change, gitRepoFiles);
log.debug("Initializing CallableLocator for Python projects");
languageModuleExtension = PYTHON_MODULE_EXTENSION;
+ importPattern = Pattern.compile(
+ String.format(
+ "^(?:from\\s+(%1$s)\\s+import\\s+(\\*|\\w+(?:%2$s\\w+)*)|import\\s+(%1$s(?:%2$s%1$s))*)",
+ DOT_NOTATION_REGEX,
+ ITEM_COMMA_DELIMITED_REGEX
+ ),
+ Pattern.MULTILINE
+ );
}
@Override
@@ -43,15 +43,9 @@
}
@Override
- protected String findImportedFunctionDefinition(String functionName, String content) {
- parseImportStatements(content);
-
- return findInImportModules(functionName);
- }
-
- private void parseImportStatements(String content) {
+ protected void parseImportStatements(String content) {
log.debug("Parsing import statements");
- Matcher importMatcher = IMPORT_PATTERN.matcher(content);
+ Matcher importMatcher = importPattern.matcher(content);
while (importMatcher.find()) {
String fromModuleGroup = importMatcher.group(1);
String fromEntitiesGroup = importMatcher.group(2);
@@ -73,7 +67,8 @@
log.debug("Found importModules: {}", importModules);
}
- private String findInImportModules(String functionName) {
+ @Override
+ protected String findInImportModules(String functionName) {
// Check if the function is directly imported via `from MODULE import ENTITY`
if (fromModuleMap.containsKey(functionName)) {
String module = fromModuleMap.get(functionName);