diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/JDTUtils.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/JDTUtils.java index 2a67ec3098..f51a436ce2 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/JDTUtils.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/JDTUtils.java @@ -772,8 +772,7 @@ public static URI toURI(String uriString) { } public static boolean isHiddenGeneratedElement(IJavaElement element) { - // generated elements are tagged with javax.annotation.Generated and - // they need to be filtered out + // generated elements are annotated with @Generated and they need to be filtered out if (element instanceof IAnnotatable) { try { IAnnotation[] annotations = ((IAnnotatable) element).getAnnotations(); @@ -792,7 +791,7 @@ public static boolean isHiddenGeneratedElement(IJavaElement element) { } private static boolean isSilencedGeneratedAnnotation(IAnnotation annotation) throws JavaModelException { - if ("javax.annotation.Generated".equals(annotation.getElementName())) { + if ("javax.annotation.Generated".equals(annotation.getElementName()) || "javax.annotation.processing.Generated".equals(annotation.getElementName())) { IMemberValuePair[] memberValuePairs = annotation.getMemberValuePairs(); for (IMemberValuePair m : memberValuePairs) { if ("value".equals(m.getMemberName()) diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CodeLensHandler.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CodeLensHandler.java index b94d3dc804..f6c9d7de0b 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CodeLensHandler.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CodeLensHandler.java @@ -12,7 +12,9 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; +import java.util.LinkedHashSet; import java.util.List; import org.eclipse.core.resources.ResourcesPlugin; @@ -56,8 +58,8 @@ public class CodeLensHandler { private static final String JAVA_SHOW_REFERENCES_COMMAND = "java.show.references"; private static final String JAVA_SHOW_IMPLEMENTATIONS_COMMAND = "java.show.implementations"; - private static final String IMPLEMENTATION_TYPE = "implementations"; - private static final String REFERENCES_TYPE = "references"; + public static final String IMPLEMENTATION_TYPE = "implementations"; + public static final String REFERENCES_TYPE = "references"; private final PreferenceManager preferenceManager; @@ -181,19 +183,19 @@ public List getCodeLensSymbols(String uri, IProgressMonitor monitor) { try { ITypeRoot typeRoot = unit != null ? unit : classFile; IJavaElement[] elements = typeRoot.getChildren(); - ArrayList lenses = new ArrayList<>(elements.length); + LinkedHashSet lenses = new LinkedHashSet<>(elements.length); collectCodeLenses(typeRoot, elements, lenses, monitor); if (monitor.isCanceled()) { lenses.clear(); } - return lenses; + return new ArrayList<>(lenses); } catch (JavaModelException e) { JavaLanguageServerPlugin.logException("Problem getting code lenses for" + unit.getElementName(), e); } return Collections.emptyList(); } - private void collectCodeLenses(ITypeRoot typeRoot, IJavaElement[] elements, ArrayList lenses, + private void collectCodeLenses(ITypeRoot typeRoot, IJavaElement[] elements, Collection lenses, IProgressMonitor monitor) throws JavaModelException { for (IJavaElement element : elements) { @@ -202,27 +204,51 @@ private void collectCodeLenses(ITypeRoot typeRoot, IJavaElement[] elements, Arra } if (element.getElementType() == IJavaElement.TYPE) { collectCodeLenses(typeRoot, ((IType) element).getChildren(), lenses, monitor); - } else if (element.getElementType() != IJavaElement.METHOD || JDTUtils.isHiddenGeneratedElement(element)) { + } else if (element.getElementType() == IJavaElement.METHOD) { + if (JDTUtils.isHiddenGeneratedElement(element)) { + continue; + } + //ignore element if method range overlaps the type range, happens for generated bytcode, i.e. with lombok + IJavaElement parentType = element.getAncestor(IJavaElement.TYPE); + if (parentType != null && overlaps(((ISourceReference) parentType).getNameRange(), ((ISourceReference) element).getNameRange())) { + continue; + } + } else {//neither a type nor a method, we bail continue; } if (preferenceManager.getPreferences().isReferencesCodeLensEnabled()) { CodeLens lens = getCodeLens(REFERENCES_TYPE, element, typeRoot); - lenses.add(lens); + if (lens != null) { + lenses.add(lens); + } } if (preferenceManager.getPreferences().isImplementationsCodeLensEnabled() && element instanceof IType) { IType type = (IType) element; if (type.isInterface() || Flags.isAbstract(type.getFlags())) { CodeLens lens = getCodeLens(IMPLEMENTATION_TYPE, element, typeRoot); - lenses.add(lens); + if (lens != null) { + lenses.add(lens); + } } } } } + private boolean overlaps(ISourceRange typeRange, ISourceRange methodRange) { + if (typeRange == null || methodRange == null) { + return false; + } + //method range is overlapping if it appears before or actually overlaps the type's range + return methodRange.getOffset() < typeRange.getOffset() || methodRange.getOffset() >= typeRange.getOffset() && methodRange.getOffset() <= (typeRange.getOffset() + typeRange.getLength()); + } + private CodeLens getCodeLens(String type, IJavaElement element, ITypeRoot typeRoot) throws JavaModelException { - CodeLens lens = new CodeLens(); ISourceRange r = ((ISourceReference) element).getNameRange(); + if (r == null) { + return null; + } + CodeLens lens = new CodeLens(); final Range range = JDTUtils.toRange(typeRoot, r.getOffset(), r.getLength()); lens.setRange(range); String uri = ResourceUtils.toClientUri(JDTUtils.toUri(typeRoot)); diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/CodeLensHandlerTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/CodeLensHandlerTest.java index 82be2e34cb..04ee6382ba 100644 --- a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/CodeLensHandlerTest.java +++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/CodeLensHandlerTest.java @@ -157,6 +157,7 @@ public void testGetCodeLensSymbols() throws Exception { } @Test + @SuppressWarnings("unchecked") public void testGetCodeLensSymbolsForClass() throws Exception { Preferences implementationsCodeLenses = Preferences.createFrom(Collections.singletonMap(Preferences.IMPLEMENTATIONS_CODE_LENS_ENABLED_KEY, "true")); Mockito.reset(preferenceManager); @@ -168,7 +169,11 @@ public void testGetCodeLensSymbolsForClass() throws Exception { String uri = codeLensParams.getTextDocument().getUri(); assertFalse(uri.isEmpty()); List lenses = handler.getCodeLensSymbols(uri, monitor); - assertEquals("Found " + lenses, 3, lenses.size()); + assertEquals("Found " + lenses, 2, lenses.size()); + List data = (List) lenses.get(0).getData(); + assertTrue("Unexpected type " + data, data.contains(CodeLensHandler.REFERENCES_TYPE)); + data = (List) lenses.get(1).getData(); + assertTrue("Unexpected type " + data, data.contains(CodeLensHandler.IMPLEMENTATION_TYPE)); } @Test