Skip to content

Commit 7c4e553

Browse files
committed
Fix race condition in executeQuickFix: serialize per-file and wait for auto-build
1 parent 5be6059 commit 7c4e553

1 file changed

Lines changed: 57 additions & 18 deletions

File tree

  • plugins/com.github.gradusnikov.eclipse.plugin.assistai.main/src/com/github/gradusnikov/eclipse/assistai/mcp/services

plugins/com.github.gradusnikov.eclipse.plugin.assistai.main/src/com/github/gradusnikov/eclipse/assistai/mcp/services/CodeAnalysisService.java

Lines changed: 57 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
public class CodeAnalysisService
4747
{
4848

49+
private final java.util.concurrent.ConcurrentHashMap<org.eclipse.core.runtime.IPath, Object> fileLocks = new java.util.concurrent.ConcurrentHashMap<>();
50+
4951
@Inject
5052
ILog logger;
5153

@@ -758,27 +760,42 @@ public String executeQuickFix(long markerId, int proposalIndex)
758760
return "Error: Marker with ID " + markerId + " not found. It may have been resolved already.";
759761
}
760762

761-
List<QuickFix> fixes = collectQuickFixes(marker);
762-
if (fixes.isEmpty())
763-
{
764-
return "Error: No quick fix proposals available for marker " + markerId + ".";
765-
}
766-
if (proposalIndex < 0 || proposalIndex >= fixes.size())
763+
Object lock = (marker.getResource() instanceof IFile file)
764+
? fileLocks.computeIfAbsent(file.getFullPath(), k -> new Object())
765+
: new Object();
766+
767+
synchronized (lock)
767768
{
768-
return "Error: Proposal index " + proposalIndex + " is out of range (0-" + (fixes.size() - 1) + ").";
769-
}
769+
marker = findMarkerById(markerId);
770+
if (marker == null)
771+
{
772+
return "Error: Marker with ID " + markerId + " not found. It may have been resolved already.";
773+
}
770774

771-
QuickFix fix = fixes.get(proposalIndex);
772-
fix.apply(marker);
775+
List<QuickFix> fixes = collectQuickFixes(marker);
776+
if (fixes.isEmpty())
777+
{
778+
return "Error: No quick fix proposals available for marker " + markerId + ".";
779+
}
780+
if (proposalIndex < 0 || proposalIndex >= fixes.size())
781+
{
782+
return "Error: Proposal index " + proposalIndex + " is out of range (0-" + (fixes.size() - 1) + ").";
783+
}
773784

774-
if (marker.getResource() instanceof IFile file)
775-
{
776-
saveFileBuffer(file);
777-
file.refreshLocal(IResource.DEPTH_ZERO, new NullProgressMonitor());
778-
}
785+
QuickFix fix = fixes.get(proposalIndex);
786+
fix.apply(marker);
787+
788+
if (marker.getResource() instanceof IFile f)
789+
{
790+
saveFileBuffer(f);
791+
f.refreshLocal(IResource.DEPTH_ZERO, new NullProgressMonitor());
792+
}
779793

780-
String status = marker.exists() ? "applied (marker still present)" : "applied and marker resolved";
781-
return "Quick fix applied: \"" + fix.label() + "\" on marker " + markerId + " - " + status;
794+
waitForAutoBuild();
795+
796+
String status = marker.exists() ? "applied (marker still present)" : "applied and marker resolved";
797+
return "Quick fix applied: \"" + fix.label() + "\" on marker " + markerId + " - " + status;
798+
}
782799
}
783800
catch (Exception e)
784801
{
@@ -971,6 +988,28 @@ private void saveFileBuffer(IFile file)
971988
}
972989
}
973990

991+
/**
992+
* Waits for Eclipse's auto-build to complete so that markers are refreshed
993+
* with correct offsets before the next quick fix is applied.
994+
*/
995+
private void waitForAutoBuild()
996+
{
997+
try
998+
{
999+
org.eclipse.core.runtime.jobs.Job.getJobManager()
1000+
.join(ResourcesPlugin.FAMILY_AUTO_BUILD, new NullProgressMonitor());
1001+
}
1002+
catch (InterruptedException e)
1003+
{
1004+
Thread.currentThread().interrupt();
1005+
}
1006+
catch (Exception e)
1007+
{
1008+
// best-effort
1009+
}
1010+
}
1011+
1012+
9741013

9751014
/** Reads the raw problem arguments from a marker. */
9761015
private String[] readMarkerArguments(IMarker marker)
@@ -1149,4 +1188,4 @@ private List<IJavaProject> getAvailableJavaProjects()
11491188
return javaProjects;
11501189
}
11511190

1152-
}
1191+
}

0 commit comments

Comments
 (0)