diff --git a/README.md b/README.md index cf18b2d..cbb2101 100644 --- a/README.md +++ b/README.md @@ -1,149 +1,48 @@ -# xmldoclet +# xmldoclet - link-bug-report branch + +This branch contains the doclet stripped down to demonstrate two (apparent) +issues in the Doclet API. It doesn’t build complete or useful documentation, it +builds just enough to demonstrate two problems. + +To reproduce the issues: + +1. Build the project +2. Run the unit test in `DocletTest`; this will build JavaDoc for the toy example in `sample`. +3. Examine the doclet output, by default in `xmldoclet/doclet.xml`. + +There are two problems: + +1. In the JavaDoc for `ItemProcessor`, the link target is incorrect: + + ``` + + This is a link to Item. + + ``` + + The `Item` is defined in `packageb`, but I don’t see anywhere in the API that + exposes that information. Poking around in the debugger, I think the + information about what has been imported into `packagea` is known, but it + isn’t exposed. + +2. The JavaDoc for variables doesn’t expose the initializing expression. See `hello`: + + ``` + + + + ``` + + The initializing expression is `H\u0065llo`. Again, with the debugger, that + appears to be in the private API but unaccessible. I would like it to be possible + for the documentation to reflect the actual initializing expression. This is particularly + useful when, for example, a string contains many non-Latin characters. -This is a Javadoc doclet that produces XML output. The goal is that -all of the data available in the Doclet API should be available in the -resulting XML. - -It’s still a little rough around the edges, but it does use the modern -JavaDoc APIs and not the old, now deprecated ones that appear in -several other doclets for this purpose. - -## Installing the doclet - -You have two choices for installing xmldoclet. You can download a release -from the Github [releases](https://github.com/Saxonica/xmldoclet/releases) page, -or you can use the Saxonica Maven repository at `https://dev.saxonica.com/maven`. -The Maven artifact is: - -```xml - - com.saxonica - xmldoclet - x.y.z - -``` - -Where `x.y.z` should be replaced by the appropriate version. - -Make sure that the xmldoclet jar file is on the classpath used by the Javadoc -command. - -## Running the doclet - -The xmldoclet recognizes the following options: - -
-
-
-d
-
The destination directory, if specified this is where the output file -will be stored. By default, this is ., the current directory. -
-
-
-
-outputfile
-
The name of the output file. By default, this is doclet.xml. -
-
-
-
-sourcepath
-
A list of directories where Java source files can be found. See source paths -below. -
-
-
-
-doctitle, -windowtitle, -notimestamp
-
These options are accepted, but ignored. This allows the doclet to be -used with build tools that send them without having to work out how to -suppress them. -
-
- - -### Source paths - -The new Javadoc APIs don’t appear to expose any record of imported -classes. You can’t tell, for example, that `org.example.MyClass` -contains an `import java.util.Locale` statement. Inspecting the source -code for the standard doclet, reveals that this information is -accessed through a variety of private APIs (the information is *in* -the objects, but not exposed in any public APIs!). - -Unfortunately, *without* access to the imports, it’s not possible to -tell what an unqualified type name refers to! What is _Locale -mylocale_? It could be `java.util.Local` or it could be -`org.example.otherpackage.Locale`. - -The xmldoclet applies brute force. It relies on the `javaparser` APIs -and simply reads the sources itself. That’s why you have to specify a -source path. This can lead to spurious warnings from the Java parser, -but they aren’t relevant because the only thing xmldoclet uses the -parsed AST for is to extract the list of imports. - -## XML output - -The XML output is in the `https://saxonica.com/ns/doclet` namespace. -It conforms to the RELAX NG schema `doclet.rnc` in -`xmldoclet/src/main/resources/doclet.rnc`. - -All of the comments and tags are in the HTML namespace, wrapped in a -`body` element. They are guaranteed to be well-formed, even if the -markup in the Java sources is not. This is achieved by parsing them -with the Validator.nu HTML 5 parser. - -Notes: - -* The HTML 5 parser doesn’t preserve comments. To work around this - limitation, any literal comments in the Javadoc source: - - ```xml - - ``` - - are represented using an HTML extension element: - `xmldoclet-comment`. For example: - - ```xml - - ``` - -* Some `char` constant values can’t be represented in XML. For - surrogate pairs and characters less than 0x20, the string - `(char) 0x…` is used for the value instead of the character’s - literal value. - -## Feedback welcome - -Much of the output is the result of experimentation and exploring the -Javadoc APIs. If you discover that xmldoclet produces output that -doesn’t conform to the schema, or if you think that the output is -incomplete or incorrect, please [open an issue](https://github.com/Saxonica/xmldoclet/issues). - -## Change log - -* **0.8.0** Fixed method names - - Output the “simple” method name in the name attribute on method elements. - The full signature is also provided and the parameters and their types are available - from children. - -* **0.7.0** Improved presentation of interfaces - - Reworked the way interfaces are presented so that the methods inherited - from those interfaces (i.e., the methods not actually implemented on this class) - are shown. - -* **0.6.0** Improved handling of method names and inheritance - - Changed the “name” of methods to include the parameter types. (i.e., `foo(int)` - instead of `foo`). This allows them to be distinguished. - - Fixed a bug where the methods inherited from interfaces were not shown. - - Fixed a bug in computing visibility. Previously, the code looked for an explicit - ~public~ or ~protected~ modifier. Now it *excludes* things explicitly marked ~private~. - - Experimentally removed ~java.lang.Object~ as a supertype in the generated XML. - -The previous version looked for methods and fields marked as public or protected, but that's not the same thing! - -* **0.5.0** String constants now use “backslash-U” escapes for non-ASCII characters. diff --git a/sample/src/main/java/org/example/AbstractClass.java b/sample/src/main/java/org/example/AbstractClass.java deleted file mode 100644 index bcf5e41..0000000 --- a/sample/src/main/java/org/example/AbstractClass.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.example; - -abstract public class AbstractClass implements TestInterface { - abstract void one(int value); - abstract void one(int value, int otherValue); - abstract void one(String value); - public void foo() { - System.err.println("impl in AbstractClass"); - } - public void inAbsr() { - System.err.println("impl in AbstractClass"); - } -} diff --git a/sample/src/main/java/org/example/AlternateImplementation.java b/sample/src/main/java/org/example/AlternateImplementation.java deleted file mode 100644 index ff6a2d5..0000000 --- a/sample/src/main/java/org/example/AlternateImplementation.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.example; - -public class AlternateImplementation extends Implementation { - @Override - void one(int value, int otherValue) { - System.err.println("alternate: " + value + ", " + otherValue); - } - - @Override - void one(String value) { - // nop - } - - @Override - public void foo() { - System.err.println("alternate foo"); - } - - @Override - public void baz() { - System.err.println("alternate baz"); - } -} diff --git a/sample/src/main/java/org/example/AnnoType.java b/sample/src/main/java/org/example/AnnoType.java deleted file mode 100644 index 81fb966..0000000 --- a/sample/src/main/java/org/example/AnnoType.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.example; - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2023 Saxonica Limited -// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. -// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotate a Java class or interface to indicate whether the corresponding C# class should be implemented - * as a delegate. By default, if there is an @FunctionalInterface annotation, then it becomes a delegate. - */ - -@Retention(RetentionPolicy.SOURCE) -@Target(ElementType.TYPE) -public @interface AnnoType { - boolean value() default false; -} diff --git a/sample/src/main/java/org/example/AxisIterator.java b/sample/src/main/java/org/example/AxisIterator.java deleted file mode 100644 index bcf6a58..0000000 --- a/sample/src/main/java/org/example/AxisIterator.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.example; - -public interface AxisIterator extends SequenceIterator { - @Override - String next(); -} diff --git a/sample/src/main/java/org/example/EmptyIterator.java b/sample/src/main/java/org/example/EmptyIterator.java deleted file mode 100644 index 6a0a5a8..0000000 --- a/sample/src/main/java/org/example/EmptyIterator.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.example; - -public class EmptyIterator implements SequenceIterator { - @Override - public Object next() { - return null; - } - - private static class OfNodes extends EmptyIterator implements AxisIterator { - - public final static OfNodes THE_INSTANCE = new OfNodes(); - @Override - public String next() { - return null; - } - } -} diff --git a/sample/src/main/java/org/example/Impl.java b/sample/src/main/java/org/example/Impl.java deleted file mode 100644 index 758b751..0000000 --- a/sample/src/main/java/org/example/Impl.java +++ /dev/null @@ -1,4 +0,0 @@ -package org.example; - -abstract public class Impl implements InterfaceAB, InterfaceA { -} diff --git a/sample/src/main/java/org/example/ImplAB.java b/sample/src/main/java/org/example/ImplAB.java deleted file mode 100644 index a7969fe..0000000 --- a/sample/src/main/java/org/example/ImplAB.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.example; - -abstract public class ImplAB implements InterfaceAB { - @Override - public void a() { - System.err.println("ImplAB implements a"); - } -} diff --git a/sample/src/main/java/org/example/ImplABC.java b/sample/src/main/java/org/example/ImplABC.java deleted file mode 100644 index 6d4b9e9..0000000 --- a/sample/src/main/java/org/example/ImplABC.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.example; - -public class ImplABC extends ImplAB implements InterfaceABC { - @Override - public void b() { - System.err.println("ImplABC implements b"); - } - - @Override - public void c() { - System.err.println("ImplABC implements c"); - } -} diff --git a/sample/src/main/java/org/example/Implementation.java b/sample/src/main/java/org/example/Implementation.java deleted file mode 100644 index 3c5d770..0000000 --- a/sample/src/main/java/org/example/Implementation.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.example; - -public abstract class Implementation extends AbstractClass { - @Override - public void foo() { - // nop - } - - @Override - public void bar() { - // nop - } - - @Override - void one(int value) { - System.err.println("int: " + value); - } - - @Override - void one(int value, int otherValue) { - System.err.println("int: " + value + ", " + otherValue); - } - - void inImpl() { - System.err.println("In impl"); - } -} diff --git a/sample/src/main/java/org/example/InterfaceA.java b/sample/src/main/java/org/example/InterfaceA.java deleted file mode 100644 index 23807bf..0000000 --- a/sample/src/main/java/org/example/InterfaceA.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.example; - -public interface InterfaceA { - void a(); -} diff --git a/sample/src/main/java/org/example/InterfaceAB.java b/sample/src/main/java/org/example/InterfaceAB.java deleted file mode 100644 index af7499c..0000000 --- a/sample/src/main/java/org/example/InterfaceAB.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.example; - -public interface InterfaceAB extends InterfaceA { - void b(); -} diff --git a/sample/src/main/java/org/example/InterfaceABC.java b/sample/src/main/java/org/example/InterfaceABC.java deleted file mode 100644 index f58dd7c..0000000 --- a/sample/src/main/java/org/example/InterfaceABC.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.example; - -public interface InterfaceABC extends InterfaceAB { - void c(); -} diff --git a/sample/src/main/java/org/example/IterImpl.java b/sample/src/main/java/org/example/IterImpl.java deleted file mode 100644 index 949f433..0000000 --- a/sample/src/main/java/org/example/IterImpl.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.example; - -public class IterImpl implements SequenceIterator { - public boolean hasNext() { - return false; - } - - @Override - public Object next() { - return null; - } - - @Override - public void close() { - // nop - } -} diff --git a/sample/src/main/java/org/example/Locale.java b/sample/src/main/java/org/example/Locale.java deleted file mode 100644 index 1fa48fc..0000000 --- a/sample/src/main/java/org/example/Locale.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.example; - -public class Locale { - // Not the java.util.Locale class -} diff --git a/sample/src/main/java/org/example/Main.java b/sample/src/main/java/org/example/Main.java new file mode 100644 index 0000000..794b109 --- /dev/null +++ b/sample/src/main/java/org/example/Main.java @@ -0,0 +1,13 @@ +package org.example; + +public class Main { + public final static String hello = "H\u0065llo"; + + /** + * The main entry point. + * @param args Command line arguments. + */ + public static void main(String[] args) { + System.out.println(hello); + } +} diff --git a/sample/src/main/java/org/example/ParameterizedClass.java b/sample/src/main/java/org/example/ParameterizedClass.java deleted file mode 100644 index 6bd1550..0000000 --- a/sample/src/main/java/org/example/ParameterizedClass.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.example; - -public class ParameterizedClass { - private T[] _value; - public T get(int key) { - return _value[key]; - } -} diff --git a/sample/src/main/java/org/example/Sample.java b/sample/src/main/java/org/example/Sample.java deleted file mode 100644 index fd6d586..0000000 --- a/sample/src/main/java/org/example/Sample.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.example; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; - -/** - * Sample application - *

This application exists just to test the various features of the xmldoclet.

- * @since 0.1.0 - * @author Norm Tovey-Walsh - */ -public class Sample { - protected static final String cyrillicLower = - "\u0430\u0431\u0432\u0433\u0434\u0435\u0436\u0437\u0438" + - "\u043a\u043b\u043c\u043d\u043e\u043f\u0440\u0441\u0441\u0443" + - "\u0444\u0445\u0446\u0447\u0448\u0449\u044b\u044d\u044e\u044f"; - - public static void main(String[] args) { - SampleRuntime runtime = new SampleRuntime(); - runtime.run(); - } - - public void throwsOne() throws IOException { - try { - File f = new File("/tmp/not-likely"); - FileInputStream fis = new FileInputStream(f); - } catch (FileNotFoundException ex) { - throw ex; - } - } - - /** - * Throws two exceptions, but only documents one. - * @throws IOException if the file isn't found - */ - public void throwsTwo() throws IOException, IllegalArgumentException { - try { - File f = new File("/tmp/not-likely"); - FileInputStream fis = new FileInputStream(f); - if (fis == null) { - throw new IllegalArgumentException("Can't have a null file"); - } - } catch (FileNotFoundException ex) { - throw ex; - } - } - -} diff --git a/sample/src/main/java/org/example/SampleRuntime.java b/sample/src/main/java/org/example/SampleRuntime.java deleted file mode 100644 index 998aaae..0000000 --- a/sample/src/main/java/org/example/SampleRuntime.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.example; - -public class SampleRuntime { - public void run() { - System.out.println("Hello, world"); - } -} diff --git a/sample/src/main/java/org/example/SequenceIterator.java b/sample/src/main/java/org/example/SequenceIterator.java deleted file mode 100644 index 40e1af6..0000000 --- a/sample/src/main/java/org/example/SequenceIterator.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.example; - -import java.io.Closeable; - -public interface SequenceIterator extends Closeable { - public Object next(); - default void close() {} -} diff --git a/sample/src/main/java/org/example/TestClass.java b/sample/src/main/java/org/example/TestClass.java deleted file mode 100644 index 2eb290c..0000000 --- a/sample/src/main/java/org/example/TestClass.java +++ /dev/null @@ -1,121 +0,0 @@ -package org.example; - -import jdk.javadoc.doclet.DocletEnvironment; -import jdk.javadoc.doclet.Reporter; -import net.sf.saxon.lib.Feature; -import net.sf.saxon.serialize.charcode.CharacterSet; -import java.util.Locale; - -import java.lang.reflect.Parameter; -import java.util.*; - -/** - * A class to hold some static constants and methods associated with processing UTF16 and surrogate pairs - */ - -public class TestClass implements CharacterSet { - public static final TestClass CONSTANTVALUE = new TestClass(); - protected ParameterizedClass stringParameterizedClass = new ParameterizedClass<>(); - - /** The tick! With {@value}*/ - protected final int spoon = 17; - - private static final TestClass theInstance = new TestClass(); - - /** - * Constant indicating 1.0 - */ - - public static final int XML10 = 10; - - /** - * Private constructor to force the singular instance to be used - */ - - private TestClass() { - } - - /** - * Get the singular instance of this class - * - * @return the singular instance of this class - */ - - public static TestClass getInstance() { - return theInstance; - } - - @Override - public boolean inCharset(int c) { - return true; - } - - @Override - public String getCanonicalName() { - return "UTF-16"; - } - - public static final int NONBMP_MIN = 0x10000; - public static final int NONBMP_MAX = 0x10FFFF; - - public static final char SURROGATE1_MIN = (char)0xD800; - public static final char SURROGATE1_MAX = (char)0xDBFF; - public static final char SURROGATE2_MIN = (char)0xDC00; - public static final char SURROGATE2_MAX = (char)0xDFFF; - public static final char NULL = (char)0x0; - public static final char LT = (char)0x3C; - public static final char SOH = (char)0x1; - - /** - * Return the non-BMP character corresponding to a given surrogate pair - * surrogates. - * - * @param high The high surrogate. - * @param low The low surrogate. - * @return the Unicode codepoint represented by the surrogate pair - */ - public static int combinePair(char high, char low) { - return (high - SURROGATE1_MIN) * 0x400 + (low - SURROGATE2_MIN) + NONBMP_MIN; - } - - public void foo(Class spoon) { - } - - public void bar(Locale myLocal) { - - } - - /** {@summary A thing} A test method. - *

don't need to say more than that.

- *
some
-     * pre code
- *

I can haz & © code and enphasis.

- * - *

{@code 3 < 5}

- *

What about {@link Sample} here?

- *

What about testing {@link org.example.TestClass#testing(String)} and {@linkplain Sample}.

- *

What about testing {@link #combinePair(char, char)}

- *

And {@link com.saxonica.xmldoclet.builder.MarkupBuilder}

- *

Or {@linkplain TestInterface#foo()}, {@link jdk.javadoc.doclet.Doclet#run(DocletEnvironment)}

- *

{@link jdk.javadoc.doclet.Doclet#init(Locale, Reporter)}

- *

{@link Spooner#m()}

- *

Try {@link Spooner}

- *

Or a {@literal thing}.

- * @see Example.org - * @param spoon the string {@link com.sun.source.doctree.DocTree} - * @throws IllegalAccessError when something goes wrong - * @throws NullPointerException this is an error. No colon is allowed in the exception name. - * @see jdk.javadoc.doclet.Doclet#init(Locale, Reporter) - * @see net.sf.saxon.s9api.Processor#getConfigurationProperty(Feature) - * @return something - */ - public int testing(String spoon) { - return 7; - } - - private class Spooner { - public void m() { - - } - } -} diff --git a/sample/src/main/java/org/example/TestEnum.java b/sample/src/main/java/org/example/TestEnum.java deleted file mode 100644 index 4531fda..0000000 --- a/sample/src/main/java/org/example/TestEnum.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.example; - -/** testing - *

What is this?

- */ -public enum TestEnum { - /** is earley? - * - */ - Earley, - /** is gll? - * - */ - GLL -} diff --git a/sample/src/main/java/org/example/TestInterface.java b/sample/src/main/java/org/example/TestInterface.java deleted file mode 100644 index 8460da8..0000000 --- a/sample/src/main/java/org/example/TestInterface.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.example; - -/** A test interface. - * @author John Bigboote - * @author Someone else - */ -public interface TestInterface { - void foo(); - - /** - * This is a bar. - *

See also {@link #foo()}.

- */ - void bar(); - void baz(); -} diff --git a/sample/src/main/java/org/example/package-info.java b/sample/src/main/java/org/example/package-info.java deleted file mode 100644 index ebdb27e..0000000 --- a/sample/src/main/java/org/example/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -/** - *

This description is a mistake.

- *

The first sentence should not be in a "p" element.

- */ -package org.example; \ No newline at end of file diff --git a/xmldoclet/src/main/java/com/saxonica/xmldoclet/XmlDoclet.java b/xmldoclet/src/main/java/com/saxonica/xmldoclet/XmlDoclet.java index 1061d0a..5d96187 100644 --- a/xmldoclet/src/main/java/com/saxonica/xmldoclet/XmlDoclet.java +++ b/xmldoclet/src/main/java/com/saxonica/xmldoclet/XmlDoclet.java @@ -26,7 +26,6 @@ public class XmlDoclet implements Doclet { private String windowtitle; /** Passed by Gradle; ignored. */ private boolean notimestamp; - private List sourcepath = null; private final Set