Skip to content

Commit

Permalink
8288660: JavaDoc should be more helpful if it doesn't recognize a tag
Browse files Browse the repository at this point in the history
Reviewed-by: jjg
  • Loading branch information
pavelrappo committed Sep 6, 2023
1 parent ba1a463 commit a01b3fb
Show file tree
Hide file tree
Showing 12 changed files with 213 additions and 32 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -1174,13 +1174,17 @@ public void printMessage(Diagnostic.Kind kind, CharSequence msg,
printMessage(kind, msg, ((DCTree) t).pos((DCDocComment) c), root);
}

public void printMessage(Diagnostic.Kind kind, CharSequence msg) {
printMessage(kind, msg, (JCDiagnostic.DiagnosticPosition) null, null);
}

private void printMessage(Diagnostic.Kind kind, CharSequence msg,
JCDiagnostic.DiagnosticPosition pos,
com.sun.source.tree.CompilationUnitTree root) {
JavaFileObject oldSource = null;
JavaFileObject newSource = null;

newSource = root.getSourceFile();
newSource = root == null ? null : root.getSourceFile();
if (newSource == null) {
pos = null;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
import jdk.javadoc.internal.doclets.toolkit.Resources;
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
import jdk.javadoc.internal.doclint.DocLint;

import static com.sun.source.doctree.DocTree.Kind.AUTHOR;
import static com.sun.source.doctree.DocTree.Kind.EXCEPTION;
Expand Down Expand Up @@ -123,13 +124,6 @@ public class TagletManager {
*/
private final Set<String> standardTags;

/**
* Keep track of standard tags in lowercase to compare for better
* error messages when a tag like {@code @docRoot} is mistakenly spelled
* lowercase {@code @docroot}.
*/
private final Set<String> standardTagsLowercase;

/**
* Keep track of overridden standard tags.
*/
Expand Down Expand Up @@ -185,7 +179,6 @@ public TagletManager(HtmlConfiguration config) {
overriddenStandardTags = new HashSet<>();
potentiallyConflictingTags = new HashSet<>();
standardTags = new HashSet<>();
standardTagsLowercase = new HashSet<>();
unseenCustomTags = new HashSet<>();
allTaglets = new LinkedHashMap<>();
this.config = config;
Expand Down Expand Up @@ -363,10 +356,12 @@ public void checkTags(Element element, Iterable<? extends DocTree> trees) {
if (!allTaglets.containsKey(name)) {
if (!config.isDocLintSyntaxGroupEnabled()) {
var ch = utils.getCommentHelper(element);
if (standardTagsLowercase.contains(Utils.toLowerCase(name))) {
messages.warning(ch.getDocTreePath(tag), "doclet.UnknownTagLowercase", ch.getTagName(tag));
List<String> suggestions = DocLint.suggestSimilar(allTaglets.keySet(), name);
if (!suggestions.isEmpty()) {
messages.warning(ch.getDocTreePath(tag), "doclet.UnknownTagWithHint",
String.join(", ", suggestions)); // TODO: revisit after 8041488
} else {
messages.warning(ch.getDocTreePath(tag), "doclet.UnknownTag", ch.getTagName(tag));
messages.warning(ch.getDocTreePath(tag), "doclet.UnknownTag");
}
}
continue; // unknown tag
Expand Down Expand Up @@ -660,15 +655,13 @@ private void addStandardTaglet(Taglet taglet) {
String name = taglet.getName();
allTaglets.put(name, taglet);
standardTags.add(name);
standardTagsLowercase.add(Utils.toLowerCase(name));
}

private void addStandardTaglet(Taglet taglet, DocTree.Kind alias) {
addStandardTaglet(taglet);
String name = alias.tagName;
allTaglets.put(name, taglet);
standardTags.add(name);
standardTagsLowercase.add(Utils.toLowerCase(name));
}

public boolean isKnownCustomTag(String tagName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,8 @@ doclet.Since=Since:
doclet.Throws=Throws:
doclet.Version=Version:
doclet.Factory=Factory:
doclet.UnknownTag={0} is an unknown tag.
doclet.UnknownTagLowercase={0} is an unknown tag -- same as a known tag except for case.
doclet.UnknownTag=unknown tag. Unregistered custom tag?
doclet.UnknownTagWithHint=unknown tag. Mistyped @{0} or an unregistered custom tag?
doclet.inheritDocBadSupertype=cannot find the overridden method
doclet.inheritDocWithinInappropriateTag=@inheritDoc cannot be used within this tag
doclet.inheritDocNoDoc=overridden methods do not document exception type {0}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1147,8 +1147,15 @@ private void checkUnknownTag(DocTree tree, String tagName) {
|| k == DocTree.Kind.UNKNOWN_INLINE_TAG;
assert !getStandardTags().contains(tagName);
// report an unknown tag only if custom tags are set, see 8314213
if (env.customTags != null && !env.customTags.contains(tagName))
env.messages.error(SYNTAX, tree, "dc.tag.unknown", tagName);
if (env.customTags != null && !env.customTags.contains(tagName)) {
var suggestions = DocLint.suggestSimilar(env.customTags, tagName);
if (suggestions.isEmpty()) {
env.messages.error(SYNTAX, tree, "dc.unknown.javadoc.tag");
} else {
env.messages.error(SYNTAX, tree, "dc.unknown.javadoc.tag.with.hint",
String.join(", ", suggestions)); // TODO: revisit after 8041488
}
}
}

private Set<String> getStandardTags() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -29,6 +29,8 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
Expand Down Expand Up @@ -61,6 +63,7 @@
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.DefinedBy;
import com.sun.tools.javac.util.DefinedBy.Api;
import com.sun.tools.javac.util.StringUtils.DamerauLevenshteinDistance;

/**
* Multi-function entry point for the doc check utility.
Expand Down Expand Up @@ -373,6 +376,29 @@ public void reportStats(PrintWriter out) {
Env env;
Checker checker;

public static List<String> suggestSimilar(Collection<String> knownTags, String unknownTag) {
final double MIN_SIMILARITY = 2.0 / 3;
record Pair(String tag, double similarity) { }
return knownTags.stream()
.distinct() // filter duplicates in known, otherwise they will result in duplicates in suggested
.map(t -> new Pair(t, similarity(t, unknownTag)))
.sorted(Comparator.comparingDouble(Pair::similarity).reversed() /* more similar first */)
// .peek(p -> System.out.printf("%.3f, (%s ~ %s)%n", p.similarity, p.tag, unknownTag)) // debug
.takeWhile(p -> Double.compare(p.similarity, MIN_SIMILARITY) >= 0)
.map(Pair::tag)
.toList();
}

// a value in [0, 1] range: the closer the value is to 1, the more similar
// the strings are
private static double similarity(String a, String b) {
// Normalize the distance so that similarity between "x" and "y" is
// less than that of "ax" and "ay". Use the greater of two lengths
// as normalizer, as it's an upper bound for the distance.
return 1.0 - ((double) DamerauLevenshteinDistance.of(a, b))
/ Math.max(a.length(), b.length());
}

public boolean isValidOption(String opt) {
if (opt.equals(XMSGS_OPTION))
return true;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -41,6 +41,7 @@

import com.sun.source.doctree.DocTree;
import com.sun.source.tree.Tree;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.util.StringUtils;
import jdk.javadoc.internal.doclint.Env.AccessKind;

Expand Down Expand Up @@ -96,6 +97,10 @@ void warning(Group group, DocTree tree, String code, Object... args) {
report(group, Diagnostic.Kind.WARNING, tree, code, args);
}

void note(Group group, String code, Object... args) {
report(group, Diagnostic.Kind.NOTE, code, args);
}

void setOptions(String opts) {
options.setOptions(opts);
}
Expand All @@ -112,6 +117,18 @@ void reportStats(PrintWriter out) {
stats.report(out);
}

protected void report(Group group, Diagnostic.Kind dkind, String code, Object... args) {
if (options.isEnabled(group, env.currAccess)) {
if (dkind == Diagnostic.Kind.WARNING && env.suppressWarnings(group)) {
return;
}
String msg = (code == null) ? (String) args[0] : localize(code, args);
((JavacTrees) env.trees).printMessage(dkind, msg);

stats.record(group, dkind, code);
}
}

protected void report(Group group, Diagnostic.Kind dkind, DocTree tree, String code, Object... args) {
if (options.isEnabled(group, env.currAccess)) {
if (dkind == Diagnostic.Kind.WARNING && env.suppressWarnings(group)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -84,6 +84,8 @@ dc.tag.p.in.pre= unexpected use of <p> inside <pre> element
dc.tag.requires.heading = heading not found for </{0}>
dc.tag.self.closing = self-closing element not allowed
dc.tag.start.unmatched = end tag missing: </{0}>
dc.unknown.javadoc.tag = unknown tag. Unregistered custom tag?
dc.unknown.javadoc.tag.with.hint = unknown tag. Mistyped @{0} or an unregistered custom tag?
dc.tag.unknown = unknown tag: {0}
dc.tag.not.supported.html5 = tag not supported in HTML5: {0}
dc.text.not.allowed = text not allowed in <{0}> element
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -664,7 +664,7 @@ public void testNegativeInlineTagUnknownTag(Path base) throws IOException {
"-sourcepath", srcDir.toString(),
"pkg");
checkExit(Exit.ERROR);
long actual = Pattern.compile("error: unknown tag: snippet:")
long actual = Pattern.compile("error: unknown tag. Mistyped @snippet")
.matcher(getOutput(Output.OUT)).results().count();
checking("Number of errors");
int expected = unknownTags.size();
Expand Down

1 comment on commit a01b3fb

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.