Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,11 @@ public void tearDown() throws Exception {
}
}

private void waitReconciled(JavaSourceViewer viewer) {
private void waitReconciled(JavaEditor editor, JavaSourceViewer viewer) {
assertTrue(new DisplayHelper() {
@Override
protected boolean condition() {
return JavaCodeMiningReconciler.isReconciled(viewer);
return JavaCodeMiningReconciler.getFuture(editor).isDone();
}
}.waitForCondition(viewer.getTextWidget().getDisplay(), 2000), "Editor not reconciled");
}
Expand All @@ -122,7 +122,7 @@ public class Foo {
JavaEditor editor= (JavaEditor) EditorUtility.openInEditor(compilationUnit);
fParameterNameCodeMiningProvider.setContext(editor);
JavaSourceViewer viewer= (JavaSourceViewer)editor.getViewer();
waitReconciled(viewer);
waitReconciled(editor, viewer);

assertEquals(3, fParameterNameCodeMiningProvider.provideCodeMinings(viewer, new NullProgressMonitor()).get().size());
}
Expand All @@ -138,7 +138,7 @@ public class Foo {
JavaEditor editor= (JavaEditor) EditorUtility.openInEditor(compilationUnit);
fParameterNameCodeMiningProvider.setContext(editor);
JavaSourceViewer viewer= (JavaSourceViewer)editor.getViewer();
waitReconciled(viewer);
waitReconciled(editor, viewer);
assertEquals(2, fParameterNameCodeMiningProvider.provideCodeMinings(viewer, new NullProgressMonitor()).get().size());
}

Expand All @@ -162,7 +162,7 @@ public void foo() {
viewer.setCodeMiningProviders(new ICodeMiningProvider[] {
fParameterNameCodeMiningProvider
});
waitReconciled(viewer);
waitReconciled(editor, viewer);
StyledText widget= viewer.getTextWidget();
//
assertEquals(2, fParameterNameCodeMiningProvider.provideCodeMinings(viewer, new NullProgressMonitor()).get().size());
Expand Down Expand Up @@ -192,7 +192,7 @@ public void mehod() {
JavaEditor editor= (JavaEditor) EditorUtility.openInEditor(compilationUnit);
fParameterNameCodeMiningProvider.setContext(editor);
JavaSourceViewer viewer= (JavaSourceViewer)editor.getViewer();
waitReconciled(viewer);
waitReconciled(editor, viewer);
// Only code mining on "printf" parameters
assertEquals(2, fParameterNameCodeMiningProvider.provideCodeMinings(viewer, new NullProgressMonitor()).get().size());
}
Expand Down Expand Up @@ -221,7 +221,7 @@ public class Foo {
viewer.setCodeMiningProviders(new ICodeMiningProvider[] {
fParameterNameCodeMiningProvider
});
waitReconciled(viewer);
waitReconciled(editor, viewer);

AtomicReference<IStatus> errorInLog= new AtomicReference<>();
ILogListener logListener= (status, plugin) -> {
Expand Down Expand Up @@ -254,7 +254,7 @@ public class Foo {
viewer.setCodeMiningProviders(new ICodeMiningProvider[] {
fParameterNameCodeMiningProvider
});
waitReconciled(viewer);
waitReconciled(editor, viewer);
//
StyledText widget= viewer.getTextWidget();
int charWidth= widget.getTextBounds(0, 1).width;
Expand Down Expand Up @@ -324,7 +324,7 @@ public void testBug547232() throws Exception {
JavaEditor editor= (JavaEditor) EditorUtility.openInEditor(compilationUnit);
fParameterNameCodeMiningProvider.setContext(editor);
JavaSourceViewer viewer= (JavaSourceViewer)editor.getViewer();
waitReconciled(viewer);
waitReconciled(editor, viewer);

assertEquals(2, fParameterNameCodeMiningProvider.provideCodeMinings(viewer, new NullProgressMonitor()).get().size());
}
Expand All @@ -351,7 +351,7 @@ public void testBug549023() throws Exception {
JavaEditor editor= (JavaEditor) EditorUtility.openInEditor(compilationUnit);
fParameterNameCodeMiningProvider.setContext(editor);
JavaSourceViewer viewer= (JavaSourceViewer)editor.getViewer();
waitReconciled(viewer);
waitReconciled(editor, viewer);

assertEquals(2, fParameterNameCodeMiningProvider.provideCodeMinings(viewer, new NullProgressMonitor()).get().size());
}
Expand All @@ -374,7 +374,7 @@ public void testBug549126() throws Exception {
JavaEditor editor= (JavaEditor) EditorUtility.openInEditor(compilationUnit);
fParameterNameCodeMiningProvider.setContext(editor);
JavaSourceViewer viewer= (JavaSourceViewer)editor.getViewer();
waitReconciled(viewer);
waitReconciled(editor, viewer);

assertEquals(2, fParameterNameCodeMiningProvider.provideCodeMinings(viewer, new NullProgressMonitor()).get().size());
}
Expand Down Expand Up @@ -405,7 +405,7 @@ record Ca (int size){
JavaEditor editor= (JavaEditor) EditorUtility.openInEditor(compilationUnit);
fParameterNameCodeMiningProvider.setContext(editor);
JavaSourceViewer viewer= (JavaSourceViewer)editor.getViewer();
waitReconciled(viewer);
waitReconciled(editor, viewer);

assertEquals(expectedShownNames, fParameterNameCodeMiningProvider.provideCodeMinings(viewer, new NullProgressMonitor()).get().size());
}
Expand Down Expand Up @@ -440,7 +440,7 @@ public void test () {
JavaEditor editor= (JavaEditor) EditorUtility.openInEditor(compilationUnit);
fParameterNameCodeMiningProvider.setContext(editor);
JavaSourceViewer viewer= (JavaSourceViewer)editor.getViewer();
waitReconciled(viewer);
waitReconciled(editor, viewer);

// 6 parameter names from Edge
// 4 parameter names from the 2 Map.entry(int, int) calls
Expand Down Expand Up @@ -484,7 +484,7 @@ public void foo() {
JavaEditor editor= (JavaEditor) EditorUtility.openInEditor(compilationUnit);
fParameterNameCodeMiningProvider.setContext(editor);
JavaSourceViewer viewer= (JavaSourceViewer)editor.getViewer();
waitReconciled(viewer);
waitReconciled(editor,viewer);
assertEquals(0, fParameterNameCodeMiningProvider.provideCodeMinings(viewer, new NullProgressMonitor()).get().size());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,18 @@
*******************************************************************************/
package org.eclipse.jdt.internal.ui.javaeditor;

import java.util.HashSet;
import java.util.Set;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;

import org.eclipse.core.runtime.IProgressMonitor;

import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.ISourceViewerExtension5;

import org.eclipse.ui.texteditor.ITextEditor;

import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.core.dom.CompilationUnit;

import org.eclipse.jdt.internal.ui.text.java.IJavaReconcilingListener;
Expand All @@ -31,10 +35,12 @@
public class JavaCodeMiningReconciler implements IJavaReconcilingListener {

/**
* Stores the set of viewers for which source is reconciled and requests
* for references can be performed.
* Maps Java editors to futures representing their associated {@link ITypeRoot}.
* <p>
* The future is completed when a reconciled {@link ITypeRoot} becomes available for the editor,
* or cancelled/replaced when a new reconciliation cycle starts.
*/
private static final Set<ISourceViewerExtension5> reconciledViewers= new HashSet<>();
private static final Map<ITextEditor, CompletableFuture<ITypeRoot>> typeRootFutureByEditor= new ConcurrentHashMap<>();

/** The Java editor this Java code mining reconciler is installed on */
private JavaEditor fEditor;
Expand All @@ -45,17 +51,45 @@ public class JavaCodeMiningReconciler implements IJavaReconcilingListener {

@Override
public void reconciled(CompilationUnit ast, boolean forced, IProgressMonitor progressMonitor) {
final ISourceViewerExtension5 sourceViewer= fSourceViewer; // take a copy as this can be null-ed in the meantime
if (sourceViewer != null) {
reconciledViewers.add(sourceViewer);
final JavaEditor editor= fEditor; // take a copy as this can be null-ed in the meantime
final ISourceViewerExtension5 sourceViewer= fSourceViewer;
if (editor != null && sourceViewer != null) {
sourceViewer.updateCodeMinings();
CompletableFuture<ITypeRoot> future= typeRootFutureByEditor.get(editor);
if (future != null && !future.isDone()) {
if (ast != null && ast.getTypeRoot() != null) {
future.complete(ast.getTypeRoot());
} else {
future.cancel(false);
}
}
}
}

public static CompletableFuture<ITypeRoot> getFuture(ITextEditor editor) {
return typeRootFutureByEditor.computeIfAbsent(editor, JavaCodeMiningReconciler::typeRootFor);
}

private static CompletableFuture<ITypeRoot> typeRootFor(ITextEditor editor) {
CompletableFuture<ITypeRoot> future= new CompletableFuture<>();
ITypeRoot unit= EditorUtility.getEditorInputJavaElement(editor, true);
if (unit != null) {
future.complete(unit);
}
return future;
}

@Override
public void aboutToBeReconciled() {
// interrupt code minings if modification occurs
reconciledViewers.remove(fSourceViewer);
if (fEditor == null) {
return;
}
typeRootFutureByEditor.compute(fEditor, (editor, existingFuture) -> {
if (existingFuture != null) {
existingFuture.cancel(false);
}
return new CompletableFuture<ITypeRoot>();
});
}

/**
Expand Down Expand Up @@ -83,16 +117,14 @@ public void install(JavaEditor editor, ISourceViewer sourceViewer) {
* Uninstall this reconciler from the editor.
*/
public void uninstall() {
reconciledViewers.remove(fSourceViewer);
CompletableFuture<ITypeRoot> future= typeRootFutureByEditor.remove(fEditor);
if (future != null) {
future.cancel(false);
}
if (fEditor instanceof CompilationUnitEditor) {
((CompilationUnitEditor) fEditor).removeReconcileListener(this);
}
fEditor= null;
fSourceViewer= null;
}

public static boolean isReconciled(ISourceViewerExtension5 viewer) {
return reconciledViewers.contains(viewer);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,17 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.TimeUnit;

import org.eclipse.core.runtime.IProgressMonitor;

import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.codemining.AbstractCodeMiningProvider;
import org.eclipse.jface.text.codemining.ICodeMining;
import org.eclipse.jface.text.source.ISourceViewerExtension5;

import org.eclipse.ui.texteditor.ITextEditor;

Expand All @@ -36,7 +38,6 @@

import org.eclipse.jdt.ui.PreferenceConstants;

import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility;
import org.eclipse.jdt.internal.ui.javaeditor.JavaCodeMiningReconciler;
import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesPropertyTester;
Expand Down Expand Up @@ -83,40 +84,34 @@ public CompletableFuture<List<? extends ICodeMining>> provideCodeMinings(ITextVi
if (!editorEnabled) {
return CompletableFuture.completedFuture(Collections.emptyList());
}
if (viewer instanceof ISourceViewerExtension5) {
ISourceViewerExtension5 codeMiningViewer = (ISourceViewerExtension5)viewer;
if (!JavaCodeMiningReconciler.isReconciled(codeMiningViewer)) {
// the provider isn't able to return code minings for non-reconciled viewers
return CompletableFuture.completedFuture(Collections.emptyList());
ITextEditor textEditor= super.getAdapter(ITextEditor.class);
CompletableFuture<ITypeRoot> future= JavaCodeMiningReconciler.getFuture(textEditor);
return future.thenApplyAsync(typeRoot -> {
return computeCodeMinings(viewer, textEditor, monitor, typeRoot);
}).orTimeout(15, TimeUnit.SECONDS).handle((result, ex) -> {
if (ex instanceof CompletionException ce &&
ce.getCause() instanceof CancellationException) {
monitor.setCanceled(true);
}
}
return CompletableFuture.supplyAsync(() -> {
monitor.isCanceled();
ITextEditor textEditor= super.getAdapter(ITextEditor.class);
ITypeRoot unit= EditorUtility.getEditorInputJavaElement(textEditor, true);
if (unit == null) {
return Collections.emptyList();
}
try {
IJavaElement[] elements= unit.getChildren();
List<ICodeMining> minings= new ArrayList<>(elements.length);
collectMinings(unit, textEditor, unit.getChildren(), minings, viewer, monitor);
// interrupt if editor was marked to be reconciled in the meantime
if (viewer instanceof ISourceViewerExtension5) {
ISourceViewerExtension5 codeMiningViewer= (ISourceViewerExtension5)viewer;
if (!JavaCodeMiningReconciler.isReconciled(codeMiningViewer)) {
monitor.setCanceled(true);
}
}
monitor.isCanceled();
return minings;
} catch (JavaModelException e) {
// Should never occur
}
return Collections.emptyList();
return result;
});
}

private List<? extends ICodeMining> computeCodeMinings(ITextViewer viewer, ITextEditor textEditor, IProgressMonitor monitor, ITypeRoot unit) {
if (unit == null) {
return Collections.emptyList();
}
try {
IJavaElement[] elements= unit.getChildren();
List<ICodeMining> minings= new ArrayList<>(elements.length);
collectMinings(unit, textEditor, unit.getChildren(), minings, viewer, monitor);
return minings;
} catch (JavaModelException e) {
// Should never occur
}
return Collections.emptyList();
}

/**
* Collect java code minings.
*
Expand Down
Loading
Loading