Fix recursion issues in ON_DEMAND module scanning

Improved the method for traversing the import tree in ON_DEMAND context
to enhance performance and prevent recursion problems in large projects.

Change-Id: I2b36af1d1c81f5ee0223b3ab06c5eaf221e68066
Signed-off-by: Patrizio <patrizio.gelosi@amarulasolutions.com>
diff --git a/pom.xml b/pom.xml
index 6520ac8..be46be6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -78,6 +78,7 @@
                             <artifactSet>
                                 <includes>
                                     <include>com.squareup.*</include>
+                                    <include>org.apache.commons*</include>
                                     <include>org.jetbrains*</include>
                                 </includes>
                             </artifactSet>
@@ -133,6 +134,11 @@
             <version>${Gerrit-ApiVersion}</version>
         </dependency>
         <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-collections4</artifactId>
+            <version>4.4</version>
+        </dependency>
+        <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
             <version>1.7.30</version>
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 7fde3d5..a8301b6 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
@@ -8,6 +8,7 @@
 import com.googlesource.gerrit.plugins.chatgpt.mode.stateful.client.api.git.GitRepoFiles;
 import com.googlesource.gerrit.plugins.chatgpt.mode.stateful.client.code.context.ondemand.CodeFileFetcher;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.set.ListOrderedSet;
 
 import java.io.IOException;
 import java.util.*;
@@ -25,13 +26,14 @@
     protected static final String DOT_NOTATION_REGEX = "[\\w.]+";
     private static final int LOG_MAX_CONTENT_SIZE = 256;
 
-    protected final List<String> importModules = new ArrayList<>();
+    protected final ListOrderedSet<String> importModules = new ListOrderedSet<>();
     protected final CodeFileFetcher codeFileFetcher;
 
     protected Pattern importPattern;
     protected String languageModuleExtension;
     protected String rootFileDir;
 
+    private int importModulesPointer = 0;
     private Set<String> visitedFiles;
 
     public CallableLocatorBase(Configuration config, GerritChange change, GitRepoFiles gitRepoFiles) {
@@ -47,6 +49,7 @@
         String functionName = getSimpleName(chatGptGetContextItem.getContextRequiredEntity());
         rootFileDir = getDirName(filename);
         log.debug("Root file dir: {}", rootFileDir);
+        beforeSearchingFunction();
 
         return findFunctionInFile(filename, functionName);
     }
@@ -57,6 +60,9 @@
 
     protected abstract String findInImportModules(String functionName);
 
+    protected void beforeSearchingFunction() {
+    }
+
     protected String getFunctionFromModule(String functionName, String module) {
         String modulePath = convertDotNotationToPath(module) + languageModuleExtension;
         modulePath = modulePath.replaceAll("^(?=/)", rootFileDir);
@@ -72,10 +78,13 @@
     }
 
     protected String findInModules(String functionName) {
-        for (String module : importModules) {
+        log.debug("Finding function in modules {} with index {}", importModules, importModulesPointer);
+        while (importModulesPointer < importModules.size()) {
+            String module = importModules.get(importModulesPointer);
             log.debug("Searching for function `{}` in module: {}", functionName, module);
             String result = getFunctionFromModule(functionName, module);
             if (result != null) return result;
+            importModulesPointer++;
         }
         return null;
     }
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
index 78cdac5..10cc9f8 100644
--- 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
@@ -7,8 +7,9 @@
 import com.googlesource.gerrit.plugins.chatgpt.utils.FileUtils;
 import lombok.extern.slf4j.Slf4j;
 
-import java.util.List;
+import java.util.Set;
 import java.util.regex.Matcher;
+import java.util.stream.Collectors;
 
 @Slf4j
 public abstract class CallableLocatorJVM extends CallableLocatorBase implements IEntityLocator {
@@ -19,8 +20,7 @@
 
     @Override
     protected void parseImportStatements(String content) {
-        parseDirectImportStatements(content, importModules);
-        retrievePackageModules();
+        parseDirectImportStatements(content);
     }
 
     @Override
@@ -28,7 +28,7 @@
         return findInModules(functionName);
     }
 
-    protected void parseDirectImportStatements(String content, List<String> importModules) {
+    protected void parseDirectImportStatements(String content) {
         log.debug("Parsing import statements");
         Matcher importMatcher = importPattern.matcher(content);
         while (importMatcher.find()) {
@@ -39,12 +39,13 @@
         log.debug("Found import modules from import statements: {}", importModules);
     }
 
-    protected void retrievePackageModules() {
+    @Override
+    protected void beforeSearchingFunction() {
         log.debug("Retrieving modules from current package");
-        List<String> packageModules = codeFileFetcher.getFilesInDir(rootFileDir)
+        Set<String> packageModules = codeFileFetcher.getFilesInDir(rootFileDir)
                 .stream()
                 .map(FileUtils::removeExtension)
-                .toList();
+                .collect(Collectors.toSet());
         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/language/kotlin/CallableLocator.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/stateful/client/code/context/ondemand/locator/language/kotlin/CallableLocator.java
index 384d6f2..fbbc6d9 100644
--- 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
@@ -7,7 +7,9 @@
 import com.googlesource.gerrit.plugins.chatgpt.mode.stateful.client.code.context.ondemand.locator.CallableLocatorJVM;
 import lombok.extern.slf4j.Slf4j;
 
+import java.util.Set;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
 @Slf4j
 public class CallableLocator extends CallableLocatorJVM implements IEntityLocator {
@@ -37,12 +39,11 @@
 
     @Override
     protected void parseImportStatements(String content) {
-        parseDirectImportStatements(content, importModules);
-        importModules.addAll(importModules.stream()
+        parseDirectImportStatements(content);
+        Set<String> alternativePathModules = importModules.stream()
                 .filter(s -> !s.startsWith(NON_MODIFIABLE_BASE_PATH))
                 .map(s -> ALTERNATIVE_BASE_PATH + s)
-                .toList()
-        );
-        retrievePackageModules();
+                .collect(Collectors.toSet());
+        importModules.addAll(alternativePathModules);
     }
 }