diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/HoverInfoProvider.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/HoverInfoProvider.java index c28128d06e..011403bd3b 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/HoverInfoProvider.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/HoverInfoProvider.java @@ -46,9 +46,8 @@ import org.eclipse.jdt.core.search.SearchPattern; import org.eclipse.jdt.core.search.SearchRequestor; import org.eclipse.jdt.internal.core.BinaryMember; -import org.eclipse.jdt.ls.core.internal.handlers.CompletionResolveHandler; import org.eclipse.jdt.internal.core.manipulation.JavaElementLabelsCore; -import org.eclipse.jdt.ls.core.internal.javadoc.JavaDocSnippetStringEvaluator; +import org.eclipse.jdt.ls.core.internal.handlers.CompletionResolveHandler; import org.eclipse.jdt.ls.core.internal.javadoc.JavadocContentAccess2; import org.eclipse.jdt.ls.core.internal.managers.IBuildSupport; import org.eclipse.jdt.ls.core.internal.preferences.PreferenceManager; @@ -164,13 +163,13 @@ public List> computeHover(int line, int column, IPr } private String fixSnippet(String value) { - if (value.contains(JavaDocSnippetStringEvaluator.SNIPPET)) { + if (value.contains(JavadocContentAccess2.SNIPPET)) { StringBuilder builder = new StringBuilder(); value.lines().forEach((line) -> { - if (line.contains(JavaDocSnippetStringEvaluator.SNIPPET)) { + if (line.contains(JavadocContentAccess2.SNIPPET)) { line = line.stripLeading(); - if (line.startsWith(JavaDocSnippetStringEvaluator.SNIPPET)) { - line = line.replaceFirst(JavaDocSnippetStringEvaluator.SNIPPET, ""); + if (line.startsWith(JavadocContentAccess2.SNIPPET)) { + line = line.replaceFirst(JavadocContentAccess2.SNIPPET, ""); line = replaceLeadingSpaces(line); } } 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 c03234ee0e..00802eccc4 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 @@ -122,12 +122,12 @@ import org.eclipse.jdt.internal.corext.template.java.SignatureUtil; import org.eclipse.jdt.internal.corext.util.JavaModelUtil; import org.eclipse.jdt.internal.corext.util.JdtFlags; +import org.eclipse.jdt.internal.ui.viewsupport.CoreJavaElementLinks; import org.eclipse.jdt.launching.IVMInstall; import org.eclipse.jdt.launching.JavaRuntime; import org.eclipse.jdt.launching.environments.IExecutionEnvironment; import org.eclipse.jdt.launching.environments.IExecutionEnvironmentsManager; import org.eclipse.jdt.ls.core.internal.handlers.JsonRpcHelpers; -import org.eclipse.jdt.ls.core.internal.javadoc.JavaElementLinks; import org.eclipse.jdt.ls.core.internal.managers.ContentProviderManager; import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager; import org.eclipse.jdt.ls.core.internal.preferences.PreferenceManager; @@ -999,7 +999,7 @@ public static String toURI(ICompilationUnit cu) { } } catch (JavaModelException ex) { JavaLanguageServerPlugin.logException(ex); - } + } return null; } @@ -1460,7 +1460,7 @@ private static void addValue(StringBuilder buf, Object value, boolean addLinks) if (type == null || !addLinks) { buf.append(typeBinding.getName()); } else { - String uri = JavaElementLinks.createURI(JavaElementLinks.JAVADOC_SCHEME, type); + String uri = CoreJavaElementLinks.createURI(CoreJavaElementLinks.JAVADOC_SCHEME, type); String name = type.getElementName(); addLink(buf, uri, name); } @@ -1471,7 +1471,7 @@ private static void addValue(StringBuilder buf, Object value, boolean addLinks) if (variable == null || !addLinks) { buf.append(variableBinding.getName()); } else { - String uri = JavaElementLinks.createURI(JavaElementLinks.JAVADOC_SCHEME, variable); + String uri = CoreJavaElementLinks.createURI(CoreJavaElementLinks.JAVADOC_SCHEME, variable); String name = variable.getElementName(); addLink(buf, uri, name); } @@ -1501,7 +1501,7 @@ private static void addValue(StringBuilder buf, Object value, boolean addLinks) } private static StringBuilder addLink(StringBuilder buf, String uri, String label) { - return buf.append(JavaElementLinks.createLink(uri, label)); + return buf.append(CoreJavaElementLinks.createLink(uri, label)); } private static void addAnnotation(StringBuilder buf, IAnnotationBinding annotation, boolean addLinks) throws URISyntaxException { @@ -1510,7 +1510,7 @@ private static void addAnnotation(StringBuilder buf, IAnnotationBinding annotati if (javaElement == null || !addLinks) { buf.append(annotation.getName()); } else { - String uri = JavaElementLinks.createURI(JavaElementLinks.JAVADOC_SCHEME, javaElement); + String uri = CoreJavaElementLinks.createURI(CoreJavaElementLinks.JAVADOC_SCHEME, javaElement); addLink(buf, uri, annotation.getName()); } @@ -1523,7 +1523,7 @@ private static void addAnnotation(StringBuilder buf, IAnnotationBinding annotati } IMemberValuePairBinding mvPair = mvPairs[j]; if (addLinks) { - String memberURI = JavaElementLinks.createURI(JavaElementLinks.JAVADOC_SCHEME, mvPair.getMethodBinding().getJavaElement()); + String memberURI = CoreJavaElementLinks.createURI(CoreJavaElementLinks.JAVADOC_SCHEME, mvPair.getMethodBinding().getJavaElement()); addLink(buf, memberURI, mvPair.getName()); } else { buf.append(mvPair.getName()); diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/contentassist/SignatureHelpRequestor.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/contentassist/SignatureHelpRequestor.java index 7974a5c512..14d471ee8a 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/contentassist/SignatureHelpRequestor.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/contentassist/SignatureHelpRequestor.java @@ -44,7 +44,7 @@ import org.eclipse.jdt.internal.corext.util.JavaModelUtil; import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; import org.eclipse.jdt.ls.core.internal.handlers.SignatureHelpUtils; -import org.eclipse.jdt.ls.core.internal.javadoc.JavadocContentAccess; +import org.eclipse.jdt.ls.core.internal.javadoc.JavadocContentAccess2; import org.eclipse.jdt.ls.core.internal.preferences.PreferenceManager; import org.eclipse.jdt.ls.core.internal.preferences.Preferences; import org.eclipse.lsp4j.ParameterInformation; @@ -231,7 +231,7 @@ public String computeJavaDoc(CompletionProposal proposal) { String javadoc = null; try { javadoc = SimpleTimeLimiter.create(JavaLanguageServerPlugin.getExecutorService()).callWithTimeout(() -> { - Reader reader = JavadocContentAccess.getPlainTextContentReader(method); + Reader reader = JavadocContentAccess2.getPlainTextContentReader(method); return reader == null ? null : CharStreams.toString(reader); }, 500, TimeUnit.MILLISECONDS); } catch (UncheckedTimeoutException tooSlow) { diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corext/refactoring/rename/RippleMethodFinder.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corext/refactoring/rename/RippleMethodFinder.java deleted file mode 100644 index 6515a10a70..0000000000 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corext/refactoring/rename/RippleMethodFinder.java +++ /dev/null @@ -1,402 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2011 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Code copied from org.eclipse.jdt.internal.corext.refactoring.rename.RippleMethodFinder - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ - -package org.eclipse.jdt.ls.core.internal.corext.refactoring.rename; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.Assert; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.OperationCanceledException; -import org.eclipse.core.runtime.SubProgressMonitor; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.IMember; -import org.eclipse.jdt.core.IMethod; -import org.eclipse.jdt.core.IRegion; -import org.eclipse.jdt.core.IType; -import org.eclipse.jdt.core.ITypeHierarchy; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jdt.core.WorkingCopyOwner; -import org.eclipse.jdt.core.search.IJavaSearchConstants; -import org.eclipse.jdt.core.search.IJavaSearchScope; -import org.eclipse.jdt.core.search.SearchEngine; -import org.eclipse.jdt.core.search.SearchMatch; -import org.eclipse.jdt.core.search.SearchParticipant; -import org.eclipse.jdt.core.search.SearchPattern; -import org.eclipse.jdt.core.search.SearchRequestor; -import org.eclipse.jdt.internal.corext.util.JavaModelUtil; -import org.eclipse.jdt.internal.corext.util.JdtFlags; - -public class RippleMethodFinder { - - private final IMethod fMethod; - private List fDeclarations; - private ITypeHierarchy fHierarchy; - private Map fTypeToMethod; - private Set fRootTypes; - private MultiMap fRootReps; - private Map fRootHierarchies; - private UnionFind fUnionFind; - - private static class MultiMap { - HashMap> fImplementation = new HashMap<>(); - - public void put(K key, V value) { - Collection collection = fImplementation.get(key); - if (collection == null) { - collection = new HashSet<>(); - fImplementation.put(key, collection); - } - collection.add(value); - } - - public Collection get(K key) { - return fImplementation.get(key); - } - } - - private static class UnionFind { - HashMap fElementToRepresentative = new HashMap<>(); - - public void init(IType type) { - fElementToRepresentative.put(type, type); - } - - //path compression: - public IType find(IType element) { - IType root = element; - IType rep = fElementToRepresentative.get(root); - while (rep != null && !rep.equals(root)) { - root = rep; - rep = fElementToRepresentative.get(root); - } - if (rep == null) { - return null; - } - - rep = fElementToRepresentative.get(element); - while (!rep.equals(root)) { - IType temp = element; - element = rep; - fElementToRepresentative.put(temp, root); - rep = fElementToRepresentative.get(element); - } - return root; - } - - public void union(IType rep1, IType rep2) { - fElementToRepresentative.put(rep1, rep2); - } - } - - - private RippleMethodFinder(IMethod method) { - fMethod = method; - } - - public static IMethod[] getRelatedMethods(IMethod method, IProgressMonitor pm, WorkingCopyOwner owner) throws CoreException { - try { - if (!isVirtual(method)) { - return new IMethod[]{ method }; - } - - return new RippleMethodFinder(method).getAllRippleMethods(pm, owner); - } finally { - pm.done(); - } - } - - private static boolean isVirtual(IMethod method) throws JavaModelException { - if (method.isConstructor()) { - return false; - } - if (JdtFlags.isPrivate(method)) { - return false; - } - if (JdtFlags.isStatic(method)) { - return false; - } - return true; - } - - private IMethod[] getAllRippleMethods(IProgressMonitor pm, WorkingCopyOwner owner) throws CoreException { - IMethod[] rippleMethods = findAllRippleMethods(pm, owner); - return rippleMethods; - } - - private IMethod[] findAllRippleMethods(IProgressMonitor pm, WorkingCopyOwner owner) throws CoreException { - pm.beginTask("", 4); //$NON-NLS-1$ - - findAllDeclarations(pm, owner); - - //TODO: report assertion as error status and fall back to only return fMethod - //check for bug 81058: - if (!fDeclarations.contains(fMethod)) - { - Assert.isTrue(false, "Search for method declaration did not find original element: " + fMethod.toString()); //$NON-NLS-1$ - } - - createHierarchyOfDeclarations(new SubProgressMonitor(pm, 1), owner); - createTypeToMethod(); - createUnionFind(); - if (pm.isCanceled()) { - throw new OperationCanceledException(); - } - - fHierarchy = null; - fRootTypes = null; - - Map> partitioning = new HashMap<>(); - for (Iterator iter = fTypeToMethod.keySet().iterator(); iter.hasNext();) { - IType type = iter.next(); - IType rep = fUnionFind.find(type); - List types = partitioning.get(rep); - if (types == null) { - types = new ArrayList<>(); - } - types.add(type); - partitioning.put(rep, types); - } - Assert.isTrue(partitioning.size() > 0); - if (partitioning.size() == 1) { - return fDeclarations.toArray(new IMethod[fDeclarations.size()]); - } - - //Multiple partitions; must look out for nasty marriage cases - //(types inheriting method from two ancestors, but without redeclaring it). - IType methodTypeRep = fUnionFind.find(fMethod.getDeclaringType()); - List relatedTypes = partitioning.get(methodTypeRep); - boolean hasRelatedInterfaces = false; - List relatedMethods = new ArrayList<>(); - for (Iterator iter = relatedTypes.iterator(); iter.hasNext();) { - IType relatedType = iter.next(); - relatedMethods.add(fTypeToMethod.get(relatedType)); - if (relatedType.isInterface()) { - hasRelatedInterfaces = true; - } - } - - //Definition: An alien type is a type that is not a related type. The set of - // alien types diminishes as new types become related (a.k.a marry a relatedType). - - List alienDeclarations = new ArrayList<>(fDeclarations); - fDeclarations = null; - alienDeclarations.removeAll(relatedMethods); - List alienTypes = new ArrayList<>(); - boolean hasAlienInterfaces = false; - for (Iterator iter = alienDeclarations.iterator(); iter.hasNext();) { - IMethod alienDeclaration = iter.next(); - IType alienType = alienDeclaration.getDeclaringType(); - alienTypes.add(alienType); - if (alienType.isInterface()) { - hasAlienInterfaces= true; - } - } - if (alienTypes.size() == 0) { - return relatedMethods.toArray(new IMethod[relatedMethods.size()]); - } - if (!hasRelatedInterfaces && !hasAlienInterfaces) { - return relatedMethods.toArray(new IMethod[relatedMethods.size()]); - } - - //find all subtypes of related types: - HashSet relatedSubTypes = new HashSet<>(); - List relatedTypesToProcess = new ArrayList<>(relatedTypes); - while (relatedTypesToProcess.size() > 0) { - //TODO: would only need subtype hierarchies of all top-of-ripple relatedTypesToProcess - for (Iterator iter = relatedTypesToProcess.iterator(); iter.hasNext();) { - if (pm.isCanceled()) { - throw new OperationCanceledException(); - } - IType relatedType = iter.next(); - ITypeHierarchy hierarchy = getCachedHierarchy(relatedType, owner, new SubProgressMonitor(pm, 1)); - if (hierarchy == null) { - hierarchy = relatedType.newTypeHierarchy(owner, new SubProgressMonitor(pm, 1)); - } - IType[] allSubTypes = hierarchy.getAllSubtypes(relatedType); - for (int i = 0; i < allSubTypes.length; i++) { - relatedSubTypes.add(allSubTypes[i]); - } - } - relatedTypesToProcess.clear(); //processed; make sure loop terminates - - HashSet marriedAlienTypeReps = new HashSet<>(); - for (Iterator iter = alienTypes.iterator(); iter.hasNext();) { - if (pm.isCanceled()) { - throw new OperationCanceledException(); - } - IType alienType = iter.next(); - IMethod alienMethod = fTypeToMethod.get(alienType); - ITypeHierarchy hierarchy = getCachedHierarchy(alienType, owner, new SubProgressMonitor(pm, 1)); - if (hierarchy == null) { - hierarchy = alienType.newTypeHierarchy(owner, new SubProgressMonitor(pm, 1)); - } - IType[] allSubtypes = hierarchy.getAllSubtypes(alienType); - for (int i = 0; i < allSubtypes.length; i++) { - IType subtype = allSubtypes[i]; - if (relatedSubTypes.contains(subtype)) { - if (JavaModelUtil.isVisibleInHierarchy(alienMethod, subtype.getPackageFragment())) { - marriedAlienTypeReps.add(fUnionFind.find(alienType)); - } else { - // not overridden - } - } - } - } - - if (marriedAlienTypeReps.size() == 0) { - return relatedMethods.toArray(new IMethod[relatedMethods.size()]); - } - - for (Iterator iter = marriedAlienTypeReps.iterator(); iter.hasNext();) { - IType marriedAlienTypeRep = iter.next(); - List marriedAlienTypes = partitioning.get(marriedAlienTypeRep); - for (Iterator iterator = marriedAlienTypes.iterator(); iterator.hasNext();) { - IType marriedAlienInterfaceType = iterator.next(); - relatedMethods.add(fTypeToMethod.get(marriedAlienInterfaceType)); - } - alienTypes.removeAll(marriedAlienTypes); //not alien any more - relatedTypesToProcess.addAll(marriedAlienTypes); //process freshly married types again - } - } - - fRootReps = null; - fRootHierarchies = null; - fTypeToMethod = null; - fUnionFind = null; - - return relatedMethods.toArray(new IMethod[relatedMethods.size()]); - } - - private ITypeHierarchy getCachedHierarchy(IType type, WorkingCopyOwner owner, IProgressMonitor monitor) throws JavaModelException { - IType rep = fUnionFind.find(type); - if (rep != null) { - Collection collection = fRootReps.get(rep); - for (Iterator iter = collection.iterator(); iter.hasNext();) { - IType root = iter.next(); - ITypeHierarchy hierarchy = fRootHierarchies.get(root); - if (hierarchy == null) { - hierarchy = root.newTypeHierarchy(owner, new SubProgressMonitor(monitor, 1)); - fRootHierarchies.put(root, hierarchy); - } - if (hierarchy.contains(type)) { - return hierarchy; - } - } - } - return null; - } - - private void findAllDeclarations(IProgressMonitor monitor, WorkingCopyOwner owner) throws CoreException { - fDeclarations = new ArrayList<>(); - - class MethodRequestor extends SearchRequestor { - @Override - public void acceptSearchMatch(SearchMatch match) throws CoreException { - IMethod method = (IMethod) match.getElement(); - boolean isBinary = method.isBinary(); - if (!isBinary) { - fDeclarations.add(method); - } - } - } - - int limitTo = IJavaSearchConstants.DECLARATIONS | IJavaSearchConstants.IGNORE_DECLARING_TYPE | IJavaSearchConstants.IGNORE_RETURN_TYPE; - int matchRule = SearchPattern.R_ERASURE_MATCH | SearchPattern.R_CASE_SENSITIVE; - SearchPattern pattern = SearchPattern.createPattern(fMethod, limitTo, matchRule); - MethodRequestor requestor = new MethodRequestor(); - SearchEngine searchEngine = owner != null ? new SearchEngine(owner) : new SearchEngine(); - - searchEngine.search(pattern, new SearchParticipant[] { SearchEngine.getDefaultSearchParticipant() }, createSearchScope(), requestor, monitor); - } - - private void createHierarchyOfDeclarations(IProgressMonitor pm, WorkingCopyOwner owner) throws JavaModelException { - IRegion region = JavaCore.newRegion(); - for (Iterator iter = fDeclarations.iterator(); iter.hasNext();) { - IType declaringType = iter.next().getDeclaringType(); - region.add(declaringType); - } - fHierarchy = JavaCore.newTypeHierarchy(region, owner, pm); - } - - private void createTypeToMethod() { - fTypeToMethod = new HashMap<>(); - for (Iterator iter = fDeclarations.iterator(); iter.hasNext();) { - IMethod declaration = iter.next(); - fTypeToMethod.put(declaration.getDeclaringType(), declaration); - } - } - - private void createUnionFind() throws JavaModelException { - fRootTypes = new HashSet<>(fTypeToMethod.keySet()); - fUnionFind = new UnionFind(); - for (Iterator iter = fTypeToMethod.keySet().iterator(); iter.hasNext();) { - IType type = iter.next(); - fUnionFind.init(type); - } - for (Iterator iter = fTypeToMethod.keySet().iterator(); iter.hasNext();) { - IType type = iter.next(); - uniteWithSupertypes(type, type); - } - fRootReps = new MultiMap<>(); - for (Iterator iter = fRootTypes.iterator(); iter.hasNext();) { - IType type = iter.next(); - IType rep = fUnionFind.find(type); - if (rep != null) { - fRootReps.put(rep, type); - } - } - fRootHierarchies = new HashMap<>(); - } - - private void uniteWithSupertypes(IType anchor, IType type) throws JavaModelException { - IType[] supertypes = fHierarchy.getSupertypes(type); - for (int i = 0; i < supertypes.length; i++) { - IType supertype = supertypes[i]; - IType superRep = fUnionFind.find(supertype); - if (superRep == null) { - //Type doesn't declare method, but maybe supertypes? - uniteWithSupertypes(anchor, supertype); - } else { - //check whether method in supertype is really overridden: - IMember superMethod = fTypeToMethod.get(supertype); - if (JavaModelUtil.isVisibleInHierarchy(superMethod, anchor.getPackageFragment())) { - IType rep = fUnionFind.find(anchor); - fUnionFind.union(rep, superRep); - // current type is no root anymore - fRootTypes.remove(anchor); - uniteWithSupertypes(supertype, supertype); - } else { - //Not overridden -> overriding chain ends here. - } - } - } - } - - private IJavaSearchScope createSearchScope() throws JavaModelException { - IJavaProject[] projects = JavaCore.create(ResourcesPlugin.getWorkspace().getRoot()).getJavaProjects(); - return SearchEngine.createJavaSearchScope(projects, IJavaSearchScope.SOURCES); - } -} diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionResolveHandler.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionResolveHandler.java index a3832358ea..584a183b76 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionResolveHandler.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionResolveHandler.java @@ -51,7 +51,6 @@ import org.eclipse.jdt.ls.core.internal.corext.template.java.JavaPostfixContext; import org.eclipse.jdt.ls.core.internal.corext.template.java.PostfixCompletionProposal; import org.eclipse.jdt.ls.core.internal.corext.template.java.PostfixTemplateEngine; -import org.eclipse.jdt.ls.core.internal.javadoc.JavadocContentAccess; import org.eclipse.jdt.ls.core.internal.javadoc.JavadocContentAccess2; import org.eclipse.jdt.ls.core.internal.preferences.PreferenceManager; import org.eclipse.jface.text.Region; @@ -265,7 +264,7 @@ public CompletionItem resolve(CompletionItem param, IProgressMonitor monitor) { if (manager.getClientPreferences().isSupportsCompletionDocumentationMarkdown()) { reader = JavadocContentAccess2.getMarkdownContentReader(curMember); } else { - reader = JavadocContentAccess.getPlainTextContentReader(curMember); + reader = JavadocContentAccess2.getPlainTextContentReader(curMember); } return reader == null? null:CharStreams.toString(reader); }, 500, TimeUnit.MILLISECONDS); diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/AbstractJavaDocConverter.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/AbstractJavaDocConverter.java index 7a4271139c..bdf7e1de76 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/AbstractJavaDocConverter.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/AbstractJavaDocConverter.java @@ -15,6 +15,10 @@ import java.io.IOException; import java.io.Reader; import java.io.StringReader; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jdt.core.manipulation.internal.javadoc.CoreJavaDoc2HTMLTextReader; /** * Converts JavaDoc tags into an output format. @@ -23,10 +27,9 @@ */ abstract class AbstractJavaDocConverter { - private JavaDoc2HTMLTextReader reader; + private CoreJavaDoc2HTMLTextReader reader; private boolean read; - private String result; public AbstractJavaDocConverter(Reader reader) { @@ -38,13 +41,78 @@ public AbstractJavaDocConverter(String javadoc) { } private void setJavaDoc2HTMLTextReader(Reader reader) { - if (reader == null || reader instanceof JavaDoc2HTMLTextReader) { - this.reader = (JavaDoc2HTMLTextReader) reader; + if (reader == null || reader instanceof CoreJavaDoc2HTMLTextReader) { + this.reader = (CoreJavaDoc2HTMLTextReader) reader; } else { - this.reader = new JavaDoc2HTMLTextReader(reader); + this.reader = createHTMLTextReader(reader); } } + private CoreJavaDoc2HTMLTextReader createHTMLTextReader(Reader r) { + return new CoreJavaDoc2HTMLTextReader(r) { + + @Override + protected String getPrintSingleDefinitionStartTags() { + return "
  • "; //$NON-NLS-1$ + } + + @Override + protected String getPrintSingleDefinitionEndTags() { + return "
  • "; //$NON-NLS-1$ + } + + @Override + protected void print(StringBuilder buffer, String tag, List elements, boolean firstword) { + if (!elements.isEmpty()) { + buffer.append("
  • "); //$NON-NLS-1$ + buffer.append(tag); + buffer.append("
      "); //$NON-NLS-1$ + printDefinitions(buffer, elements, firstword); + buffer.append("
  • "); //$NON-NLS-1$ + } + } + + @Override + protected void print(StringBuilder buffer, String tag, String content) { + if (content != null) { + buffer.append("
  • "); //$NON-NLS-1$ + buffer.append(tag); + buffer.append("
    • "); //$NON-NLS-1$ + buffer.append(content); + buffer.append("
  • "); //$NON-NLS-1$ + } + } + + @Override + protected void printRest(StringBuilder buffer, List rest) { + if (!rest.isEmpty()) { + Iterator e = rest.iterator(); + while (e.hasNext()) { + Pair p = e.next(); + buffer.append("
  • "); //$NON-NLS-1$ + if (p.fTag() != null) { + buffer.append(p.fTag()); + } + buffer.append("
    • "); //$NON-NLS-1$ + if (p.fContent() != null) { + buffer.append(p.fContent()); + } + buffer.append("
  • "); //$NON-NLS-1$ + } + } + } + @Override + protected String printSimpleTag(List rest) { + StringBuilder buffer = new StringBuilder(); + buffer.append("
      "); //$NON-NLS-1$ + printTagAttributes(buffer); + printRest(buffer, rest); + buffer.append("
    "); //$NON-NLS-1$ + return buffer.toString(); + } + }; + } + public String getAsString() throws IOException { if (!read && reader != null) { String rawHtml = reader.getString(); diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/JavaDoc2HTMLTextReader.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/JavaDoc2HTMLTextReader.java deleted file mode 100644 index 8cd76dc2ea..0000000000 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/JavaDoc2HTMLTextReader.java +++ /dev/null @@ -1,431 +0,0 @@ -package org.eclipse.jdt.ls.core.internal.javadoc; - -import java.io.IOException; -import java.io.Reader; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.eclipse.jdt.core.dom.TagElement; -import org.eclipse.jdt.ls.core.internal.javadoc.html.SubstitutionTextReader; - -/** - * Processes JavaDoc tags. - */ -public class JavaDoc2HTMLTextReader extends SubstitutionTextReader { - - - static private class Pair { - String fTag; - String fContent; - - Pair(String tag, String content) { - fTag= tag; - fContent= content; - } - } - - private List fParameters; - private String fReturn; - private List fExceptions; - private List fAuthors; - private List fSees; - private List fSince; - private List fRest; // list of Pair objects - - public JavaDoc2HTMLTextReader(Reader reader) { - super(reader); - setSkipWhitespace(false); - } - - private int getTag(StringBuilder buffer) throws IOException { - int c= nextChar(); - while (c == '.' || c != -1 && Character.isLetter((char) c)) { - buffer.append((char) c); - c= nextChar(); - } - return c; - } - - private int getContent(StringBuilder buffer, char stopChar) throws IOException { - int c= nextChar(); - while (c != -1 && c != stopChar) { - buffer.append((char) c); - c= nextChar(); - } - return c; - } - - private int getContentUntilNextTag(StringBuilder buffer) throws IOException { - int c= nextChar(); - boolean blockStartRead= false; - while (c != -1) { - if (c == '@') { - int index= buffer.length(); - while (--index >= 0 && Character.isWhitespace(buffer.charAt(index))) { - switch (buffer.charAt(index)) { - case '\n': - case '\r': - return c; - } - if (index <= 0) { - return c; - } - } - } - if (blockStartRead) { - buffer.append(processBlockTag()); - blockStartRead= false; - } else { - buffer.append((char) c); - } - - c= nextChar(); - blockStartRead= c == '{'; - } - return c; - } - - private String substituteQualification(String qualification) { - String result; - if (qualification.indexOf("') { - insideTag= false; - } - if (charAt == '#' && !insideTag) - { - result= result.substring(0, i) + "." + result.substring(i + 1); //$NON-NLS-1$ - } - } - } - - if (result.startsWith(".")) { - result= result.substring(1); - } - return result; - } - - private void printDefinitions(StringBuilder buffer, List list, boolean firstword) { - Iterator e= list.iterator(); - while (e.hasNext()) { - String s= e.next(); - buffer.append("
  • "); //$NON-NLS-1$ - if (!firstword) { - buffer.append(s); - } else { - buffer.append(""); //$NON-NLS-1$ - - int i= getParamEndOffset(s); - if (i <= s.length()) { - buffer.append(convertToHTMLContent(s.substring(0, i))); - buffer.append(""); //$NON-NLS-1$ - buffer.append(s.substring(i)); - } else { - buffer.append(""); //$NON-NLS-1$ - } - } - buffer.append("
  • "); //$NON-NLS-1$ - } - } - - private int getParamEndOffset(String s) { - int i= 0; - final int length= s.length(); - // \s* - while (i < length && Character.isWhitespace(s.charAt(i))) { - ++i; - } - if (i < length && s.charAt(i) == '<') { - // generic type parameter - // read <\s*\w*\s*> - while (i < length && Character.isWhitespace(s.charAt(i))) { - ++i; - } - while (i < length && Character.isJavaIdentifierPart(s.charAt(i))) { - ++i; - } - while (i < length && s.charAt(i) != '>') { - ++i; - } - ++i; // > - } else { - // simply read an identifier - while (i < length && Character.isJavaIdentifierPart(s.charAt(i))) { - ++i; - } - } - - return i; - } - - private void print(StringBuilder buffer, String tag, List elements, boolean firstword) { - if ( !elements.isEmpty()) { - buffer.append("
  • "); //$NON-NLS-1$ - buffer.append(tag); - buffer.append("
      "); - printDefinitions(buffer, elements, firstword); - buffer.append("
  • "); //$NON-NLS-1$ - } - } - - private void print(StringBuilder buffer, String tag, String content) { - if (content != null) { - buffer.append("
  • "); //$NON-NLS-1$ - buffer.append(tag); - buffer.append("
    • "); //$NON-NLS-1$ - buffer.append(content); - buffer.append("
  • "); //$NON-NLS-1$ - } - } - - private void printRest(StringBuilder buffer) { - if ( !fRest.isEmpty()) { - Iterator e= fRest.iterator(); - while (e.hasNext()) { - Pair p= e.next(); - buffer.append("
  • "); //$NON-NLS-1$ - if (p.fTag != null) { - buffer.append(p.fTag); - } - buffer.append("
    • "); //$NON-NLS-1$ - if (p.fContent != null) { - buffer.append(p.fContent); - } - buffer.append("
  • "); //$NON-NLS-1$ - } - } - } - - private String printSimpleTag() { - StringBuilder buffer= new StringBuilder(); - buffer.append("
      "); //$NON-NLS-1$ - print(buffer, "See Also:",fSees, false); - print(buffer, "Parameters:", fParameters, true); - print(buffer, "Returns:", fReturn); - print(buffer, "Throws:", fExceptions, false); - print(buffer, "Author:", fAuthors, false); - print(buffer, "Since:", fSince, false); - printRest(buffer); - buffer.append("
    "); //$NON-NLS-1$ - - return buffer.toString(); - } - - private void handleTag(String tag, String tagContent) { - - tagContent= tagContent.trim(); - - if (TagElement.TAG_PARAM.equals(tag)) { - fParameters.add(tagContent); - } else if (TagElement.TAG_RETURN.equals(tag)) { - fReturn= tagContent; - } else if (TagElement.TAG_EXCEPTION.equals(tag)) { - fExceptions.add(tagContent); - } else if (TagElement.TAG_THROWS.equals(tag)) { - fExceptions.add(tagContent); - } else if (TagElement.TAG_AUTHOR.equals(tag)) { - fAuthors.add(substituteQualification(tagContent)); - } else if (TagElement.TAG_SEE.equals(tag)) { - fSees.add(substituteQualification(tagContent)); - } else if (TagElement.TAG_SINCE.equals(tag)) { - fSince.add(substituteQualification(tagContent)); - } else if (tagContent != null) { - fRest.add(new Pair(tag, tagContent)); - } - } - - /* - * A '@' has been read. Process a javadoc tag - */ - private String processSimpleTag() throws IOException { - - fParameters= new ArrayList<>(); - fExceptions= new ArrayList<>(); - fAuthors= new ArrayList<>(); - fSees= new ArrayList<>(); - fSince= new ArrayList<>(); - fRest= new ArrayList<>(); - - StringBuilder buffer= new StringBuilder(); - int c= '@'; - while (c != -1) { - - buffer.setLength(0); - buffer.append((char) c); - c= getTag(buffer); - String tag= buffer.toString(); - - buffer.setLength(0); - if (c != -1) { - c= getContentUntilNextTag(buffer); - } - - handleTag(tag, buffer.toString()); - } - - return printSimpleTag(); - } - - private String printBlockTag(String tag, String tagContent) { - - if (TagElement.TAG_LINK.equals(tag) || TagElement.TAG_LINKPLAIN.equals(tag)) { - - char[] contentChars= tagContent.toCharArray(); - boolean inParentheses= false; - int labelStart= 0; - - for (int i= 0; i < contentChars.length; i++) { - char nextChar= contentChars[i]; - - // tagContent always has a leading space - if (i == 0 && Character.isWhitespace(nextChar)) { - labelStart= 1; - continue; - } - - if (nextChar == '(') { - inParentheses= true; - continue; - } - - if (nextChar == ')') { - inParentheses= false; - continue; - } - - // Stop at first whitespace that is not in parentheses - if (!inParentheses && Character.isWhitespace(nextChar)) { - labelStart= i+1; - break; - } - } - if (TagElement.TAG_LINK.equals(tag)) { - return "" + substituteQualification(tagContent.substring(labelStart)) + ""; //$NON-NLS-1$//$NON-NLS-2$ - } else { - return substituteQualification(tagContent.substring(labelStart)); - } - - } else if (TagElement.TAG_LITERAL.equals(tag) || TagElement.TAG_CODE.equals(tag)) { - return printLiteral(tagContent); - - } else if (TagElement.TAG_CODE.equals(tag)) { - return "" + printLiteral(tagContent) + ""; //$NON-NLS-1$//$NON-NLS-2$ - } - - // If something went wrong at least replace the {} with the content - return substituteQualification(tagContent); - } - - private String printLiteral(String tagContent) { - int contentStart= 0; - for (int i= 0; i < tagContent.length(); i++) { - if (! Character.isWhitespace(tagContent.charAt(i))) { - contentStart= i; - break; - } - } - return convertToHTMLContent(tagContent.substring(contentStart)); - } - - /* - * A '{' has been read. Process a block tag - */ - private String processBlockTag() throws IOException { - - int c= nextChar(); - - if (c != '@') { - StringBuilder buffer= new StringBuilder(); - buffer.append('{'); - buffer.append((char) c); - return buffer.toString(); - } - - StringBuilder buffer= new StringBuilder(); - if (c != -1) { - - buffer.setLength(0); - buffer.append((char) c); - - c= getTag(buffer); - String tag= buffer.toString(); - - buffer.setLength(0); - if (c != -1 && c != '}') { - buffer.append((char) c); - getContent(buffer, '}'); - } - - return printBlockTag(tag, buffer.toString()); - } - - return null; - } - - /* - * @see SubstitutionTextReaderr#computeSubstitution(int) - */ - @Override - protected String computeSubstitution(int c) throws IOException { - if (c == '@' && fWasWhiteSpace) { - return processSimpleTag(); - } - - if (c == '{') { - return processBlockTag(); - } - - return null; - } - - /** - * Escapes reserved HTML characters in the given string. - *

    - * Warning: Does not preserve whitespace. - * - * @param content the input string - * @return the string with escaped characters - * - * @see #convertToHTMLContentWithWhitespace(String) for use in browsers - * @see #addPreFormatted(StringBuilder, String) for rendering with an {@link HTML2TextReader} - */ - private static String convertToHTMLContent(String content) { - content= replace(content, '&', "&"); //$NON-NLS-1$ - content= replace(content, '"', """); //$NON-NLS-1$ - content= replace(content, '<', "<"); //$NON-NLS-1$ - return replace(content, '>', ">"); //$NON-NLS-1$ - } - - private static String replace(String text, char c, String s) { - - int previous= 0; - int current= text.indexOf(c, previous); - - if (current == -1) { - return text; - } - - StringBuilder buffer= new StringBuilder(); - while (current > -1) { - buffer.append(text.substring(previous, current)); - buffer.append(s); - previous= current + 1; - current= text.indexOf(c, previous); - } - buffer.append(text.substring(previous)); - - return buffer.toString(); - } -} diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/JavaDocCommentReader.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/JavaDocCommentReader.java deleted file mode 100644 index 944f53df7a..0000000000 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/JavaDocCommentReader.java +++ /dev/null @@ -1,121 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.ls.core.internal.javadoc; - -import org.eclipse.jdt.core.IBuffer; -import org.eclipse.jdt.core.formatter.IndentManipulation; -import org.eclipse.jdt.ls.core.internal.javadoc.html.SingleCharReader; - - -/** - * Reads a java doc comment from a java doc comment. Skips star-character on begin of line. - */ -public class JavaDocCommentReader extends SingleCharReader { - - private IBuffer fBuffer; - - private String fSource; - - private int fCurrPos; - - private int fStartPos; - - private int fEndPos; - - private boolean fWasNewLine; - - public JavaDocCommentReader(IBuffer buf, int start, int end) { - fBuffer= buf; - fStartPos= start + 3; - fEndPos= end - 2; - - reset(); - } - - public JavaDocCommentReader(String source, int start, int end) { - fSource= source; - fStartPos= start + 3; - fEndPos= end - 2; - - reset(); - } - - /** - * @see java.io.Reader#read() - */ - @Override - public int read() { - if (fCurrPos < fEndPos) { - char ch= getChar(fCurrPos++); - if (fWasNewLine && !IndentManipulation.isLineDelimiterChar(ch)) { - while (fCurrPos < fEndPos && Character.isWhitespace(ch)) { - ch= getChar(fCurrPos++); - } - if (ch == '*') { - if (fCurrPos < fEndPos) { - do { - ch= getChar(fCurrPos++); - } while (ch == '*'); - } else { - return -1; - } - } - } - fWasNewLine= IndentManipulation.isLineDelimiterChar(ch); - - return ch; - } - return -1; - } - - /** - * @see java.io.Reader#close() - */ - @Override - public void close() { - fSource = null; - fBuffer= null; - } - - /** - * @see java.io.Reader#reset() - */ - @Override - public void reset() { - fCurrPos= fStartPos; - fWasNewLine= true; - // skip first line delimiter: - if (fCurrPos < fEndPos && '\r' == getChar(fCurrPos)) { - fCurrPos++; - } - if (fCurrPos < fEndPos && '\n' == getChar(fCurrPos)) { - fCurrPos++; - } - } - - private char getChar(int pos) { - if (fBuffer != null) { - return fBuffer.getChar(fCurrPos); - } - return fSource.charAt(pos); - } - - /** - * Returns the offset of the last read character in the passed buffer. - * - * @return the offset - */ - public int getOffset() { - return fCurrPos; - } -} diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/JavaDocHTMLPathHandler.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/JavaDocHTMLPathHandler.java index 32fcbc332a..c4960dff96 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/JavaDocHTMLPathHandler.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/JavaDocHTMLPathHandler.java @@ -33,6 +33,7 @@ import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.dom.TextElement; +import org.eclipse.jdt.core.manipulation.internal.javadoc.CoreJavaDocLocations; import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; import org.eclipse.jdt.ls.core.internal.ResourceUtils; @@ -131,7 +132,7 @@ public static String getValidatedHTMLSrcAttribute(TextElement child, IJavaElemen ZipEntry currentZipEntry = null; - URL javadocJarBaseLocationURL = JavaDocLocations.getJavadocBaseLocation(internalJarFragment); //Absolute location of javadoc jar (not class or source jar) + URL javadocJarBaseLocationURL = CoreJavaDocLocations.getJavadocBaseLocation(internalJarFragment); //Absolute location of javadoc jar (not class or source jar) //Attempt to get file from javadoc jar if (javadocJarBaseLocationURL != null) { URI javadocJarBaseLocationURI = javadocJarBaseLocationURL.toURI(); diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/JavaDocLocations.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/JavaDocLocations.java deleted file mode 100644 index 73f8e45a5b..0000000000 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/JavaDocLocations.java +++ /dev/null @@ -1,426 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2016 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Code copied from org.eclipse.jdt.internal.corext.javadoc.JavaDocLocations - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.ls.core.internal.javadoc; - -import java.io.File; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; - -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.QualifiedName; -import org.eclipse.core.runtime.URIUtil; -import org.eclipse.jdt.core.Flags; -import org.eclipse.jdt.core.IClasspathAttribute; -import org.eclipse.jdt.core.IClasspathEntry; -import org.eclipse.jdt.core.ICompilationUnit; -import org.eclipse.jdt.core.IField; -import org.eclipse.jdt.core.IImportDeclaration; -import org.eclipse.jdt.core.IJavaElement; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.IMember; -import org.eclipse.jdt.core.IMethod; -import org.eclipse.jdt.core.IModularClassFile; -import org.eclipse.jdt.core.IModuleDescription; -import org.eclipse.jdt.core.IOrdinaryClassFile; -import org.eclipse.jdt.core.IPackageFragment; -import org.eclipse.jdt.core.IPackageFragmentRoot; -import org.eclipse.jdt.core.IType; -import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jdt.core.Signature; -import org.eclipse.jdt.internal.corext.util.JavaModelUtil; - -public class JavaDocLocations { - - private static final String JAR_PROTOCOL = "jar"; //$NON-NLS-1$ - public static final String ARCHIVE_PREFIX = "jar:"; //$NON-NLS-1$ - - private static final QualifiedName PROJECT_JAVADOC = new QualifiedName("test", "project_javadoc_location"); //$NON-NLS-1$ - - /** - * Sets the Javadoc location for an archive with the given path. - * - * @param project - * the Java project - * @param url - * the Javadoc location - */ - public static void setProjectJavadocLocation(IJavaProject project, URL url) { - try { - String location = url != null ? url.toExternalForm() : null; - setProjectJavadocLocation(project, location); - } catch (CoreException e) { - //JavaPlugin.log(e); - } - } - - private static void setProjectJavadocLocation(IJavaProject project, String url) throws CoreException { - project.getProject().setPersistentProperty(PROJECT_JAVADOC, url); - } - - public static URL getProjectJavadocLocation(IJavaProject project) { - if (!project.getProject().isAccessible()) { - return null; - } - try { - String prop = project.getProject().getPersistentProperty(PROJECT_JAVADOC); - if (prop == null) { - return null; - } - return parseURL(prop); - } catch (CoreException e) { - //JavaPlugin.log(e); - } - return null; - } - - public static URL getLibraryJavadocLocation(IClasspathEntry entry) { - if (entry == null) { - throw new IllegalArgumentException("Entry must not be null"); //$NON-NLS-1$ - } - - int kind = entry.getEntryKind(); - if (kind != IClasspathEntry.CPE_LIBRARY && kind != IClasspathEntry.CPE_VARIABLE) { - throw new IllegalArgumentException("Entry must be of kind CPE_LIBRARY or CPE_VARIABLE"); //$NON-NLS-1$ - } - - IClasspathAttribute[] extraAttributes = entry.getExtraAttributes(); - for (int i = 0; i < extraAttributes.length; i++) { - IClasspathAttribute attrib = extraAttributes[i]; - if (IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME.equals(attrib.getName())) { - return parseURL(attrib.getValue()); - } - } - return null; - } - - public static URL getJavadocBaseLocation(IJavaElement element) throws JavaModelException { - if (element.getElementType() == IJavaElement.JAVA_PROJECT) { - return getProjectJavadocLocation((IJavaProject) element); - } - - IPackageFragmentRoot root = JavaModelUtil.getPackageFragmentRoot(element); - if (root == null) { - return null; - } - - if (root.getKind() == IPackageFragmentRoot.K_BINARY) { - IClasspathEntry entry = root.getResolvedClasspathEntry(); - URL javadocLocation = getLibraryJavadocLocation(entry); - if (javadocLocation != null) { - return getLibraryJavadocLocation(entry); - } - entry = root.getRawClasspathEntry(); - switch (entry.getEntryKind()) { - case IClasspathEntry.CPE_LIBRARY: - case IClasspathEntry.CPE_VARIABLE: - return getLibraryJavadocLocation(entry); - default: - return null; - } - } else { - return getProjectJavadocLocation(root.getJavaProject()); - } - } - - public static URL getJavadocLocation(IJavaElement element, boolean includeMemberReference) throws JavaModelException { - URL baseLocation = getJavadocBaseLocation(element); - if (baseLocation == null) { - return null; - } - - String urlString = baseLocation.toExternalForm(); - - StringBuffer urlBuffer = new StringBuffer(urlString); - if (!urlString.endsWith("/")) { //$NON-NLS-1$ - urlBuffer.append('/'); - } - - StringBuffer pathBuffer = new StringBuffer(); - StringBuffer fragmentBuffer = new StringBuffer(); - - switch (element.getElementType()) { - case IJavaElement.PACKAGE_FRAGMENT: - appendPackageSummaryPath((IPackageFragment) element, pathBuffer); - break; - case IJavaElement.JAVA_PROJECT: - case IJavaElement.PACKAGE_FRAGMENT_ROOT: - appendIndexPath(pathBuffer); - break; - case IJavaElement.IMPORT_CONTAINER: - element = element.getParent(); - //$FALL-THROUGH$ - case IJavaElement.COMPILATION_UNIT: - IType mainType = ((ICompilationUnit) element).findPrimaryType(); - if (mainType == null) { - return null; - } - appendTypePath(mainType, pathBuffer); - break; - case IJavaElement.CLASS_FILE: - if (element instanceof IModularClassFile modularClassFile) { - try { - appendModuleSummaryPath(modularClassFile.getModule(), pathBuffer); - } catch (JavaModelException e) { - return null; - } - } else { - appendTypePath(((IOrdinaryClassFile) element).getType(), pathBuffer); - } - break; - case IJavaElement.TYPE: - appendTypePath((IType) element, pathBuffer); - break; - case IJavaElement.FIELD: - IField field = (IField) element; - appendTypePath(field.getDeclaringType(), pathBuffer); - if (includeMemberReference) { - appendFieldReference(field, fragmentBuffer); - } - break; - case IJavaElement.METHOD: - IMethod method = (IMethod) element; - appendTypePath(method.getDeclaringType(), pathBuffer); - if (includeMemberReference) { - appendMethodReference(method, fragmentBuffer); - } - break; - case IJavaElement.INITIALIZER: - appendTypePath(((IMember) element).getDeclaringType(), pathBuffer); - break; - case IJavaElement.IMPORT_DECLARATION: - IImportDeclaration decl = (IImportDeclaration) element; - - if (decl.isOnDemand()) { - IJavaElement cont = JavaModelUtil.findTypeContainer(element.getJavaProject(), Signature.getQualifier(decl.getElementName())); - if (cont instanceof IType type) { - appendTypePath(type, pathBuffer); - } else if (cont instanceof IPackageFragment pkg) { - appendPackageSummaryPath(pkg, pathBuffer); - } - } else { - IType imp = element.getJavaProject().findType(decl.getElementName()); - appendTypePath(imp, pathBuffer); - } - break; - case IJavaElement.PACKAGE_DECLARATION: - IJavaElement pack = element.getAncestor(IJavaElement.PACKAGE_FRAGMENT); - if (pack != null) { - appendPackageSummaryPath((IPackageFragment) pack, pathBuffer); - } else { - return null; - } - break; - case IJavaElement.JAVA_MODULE: - IModuleDescription module = (IModuleDescription) element; - appendModuleSummaryPath(module, pathBuffer); - break; - default: - return null; - } - - try { - String fragment = fragmentBuffer.length() == 0 ? null : fragmentBuffer.toString(); - try { - URI relativeURI = new URI(null, null, pathBuffer.toString(), fragment); - urlBuffer.append(relativeURI.toString()); - return new URL(urlBuffer.toString()); - } catch (URISyntaxException e) { - //JavaPlugin.log(e); - return new URL(urlBuffer.append(pathBuffer).toString()); - } - } catch (MalformedURLException e) { - //JavaPlugin.log(e); - } - return null; - } - - private static void appendPackageSummaryPath(IPackageFragment pack, StringBuffer buf) { - String packPath = pack.getElementName().replace('.', '/'); - buf.append(packPath); - buf.append("/package-summary.html"); //$NON-NLS-1$ - } - - private static void appendModuleSummaryPath(IModuleDescription module, StringBuffer buf) { - String moduleName = module.getElementName(); - buf.append(moduleName); - buf.append("-summary.html"); //$NON-NLS-1$ - } - - private static void appendIndexPath(StringBuffer buf) { - buf.append("index.html"); //$NON-NLS-1$ - } - - private static void appendTypePath(IType type, StringBuffer buf) { - IPackageFragment pack = type.getPackageFragment(); - String packPath = pack.getElementName().replace('.', '/'); - String typePath = type.getTypeQualifiedName('.'); - if (packPath.length() > 0) { - buf.append(packPath); - buf.append('/'); - } - buf.append(typePath); - buf.append(".html"); //$NON-NLS-1$ - } - - private static void appendFieldReference(IField field, StringBuffer buf) { - buf.append(field.getElementName()); - } - - private static void appendMethodReference(IMethod meth, StringBuffer buf) throws JavaModelException { - buf.append(meth.getElementName()); - - /* - * The Javadoc tool for Java SE 8 changed the anchor syntax and now tries to avoid "strange" characters in URLs. - * This breaks all clients that directly create such URLs. - * We can't know what format is required, so we just guess by the project's compiler compliance. - */ - boolean is1d8OrHigher = JavaModelUtil.is1d8OrHigher(meth.getJavaProject()); - buf.append(is1d8OrHigher ? '-' : '('); - String[] params = meth.getParameterTypes(); - IType declaringType = meth.getDeclaringType(); - boolean isVararg = Flags.isVarargs(meth.getFlags()); - int lastParam = params.length - 1; - for (int i = 0; i <= lastParam; i++) { - if (i != 0) { - buf.append(is1d8OrHigher ? "-" : ", "); //$NON-NLS-1$ //$NON-NLS-2$ - } - String curr = Signature.getTypeErasure(params[i]); - String fullName = JavaModelUtil.getResolvedTypeName(curr, declaringType); - if (fullName == null) { // e.g. a type parameter "QE;" - fullName = Signature.toString(Signature.getElementType(curr)); - } - if (fullName != null) { - buf.append(fullName); - int dim = Signature.getArrayCount(curr); - if (i == lastParam && isVararg) { - dim--; - } - while (dim > 0) { - buf.append(is1d8OrHigher ? ":A" : "[]"); //$NON-NLS-1$ //$NON-NLS-2$ - dim--; - } - if (i == lastParam && isVararg) { - buf.append("..."); //$NON-NLS-1$ - } - } - } - buf.append(is1d8OrHigher ? '-' : ')'); - } - - /** - * Returns the location of the Javadoc. - * - * @param element - * whose Javadoc location has to be found - * @param isBinary - * true if the Java element is from a binary container - * @return the location URL of the Javadoc or null if the location - * cannot be found - * @throws JavaModelException - * thrown when the Java element cannot be accessed - * @since 3.9 - */ - public static String getBaseURL(IJavaElement element, boolean isBinary) throws JavaModelException { - if (isBinary) { - // Source attachment usually does not include Javadoc resources - // => Always use the Javadoc location as base: - URL baseURL = JavaDocLocations.getJavadocLocation(element, false); - if (baseURL != null) { - if (baseURL.getProtocol().equals(JAR_PROTOCOL)) { - // It's a JarURLConnection, which is not known to the browser widget. - // Let's start the help web server: - // URL baseURL2 = PlatformUI.getWorkbench().getHelpSystem().resolve(baseURL.toExternalForm(), true); - // if (baseURL2 != null) { // can be null if org.eclipse.help.ui is not available - // baseURL = baseURL2; - // } - } - return baseURL.toExternalForm(); - } - } else { - IResource resource = element.getResource(); - if (resource != null) { - /* - * Too bad: Browser widget knows nothing about EFS and custom URL handlers, - * so IResource#getLocationURI() does not work in all cases. - * We only support the local file system for now. - * A solution could be https://bugs.eclipse.org/bugs/show_bug.cgi?id=149022 . - */ - IPath location = resource.getLocation(); - if (location != null) { - return location.toFile().toURI().toString(); - } - } - } - return null; - } - - /** - * Parse a URL from a String. This method first tries to treat url - * as a valid, encoded URL. If that didn't work, it tries to recover from bad - * URLs, e.g. the unencoded form we used to use in persistent storage. - * - * @param url - * a URL - * @return the parsed URL or null if the URL couldn't be parsed - * @since 3.9 - */ - public static URL parseURL(String url) { - try { - try { - return new URI(url).toURL(); - } catch (URISyntaxException e) { - try { - // don't log, since we used to store bad (unencoded) URLs - if (url.startsWith("file:/")) { //$NON-NLS-1$ - // workaround for a bug in the 3-arg URI constructor for paths that contain '[' or ']': - return new URI("file", null, url.substring(5), null).toURL(); //$NON-NLS-1$ - } else { - return URIUtil.fromString(url).toURL(); - } - } catch (URISyntaxException e1) { - // last try, not expected to happen - //JavaPlugin.log(e); - return new URL(url); - } - } - } catch (MalformedURLException e) { - //JavaPlugin.log(e); - return null; - } - } - - /** - * Returns the {@link File} of a file: URL. This method tries to - * recover from bad URLs, e.g. the unencoded form we used to use in persistent - * storage. - * - * @param url - * a file: URL - * @return the file - * @since 3.9 - */ - public static File toFile(URL url) { - try { - return URIUtil.toFile(url.toURI()); - } catch (URISyntaxException e) { - //JavaPlugin.log(e); - return new File(url.getFile()); - } - } -} \ No newline at end of file diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/JavaDocSnippetStringEvaluator.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/JavaDocSnippetStringEvaluator.java deleted file mode 100644 index 5dbdd00569..0000000000 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/JavaDocSnippetStringEvaluator.java +++ /dev/null @@ -1,681 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2022 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Code copied from org.eclipse.jdt.internal.ui.text.javadoc.JavaDocSnippetStringEvaluator - * - * This is an implementation of an early-draft specification developed under the Java - * Community Process (JCP) and is made available for testing and evaluation purposes - * only. The code is not compatible with any specification of the JCP. - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.ls.core.internal.javadoc; - -import java.io.IOException; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.List; -import java.util.ListIterator; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -import org.eclipse.jdt.core.IJavaElement; -import org.eclipse.jdt.core.dom.ASTNode; -import org.eclipse.jdt.core.dom.JavaDocRegion; -import org.eclipse.jdt.core.dom.MemberRef; -import org.eclipse.jdt.core.dom.MethodRef; -import org.eclipse.jdt.core.dom.MethodRefParameter; -import org.eclipse.jdt.core.dom.Name; -import org.eclipse.jdt.core.dom.SimpleName; -import org.eclipse.jdt.core.dom.TagElement; -import org.eclipse.jdt.core.dom.TagProperty; -import org.eclipse.jdt.core.dom.TextElement; -import org.eclipse.jdt.internal.corext.dom.ASTNodes; -import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; - -public class JavaDocSnippetStringEvaluator { - - public static final String SNIPPET = "SNIPPET"; - - /** - * Either an IMember or an IPackageFragment. - */ - private final IJavaElement fElement; - - public enum ReplacementStringIntervalStatus { - /** - * replacement interval occurs before the given ActionElement interval - */ - BEFORE, - /** - * replacement interval occurs after the given ActionElement interval - */ - AFTER, - /** - * replacement interval occurs within the given ActionElement interval - */ - WITHIN, - /** - * replacement interval contains the given ActionElement interval - */ - ENCOMPASS, - /** - * replacement interval starts before the given ActionElement interval and ends within the ActionElement interval - */ - PREV_OVERLAP, - /** - * replacement interval starts within the given ActionElement interval and ends after the ActionElement interval - */ - POST_OVERLAP, - /** - * Default Value, do nothing - */ - DEFAULT - } - - public class ActionElement{ - public int start; - public int end; - public String startTag; - public String endTag; - - public ActionElement(int start, int end, String startTag, String endTag) { - this.start= start; - this.end= end; - this.startTag= startTag; - this.endTag= endTag; - } - - public ReplacementStringIntervalStatus getIntervalStatus(int replacementIntervalStart, int replacementIntervalEnd) { - ReplacementStringIntervalStatus intervalStatus= ReplacementStringIntervalStatus.DEFAULT; - int startDiff = replacementIntervalStart - this.start; - int endDiff = replacementIntervalEnd - this.end; - - if (this.end <= replacementIntervalStart) { - intervalStatus= ReplacementStringIntervalStatus.AFTER; - } else if (this.start >= replacementIntervalEnd) { - intervalStatus= ReplacementStringIntervalStatus.BEFORE; - } else if (startDiff <= 0 && endDiff >= 0) { - intervalStatus= ReplacementStringIntervalStatus.ENCOMPASS; - } else if (startDiff > 0 && endDiff < 0) { - intervalStatus= ReplacementStringIntervalStatus.WITHIN; - } else if (startDiff > 0) { - intervalStatus= ReplacementStringIntervalStatus.POST_OVERLAP; - } else if (endDiff < 0) { - intervalStatus= ReplacementStringIntervalStatus.PREV_OVERLAP; - } - - return intervalStatus; - } - - } - - public class StringItem{ - public int index; - public String tag; - public StringItem(int index, String tag) { - this.index= index; - this.tag= tag; - } - } - - public JavaDocSnippetStringEvaluator(IJavaElement element) { - this.fElement= element; - } - - public void AddTagElementString(TagElement snippetTag, StringBuffer buffer) { - if (snippetTag != null) { - List fragments = snippetTag.fragments(); - for( Object fragment : fragments) { - String str= ""; //$NON-NLS-1$ - if (fragment instanceof TextElement textElement) { - List tagElements= getTagElementsForTextElement(snippetTag, textElement); - str = getModifiedString(textElement, tagElements); - } else if (fragment instanceof JavaDocRegion region) { - if (region.isDummyRegion()) { - List tagElements= getTagElementsForDummyJavaDocRegion(snippetTag, region); - str = getModifiedString(region, tagElements); - } - } else if (fragment instanceof TagElement tagElement) { - List tagElements= getTagElementsForTagElement(snippetTag, tagElement); - str = getModifiedString(tagElement, tagElements); - if (TagElement.TAG_LINK.equals(tagElement.getTagName())) { - int leadingSpaces = 0; - while (str.length() > leadingSpaces + 1 && str.charAt(leadingSpaces) == ' ') { - leadingSpaces++; - } - try { - str = new JavaDoc2MarkdownConverter(str).getAsString(); - for (int i = 0; i < leadingSpaces; i++) { - str = " " + str; - } - str = str + " \n"; - } catch (IOException e) { - JavaLanguageServerPlugin.logException(e.getMessage(), e); - } - } - } - buffer.append(SNIPPET); - buffer.append(str); - } - } - } - - private String getModifiedString(TextElement textElement, List tags) { - return getModifiedString(textElement.getText(), tags); - } - - private String getModifiedString(TagElement tagElement, List tags) { - return getModifiedString(((TextElement)tagElement.fragments().get(0)).getText(), tags); - } - - private String getModifiedString(JavaDocRegion region, List tags) { - return getModifiedString(((TextElement)region.fragments().get(0)).getText(), tags); - } - - private String getModifiedString(String str, List tags) { - List actionElements= new ArrayList<>(); - String modifiedStr= str; - for (TagElement tag : tags) { - String name= tag.getTagName(); - if (TagElement.TAG_HIGHLIGHT.equals(name)) { - handleSnippetHighlight(modifiedStr, tag, actionElements); - } else if (TagElement.TAG_REPLACE.equals(name)) { - modifiedStr= handleSnippetReplace(modifiedStr, tag, actionElements); - } else if (TagElement.TAG_LINK.equals(name)) { - handleSnippetLink(modifiedStr, tag, actionElements); - } - } - return getString( modifiedStr, actionElements); - } - - private String getString(String str, List actionElements) { - String modifiedStr = str; - List items= new ArrayList<>(); - for (ActionElement actElem : actionElements) { - StringItem startItem = new StringItem(actElem.start, actElem.startTag); - StringItem endItem = new StringItem(actElem.end, actElem.endTag); - ListIterator iterator = items.listIterator(); - boolean endIndexAdded = false; - boolean startIndexAdded = false; - while (iterator.hasNext()) { - StringItem elem= iterator.next(); - if (!endIndexAdded && elem.index < endItem.index) { - iterator.previous(); - iterator.add(endItem); - endIndexAdded = true; - iterator.next(); - } - if (!startIndexAdded && elem.index < startItem.index) { - iterator.previous(); - iterator.add(startItem); - startIndexAdded = true; - iterator.next(); - } - if (startIndexAdded && endIndexAdded) { - break; - } - } - if (!endIndexAdded) { - items.add(endItem); - } - if (!startIndexAdded) { - items.add(startItem); - } - } - for (StringItem item : items) { - modifiedStr = modifiedStr.substring(0, item.index) + item.tag + modifiedStr.substring(item.index); - } - return modifiedStr; - } - - private void modifyPrevActionItemsReplacement(int replacementIntervalStart, int relacementIntervalEnd, int replacementStrNewLength, List actionElements) { - ListIterator iterator = actionElements.listIterator(); - int oldLength = relacementIntervalEnd - replacementIntervalStart; - int diff = replacementStrNewLength - oldLength; - while (iterator.hasNext()) { - ActionElement elem= iterator.next(); - ReplacementStringIntervalStatus intervalStatus= elem.getIntervalStatus(replacementIntervalStart, relacementIntervalEnd); - switch(intervalStatus) { - case AFTER: - //do nothing., nothing needs to be done here - break; - case BEFORE: - if (diff != 0) { - elem.start+= diff; - elem.end+= diff; - } - break; - case ENCOMPASS: - iterator.remove(); - break; - case POST_OVERLAP: - elem.end= replacementIntervalStart; - break; - case PREV_OVERLAP: - elem.end += diff; - elem.start = relacementIntervalEnd + diff; - break; - case WITHIN: - // modify the old ActionElement to end before the replacement string start - // Create a new Element element to start from the replacement string end - int newEnd = elem.end + diff; - elem.end= replacementIntervalStart; - int newStart = relacementIntervalEnd + diff; - ActionElement newElem= new ActionElement(newStart, newEnd, elem.startTag, elem.endTag); - iterator.add(newElem); - break; - case DEFAULT: - default: - break; - } - } - } - - private List getTagElementsForTextElement(TagElement snippetTag, TextElement textElement) { - List tagElements= new ArrayList<>(); - List regions= snippetTag.tagRegionsStartingAtTextElement(textElement); - List masterList= snippetTag.tagRegionsContainingTextElement(textElement); - masterList.removeAll(regions); - for (JavaDocRegion region : masterList) { - for (Object tagObj : region.tags()) { - tagElements.add((TagElement) tagObj); - } - } - for (JavaDocRegion region : regions) { - for (Object tagObj : region.tags()) { - if (tagObj instanceof TagElement tagElem) { - Object prop= tagElem.getProperty(TagProperty.TAG_PROPERTY_SNIPPET_INLINE_TAG_COUNT); - if (prop instanceof Integer intProp) { - int val = intProp.intValue(); - ListIterator listIterator= tagElements.listIterator(); - TagElement addBefore= null; - while (listIterator.hasNext()) { - TagElement tElem= listIterator.next(); - Object prop2= tElem.getProperty(TagProperty.TAG_PROPERTY_SNIPPET_INLINE_TAG_COUNT); - if (prop2 instanceof Integer intProp2) { - int val2 = intProp2.intValue(); - if (val2 > val) { - addBefore= tElem; - break; - } - } - } - if (addBefore == null) { - tagElements.add(tagElem); - } else { - tagElements.add(tagElements.indexOf(addBefore), tagElem); - } - } - } - } - } - return tagElements; - } - - private List getTagElementsForDummyJavaDocRegion(TagElement snippetTag, JavaDocRegion javaDocRegion) { - List tagElements= new ArrayList<>(); - TextElement textElement= (TextElement) javaDocRegion.fragments().get(0); - List regions= snippetTag.tagRegionsStartingAtTextElement(textElement); - List masterList= snippetTag.tagRegionsContainingTextElement(textElement); - masterList.removeAll(regions); - for (JavaDocRegion region : masterList) { - for (Object tagObj : region.tags()) { - tagElements.add((TagElement) tagObj); - } - } - regions.add(javaDocRegion); - for (JavaDocRegion region : regions) { - for (Object tagObj : region.tags()) { - if (tagObj instanceof TagElement tagElem) { - Object prop= tagElem.getProperty(TagProperty.TAG_PROPERTY_SNIPPET_INLINE_TAG_COUNT); - if (prop instanceof Integer intProp) { - int val = intProp.intValue(); - ListIterator listIterator= tagElements.listIterator(); - TagElement addBefore= null; - while (listIterator.hasNext()) { - TagElement tElem= listIterator.next(); - Object prop2= tElem.getProperty(TagProperty.TAG_PROPERTY_SNIPPET_INLINE_TAG_COUNT); - if (prop2 instanceof Integer intProp2) { - int val2 = intProp2.intValue(); - if (val2 > val) { - addBefore= tElem; - break; - } - } - } - if (addBefore == null) { - tagElements.add(tagElem); - } else { - tagElements.add(tagElements.indexOf(addBefore), tagElem); - } - } - } - } - } - - return tagElements; - } - - private List getTagElementsForTagElement(TagElement snippetTag, TagElement tag) { - List tagElements= new ArrayList<>(); - TextElement textElement= (TextElement) tag.fragments().get(0); - List regions= snippetTag.tagRegionsStartingAtTextElement(textElement); - List masterList= snippetTag.tagRegionsContainingTextElement(textElement); - masterList.removeAll(regions); - for (JavaDocRegion region : masterList) { - for (Object tagObj : region.tags()) { - tagElements.add((TagElement) tagObj); - } - } - for (JavaDocRegion region : regions) { - for (Object tagObj : region.tags()) { - if (tagObj instanceof TagElement tagElem) { - Object prop= tagElem.getProperty(TagProperty.TAG_PROPERTY_SNIPPET_INLINE_TAG_COUNT); - if (prop instanceof Integer intProp) { - int val = intProp.intValue(); - ListIterator listIterator= tagElements.listIterator(); - TagElement addBefore= null; - while (listIterator.hasNext()) { - TagElement tElem= listIterator.next(); - Object prop2= tElem.getProperty(TagProperty.TAG_PROPERTY_SNIPPET_INLINE_TAG_COUNT); - if (prop2 instanceof Integer intProp2) { - int val2 = intProp2.intValue(); - if (val2 > val) { - addBefore= tElem; - break; - } - } - } - if (addBefore == null) { - tagElements.add(tagElem); - } else { - tagElements.add(tagElements.indexOf(addBefore), tagElem); - } - } - } - } - } - Object prop3= tag.getProperty(TagProperty.TAG_PROPERTY_SNIPPET_INLINE_TAG_COUNT); - if (prop3 instanceof Integer intProp3) { - int val = intProp3.intValue(); - ListIterator listIterator= tagElements.listIterator(); - TagElement addBefore= null; - while (listIterator.hasNext()) { - TagElement tElem= listIterator.next(); - Object prop2= tElem.getProperty(TagProperty.TAG_PROPERTY_SNIPPET_INLINE_TAG_COUNT); - if (prop2 instanceof Integer intProp2) { - int val2 = intProp2.intValue(); - if (val2 > val) { - addBefore= tElem; - break; - } - } - } - if (addBefore == null) { - tagElements.add(tag); - } else { - tagElements.add(tagElements.indexOf(addBefore), tag); - } - } - return tagElements; - } - - private void handleSnippetHighlight(String text, TagElement tagElement, List actionElements) { - try { - List tagProperties= tagElement.tagProperties(); - String defHighlight= getHighlightHtmlTag(tagProperties); - String startDefHighlight = defHighlight; // $NON-NLS-1$ - String endDefHighlight = defHighlight; // $NON-NLS-1$ - String regExValue = getPropertyValue("regex", tagProperties); //$NON-NLS-1$ - String subStringValue = getPropertyValue("substring", tagProperties); //$NON-NLS-1$ - Pattern regexPattern = null; - if (regExValue != null) { - regexPattern = Pattern.compile(regExValue); - } - if (regexPattern != null) { - Matcher matcher = regexPattern.matcher(text); - while (matcher.find()) { - actionElements.add(new ActionElement(matcher.start(), matcher.end(), startDefHighlight, endDefHighlight)); - } - } else if (subStringValue != null) { - int startIndex = 0; - while ((startIndex = text.indexOf(subStringValue, startIndex)) != -1) { - actionElements.add(new ActionElement(startIndex, startIndex + subStringValue.length(), startDefHighlight, endDefHighlight)); - startIndex += subStringValue.length(); - } - } else { - actionElements.add(new ActionElement(0, text.length(), startDefHighlight, endDefHighlight)); - } - return; - } catch (PatternSyntaxException e) { - // do nothing - } - return; - } - - private String handleSnippetReplace(String text, TagElement tagElement, List actionElements) { - try { - List tagProperties= tagElement.tagProperties(); - String regExValue = getPropertyValue("regex", tagProperties); //$NON-NLS-1$ - String subStringValue = getPropertyValue("substring", tagProperties); //$NON-NLS-1$ - String substitution = getPropertyValue("replacement", tagProperties); //$NON-NLS-1$ - Pattern regexPattern = null; - if (regExValue != null) { - regexPattern = Pattern.compile(regExValue); - } - String modifiedText = text; - if (regexPattern != null) { - Matcher matcher = regexPattern.matcher(modifiedText); - StringBuilder strBuild= new StringBuilder(); - int finalMatchIndex = 0; - while (matcher.find()) { - finalMatchIndex = matcher.end(); - modifyPrevActionItemsReplacement(matcher.start(), matcher.end(), substitution.length(), actionElements); - matcher.appendReplacement(strBuild, substitution); - } - modifiedText = strBuild.toString() + modifiedText.substring(finalMatchIndex); - } else if (subStringValue != null) { - int startIndex = 0; - while ((startIndex = modifiedText.indexOf(subStringValue, startIndex)) != -1) { - modifyPrevActionItemsReplacement(startIndex, startIndex+ subStringValue.length(), substitution.length(), actionElements); - modifiedText = modifiedText.substring(0, startIndex) + substitution + modifiedText.substring(startIndex + subStringValue.length()); - startIndex += substitution.length() ; - } - } else { - actionElements.clear(); - modifiedText = substitution; - } - return modifiedText; - } catch (PatternSyntaxException e) { - // do nothing - } - return text; - } - - - private void handleSnippetLink(String text, TagElement tagElement, List actionElements) { - try { - List tagProperties= tagElement.tagProperties(); - String regExValue = getPropertyValue("regex", tagProperties); //$NON-NLS-1$ - String subStringValue = getPropertyValue("substring", tagProperties); //$NON-NLS-1$ - String additionalStartTag= getLinkHtmlTag(tagProperties); - String additionalEndTag= ""; //$NON-NLS-1$ - if (additionalStartTag.length() > 0) { - additionalEndTag= "'; //$NON-NLS-1$ - additionalStartTag= '<' + additionalStartTag + '>'; - } - ASTNode target = getPropertyNodeValue("target", tagProperties); //$NON-NLS-1$ - String linkRefTxt = getLinkRef(target); - String startDefLink = linkRefTxt + additionalStartTag; - String endDefLink = additionalEndTag+""; //$NON-NLS-1$ - Pattern regexPattern = null; - if (regExValue != null) { - regexPattern = Pattern.compile(regExValue); - } - String modifiedText = text; - if (regexPattern != null) { - Matcher matcher = regexPattern.matcher(modifiedText); - while (matcher.find()) { - actionElements.add(new ActionElement(matcher.start(), matcher.end(), startDefLink, endDefLink)); - } - } else if (subStringValue != null) { - int startIndex = 0; - while ((startIndex = modifiedText.indexOf(subStringValue, startIndex)) != -1) { - actionElements.add(new ActionElement(startIndex, startIndex+ subStringValue.length(), startDefLink, endDefLink)); - startIndex = startIndex+ subStringValue.length() ; - } - } else { - String subText = modifiedText.trim(); - if (subText.length() < text.length()) { - int startIndex = text.indexOf(subText); - actionElements.add(new ActionElement(startIndex, startIndex + subText.length(), startDefLink, endDefLink)); - } - } - return; - } catch (PatternSyntaxException e) { - // do nothing - } - return; - } - - private String getLinkRef(ASTNode node) { - String str= ""; //$NON-NLS-1$ - String refTypeName= null; - String refMemberName= null; - String[] refMethodParamTypes= null; - String[] refMethodParamNames= null; - int startPosition = -1; - if (node instanceof Name name) { - refTypeName= name.getFullyQualifiedName(); - startPosition = name.getStartPosition(); - } else if (node instanceof MemberRef memberRef) { - Name qualifier= memberRef.getQualifier(); - refTypeName= qualifier == null ? "" : qualifier.getFullyQualifiedName(); //$NON-NLS-1$ - refMemberName= memberRef.getName().getIdentifier(); - startPosition = memberRef.getStartPosition(); - } else if (node instanceof MethodRef methodRef) { - Name qualifier= methodRef.getQualifier(); - refTypeName= qualifier == null ? "" : qualifier.getFullyQualifiedName(); //$NON-NLS-1$ - refMemberName= methodRef.getName().getIdentifier(); - List params= methodRef.parameters(); - int ps= params.size(); - refMethodParamTypes= new String[ps]; - refMethodParamNames= new String[ps]; - for (int i= 0; i < ps; i++) { - MethodRefParameter param= params.get(i); - refMethodParamTypes[i]= ASTNodes.asString(param.getType()); - SimpleName paramName= param.getName(); - if (paramName != null) { - refMethodParamNames[i]= paramName.getIdentifier(); - } - } - startPosition = methodRef.getStartPosition(); - } - - if (refTypeName != null) { - str += ""; //$NON-NLS-1$ - } - return str; - } - - private String getLinkHtmlTag(List tagProperties) { - // String defaultTag= "code"; //$NON-NLS-1$ - String defaultTag = ""; //$NON-NLS-1$ - if (tagProperties != null) { - for (ASTNode node : tagProperties) { - if (node instanceof TagProperty tagProp) { - if ("type".equals(tagProp.getName())) { //$NON-NLS-1$ - String tagValue = tagProp.getStringValue(); - switch (tagValue) { - case "linkplain" : //$NON-NLS-1$ - defaultTag= ""; //$NON-NLS-1$ - break; - default: - break; - } - break; - } - } - } - } - return defaultTag; - } - - private String getPropertyValue(String property, List tagProperties) { - String defaultTag= null; - if (tagProperties != null && property!= null) { - for (ASTNode node : tagProperties) { - if (node instanceof TagProperty tagProp) { - if (property.equals(tagProp.getName())) { - defaultTag= tagProp.getStringValue(); - break; - } - } - } - } - return defaultTag; - } - private ASTNode getPropertyNodeValue(String property, List tagProperties) { - ASTNode defaultTag= null; - if (tagProperties != null && property!= null) { - for (ASTNode node : tagProperties) { - if (node instanceof TagProperty tagProp) { - if (property.equals(tagProp.getName())) { - defaultTag= tagProp.getNodeValue(); - break; - } - } - } - } - return defaultTag; - } - - private String getHighlightHtmlTag(List tagProperties) { - String defaultTag = "**"; //$NON-NLS-1$ - if (tagProperties != null) { - for (ASTNode node : tagProperties) { - if (node instanceof TagProperty tagProp) { - if ("type".equals(tagProp.getName())) { //$NON-NLS-1$ - String tagValue = tagProp.getStringValue(); - switch (tagValue) { - case "bold" : //$NON-NLS-1$ - defaultTag = "**"; //$NON-NLS-1$ - break; - case "italic" : //$NON-NLS-1$ - defaultTag = "*"; //$NON-NLS-1$ - break; - case "highlighted" : //$NON-NLS-1$ - defaultTag = "***"; //$NON-NLS-1$ - break; - default : - defaultTag= ""; //$NON-NLS-1$ - break; - } - break; - } - } - } - } - return defaultTag; - } - -} diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/JavaElementLinks.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/JavaElementLinks.java deleted file mode 100644 index 91658697b7..0000000000 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/JavaElementLinks.java +++ /dev/null @@ -1,491 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2008, 2016 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Code copied from org.eclipse.jdt.internal.ui.viewsupport.JavaElementLinks - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for Bug 403917 - [1.8] Render TYPE_USE annotations in Javadoc hover/view - *******************************************************************************/ -package org.eclipse.jdt.ls.core.internal.javadoc; - -import java.net.URI; -import java.net.URISyntaxException; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.jdt.core.IAnnotation; -import org.eclipse.jdt.core.IField; -import org.eclipse.jdt.core.IJavaElement; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.ILocalVariable; -import org.eclipse.jdt.core.IMember; -import org.eclipse.jdt.core.IMethod; -import org.eclipse.jdt.core.IPackageFragment; -import org.eclipse.jdt.core.IType; -import org.eclipse.jdt.core.ITypeHierarchy; -import org.eclipse.jdt.core.ITypeParameter; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jdt.core.Signature; -import org.eclipse.jdt.internal.corext.util.JavaModelUtil; -import org.eclipse.jdt.internal.corext.util.SuperTypeHierarchyCache; -import org.eclipse.jdt.ls.core.internal.JDTUtils; -import org.eclipse.lsp4j.Location; - -/** - * Links inside Javadoc hovers and Javadoc view. - * - * @since 3.4 - */ -public class JavaElementLinks { - - /** - * A handler is asked to handle links to targets. - * - * @see JavaElementLinks#createLocationListener(JavaElementLinks.ILinkHandler) - */ - public interface ILinkHandler { - - /** - * Handle normal kind of link to given target. - * - * @param target - * the target to show - */ - void handleInlineJavadocLink(IJavaElement target); - - /** - * Handle link to given target to open in javadoc view. - * - * @param target - * the target to show - */ - void handleJavadocViewLink(IJavaElement target); - - /** - * Handle link to given target to open its declaration - * - * @param target - * the target to show - */ - void handleDeclarationLink(IJavaElement target); - - /** - * Informs the handler that the text of the browser was set. - */ - void handleTextSet(); - } - - private static final char LINK_BRACKET_REPLACEMENT = '\u2603'; - - public static final String JAVADOC_SCHEME = "eclipse-javadoc"; //$NON-NLS-1$ - - /** - * The link is composed of a number of segments, separated by LINK_SEPARATOR: - *

    - * segments[0]: ""
    - * segments[1]: baseElementHandle
    - * segments[2]: typeName
    - * segments[3]: memberName
    - * segments[4...]: parameterTypeName (optional) - */ - private static final char LINK_SEPARATOR = '\u2602'; - - private JavaElementLinks() { - // static only - } - - /** - * Creates an {@link URI} with the given scheme for the given element. - * - * @param scheme - * the scheme - * @param element - * the element - * @return an {@link URI}, encoded as {@link URI#toASCIIString() ASCII} string, - * ready to be used as href attribute in an - * <a> tag - * @throws URISyntaxException - * if the arguments were invalid - */ - public static String createURI(String scheme, IJavaElement element) throws URISyntaxException { - return createURI(scheme, element, null, null, null, -1); - } - - /** - * Creates an {@link URI} with the given scheme based on the given element. The - * additional arguments specify a member referenced from the given element. - * - * @param scheme - * a scheme - * @param element - * the declaring element - * @param refTypeName - * a (possibly qualified) type or package name, can be - * null - * @param refMemberName - * a member name, can be null - * @param refParameterTypes - * a (possibly empty) array of (possibly qualified) parameter type - * names, can be null - * @return an {@link URI}, encoded as {@link URI#toASCIIString() ASCII} string, - * ready to be used as href attribute in an - * <a> tag - * @throws URISyntaxException - * if the arguments were invalid - */ - public static String createURI(String scheme, IJavaElement element, String refTypeName, String refMemberName, String[] refParameterTypes, int startPosition) throws URISyntaxException { - /* - * We use an opaque URI, not ssp and fragments (to work around Safari bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=212527 (wrongly encodes #)). - */ - - StringBuffer ssp = new StringBuffer(60); - ssp.append(LINK_SEPARATOR); // make sure first character is not a / (would be hierarchical URI) - - // replace '[' manually, since URI confuses it for an IPv6 address as per RFC 2732: - ssp.append(element.getHandleIdentifier().toString().replace('[', LINK_BRACKET_REPLACEMENT)); // segments[1] - - if (refTypeName != null) { - ssp.append(LINK_SEPARATOR); - ssp.append(refTypeName); // segments[2] - - if (refMemberName != null) { - ssp.append(LINK_SEPARATOR); - ssp.append(refMemberName); // segments[3] - - if (refParameterTypes != null) { - ssp.append(LINK_SEPARATOR); - for (int i = 0; i < refParameterTypes.length; i++) { - ssp.append(refParameterTypes[i]); // segments[4|5|..] - if (i != refParameterTypes.length - 1) { - ssp.append(LINK_SEPARATOR); - } - } - } - } - } - - URI javadocURI = new URI("eclipse-javadoc", ssp.toString(), null); - - IJavaElement linkTarget = parseURI(javadocURI); - if (linkTarget == null) { - return ""; - } - - try { - Location locationToElement = JDTUtils.toLocation(linkTarget); - if (locationToElement != null) { - return locationToElement.getUri() + "#" + (locationToElement.getRange().getStart().getLine() + 1); - } - } catch (JavaModelException e) { - - } - - return ""; - } - - /** - * Creates an {@link URI} with the given scheme based on the given element. The - * additional arguments specify a member referenced from the given element. - * - * @param scheme - * a scheme - * @param element - * the declaring element - * @param refTypeName - * a (possibly qualified) type or package name, can be - * null - * @param refMemberName - * a member name, can be null - * @param refParameterTypes - * a (possibly empty) array of (possibly qualified) parameter type - * names, can be null - * @return an {@link URI}, encoded as {@link URI#toASCIIString() ASCII} string, - * ready to be used as href attribute in an - * <a> tag - * @throws URISyntaxException - * if the arguments were invalid - */ - public static String createURI(String scheme, IJavaElement element, String refTypeName, String refMemberName, String[] refParameterTypes) throws URISyntaxException { - /* - * We use an opaque URI, not ssp and fragments (to work around Safari bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=212527 (wrongly encodes #)). - */ - - StringBuilder ssp = new StringBuilder(60); - ssp.append(LINK_SEPARATOR); // make sure first character is not a / (would be hierarchical URI) - - // replace '[' manually, since URI confuses it for an IPv6 address as per RFC 2732: - ssp.append(element.getHandleIdentifier().replace('[', LINK_BRACKET_REPLACEMENT)); // segments[1] - - if (refTypeName != null) { - ssp.append(LINK_SEPARATOR); - ssp.append(refTypeName); // segments[2] - - if (refMemberName != null) { - ssp.append(LINK_SEPARATOR); - ssp.append(refMemberName); // segments[3] - - if (refParameterTypes != null) { - ssp.append(LINK_SEPARATOR); - for (int i = 0; i < refParameterTypes.length; i++) { - ssp.append(refParameterTypes[i]); // segments[4|5|..] - if (i != refParameterTypes.length - 1) { - ssp.append(LINK_SEPARATOR); - } - } - } - } - } - return new URI(scheme, ssp.toString(), null).toASCIIString(); - } - - public static IJavaElement parseURI(URI uri) { - String ssp = uri.getSchemeSpecificPart(); - String[] segments = ssp.split(String.valueOf(LINK_SEPARATOR), -1); - - // replace '[' manually, since URI confuses it for an IPv6 address as per RFC 2732: - IJavaElement element = JavaCore.create(segments[1].replace(LINK_BRACKET_REPLACEMENT, '[')); - - if (segments.length > 2) { - String refTypeName = segments[2]; - if (refTypeName.indexOf('.') == -1) { - try { - ITypeParameter resolvedTypeVariable = resolveTypeVariable(element, refTypeName); - if (resolvedTypeVariable != null) { - return resolvedTypeVariable; - } - } catch (JavaModelException e) { - //JavaPlugin.log(e); - } - } - if (element instanceof IAnnotation) { - element = element.getParent(); - } - - if (element instanceof ILocalVariable localVariable) { - element = localVariable.getDeclaringMember(); - } else if (element instanceof ITypeParameter typeParameter) { - element = typeParameter.getDeclaringMember(); - } - if (element instanceof IMember member && !(element instanceof IType)) { - element = member.getDeclaringType(); - } - - if (element instanceof IPackageFragment root) { - try { - element = resolvePackageInfoType(root, refTypeName); - if (element == null) { - // find it as package - IJavaProject javaProject = root.getJavaProject(); - return JavaModelUtil.findTypeContainer(javaProject, refTypeName); - } - } catch (JavaModelException e) { - - } - } - - if (element instanceof IType type) { - try { - if (refTypeName.length() > 0) { - type = resolveType(type, refTypeName); - if (type == null) { - IPackageFragment pack = JavaModelUtil.getPackageFragmentRoot(element).getPackageFragment(refTypeName); - if (pack.exists()) { - return pack; - } - } - } - if (type != null) { - element = type; - if (segments.length > 3) { - String refMemberName = segments[3]; - if (segments.length > 4) { - String[] paramSignatures = new String[segments[4].length() == 0 ? 0 : segments.length - 4]; - for (int i = 0; i < paramSignatures.length; i++) { - paramSignatures[i] = Signature.createTypeSignature(segments[i + 4], false); - } - IMethod method = type.getMethod(refMemberName, paramSignatures); - IMethod[] methods = type.findMethods(method); - if (methods != null) { - return methods[0]; - } else { - //TODO: methods whose signature contains type parameters can not be found - // easily, since the Javadoc references are erasures - - //Shortcut: only check name and parameter count: - methods = type.getMethods(); - for (int i = 0; i < methods.length; i++) { - method = methods[i]; - if (method.getElementName().equals(refMemberName) && method.getNumberOfParameters() == paramSignatures.length) { - return method; - } - } - - // reference can also point to method from supertype: - ITypeHierarchy hierarchy = SuperTypeHierarchyCache.getTypeHierarchy(type); - method = JavaModelUtil.findMethodInHierarchy(hierarchy, type, refMemberName, paramSignatures, false); - if (method != null) { - return method; - } - } - } else { - IField field = type.getField(refMemberName); - if (field.exists()) { - return field; - } else { - IMethod[] methods = type.getMethods(); - for (int i = 0; i < methods.length; i++) { - IMethod method = methods[i]; - if (method.getElementName().equals(refMemberName)) { - return method; - } - } - } - } - - } - } else { - // FIXME: either remove or show dialog - // JavaPlugin.logErrorMessage("JavaElementLinks could not resolve " + uri); //$NON-NLS-1$ - } - return type; - } catch (JavaModelException e) { - //JavaPlugin.log(e); - } - } - } - return element; - } - - private static IType resolvePackageInfoType(IPackageFragment pack, String refTypeName) throws JavaModelException { - // Note: The scoping rules of JLS7 6.3 are broken for package-info.java, see https://bugs.eclipse.org/216451#c4 - // We follow the javadoc tool's implementation and only support fully-qualified type references: - IJavaProject javaProject = pack.getJavaProject(); - return javaProject.findType(refTypeName, (IProgressMonitor) null); - - } - - private static ITypeParameter resolveTypeVariable(IJavaElement baseElement, String typeVariableName) throws JavaModelException { - while (baseElement != null) { - switch (baseElement.getElementType()) { - case IJavaElement.METHOD: - IMethod method = (IMethod) baseElement; - ITypeParameter[] typeParameters = method.getTypeParameters(); - for (int i = 0; i < typeParameters.length; i++) { - ITypeParameter typeParameter = typeParameters[i]; - if (typeParameter.getElementName().equals(typeVariableName)) { - return typeParameter; - } - } - break; - - case IJavaElement.TYPE: - IType type = (IType) baseElement; - typeParameters = type.getTypeParameters(); - for (int i = 0; i < typeParameters.length; i++) { - ITypeParameter typeParameter = typeParameters[i]; - if (typeParameter.getElementName().equals(typeVariableName)) { - return typeParameter; - } - } - break; - - case IJavaElement.JAVA_MODEL: - case IJavaElement.JAVA_PROJECT: - case IJavaElement.PACKAGE_FRAGMENT: - case IJavaElement.PACKAGE_FRAGMENT_ROOT: - - case IJavaElement.CLASS_FILE: - case IJavaElement.COMPILATION_UNIT: - - case IJavaElement.PACKAGE_DECLARATION: - case IJavaElement.IMPORT_CONTAINER: - case IJavaElement.IMPORT_DECLARATION: - return null; - - default: - break; - } - // look for type parameters in enclosing members: - baseElement = baseElement.getParent(); - } - return null; - } - - private static IType resolveType(IType baseType, String refTypeName) throws JavaModelException { - if (refTypeName.length() == 0) { - return baseType; - } - - String[][] resolvedNames = baseType.resolveType(refTypeName); - if (resolvedNames != null && resolvedNames.length > 0) { - return baseType.getJavaProject().findType(resolvedNames[0][0], resolvedNames[0][1].replace('$', '.'), (IProgressMonitor) null); - - } else if (baseType.isBinary()) { - // workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=206597 - IType type = baseType.getJavaProject().findType(refTypeName, (IProgressMonitor) null); - if (type == null) { - // could be unqualified reference: - type = baseType.getJavaProject().findType(baseType.getPackageFragment().getElementName() + '.' + refTypeName, (IProgressMonitor) null); - } - return type; - - } else { - return null; - } - } - - /** - * Creates a link with the given URI and label text. - * - * @param uri - * the URI - * @param label - * the label - * @return the HTML link - * @since 3.6 - */ - public static String createLink(String uri, String label) { - return "
    " + label + ""; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - } - - /** - * Creates a header link with the given URI and label text. - * - * @param uri - * the URI - * @param label - * the label - * @return the HTML link - * @since 3.6 - */ - public static String createHeaderLink(String uri, String label) { - return createHeaderLink(uri, label, ""); //$NON-NLS-1$ - } - - /** - * Creates a link with the given URI, label and title text. - * - * @param uri - * the URI - * @param label - * the label - * @param title - * the title to be displayed while hovering over the link (can be - * empty) - * @return the HTML link - * @since 3.10 - */ - public static String createHeaderLink(String uri, String label, String title) { - if (title.length() > 0) { - title = " title='" + title + "'"; //$NON-NLS-1$ //$NON-NLS-2$ - } - return "" + label + ""; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ - } -} \ No newline at end of file diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/JavadocContentAccess.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/JavadocContentAccess.java deleted file mode 100644 index 2e5061d382..0000000000 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/JavadocContentAccess.java +++ /dev/null @@ -1,346 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2008 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.ls.core.internal.javadoc; - -import java.io.IOException; -import java.io.Reader; -import java.io.StringReader; -import java.util.Map; - -import org.eclipse.jdt.core.IBuffer; -import org.eclipse.jdt.core.IJavaElement; -import org.eclipse.jdt.core.IJavaModelStatusConstants; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.IMember; -import org.eclipse.jdt.core.IMethod; -import org.eclipse.jdt.core.IPackageFragment; -import org.eclipse.jdt.core.IPackageFragmentRoot; -import org.eclipse.jdt.core.ISourceRange; -import org.eclipse.jdt.core.IType; -import org.eclipse.jdt.core.ITypeHierarchy; -import org.eclipse.jdt.core.ITypeRoot; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jdt.core.dom.ASTParser; -import org.eclipse.jdt.core.dom.CompilationUnit; -import org.eclipse.jdt.core.dom.Javadoc; -import org.eclipse.jdt.core.dom.PackageDeclaration; -import org.eclipse.jdt.internal.corext.dom.IASTSharedValues; -import org.eclipse.jdt.internal.corext.util.MethodOverrideTester; - -/** - * Helper needed to get the content of a Javadoc comment. - * - *

    - * This class is not intended to be subclassed or instantiated by clients. - *

    - * - * @since 3.1 - * - * @noinstantiate This class is not intended to be instantiated by clients. - * @noextend This class is not intended to be subclassed by clients. - */ -public final class JavadocContentAccess { - /** - * The name of the package-info.java file. - */ - public static final String PACKAGE_INFO_JAVA= "package-info.java"; //$NON-NLS-1$ - - /** - * The name of the package-info.class file. - */ - public static final String PACKAGE_INFO_CLASS= "package-info.class"; //$NON-NLS-1$ - - private JavadocContentAccess() { - // do not instantiate - } - - /** - * Gets a reader for an IMember's Javadoc comment content from the source attachment. - * The content does contain only the text from the comment without the Javadoc leading star characters. - * Returns null if the member does not contain a Javadoc comment or if no source is available. - * @param member The member to get the Javadoc of. - * @return Returns a reader for the Javadoc comment content or null if the member - * does not contain a Javadoc comment or if no source is available - * @throws JavaModelException is thrown when the elements javadoc can not be accessed - * @since 3.4 - */ - private static Reader internalGetContentReader(IMember member) throws JavaModelException { - IBuffer buf= member.getOpenable().getBuffer(); - if (buf == null) { - return null; // no source attachment found - } - - ISourceRange javadocRange= member.getJavadocRange(); - if (javadocRange != null) { - JavaDocCommentReader reader= new JavaDocCommentReader(buf, javadocRange.getOffset(), javadocRange.getOffset() + javadocRange.getLength() - 1); - if (!containsOnlyInheritDoc(reader, javadocRange.getLength())) { - reader.reset(); - return reader; - } - } - - return null; - } - - /** - * Gets a reader for an package fragment's Javadoc comment content from the source attachment. - * The content does contain only the text from the comment without the Javadoc leading star characters. - * Returns null if the package fragment does not contain a Javadoc comment or if no source is available. - * @param fragment The package fragment to get the Javadoc of. - * @return Returns a reader for the Javadoc comment content or null if the member - * does not contain a Javadoc comment or if no source is available - * @throws JavaModelException is thrown when the package fragment's javadoc can not be accessed - * @since 3.4 - */ - private static Reader internalGetContentReader(IPackageFragment fragment) throws JavaModelException { - IPackageFragmentRoot root= (IPackageFragmentRoot) fragment.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT); - - //1==> Handle the case when the documentation is present in package-info.java or package-info.class file - boolean isBinary= root.getKind() == IPackageFragmentRoot.K_BINARY; - ITypeRoot packageInfo; - if (isBinary) { - packageInfo= fragment.getClassFile(PACKAGE_INFO_CLASS); - } else { - packageInfo= fragment.getCompilationUnit(PACKAGE_INFO_JAVA); - } - if (packageInfo != null && packageInfo.exists()) { - String source = packageInfo.getSource(); - //the source can be null for some of the class files - if (source != null) { - Javadoc javadocNode = getPackageJavadocNode(fragment, source); - if (javadocNode != null) { - int start = javadocNode.getStartPosition(); - int length = javadocNode.getLength(); - return new JavaDocCommentReader(source, start, start + length - 1); - } - } - } - return null; - } - - private static Javadoc getPackageJavadocNode(IJavaElement element, String cuSource) { - CompilationUnit cu= createAST(element, cuSource); - if (cu != null) { - PackageDeclaration packDecl= cu.getPackage(); - if (packDecl != null) { - return packDecl.getJavadoc(); - } - } - return null; - } - - private static CompilationUnit createAST(IJavaElement element, String cuSource) { - ASTParser parser = ASTParser.newParser(IASTSharedValues.SHARED_AST_LEVEL); - - IJavaProject javaProject= element.getJavaProject(); - parser.setProject(javaProject); - Map options= javaProject.getOptions(true); - options.put(JavaCore.COMPILER_DOC_COMMENT_SUPPORT, JavaCore.ENABLED); // workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=212207 - parser.setCompilerOptions(options); - - parser.setSource(cuSource.toCharArray()); - return (CompilationUnit) parser.createAST(null); - } - - /** - * Checks whether the given reader only returns - * the inheritDoc tag. - * - * @param reader the reader - * @param length the length of the underlying content - * @return true if the reader only returns the inheritDoc tag - * @since 3.2 - */ - private static boolean containsOnlyInheritDoc(Reader reader, int length) { - char[] content= new char[length]; - try { - reader.read(content, 0, length); - } catch (IOException e) { - return false; - } - return new String(content).trim().equals("{@inheritDoc}"); //$NON-NLS-1$ - - } - - /** - * Gets a reader for an IMember's Javadoc comment content from the source - * attachment. and renders the tags in Markdown. Returns null - * if the member does not contain a Javadoc comment or if no source is - * available. - * - * @param member - * the member to get the Javadoc of. - * @return a reader for the Javadoc comment content in Markdown or - * null if the member does not contain a Javadoc - * comment or if no source is available - * @throws JavaModelException - * is thrown when the elements Javadoc can not be accessed - */ - public static Reader getMarkdownContentReader(IMember member) throws JavaModelException { - Reader contentReader = getHTMLContentReader(member, true, true); - if (contentReader != null) { - try { - return new JavaDoc2MarkdownConverter(contentReader).getAsReader(); - } catch (IOException e) { - throw new JavaModelException(e, IJavaModelStatusConstants.UNKNOWN_JAVADOC_FORMAT); - } - } - return null; - } - - /** - * Gets a reader for an IMember's Javadoc comment content from the source - * attachment. and renders the tags in plain text. Returns null if - * the member does not contain a Javadoc comment or if no source is available. - * - * @param member - * the member to get the Javadoc of. - * @return a reader for the Javadoc comment content in plain text or - * null if the member does not contain a Javadoc comment or - * if no source is available - * @throws JavaModelException - * is thrown when the elements Javadoc can not be accessed - */ - public static Reader getPlainTextContentReader(IMember member) throws JavaModelException { - Reader contentReader = getHTMLContentReader(member, true, true); - if (contentReader != null) { - try { - return new JavaDoc2PlainTextConverter(contentReader).getAsReader(); - } catch (IOException e) { - throw new JavaModelException(e, IJavaModelStatusConstants.UNKNOWN_JAVADOC_FORMAT); - } - } - return null; - } - - /** - * Gets a reader for an IMember's Javadoc comment content from the source - * attachment. and renders the tags in HTML. Returns null if - * the member does not contain a Javadoc comment or if no source is - * available. - * - * @param member - * the member to get the Javadoc of. - * @param allowInherited - * for methods with no (Javadoc) comment, the comment of the - * overridden class is returned if allowInherited is - * true - * @param useAttachedJavadoc - * if true Javadoc will be extracted from attached - * Javadoc if there's no source - * @return a reader for the Javadoc comment content in HTML or - * null if the member does not contain a Javadoc - * comment or if no source is available - * @throws JavaModelException - * is thrown when the elements Javadoc can not be accessed - * @since 3.2 - */ - static Reader getHTMLContentReader(IMember member, boolean allowInherited, boolean useAttachedJavadoc) - throws JavaModelException { - Reader contentReader= internalGetContentReader(member); - if (contentReader != null) { - return contentReader; - } - - if (useAttachedJavadoc && member.getOpenable().getBuffer() == null) { // only if no source available - String s= member.getAttachedJavadoc(null); - if (s != null) { - return new StringReader(s); - } - } - - if (allowInherited && (member.getElementType() == IJavaElement.METHOD)) { - return findDocInHierarchy((IMethod) member, useAttachedJavadoc); - } - - return null; - } - - /** - * Gets a reader for a package fragment's Javadoc comment content from the - * source attachment. and renders the tags in Markdown. Returns - * null if the package fragment does not contain a Javadoc - * comment or if no source is available. - * - * @param fragment - * the package fragment to get the Javadoc of. - * @param useAttachedJavadoc - * if true Javadoc will be extracted from attached - * Javadoc if there's no source - * @return a reader for the Javadoc comment content in Markdown or - * null if the package fragment does not contain a - * Javadoc comment or if no source is available - * @throws JavaModelException - * is thrown when the package fragment's Javadoc can not be - * accessed - */ - public static Reader getMarkdownContentReader(IPackageFragment fragment, boolean useAttachedJavadoc) throws JavaModelException { - Reader contentReader= internalGetContentReader(fragment); - if (contentReader == null && useAttachedJavadoc) { - // only if no source available - // check parent - IPackageFragmentRoot root= (IPackageFragmentRoot) fragment.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT); - - //1==> Handle the case when the documentation is present in package-info.java or package-info.class file - boolean isBinary= root.getKind() == IPackageFragmentRoot.K_BINARY; - if (isBinary) { - String s = null; - try { - s = fragment.getAttachedJavadoc(null); - } catch (JavaModelException e) { - //ignore missing package.html files in javadoc - } - if (s != null) { - contentReader = new StringReader(s); - } - } - } - if (contentReader != null) { - try { - return new JavaDoc2MarkdownConverter(contentReader).getAsReader(); - } catch (IOException e) { - throw new JavaModelException(e, IJavaModelStatusConstants.UNKNOWN_JAVADOC_FORMAT); - } - } - return null; - } - - private static Reader findDocInHierarchy(IMethod method, boolean useAttachedJavadoc) throws JavaModelException { - /* - * Catch ExternalJavaProject in which case - * no hierarchy can be built. - */ - if (!method.getJavaProject().exists()) { - return null; - } - - IType type= method.getDeclaringType(); - ITypeHierarchy hierarchy= type.newSupertypeHierarchy(null); - - MethodOverrideTester tester= new MethodOverrideTester(type, hierarchy); - - IType[] superTypes= hierarchy.getAllSupertypes(type); - for (IType curr : superTypes) { - IMethod overridden= tester.findOverriddenMethodInType(curr, method); - if (overridden != null) { - Reader reader = getHTMLContentReader(overridden, false, useAttachedJavadoc); - if (reader != null) { - return reader; - } - } - } - return null; - } - -} diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/JavadocContentAccess2.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/JavadocContentAccess2.java index 90566cddd5..c87637ff7a 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/JavadocContentAccess2.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/JavadocContentAccess2.java @@ -15,88 +15,34 @@ *******************************************************************************/ package org.eclipse.jdt.ls.core.internal.javadoc; -import java.io.BufferedReader; -import java.io.File; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.io.Reader; +import java.net.URI; import java.net.URISyntaxException; -import java.net.URL; -import java.text.MessageFormat; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; import java.util.List; -import java.util.Map; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; -import org.eclipse.core.filebuffers.FileBuffers; -import org.eclipse.core.filebuffers.ITextFileBuffer; -import org.eclipse.core.filebuffers.ITextFileBufferManager; -import org.eclipse.core.filebuffers.LocationKind; -import org.eclipse.core.resources.IContainer; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IWorkspaceRoot; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.core.runtime.Path; -import org.eclipse.jdt.core.IBuffer; -import org.eclipse.jdt.core.IClasspathAttribute; -import org.eclipse.jdt.core.IClasspathEntry; -import org.eclipse.jdt.core.IField; -import org.eclipse.jdt.core.IJarEntryResource; import org.eclipse.jdt.core.IJavaElement; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.ILocalVariable; +import org.eclipse.jdt.core.IJavaModelStatusConstants; import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.IMethod; -import org.eclipse.jdt.core.IOrdinaryClassFile; -import org.eclipse.jdt.core.IPackageDeclaration; import org.eclipse.jdt.core.IPackageFragment; -import org.eclipse.jdt.core.IPackageFragmentRoot; -import org.eclipse.jdt.core.ISourceRange; -import org.eclipse.jdt.core.IType; -import org.eclipse.jdt.core.ITypeHierarchy; -import org.eclipse.jdt.core.ITypeParameter; -import org.eclipse.jdt.core.ITypeRoot; -import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jdt.core.Signature; -import org.eclipse.jdt.core.SourceRange; import org.eclipse.jdt.core.dom.ASTNode; -import org.eclipse.jdt.core.dom.ASTParser; -import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; -import org.eclipse.jdt.core.dom.CompilationUnit; -import org.eclipse.jdt.core.dom.IBinding; -import org.eclipse.jdt.core.dom.IVariableBinding; import org.eclipse.jdt.core.dom.Javadoc; -import org.eclipse.jdt.core.dom.MemberRef; -import org.eclipse.jdt.core.dom.MethodRef; -import org.eclipse.jdt.core.dom.MethodRefParameter; -import org.eclipse.jdt.core.dom.Name; -import org.eclipse.jdt.core.dom.NodeFinder; -import org.eclipse.jdt.core.dom.PackageDeclaration; -import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.TagElement; -import org.eclipse.jdt.core.dom.TagProperty; import org.eclipse.jdt.core.dom.TextElement; -import org.eclipse.jdt.core.manipulation.CoreASTProvider; -import org.eclipse.jdt.internal.corext.dom.ASTNodes; -import org.eclipse.jdt.internal.corext.dom.IASTSharedValues; -import org.eclipse.jdt.internal.corext.util.JavaModelUtil; -import org.eclipse.jdt.internal.corext.util.JdtFlags; -import org.eclipse.jdt.internal.corext.util.MethodOverrideTester; -import org.eclipse.jdt.internal.corext.util.SuperTypeHierarchyCache; +import org.eclipse.jdt.core.manipulation.internal.javadoc.CoreJavaDocSnippetStringEvaluator; +import org.eclipse.jdt.core.manipulation.internal.javadoc.CoreJavadocAccess; +import org.eclipse.jdt.core.manipulation.internal.javadoc.CoreJavadocAccessImpl; +import org.eclipse.jdt.core.manipulation.internal.javadoc.CoreJavadocContentAccessUtility; +import org.eclipse.jdt.core.manipulation.internal.javadoc.IJavadocContentFactory; +import org.eclipse.jdt.core.manipulation.internal.javadoc.JavadocLookup; +import org.eclipse.jdt.internal.ui.viewsupport.CoreJavaElementLinks; +import org.eclipse.jdt.ls.core.internal.JDTUtils; import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; -import org.eclipse.jdt.internal.core.manipulation.JavaElementLabelsCore; +import org.eclipse.lsp4j.Location; /** * Helper to get the content of a Javadoc comment as HTML. @@ -109,2489 +55,272 @@ * @since 3.4 */ public class JavadocContentAccess2 { + public static final String SNIPPET = "SNIPPET"; - private static final String UL_CLASS_BLOCK_LIST = "
      "; - - private static final String BASE_URL_COMMENT_INTRO = " " + attachedJavadoc; //$NON-NLS-1$ - } - return attachedJavadoc; - } - } - return CONTINUE; + protected String markSnippet(String text, boolean isInSnippet) { + if (isInSnippet) { + StringBuilder builder = new StringBuilder(); + text.lines().forEach((l) -> { + builder.append(SNIPPET); + builder.append(l); + builder.append("\n"); //$NON-NLS-1$ + }); + return builder.toString(); } - }.visitInheritDoc(type, hierarchy); - } - - private String toHTML() { - fBuf = new StringBuffer(); - fLiteralContent = 0; - - if (fElement instanceof ILocalVariable || fElement instanceof ITypeParameter) { - parameterToHTML(); - } else { - elementToHTML(); + return text; } - String result = fBuf.toString(); - fBuf = null; - return result; - } - - private void parameterToHTML() { - String elementName = fElement.getElementName(); - List tags = fJavadoc.tags(); - for (Iterator iter = tags.iterator(); iter.hasNext();) { - TagElement tag = iter.next(); - String tagName = tag.getTagName(); - if (TagElement.TAG_PARAM.equals(tagName)) { - List fragments = tag.fragments(); - int size = fragments.size(); - if (size > 0) { - Object first = fragments.get(0); - if (first instanceof SimpleName simpleName) { - String name = simpleName.getIdentifier(); - if (elementName.equals(name)) { - handleContentElements(fragments.subList(1, size)); - return; - } - } else if (size > 2 && fElement instanceof ITypeParameter && first instanceof TextElement textElement) { - String firstText = textElement.getText(); - if ("<".equals(firstText)) { //$NON-NLS-1$ - Object second = fragments.get(1); - Object third = fragments.get(2); - if (second instanceof SimpleName secondName && third instanceof TextElement thirdTextElement) { - String name = secondName.getIdentifier(); - String thirdText = thirdTextElement.getText(); - if (elementName.equals(name) && ">".equals(thirdText)) { //$NON-NLS-1$ - handleContentElements(fragments.subList(3, size)); - return; - } - } - } - } - } - } - } - if (fElement instanceof ILocalVariable) { - List parameterNames = initParameterNames(); - int i = parameterNames.indexOf(elementName); - if (i != -1) { - CharSequence inheritedParamDescription = fJavadocLookup.getInheritedParamDescription(fMethod, i); - handleInherited(inheritedParamDescription); + @Override + protected String createLinkURI(String scheme, IJavaElement element, String refTypeName, String refMemberName, String[] refParameterTypes) throws URISyntaxException { + URI javadocURI = CoreJavaElementLinks.createURIAsUri(scheme, fElement, refTypeName, refMemberName, refParameterTypes); + IJavaElement linkTarget = CoreJavaElementLinks.parseURI(javadocURI); + if (linkTarget == null) { + return ""; } - } else if (fElement instanceof ITypeParameter) { - List typeParameterNames = initTypeParameterNames(); - int i = typeParameterNames.indexOf(elementName); - if (i != -1) { - CharSequence inheritedTypeParamDescription = fJavadocLookup.getInheritedTypeParamDescription(fMethod, i); - handleInherited(inheritedTypeParamDescription); + try { + Location locationToElement = JDTUtils.toLocation(linkTarget); + if (locationToElement != null) { + return locationToElement.getUri() + "#" + (locationToElement.getRange().getStart().getLine() + 1); + } + } catch (JavaModelException e) { } + return ""; } } - - private void elementToHTML() { - // After first loop, non-null entries in the following two lists are missing and need to be inherited: - List typeParameterNames = initTypeParameterNames(); - List parameterNames = initParameterNames(); - List exceptionNames = initExceptionNames(); - - TagElement deprecatedTag = null; - TagElement start = null; - List typeParameters = new ArrayList<>(); - List parameters = new ArrayList<>(); - TagElement returnTag = null; - List exceptions = new ArrayList<>(); - List versions = new ArrayList<>(); - List authors = new ArrayList<>(); - List sees = new ArrayList<>(); - List since = new ArrayList<>(); - List rest = new ArrayList<>(); - List apinote = new ArrayList<>(1); - - List tags = fJavadoc.tags(); - for (Iterator iter = tags.iterator(); iter.hasNext();) { - TagElement tag = iter.next(); - String tagName = tag.getTagName(); - if (tagName == null) { - start = tag; - - } else if (TagElement.TAG_PARAM.equals(tagName)) { - List fragments = tag.fragments(); - int size = fragments.size(); - if (size > 0) { - Object first = fragments.get(0); - if (first instanceof SimpleName simpleName) { - String name = simpleName.getIdentifier(); - int paramIndex = parameterNames.indexOf(name); - if (paramIndex != -1) { - parameterNames.set(paramIndex, null); - } - parameters.add(tag); - } else if (size > 2 && first instanceof TextElement firstTextElement) { - String firstText = firstTextElement.getText(); - if ("<".equals(firstText)) { //$NON-NLS-1$ - Object second = fragments.get(1); - Object third = fragments.get(2); - if (second instanceof SimpleName secondSimpleName && third instanceof TextElement thirdTextElement) { - String name = secondSimpleName.getIdentifier(); - String thirdText = thirdTextElement.getText(); - if (">".equals(thirdText)) { //$NON-NLS-1$ - int paramIndex = typeParameterNames.indexOf(name); - if (paramIndex != -1) { - typeParameterNames.set(paramIndex, null); - } - typeParameters.add(tag); - } - } - } - } - } - - } else if (TagElement.TAG_RETURN.equals(tagName)) { - if (returnTag == null) { - returnTag = tag; // the Javadoc tool only shows the first return tag - } - - } else if (TagElement.TAG_EXCEPTION.equals(tagName) || TagElement.TAG_THROWS.equals(tagName)) { - exceptions.add(tag); - List fragments = tag.fragments(); - if (fragments.size() > 0) { - Object first = fragments.get(0); - if (first instanceof Name firstName) { - String name = ASTNodes.getSimpleNameIdentifier(firstName); - int exceptionIndex = exceptionNames.indexOf(name); - if (exceptionIndex != -1) { - exceptionNames.set(exceptionIndex, null); - } - } - } - - } else if (TagElement.TAG_SINCE.equals(tagName)) { - since.add(tag); - } else if (TagElement.TAG_VERSION.equals(tagName)) { - versions.add(tag); - } else if (TagElement.TAG_AUTHOR.equals(tagName)) { - authors.add(tag); - } else if (TagElement.TAG_SEE.equals(tagName)) { - sees.add(tag); - } else if (TagElement.TAG_DEPRECATED.equals(tagName)) { - if (deprecatedTag == null) { - deprecatedTag = tag; // the Javadoc tool only shows the first deprecated tag - } - } else if (TagElement.TAG_API_NOTE.equals(tagName)) { - apinote.add(tag); - } else { - rest.add(tag); - } - } - - //TODO: @Documented annotations before header - if (deprecatedTag != null) { - handleDeprecatedTag(deprecatedTag); - } - if (start != null) { - handleContentElements(start.fragments()); - } else if (fMethod != null) { - CharSequence inherited = fJavadocLookup.getInheritedMainDescription(fMethod); - // The Javadoc tool adds "Description copied from class: ..." (only for the main description). - // We don't bother doing that. - handleInherited(inherited); - } - - CharSequence[] typeParameterDescriptions = new CharSequence[typeParameterNames.size()]; - boolean hasInheritedTypeParameters = inheritTypeParameterDescriptions(typeParameterNames, typeParameterDescriptions); - boolean hasTypeParameters = typeParameters.size() > 0 || hasInheritedTypeParameters; - - CharSequence[] parameterDescriptions = new CharSequence[parameterNames.size()]; - boolean hasInheritedParameters = inheritParameterDescriptions(parameterNames, parameterDescriptions); - boolean hasParameters = parameters.size() > 0 || hasInheritedParameters; - - CharSequence returnDescription = null; - if (returnTag == null && needsReturnTag()) { - returnDescription = fJavadocLookup.getInheritedReturnDescription(fMethod); - } - boolean hasReturnTag = returnTag != null || returnDescription != null; - - CharSequence[] exceptionDescriptions = new CharSequence[exceptionNames.size()]; - boolean hasInheritedExceptions = inheritExceptionDescriptions(exceptionNames, exceptionDescriptions); - boolean hasExceptions = exceptions.size() > 0 || hasInheritedExceptions; - - if (hasParameters || hasTypeParameters || hasReturnTag || hasExceptions || versions.size() > 0 || authors.size() > 0 || since.size() > 0 || sees.size() > 0 || rest.size() > 0 || apinote.size() > 0 - || (fBuf.length() > 0 && (parameterDescriptions.length > 0 || exceptionDescriptions.length > 0))) { - handleSuperMethodReferences(); - fBuf.append(BLOCK_TAG_START); - handleParameterTags(typeParameters, typeParameterNames, typeParameterDescriptions, true); - handleParameterTags(parameters, parameterNames, parameterDescriptions, false); - handleReturnTag(returnTag, returnDescription); - handleExceptionTags(exceptions, exceptionNames, exceptionDescriptions); - handleBlockTags(JavaDoc2HTMLTextReader_since_section, since); - handleBlockTags(JavaDoc2HTMLTextReader_version_section, versions); - handleBlockTags(JavaDoc2HTMLTextReader_author_section, authors); - handleBlockTags(JavaDoc2HTMLTextReader_see_section, sees); - handleBlockTags(JavaDoc2HTMLTextReader_api_note, apinote); - handleBlockTags(rest); - fBuf.append(BLOCK_TAG_END); - - } else if (fBuf.length() > 0) { - handleSuperMethodReferences(); - } - } - - private void handleDeprecatedTag(TagElement tag) { - fBuf.append("

      "); //$NON-NLS-1$ - fBuf.append(JavaDoc2HTMLTextReader_deprecated_section); - fBuf.append(" "); //$NON-NLS-1$ - handleContentElements(tag.fragments()); - fBuf.append("

      "); //$NON-NLS-1$ TODO: Why not

      ? See https://bugs.eclipse.org/bugs/show_bug.cgi?id=243318 . - } - - private void handleSuperMethodReferences() { - if (fMethod != null) { - try { - StringBuffer superMethodReferences = createSuperMethodReferences(fMethod); - if (superMethodReferences != null) { - fBuf.append(superMethodReferences); - } - } catch (JavaModelException e) { - - } - } - } - - private List initTypeParameterNames() { - if (fMethod != null) { - try { - ArrayList typeParameterNames = new ArrayList<>(); - for (ITypeParameter typeParameter : fMethod.getTypeParameters()) { - typeParameterNames.add(typeParameter.getElementName()); - } - return typeParameterNames; - } catch (JavaModelException e) { - - } - } - return Collections.emptyList(); - } - - private List initParameterNames() { - if (fMethod != null) { - try { - return new ArrayList<>(Arrays.asList(fMethod.getParameterNames())); - } catch (JavaModelException e) { - - } - } - return Collections.emptyList(); - } - - private List initExceptionNames() { - if (fMethod != null) { - try { - String[] exceptionTypes = fMethod.getExceptionTypes(); - ArrayList exceptionNames = new ArrayList<>(); - for (int i = 0; i < exceptionTypes.length; i++) { - exceptionNames.add(Signature.getSimpleName(Signature.toString(exceptionTypes[i]))); - } - return exceptionNames; - } catch (JavaModelException e) { - - } - } - return Collections.emptyList(); - } - - private boolean needsReturnTag() { - if (fMethod == null) { - return false; - } - try { - return !Signature.SIG_VOID.equals(fMethod.getReturnType()); - } catch (JavaModelException e) { - return false; - } - } - - private boolean inheritTypeParameterDescriptions(List typeParameterNames, CharSequence[] typeParameterDescriptions) { - boolean hasInheritedTypeParameters = false; - for (int i = 0; i < typeParameterNames.size(); i++) { - String name = typeParameterNames.get(i); - if (name != null) { - typeParameterDescriptions[i] = fJavadocLookup.getInheritedTypeParamDescription(fMethod, i); - if (typeParameterDescriptions[i] != null) { - hasInheritedTypeParameters = true; - } - } - } - return hasInheritedTypeParameters; - } - - private boolean inheritParameterDescriptions(List parameterNames, CharSequence[] parameterDescriptions) { - boolean hasInheritedParameters = false; - for (int i = 0; i < parameterNames.size(); i++) { - String name = parameterNames.get(i); - if (name != null) { - parameterDescriptions[i] = fJavadocLookup.getInheritedParamDescription(fMethod, i); - if (parameterDescriptions[i] != null) { - hasInheritedParameters = true; - } - } - } - return hasInheritedParameters; - } - - private boolean inheritExceptionDescriptions(List exceptionNames, CharSequence[] exceptionDescriptions) { - boolean hasInheritedExceptions = false; - for (int i = 0; i < exceptionNames.size(); i++) { - String name = exceptionNames.get(i); - if (name != null) { - exceptionDescriptions[i] = fJavadocLookup.getInheritedExceptionDescription(fMethod, name); - if (exceptionDescriptions[i] != null) { - hasInheritedExceptions = true; - } - } - } - return hasInheritedExceptions; - } - - CharSequence getMainDescription() { - if (fMainDescription == null) { - fMainDescription = new StringBuffer(); - fBuf = fMainDescription; - fLiteralContent = 0; - - List tags = fJavadoc.tags(); - for (Iterator iter = tags.iterator(); iter.hasNext();) { - TagElement tag = iter.next(); - String tagName = tag.getTagName(); - if (tagName == null) { - handleContentElements(tag.fragments()); - break; - } - } - - fBuf = null; - } - return fMainDescription.length() > 0 ? fMainDescription : null; - } - - CharSequence getReturnDescription() { - if (fReturnDescription == null) { - fReturnDescription = new StringBuffer(); - fBuf = fReturnDescription; - fLiteralContent = 0; - - List tags = fJavadoc.tags(); - for (Iterator iter = tags.iterator(); iter.hasNext();) { - TagElement tag = iter.next(); - String tagName = tag.getTagName(); - if (TagElement.TAG_RETURN.equals(tagName)) { - handleContentElements(tag.fragments()); - break; - } - } - - fBuf = null; - } - return fReturnDescription.length() > 0 ? fReturnDescription : null; - } - - CharSequence getInheritedTypeParamDescription(int typeParamIndex) { - if (fMethod != null) { - List typeParameterNames = initTypeParameterNames(); - if (fTypeParamDescriptions == null) { - fTypeParamDescriptions = new StringBuffer[typeParameterNames.size()]; - } else { - StringBuffer description = fTypeParamDescriptions[typeParamIndex]; - if (description != null) { - return description.length() > 0 ? description : null; - } - } - - StringBuffer description = new StringBuffer(); - fTypeParamDescriptions[typeParamIndex] = description; - fBuf = description; - fLiteralContent = 0; - - String typeParamName = typeParameterNames.get(typeParamIndex); - List tags = fJavadoc.tags(); - for (Iterator iter = tags.iterator(); iter.hasNext();) { - TagElement tag = iter.next(); - String tagName = tag.getTagName(); - if (TagElement.TAG_PARAM.equals(tagName)) { - List fragments = tag.fragments(); - if (fragments.size() > 2) { - Object first = fragments.get(0); - Object second = fragments.get(1); - Object third = fragments.get(2); - if (first instanceof TextElement firstTextElement && second instanceof SimpleName secondSimpleName && third instanceof TextElement thirdTextElement) { - String firstText = firstTextElement.getText(); - String thirdText = thirdTextElement.getText(); - if ("<".equals(firstText) && ">".equals(thirdText)) { //$NON-NLS-1$ //$NON-NLS-2$ - String name = secondSimpleName.getIdentifier(); - if (name.equals(typeParamName)) { - handleContentElements(fragments.subList(3, fragments.size())); - break; - } - } - } - } - } - } - - fBuf = null; - return description.length() > 0 ? description : null; - } - return null; - } - - CharSequence getInheritedParamDescription(int paramIndex) throws JavaModelException { - if (fMethod != null) { - String[] parameterNames = fMethod.getParameterNames(); - if (fParamDescriptions == null) { - fParamDescriptions = new StringBuffer[parameterNames.length]; - } else { - StringBuffer description = fParamDescriptions[paramIndex]; - if (description != null) { - return description.length() > 0 ? description : null; - } - } - - StringBuffer description = new StringBuffer(); - fParamDescriptions[paramIndex] = description; - fBuf = description; - fLiteralContent = 0; - - String paramName = parameterNames[paramIndex]; - List tags = fJavadoc.tags(); - for (Iterator iter = tags.iterator(); iter.hasNext();) { - TagElement tag = iter.next(); - String tagName = tag.getTagName(); - if (TagElement.TAG_PARAM.equals(tagName)) { - List fragments = tag.fragments(); - if (fragments.size() > 0) { - Object first = fragments.get(0); - if (first instanceof SimpleName simpleName) { - String name = simpleName.getIdentifier(); - if (name.equals(paramName)) { - handleContentElements(fragments.subList(1, fragments.size())); - break; - } - } - } - } - } - - fBuf = null; - return description.length() > 0 ? description : null; - } - return null; - } - - CharSequence getExceptionDescription(String simpleName) { - if (fMethod != null) { - if (fExceptionDescriptions == null) { - fExceptionDescriptions = new HashMap<>(); - } else { - StringBuffer description = fExceptionDescriptions.get(simpleName); - if (description != null) { - return description.length() > 0 ? description : null; - } - } - - StringBuffer description = new StringBuffer(); - fExceptionDescriptions.put(simpleName, description); - fBuf = description; - fLiteralContent = 0; - - List tags = fJavadoc.tags(); - for (Iterator iter = tags.iterator(); iter.hasNext();) { - TagElement tag = iter.next(); - String tagName = tag.getTagName(); - if (TagElement.TAG_THROWS.equals(tagName) || TagElement.TAG_EXCEPTION.equals(tagName)) { - List fragments = tag.fragments(); - if (fragments.size() > 0) { - Object first = fragments.get(0); - if (first instanceof Name firstName) { - String name = ASTNodes.getSimpleNameIdentifier(firstName); - if (name.equals(simpleName)) { - if (fragments.size() > 1) { - handleContentElements(fragments.subList(1, fragments.size())); - } - break; - } - } - } - } - } - - fBuf = null; - return description.length() > 0 ? description : null; - } - return null; - } - - private void handleContentElements(List nodes) { - handleContentElements(nodes, false); - } - - private void handleContentElements(List nodes, boolean skipLeadingWhitespace) { - ASTNode previousNode = null; - for (Iterator iter = nodes.iterator(); iter.hasNext();) { - ASTNode child = iter.next(); - boolean isInSnippet = previousNode instanceof TagElement previousTag && TagElement.TAG_SNIPPET.equals(previousTag.getTagName()); - if (previousNode != null) { - int previousEnd = previousNode.getStartPosition() + previousNode.getLength(); - int childStart = child.getStartPosition(); - if (previousEnd > childStart) { - // should never happen, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=304826 - Exception exception = new Exception("Illegal ASTNode positions: previousEnd=" + previousEnd //$NON-NLS-1$ - + ", childStart=" + childStart //$NON-NLS-1$ - + ", element=" + fElement.getHandleIdentifier() //$NON-NLS-1$ - + ", Javadoc:\n" + fSource); //$NON-NLS-1$ - } else if (previousEnd != childStart) { - // Need to preserve whitespace before a node that's not - // directly following the previous node (e.g. on a new line) - // due to https://bugs.eclipse.org/bugs/show_bug.cgi?id=206518 : - String textWithStars = fSource.substring(previousEnd, childStart); - String text = removeDocLineIntros(textWithStars); - fBuf.append(text); - } - } - - previousNode = child; - if (child instanceof TextElement textElement) { - String text = textElement.getText(); - if (JavaDocHTMLPathHandler.containsHTMLTag(text)) { - text = JavaDocHTMLPathHandler.getValidatedHTMLSrcAttribute(textElement, fElement); - } - - if (skipLeadingWhitespace) { - text = text.stripLeading(); - } - // workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=233481 : - text = text.replaceAll("(\r\n?|\n)([ \t]*\\*)", "$1"); //$NON-NLS-1$ //$NON-NLS-2$ - handleText(markSnippet(text, isInSnippet)); - } else if (child instanceof TagElement tagElement) { - handleInlineTagElement(tagElement); - } else { - // This is unexpected. Fail gracefully by just copying the source. - int start = child.getStartPosition(); - String text = fSource.substring(start, start + child.getLength()); - fBuf.append(removeDocLineIntros(text)); - } - } - } - - private String markSnippet(String text, boolean isInSnippet) { - if (isInSnippet) { - StringBuilder builder = new StringBuilder(); - text.lines().forEach((l) -> { - builder.append(JavaDocSnippetStringEvaluator.SNIPPET); - builder.append(l); - builder.append("\n"); - }); - return builder.toString(); - } - return text; - } - - private String removeDocLineIntros(String textWithStars) { - String lineBreakGroup = "(\\r\\n?|\\n)"; //$NON-NLS-1$ - String noBreakSpace = "[^\r\n&&\\s]"; //$NON-NLS-1$ - return textWithStars.replaceAll(lineBreakGroup + noBreakSpace + "*\\*" /*+ noBreakSpace + '?'*/, "$1"); //$NON-NLS-1$ //$NON-NLS-2$ - } - - private void handleText(String text) { - if (fLiteralContent == 0) { - fBuf.append(text); - } else { - appendEscaped(fBuf, text); - } - } - - private static void appendEscaped(StringBuffer buf, String text) { - int nextToCopy = 0; - int length = text.length(); - for (int i = 0; i < length; i++) { - char ch = text.charAt(i); - String rep = null; - switch (ch) { - case '&': - rep = "&"; //$NON-NLS-1$ - break; - case '"': - rep = """; //$NON-NLS-1$ - break; - case '<': - rep = "<"; //$NON-NLS-1$ - break; - case '>': - rep = ">"; //$NON-NLS-1$ - break; - } - if (rep != null) { - if (nextToCopy < i) { - buf.append(text.substring(nextToCopy, i)); - } - buf.append(rep); - nextToCopy = i + 1; - } - } - if (nextToCopy < length) { - buf.append(text.substring(nextToCopy)); - } - } - - @SuppressWarnings("unchecked") - private void handleInlineTagElement(TagElement node) { - String name = node.getTagName(); - - if (TagElement.TAG_VALUE.equals(name) && handleValueTag(node)) { - return; - } - - boolean isLink = TagElement.TAG_LINK.equals(name); - boolean isLinkplain = TagElement.TAG_LINKPLAIN.equals(name); - boolean isCode = TagElement.TAG_CODE.equals(name); - boolean isLiteral = TagElement.TAG_LITERAL.equals(name); - boolean isSummary = TagElement.TAG_SUMMARY.equals(name); - boolean isIndex = TagElement.TAG_INDEX.equals(name); - boolean isSnippet = TagElement.TAG_SNIPPET.equals(name); - - if (isLiteral || isCode || isSummary || isIndex) { - fLiteralContent++; - } - if (isCode) { - fBuf.append(""); //$NON-NLS-1$ - } - - if (isLink || isLinkplain) { - handleLink(node.fragments()); - } else if (isSummary) { - handleSummary(node.fragments()); - } else if (isIndex) { - handleIndex(node.fragments()); - } else if (isCode || isLiteral) { - handleContentElements(node.fragments(), true); - } else if (isSnippet) { - handleSnippet(node); - } - else if (handleInheritDoc(node) || handleDocRoot(node)) { - // Handled - } else { - //print uninterpreted source {@tagname ...} for unknown tags - int start= node.getStartPosition(); - String text= fSource.substring(start, start + node.getLength()); - fBuf.append(removeDocLineIntros(text)); - } - - if (isCode) { - fBuf.append(""); //$NON-NLS-1$ - } - if (isSnippet) - { - fBuf.append(""); //$NON-NLS-1$ - } - if (isLiteral || isCode) { - fLiteralContent--; - } - - } - - private boolean handleValueTag(TagElement node) { - - List fragments = node.fragments(); - try { - if (!(fElement instanceof IMember)) { - return false; - } - if (fragments.isEmpty()) { - if (fElement instanceof IField field && JdtFlags.isStatic((IField) fElement) && JdtFlags.isFinal((IField) fElement)) { - return handleConstantValue(field, false); - } - } else if (fragments.size() == 1) { - Object first = fragments.get(0); - if (first instanceof MemberRef memberRef) { - if (memberRef.getQualifier() == null) { - SimpleName name = memberRef.getName(); - IType type = fElement instanceof IType typeElement ? typeElement : ((IMember) fElement).getDeclaringType(); - while (type != null) { - IField field = type.getField(name.getIdentifier()); - if (field != null && field.exists()) { - if (JdtFlags.isStatic(field) && JdtFlags.isFinal(field)) { - return handleConstantValue(field, true); - } - break; - } - type = type.getDeclaringType(); - } - } - } - } - } catch (JavaModelException e) { - - } - - return false; - } - - private boolean handleConstantValue(IField field, boolean link) throws JavaModelException { - String text = null; - - ISourceRange nameRange = field.getNameRange(); - if (SourceRange.isAvailable(nameRange)) { - CompilationUnit cuNode = CoreASTProvider.getInstance().getAST(field.getTypeRoot(), CoreASTProvider.WAIT_YES, new NullProgressMonitor()); - if (cuNode != null) { - ASTNode nameNode = NodeFinder.perform(cuNode, nameRange); - if (nameNode instanceof SimpleName simpleName) { - IBinding binding = simpleName.resolveBinding(); - if (binding instanceof IVariableBinding variableBinding) { - Object constantValue = variableBinding.getConstantValue(); - if (constantValue != null) { - if (constantValue instanceof String s) { - text = ASTNodes.getEscapedStringLiteral(s); - } else { - text = constantValue.toString(); // Javadoc tool is even worse for chars... - } - } - } - } - } - } - - if (text == null) { - Object constant = field.getConstant(); - if (constant != null) { - text = constant.toString(); - } - } - - if (text != null) { - text = convertToHTMLContentWithWhitespace(text); - if (link) { - String uri; - try { - uri = JavaElementLinks.createURI("eclipse-javadoc", field); - fBuf.append(JavaElementLinks.createLink(uri, text)); - } catch (URISyntaxException e) { - return false; - } - } else { - handleText(text); - } - return true; - } - return false; - } - - private boolean handleDocRoot(TagElement node) { - if (!TagElement.TAG_DOCROOT.equals(node.getTagName())) { - return false; - } - - try { - String url = null; - if (fElement instanceof IMember member && member.isBinary()) { - URL javadocBaseLocation = JavaDocLocations.getJavadocBaseLocation(fElement); - if (javadocBaseLocation != null) { - url = javadocBaseLocation.toExternalForm(); - } - } else { - IPackageFragmentRoot srcRoot = JavaModelUtil.getPackageFragmentRoot(fElement); - if (srcRoot != null) { - IResource resource = srcRoot.getResource(); - if (resource != null) { - /* - * Too bad: Browser widget knows nothing about EFS and custom URL handlers, - * so IResource#getLocationURI() does not work in all cases. - * We only support the local file system for now. - * A solution could be https://bugs.eclipse.org/bugs/show_bug.cgi?id=149022 . - */ - IPath location = resource.getLocation(); - if (location != null) { - url = location.toFile().toURI().toASCIIString(); - } - } - - } - } - if (url != null) { - if (url.endsWith("/")) { //$NON-NLS-1$ - url = url.substring(0, url.length() - 1); - } - fBuf.append(url); - return true; - } - } catch (JavaModelException e) { - } - return false; - } - - /** - * Handle {@inheritDoc}. - * - * @param node - * the node - * @return true iff the node was an {@inheritDoc} node and has - * been handled - */ - private boolean handleInheritDoc(TagElement node) { - if (!TagElement.TAG_INHERITDOC.equals(node.getTagName())) { - return false; - } - try { - if (fMethod == null) { - return false; - } - - TagElement blockTag = (TagElement) node.getParent(); - String blockTagName = blockTag.getTagName(); - - if (blockTagName == null) { - CharSequence inherited = fJavadocLookup.getInheritedMainDescription(fMethod); - return handleInherited(inherited); - - } else if (TagElement.TAG_PARAM.equals(blockTagName)) { - List fragments = blockTag.fragments(); - int size = fragments.size(); - if (size > 0) { - Object first = fragments.get(0); - if (first instanceof SimpleName simpleName) { - String name = simpleName.getIdentifier(); - String[] parameterNames = fMethod.getParameterNames(); - for (int i = 0; i < parameterNames.length; i++) { - if (name.equals(parameterNames[i])) { - CharSequence inherited = fJavadocLookup.getInheritedParamDescription(fMethod, i); - return handleInherited(inherited); - } - } - } else if (size > 2 && first instanceof TextElement firstTextElement) { - String firstText = firstTextElement.getText(); - if ("<".equals(firstText)) { //$NON-NLS-1$ - Object second = fragments.get(1); - Object third = fragments.get(2); - if (second instanceof SimpleName secondSimpleName && third instanceof TextElement thirdTextElement) { - String thirdText = thirdTextElement.getText(); - if (">".equals(thirdText)) { //$NON-NLS-1$ - String name = secondSimpleName.getIdentifier(); - ITypeParameter[] typeParameters = fMethod.getTypeParameters(); - for (int i = 0; i < typeParameters.length; i++) { - ITypeParameter typeParameter = typeParameters[i]; - if (name.equals(typeParameter.getElementName())) { - CharSequence inherited = fJavadocLookup.getInheritedTypeParamDescription(fMethod, i); - return handleInherited(inherited); - } - } - } - } - } - } - } - - } else if (TagElement.TAG_RETURN.equals(blockTagName)) { - CharSequence inherited = fJavadocLookup.getInheritedReturnDescription(fMethod); - return handleInherited(inherited); - - } else if (TagElement.TAG_THROWS.equals(blockTagName) || TagElement.TAG_EXCEPTION.equals(blockTagName)) { - List fragments = blockTag.fragments(); - if (fragments.size() > 0) { - Object first = fragments.get(0); - if (first instanceof Name firstName) { - String name = ASTNodes.getSimpleNameIdentifier(firstName); - CharSequence inherited = fJavadocLookup.getInheritedExceptionDescription(fMethod, name); - return handleInherited(inherited); - } - } - } - } catch (JavaModelException e) { - - } - return false; - } - - private boolean handleInherited(CharSequence inherited) { - if (inherited == null) { - return false; - } - - fBuf.append(inherited); - return true; - } - - private void handleBlockTags(String title, List tags) { - if (tags.isEmpty()) { - return; - } - - handleBlockTagTitle(title); - - for (Iterator iter = tags.iterator(); iter.hasNext();) { - TagElement tag = iter.next(); - fBuf.append(BLOCK_TAG_START); - fBuf.append(BlOCK_TAG_ENTRY_START); - if (TagElement.TAG_SEE.equals(tag.getTagName())) { - handleSeeTag(tag); - } else { - handleContentElements(tag.fragments()); - } - fBuf.append(BlOCK_TAG_ENTRY_END); - fBuf.append(BLOCK_TAG_END); - } - fBuf.append(BlOCK_TAG_ENTRY_END); - } - - private void handleReturnTag(TagElement tag, CharSequence returnDescription) { - if (tag == null && returnDescription == null) { - return; - } - - handleBlockTagTitle(JavaDoc2HTMLTextReader_returns_section); - - fBuf.append(BLOCK_TAG_START); - fBuf.append(BlOCK_TAG_ENTRY_START); - if (tag != null) { - handleContentElements(tag.fragments()); - } else { - fBuf.append(returnDescription); - } - fBuf.append(BlOCK_TAG_ENTRY_END); - fBuf.append(BLOCK_TAG_END); - fBuf.append(BlOCK_TAG_ENTRY_END); - } - - private void handleBlockTags(List tags) { - for (Iterator iter = tags.iterator(); iter.hasNext();) { - TagElement tag = iter.next(); - handleBlockTagTitle(tag.getTagName()); - List fragments = tag.fragments(); - if (!fragments.isEmpty()) { - fBuf.append(BLOCK_TAG_START); - fBuf.append(BlOCK_TAG_ENTRY_START); - handleContentElements(fragments); - fBuf.append(BlOCK_TAG_ENTRY_END); - fBuf.append(BLOCK_TAG_END); - } - fBuf.append(BlOCK_TAG_ENTRY_END); - } - } - - private void handleBlockTagTitle(String title) { - fBuf.append("
    • "); //$NON-NLS-1$ - fBuf.append(title); - fBuf.append(""); //$NON-NLS-1$ - } - - private void handleSeeTag(TagElement tag) { - handleLink(tag.fragments()); - } - - private void handleExceptionTags(List tags, List exceptionNames, CharSequence[] exceptionDescriptions) { - if (tags.size() == 0 && containsOnlyNull(exceptionNames)) { - return; - } - - handleBlockTagTitle(JavaDoc2HTMLTextReader_throws_section); - fBuf.append(BLOCK_TAG_START); - for (Iterator iter = tags.iterator(); iter.hasNext();) { - TagElement tag = iter.next(); - fBuf.append(BlOCK_TAG_ENTRY_START); - handleThrowsTag(tag); - fBuf.append(BlOCK_TAG_ENTRY_END); - } - - for (int i = 0; i < exceptionDescriptions.length; i++) { - CharSequence description = exceptionDescriptions[i]; - String name = exceptionNames.get(i); - if (name != null) { - fBuf.append(BlOCK_TAG_ENTRY_START); - handleLink(Collections.singletonList(fJavadoc.getAST().newSimpleName(name))); - if (description != null) { - fBuf.append(JavaElementLabelsCore.CONCAT_STRING); - fBuf.append(description); - } - fBuf.append(BlOCK_TAG_ENTRY_END); - } - } - fBuf.append(BLOCK_TAG_END); - fBuf.append(BlOCK_TAG_ENTRY_END); - } - - private void handleThrowsTag(TagElement tag) { - List fragments = tag.fragments(); - int size = fragments.size(); - if (size > 0) { - handleLink(fragments.subList(0, 1)); - if (size > 1) { - fBuf.append(JavaElementLabelsCore.CONCAT_STRING); - handleContentElements(fragments.subList(1, size)); - } - } - } - - private void handleParameterTags(List tags, List parameterNames, CharSequence[] parameterDescriptions, boolean isTypeParameters) { - if (tags.size() == 0 && containsOnlyNull(parameterNames)) { - return; - } - - String tagTitle = isTypeParameters ? JavaDoc2HTMLTextReader_type_parameters_section : JavaDoc2HTMLTextReader_parameters_section; - handleBlockTagTitle(tagTitle); - - for (Iterator iter = tags.iterator(); iter.hasNext();) { - TagElement tag = iter.next(); - fBuf.append(BLOCK_TAG_START); - fBuf.append(BlOCK_TAG_ENTRY_START); - handleParamTag(tag); - fBuf.append(BlOCK_TAG_ENTRY_END); - fBuf.append(BLOCK_TAG_END); - } - for (int i = 0; i < parameterDescriptions.length; i++) { - CharSequence description = parameterDescriptions[i]; - String name = parameterNames.get(i); - if (name != null) { - fBuf.append(BLOCK_TAG_START); - fBuf.append(BlOCK_TAG_ENTRY_START); - fBuf.append(PARAM_NAME_START); - if (isTypeParameters) { - fBuf.append("<"); //$NON-NLS-1$ - } - fBuf.append(name); - if (isTypeParameters) { - fBuf.append(">"); //$NON-NLS-1$ - } - fBuf.append(PARAM_NAME_END); - if (description != null) { - fBuf.append(description); - } - fBuf.append(BlOCK_TAG_ENTRY_END); - fBuf.append(BLOCK_TAG_END); - } - } - - fBuf.append(BlOCK_TAG_ENTRY_END); - } - - private void handleParamTag(TagElement tag) { - List fragments = tag.fragments(); - int i = 0; - int size = fragments.size(); - if (size > 0) { - Object first = fragments.get(0); - fBuf.append(PARAM_NAME_START); - if (first instanceof SimpleName simpleName) { - String name = simpleName.getIdentifier(); - fBuf.append(name); - i++; - } else if (first instanceof TextElement textElement) { - String firstText = textElement.getText(); - if ("<".equals(firstText)) { //$NON-NLS-1$ - fBuf.append("<"); //$NON-NLS-1$ - i++; - if (size > 1) { - Object second = fragments.get(1); - if (second instanceof SimpleName secondSimpleName) { - String name = secondSimpleName.getIdentifier(); - fBuf.append(name); - i++; - if (size > 2) { - Object third = fragments.get(2); - String thirdText = ((TextElement) third).getText(); - if (">".equals(thirdText)) { //$NON-NLS-1$ - fBuf.append(">"); //$NON-NLS-1$ - i++; - } - } - } - } - } - } - fBuf.append(PARAM_NAME_END); - - handleContentElements(fragments.subList(i, fragments.size())); - } - } - - private void handleSummary(List fragments) { - int fs= fragments.size(); - if (fs > 0) { - Object first= fragments.get(0); - if (first instanceof TextElement memberRef) { - fBuf.append(BlOCK_TAG_TITLE_START + "Summary: " + memberRef.getText() + BlOCK_TAG_TITLE_END); //$NON-NLS-1$ - return; - } - } - } - - private void handleSnippet(TagElement node) { - if (node != null) { - Object val = node.getProperty(TagProperty.TAG_PROPERTY_SNIPPET_IS_VALID); - Object valError = node.getProperty(TagProperty.TAG_PROPERTY_SNIPPET_ERROR); - if (val instanceof Boolean bool && bool.booleanValue() && valError == null) { - int fs= node.fragments().size(); - if (fs > 0) { - fBuf.append("
      "); //$NON-NLS-1$
      -					Object valID = node.getProperty(TagProperty.TAG_PROPERTY_SNIPPET_ID);
      -					if (valID instanceof String && !valID.toString().isBlank()) {
      -						fBuf.append("" ); //$NON-NLS-1$ //$NON-NLS-2$
      -					} else {
      -						fBuf.append("") ;//$NON-NLS-1$
      -					}
      -					fBuf.append(BlOCK_TAG_ENTRY_START);
      -					fSnippetStringEvaluator.AddTagElementString(node, fBuf);
      -					fBuf.append(BlOCK_TAG_ENTRY_END);
      -				}
      -			} else {
      -				handleInvalidSnippet(node);
      -			}
      -		}
      -	}
      -
      -	private void handleInvalidSnippet(TagElement node) {
      -		fBuf.append("
      \n"); //$NON-NLS-1$
      -		fBuf.append("invalid @Snippet"); //$NON-NLS-1$
      -		Object val = node.getProperty(TagProperty.TAG_PROPERTY_SNIPPET_ERROR);
      -		if (val instanceof String) {
      -			fBuf.append("

      "+val+"

      "); //$NON-NLS-1$ //$NON-NLS-2$ - - } - - - } - - private void handleIndex(List fragments) { - int fs= fragments.size(); - if (fs > 0) { - Object first= fragments.get(0); - if (first instanceof TextElement memberRef) { - fBuf.append( memberRef.getText() ); - return; - } - } - } - - private void handleLink(List fragments) { - //TODO: Javadoc shortens type names to minimal length according to context - int fs = fragments.size(); - if (fs > 0) { - Object first = fragments.get(0); - String refTypeName = null; - String refMemberName = null; - String[] refMethodParamTypes = null; - String[] refMethodParamNames = null; - int startPosition = -1; - if (first instanceof Name name) { - refTypeName = name.getFullyQualifiedName(); - startPosition = name.getStartPosition(); - } else if (first instanceof MemberRef memberRef) { - Name qualifier = memberRef.getQualifier(); - refTypeName = qualifier == null ? "" : qualifier.getFullyQualifiedName(); //$NON-NLS-1$ - refMemberName = memberRef.getName().getIdentifier(); - startPosition = memberRef.getStartPosition(); - } else if (first instanceof MethodRef methodRef) { - Name qualifier = methodRef.getQualifier(); - refTypeName = qualifier == null ? "" : qualifier.getFullyQualifiedName(); //$NON-NLS-1$ - refMemberName = methodRef.getName().getIdentifier(); - List params = methodRef.parameters(); - int ps = params.size(); - refMethodParamTypes = new String[ps]; - refMethodParamNames = new String[ps]; - for (int i = 0; i < ps; i++) { - MethodRefParameter param = params.get(i); - refMethodParamTypes[i] = ASTNodes.asString(param.getType()); - SimpleName paramName = param.getName(); - if (paramName != null) { - refMethodParamNames[i] = paramName.getIdentifier(); - } - } - startPosition = methodRef.getStartPosition(); - } - - if (refTypeName != null) { - fBuf.append(""); //$NON-NLS-1$ - if (fs > 1 && !(fs == 2 && isWhitespaceTextElement(fragments.get(1)))) { - handleContentElements(fragments.subList(1, fs), true); - } else { - fBuf.append(refTypeName); - if (refMemberName != null) { - if (refTypeName.length() > 0) { - fBuf.append('.'); - } - fBuf.append(refMemberName); - if (refMethodParamTypes != null) { - fBuf.append('('); - for (int i = 0; i < refMethodParamTypes.length; i++) { - String pType = refMethodParamTypes[i]; - fBuf.append(pType); - String pName = refMethodParamNames[i]; - if (pName != null) { - fBuf.append(' ').append(pName); - } - if (i < refMethodParamTypes.length - 1) { - fBuf.append(", "); //$NON-NLS-1$ - } - } - fBuf.append(')'); - } - } - } - fBuf.append(""); //$NON-NLS-1$ - } else { - handleContentElements(fragments); - } - } - } - - private static boolean isWhitespaceTextElement(Object fragment) { - return fragment instanceof TextElement textElement && textElement.getText().trim().length() == 0; - } - - private boolean containsOnlyNull(List parameterNames) { - for (Iterator iter = parameterNames.iterator(); iter.hasNext();) { - if (iter.next() != null) { - return false; - } - } - return true; - } - - /** - * @param content - * HTML content produced by getHTMLContent(...) - * @return the baseURL to use for the given content, or null if - * none - * @since 3.10 - */ - public static String extractBaseURL(String content) { - int introStart = content.indexOf(BASE_URL_COMMENT_INTRO); - if (introStart != -1) { - int introLength = BASE_URL_COMMENT_INTRO.length(); - int endIndex = content.indexOf('"', introStart + introLength); - if (endIndex != -1) { - return content.substring(introStart + introLength, endIndex); - } - } - return null; - } - - /** - * Returns the Javadoc for a PackageDeclaration. - * - * @param packageDeclaration - * the Java element whose Javadoc has to be retrieved - * @return the package documentation in HTML format or null if - * there is no associated Javadoc - * @throws CoreException - * if the Java element does not exists or an exception occurs while - * accessing the file containing the package Javadoc - * @since 3.9 - */ - public static String getHTMLContent(IPackageDeclaration packageDeclaration) throws CoreException { - return packageDeclaration.getAncestor(IJavaElement.PACKAGE_FRAGMENT) instanceof IPackageFragment pkg ? getHTMLContent(pkg) : null; - } - - /** - * Returns the Javadoc for a package which could be present in package.html, - * package-info.java or from an attached Javadoc. - * - * @param packageFragment - * the package which is requesting for the document - * @return the document content in HTML format or null if there is - * no associated Javadoc - * @throws CoreException - * if the Java element does not exists or an exception occurs while - * accessing the file containing the package Javadoc - * @since 3.9 - */ - public static String getHTMLContent(IPackageFragment packageFragment) throws CoreException { - String content = readHTMLContent(packageFragment); - return sanitizePackageJavadoc(content); - } - - private static String sanitizePackageJavadoc(String content) { - if (content == null || content.isEmpty()) { - return content; - } - //Since Java 9, Javadoc format has changed and the JDT parsing in org.eclipse.jdt.internal.core.JavadocContent hasn't really caught up - //so we need to manually remove the list of classes away from the actual package Javadoc, similar to Java < 9. - //This is a simple, suboptimal but temporary (AHAHAH!) hack until JavadocContent fixes its parsing. - if (content.indexOf(CONTENT_CONTAINER) == 0) { - int nextListIndex = content.indexOf(UL_CLASS_BLOCK_LIST); - if (nextListIndex > 0) { - content = content.substring(CONTENT_CONTAINER.length(), nextListIndex); - } - } - return content; - } - - private static String readHTMLContent(IPackageFragment packageFragment) throws CoreException { - IPackageFragmentRoot root = (IPackageFragmentRoot) packageFragment.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT); - - //1==> Handle the case when the documentation is present in package-info.java or package-info.class file - ITypeRoot packageInfo; - boolean isBinary = root.getKind() == IPackageFragmentRoot.K_BINARY; - if (isBinary) { - packageInfo = packageFragment.getClassFile(JavaModelUtil.PACKAGE_INFO_CLASS); - } else { - packageInfo = packageFragment.getCompilationUnit(JavaModelUtil.PACKAGE_INFO_JAVA); - } - if (packageInfo != null && packageInfo.exists()) { - String cuSource = packageInfo.getSource(); - //the source can be null for some of the class files - if (cuSource != null) { - Javadoc packageJavadocNode = getPackageJavadocNode(packageFragment, cuSource); - if (packageJavadocNode != null) { - IJavaElement element; - if (isBinary) { - element = ((IOrdinaryClassFile) packageInfo).getType(); - } else { - element = packageInfo.getParent(); // parent is the IPackageFragment - } - return new JavadocContentAccess2(element, packageJavadocNode, cuSource).toHTML(); - } - } - } - - // 2==> Handle the case when the documentation is done in package.html file. The file can be either in normal source folder or coming from a jar file - else { - Object[] nonJavaResources = packageFragment.getNonJavaResources(); - // 2.1 ==>If the package.html file is present in the source or directly in the binary jar - for (Object nonJavaResource : nonJavaResources) { - if (nonJavaResource instanceof IFile iFile) { - if (iFile.exists() && JavaModelUtil.PACKAGE_HTML.equals(iFile.getName())) { - return getIFileContent(iFile); - } - } - } - - // 2.2==>The file is present in a binary container - if (isBinary) { - for (Object nonJavaResource : nonJavaResources) { - // The content is from an external binary class folder - if (nonJavaResource instanceof IJarEntryResource jarEntryResource) { - String encoding = getSourceAttachmentEncoding(root); - if (JavaModelUtil.PACKAGE_HTML.equals(jarEntryResource.getName()) && jarEntryResource.isFile()) { - return getHTMLContent(jarEntryResource, encoding); - } - } - } - //2.3 ==>The file is present in the source attachment path. - String contents = getHTMLContentFromAttachedSource(root, packageFragment); - if (contents != null) { - return contents; - } - } - } - - //3==> Handle the case when the documentation is coming from the attached Javadoc - if ((root.isArchive() || root.isExternal())) { - return packageFragment.getAttachedJavadoc(null); - - } - - return null; - } - - private static String getHTMLContent(IJarEntryResource jarEntryResource, String encoding) throws CoreException { - InputStream in = jarEntryResource.getContents(); - try { - return getContentsFromInputStream(in, encoding); - } finally { - if (in != null) { - try { - in.close(); - } catch (IOException e) { - //ignore - } - } - } - } - - private static String getHTMLContentFromAttachedSource(IPackageFragmentRoot root, IPackageFragment packageFragment) throws CoreException { - String filePath = packageFragment.getElementName().replace('.', '/') + '/' + JavaModelUtil.PACKAGE_INFO_JAVA; - String contents = getFileContentFromAttachedSource(root, filePath); - if (contents != null) { - Javadoc packageJavadocNode = getPackageJavadocNode(packageFragment, contents); - if (packageJavadocNode != null) { - return new JavadocContentAccess2(packageFragment, packageJavadocNode, contents).toHTML(); - } - - } - filePath = packageFragment.getElementName().replace('.', '/') + '/' + JavaModelUtil.PACKAGE_HTML; - return getFileContentFromAttachedSource(root, filePath); - } - - private static String getFileContentFromAttachedSource(IPackageFragmentRoot root, String filePath) throws CoreException { - IPath sourceAttachmentPath = root.getSourceAttachmentPath(); - if (sourceAttachmentPath != null) { - File file = null; - String encoding = null; - - if (sourceAttachmentPath.getDevice() == null) { - //the path could be a workspace relative path to a zip or to the source folder - IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot(); - IResource res = wsRoot.findMember(sourceAttachmentPath); - - if (res instanceof IFile ifile) { - // zip in the workspace - IPath location = res.getLocation(); - if (location == null) { - return null; - } - file = location.toFile(); - encoding = ifile.getCharset(false); - - } else if (res instanceof IContainer container) { - // folder in the workspace - res = container.findMember(filePath); - if (!(res instanceof IFile)) { - return null; - } - encoding = ((IFile) res).getCharset(false); - if (encoding == null) { - encoding = getSourceAttachmentEncoding(root); - } - return getContentsFromInputStream(((IFile) res).getContents(), encoding); - } - } - - if (file == null || !file.exists()) { - file = sourceAttachmentPath.toFile(); - } - - if (file.isDirectory()) { - //the path is an absolute filesystem path to the source folder - IPath packagedocPath = sourceAttachmentPath.append(filePath); - if (packagedocPath.toFile().exists()) { - return getFileContent(packagedocPath.toFile()); - } - - } else if (file.exists()) { - //the package documentation is in a Jar/Zip - IPath sourceAttachmentRootPath = root.getSourceAttachmentRootPath(); - String packagedocPath; - //consider the root path also in the search path if it exists - if (sourceAttachmentRootPath != null) { - packagedocPath = sourceAttachmentRootPath.append(filePath).toString(); - } else { - packagedocPath = filePath; - } - ZipFile zipFile = null; - InputStream in = null; - try { - zipFile = new ZipFile(file, ZipFile.OPEN_READ); - ZipEntry packagedocFile = zipFile.getEntry(packagedocPath); - if (packagedocFile != null) { - in = zipFile.getInputStream(packagedocFile); - if (encoding == null) { - encoding = getSourceAttachmentEncoding(root); - } - return getContentsFromInputStream(in, encoding); - } - } catch (IOException e) { - //throw new CoreException(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), e.getMessage(), e)); - } finally { - try { - if (in != null) { - in.close(); - } - } catch (IOException e) { - //ignore - } - try { - if (zipFile != null) { - zipFile.close();//this will close the InputStream also - } - } catch (IOException e) { - //ignore - } - } - } - } - - return null; - } - - private static String getContentsFromInputStream(InputStream in, String encoding) throws CoreException { - final int defaultFileSize = 15 * 1024; - StringBuffer buffer = new StringBuffer(defaultFileSize); - Reader reader = null; - - try { - reader = new BufferedReader(new InputStreamReader(in, encoding), defaultFileSize); - - char[] readBuffer = new char[2048]; - int charCount = reader.read(readBuffer); - - while (charCount > 0) { - buffer.append(readBuffer, 0, charCount); - charCount = reader.read(readBuffer); - } - - } catch (IOException e) { - //throw new CoreException(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), e.getMessage(), e)); - } finally { - try { - if (reader != null) { - reader.close();//this will also close the InputStream wrapped in the reader - } - } catch (IOException e) { - //ignore - } - } - return buffer.toString(); - } - - private static String getSourceAttachmentEncoding(IPackageFragmentRoot root) throws JavaModelException { - String encoding = ResourcesPlugin.getEncoding(); - IClasspathEntry entry = root.getRawClasspathEntry(); - - if (entry != null) { - int kind = entry.getEntryKind(); - if (kind == IClasspathEntry.CPE_LIBRARY || kind == IClasspathEntry.CPE_VARIABLE) { - IClasspathAttribute[] extraAttributes = entry.getExtraAttributes(); - for (int i = 0; i < extraAttributes.length; i++) { - IClasspathAttribute attrib = extraAttributes[i]; - if (IClasspathAttribute.SOURCE_ATTACHMENT_ENCODING.equals(attrib.getName())) { - return attrib.getValue(); - } - } - } - } - - return encoding; - } - - /** - * Reads the content of the IFile. - * - * @param file - * the file whose content has to be read - * @return the content of the file - * @throws CoreException - * if the file could not be successfully connected or disconnected - */ - private static String getIFileContent(IFile file) throws CoreException { - String content = null; - ITextFileBufferManager manager = FileBuffers.getTextFileBufferManager(); - IPath fullPath = file.getFullPath(); - manager.connect(fullPath, LocationKind.IFILE, null); - try { - ITextFileBuffer buffer = manager.getTextFileBuffer(fullPath, LocationKind.IFILE); - if (buffer != null) { - content = buffer.getDocument().get(); - } - } finally { - manager.disconnect(fullPath, LocationKind.IFILE, null); - } - - return content; - } - - /** - * Reads the content of the java.io.File. - * - * @param file - * the file whose content has to be read - * @return the content of the file - * @throws CoreException - * if the file could not be successfully connected or disconnected - */ - private static String getFileContent(File file) throws CoreException { - String content = null; - ITextFileBufferManager manager = FileBuffers.getTextFileBufferManager(); - - IPath fullPath = new Path(file.getAbsolutePath()); - manager.connect(fullPath, LocationKind.LOCATION, null); - try { - ITextFileBuffer buffer = manager.getTextFileBuffer(fullPath, LocationKind.LOCATION); - if (buffer != null) { - content = buffer.getDocument().get(); - } - } finally { - manager.disconnect(fullPath, LocationKind.LOCATION, null); - } - return content; - } - - /** - * Escapes reserved HTML characters in the given string and returns them in a - * way that preserves whitespace in a browser. - *

      - * Warning: Whitespace will not be preserved when rendered with an - * {@link HTML2TextReader} (e.g. in a {@link DefaultInformationControl} that - * renders simple HTML). - * - * @param content - * the input string - * @return the processed string - * @see #addPreFormatted(StringBuffer, String) - * @see #convertToHTMLContent(String) - * @since 3.7 - */ - public static String convertToHTMLContentWithWhitespace(String content) { - content = replace(content, '&', "&"); //$NON-NLS-1$ - content = replace(content, '"', """); //$NON-NLS-1$ - content = replace(content, '<', "<"); //$NON-NLS-1$ - content = replace(content, '>', ">"); //$NON-NLS-1$ - return "" + content + ""; //$NON-NLS-1$ //$NON-NLS-2$ - } - - private static String replace(String text, char c, String s) { - - int previous = 0; - int current = text.indexOf(c, previous); - - if (current == -1) { - return text; - } - - StringBuffer buffer = new StringBuffer(); - while (current > -1) { - buffer.append(text.substring(previous, current)); - buffer.append(s); - previous = current + 1; - current = text.indexOf(c, previous); - } - buffer.append(text.substring(previous)); - - return buffer.toString(); - } - - public static Reader getMarkdownContentReader(IJavaElement element) { - - try { - String rawHtml = JavadocContentAccess2.getHTMLContent(element, true); - Reader markdownReader = new JavaDoc2MarkdownConverter(rawHtml).getAsReader(); - return markdownReader; - } catch (IOException | CoreException e) { - - } - - return null; - } - } \ No newline at end of file diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/html/SingleCharReader.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/html/SingleCharReader.java deleted file mode 100644 index bfbafdb4f7..0000000000 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/html/SingleCharReader.java +++ /dev/null @@ -1,69 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.ls.core.internal.javadoc.html; - -import java.io.IOException; -import java.io.Reader; - -/** - * Copied into this package from org.eclipse.jface.internal.text.html.SingleCharReader. - */ -public abstract class SingleCharReader extends Reader { - - /** - * @see Reader#read() - */ - @Override - public abstract int read() throws IOException; - - /** - * @see Reader#read(char[],int,int) - */ - @Override - public int read(char cbuf[], int off, int len) throws IOException { - int end= off + len; - for (int i= off; i < end; i++) { - int ch= read(); - if (ch == -1) { - if (i == off) { - return -1; - } - return i - off; - } - cbuf[i]= (char)ch; - } - return len; - } - - /** - * @see Reader#ready() - */ - @Override - public boolean ready() throws IOException { - return true; - } - - /** - * Returns the readable content as string. - * @return the readable content as string - * @exception IOException in case reading fails - */ - public String getString() throws IOException { - StringBuilder builder= new StringBuilder(); - int ch; - while ((ch= read()) != -1) { - builder.append((char)ch); - } - return builder.toString(); - } -} diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/html/SubstitutionTextReader.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/html/SubstitutionTextReader.java deleted file mode 100644 index 7d32a6a9fc..0000000000 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/javadoc/html/SubstitutionTextReader.java +++ /dev/null @@ -1,171 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.ls.core.internal.javadoc.html; - -import java.io.IOException; -import java.io.Reader; - -/** - * Copied into this package from org.eclipse.jface.internal.text.html.SubstitutionTextReader. - */ -/** - * Reads the text contents from a reader and computes for each character - * a potential substitution. The substitution may eat more characters than - * only the one passed into the computation routine. - *

      - * Moved into this package from org.eclipse.jface.internal.text.revisions.

      - */ -public abstract class SubstitutionTextReader extends SingleCharReader { - - protected static final String LINE_DELIM= System.getProperty("line.separator", "\n"); //$NON-NLS-1$ //$NON-NLS-2$ - - private Reader fReader; - protected boolean fWasWhiteSpace; - private int fCharAfterWhiteSpace; - - /** - * Tells whether white space characters are skipped. - */ - private boolean fSkipWhiteSpace= true; - - private boolean fReadFromBuffer; - - private StringBuilder fBuilder; - - private int fIndex; - - - protected SubstitutionTextReader(Reader reader) { - fReader= reader; - fBuilder= new StringBuilder(); - fIndex= 0; - fReadFromBuffer= false; - fCharAfterWhiteSpace= -1; - fWasWhiteSpace= true; - } - - /** - * Computes the substitution for the given character and if necessary - * subsequent characters. Implementation should use nextChar - * to read subsequent characters. - * - * @param c the character to be substituted - * @return the substitution for c - * @throws IOException in case computing the substitution fails - */ - protected abstract String computeSubstitution(int c) throws IOException; - - /** - * Returns the internal reader. - * - * @return the internal reader - */ - protected Reader getReader() { - return fReader; - } - - /** - * Returns the next character. - * @return the next character - * @throws IOException in case reading the character fails - */ - protected int nextChar() throws IOException { - fReadFromBuffer= (fBuilder.length() > 0); - if (fReadFromBuffer) { - char ch= fBuilder.charAt(fIndex++); - if (fIndex >= fBuilder.length()) { - fBuilder.setLength(0); - fIndex= 0; - } - return ch; - } - - int ch= fCharAfterWhiteSpace; - if (ch == -1) { - ch= fReader.read(); - } - if (fSkipWhiteSpace && Character.isWhitespace((char)ch)) { - do { - ch= fReader.read(); - } while (Character.isWhitespace((char)ch)); - if (ch != -1) { - fCharAfterWhiteSpace= ch; - return ' '; - } - } else { - fCharAfterWhiteSpace= -1; - } - return ch; - } - - /** - * @see Reader#read() - */ - @Override - public int read() throws IOException { - int c; - do { - - c= nextChar(); - while (!fReadFromBuffer && c != -1) { - String s= computeSubstitution(c); - if (s == null) { - break; - } - if (s.length() > 0) { - fBuilder.insert(0, s); - } - c= nextChar(); - } - - } while (fSkipWhiteSpace && fWasWhiteSpace && (c == ' ')); - fWasWhiteSpace= (c == ' ' || c == '\r' || c == '\n'); - return c; - } - - /** - * @see Reader#ready() - */ - @Override - public boolean ready() throws IOException { - return fReader.ready(); - } - - /** - * @see Reader#close() - */ - @Override - public void close() throws IOException { - fReader.close(); - } - - /** - * @see Reader#reset() - */ - @Override - public void reset() throws IOException { - fReader.reset(); - fWasWhiteSpace= true; - fCharAfterWhiteSpace= -1; - fBuilder.setLength(0); - fIndex= 0; - } - - protected final void setSkipWhitespace(boolean state) { - fSkipWhiteSpace= state; - } - - protected final boolean isSkippingWhitespace() { - return fSkipWhiteSpace; - } -} diff --git a/org.eclipse.jdt.ls.target/org.eclipse.jdt.ls.tp.target b/org.eclipse.jdt.ls.target/org.eclipse.jdt.ls.tp.target index 90ac95b487..ec3dabdd34 100644 --- a/org.eclipse.jdt.ls.target/org.eclipse.jdt.ls.tp.target +++ b/org.eclipse.jdt.ls.target/org.eclipse.jdt.ls.tp.target @@ -25,7 +25,7 @@ - + diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionHandlerTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionHandlerTest.java index 00946bc696..8a1254b009 100644 --- a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionHandlerTest.java +++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/CompletionHandlerTest.java @@ -156,7 +156,7 @@ public void testCompletion_javadoc() throws Exception { changeDocument(unit, source, 4); CompletionList list = server.completion(position).join().getRight(); CompletionItem resolved = server.resolveCompletionItem(list.getItems().get(0)).join(); - assertEquals("Test ", resolved.getDocumentation().getLeft()); + assertEquals("Test", resolved.getDocumentation().getLeft()); } finally { unit.discardWorkingCopy(); if (joinOnCompletion == null) { diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/HoverHandlerTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/HoverHandlerTest.java index 11cb4be5eb..5871615bc9 100644 --- a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/HoverHandlerTest.java +++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/HoverHandlerTest.java @@ -301,7 +301,8 @@ public void testHoverInheritedJavadoc() throws Exception { assertNotNull(hover); String result = hover.getContents().getLeft().get(1).getLeft();// result = ResourceUtils.dos2Unix(result); - String expected = "This method comes from Foo\n" + "\n" + " * **Parameters:**\n" + " \n" + " * **input** an input String"; + String t1 = "**Overrides:** foo(...) in Foo\n\n"; + String expected = "This method comes from Foo\n" + "\n" + t1 + " * **Parameters:**\n" + " \n" + " * **input** an input String"; assertEquals("Unexpected hover ", expected, result); } @@ -551,7 +552,7 @@ public void testHoverJavadocWithExtraTags() throws Exception { " * **Since:**\n" + " \n" + " * 9\n" + - " * **@uses**\n" + + " * **Uses:**\n" + " \n" + " * java.sql.Driver\n" + " * **@moduleGraph**";