diff --git a/langtools/make/build.properties b/langtools/make/build.properties
index c1ab362490c..912342dcabc 100644
--- a/langtools/make/build.properties
+++ b/langtools/make/build.properties
@@ -68,7 +68,7 @@ javac.no.jdk.warnings = -XDignore.symbol.file=true
# set the following to -version to verify the versions of javac being used
javac.version.opt =
# in time, there should be no exceptions to -Xlint:all
-javac.lint.opts = -Xlint:all,-deprecation -Werror
+javac.lint.opts = -Xlint:all -Werror
# options for the task for javac
#javadoc.jls3.url=http://java.sun.com/docs/books/jls/
@@ -117,7 +117,8 @@ javac.includes = \
javax/lang/model/ \
javax/tools/ \
com/sun/source/ \
- com/sun/tools/javac/
+ com/sun/tools/javac/ \
+ com/sun/tools/doclint/
javac.tests = \
tools/javac
diff --git a/langtools/src/share/classes/com/sun/javadoc/ClassDoc.java b/langtools/src/share/classes/com/sun/javadoc/ClassDoc.java
index 8eda69b4bdd..bf05b418ddd 100644
--- a/langtools/src/share/classes/com/sun/javadoc/ClassDoc.java
+++ b/langtools/src/share/classes/com/sun/javadoc/ClassDoc.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2012, 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
@@ -65,6 +65,12 @@ public interface ClassDoc extends ProgramElementDoc, Type {
*/
boolean isExternalizable();
+ /**
+ * Return true if this class can be used as a target type of a lambda expression
+ * or method reference.
+ */
+ boolean isFunctionalInterface();
+
/**
* Return the serialization methods for this class or
* interface.
diff --git a/langtools/src/share/classes/com/sun/javadoc/MethodDoc.java b/langtools/src/share/classes/com/sun/javadoc/MethodDoc.java
index 16b678e3590..83bc03f1487 100644
--- a/langtools/src/share/classes/com/sun/javadoc/MethodDoc.java
+++ b/langtools/src/share/classes/com/sun/javadoc/MethodDoc.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2012, 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
@@ -38,6 +38,11 @@ public interface MethodDoc extends ExecutableMemberDoc {
*/
boolean isAbstract();
+ /**
+ * Return true if this method is default
+ */
+ boolean isDefault();
+
/**
* Get return type.
*
diff --git a/langtools/src/share/classes/com/sun/source/util/DocTrees.java b/langtools/src/share/classes/com/sun/source/util/DocTrees.java
index 68abf3f5de3..a2f6635df75 100644
--- a/langtools/src/share/classes/com/sun/source/util/DocTrees.java
+++ b/langtools/src/share/classes/com/sun/source/util/DocTrees.java
@@ -45,9 +45,7 @@ public abstract class DocTrees extends Trees {
* @throws IllegalArgumentException if the task does not support the Trees API.
*/
public static DocTrees instance(CompilationTask task) {
- if (!task.getClass().getName().equals("com.sun.tools.javac.api.JavacTaskImpl"))
- throw new IllegalArgumentException();
- return (DocTrees) getJavacTrees(CompilationTask.class, task);
+ return (DocTrees) Trees.instance(task);
}
/**
diff --git a/langtools/src/share/classes/com/sun/source/util/JavacTask.java b/langtools/src/share/classes/com/sun/source/util/JavacTask.java
index c1acc05b93b..7cd9a279dc5 100644
--- a/langtools/src/share/classes/com/sun/source/util/JavacTask.java
+++ b/langtools/src/share/classes/com/sun/source/util/JavacTask.java
@@ -139,6 +139,7 @@ public abstract class JavacTask implements CompilationTask {
* @see com.sun.source.util.Trees#getTypeMirror
*/
public abstract TypeMirror getTypeMirror(Iterable extends Tree> path);
+
/**
* Get a utility object for dealing with program elements.
*/
diff --git a/langtools/src/share/classes/com/sun/source/util/Plugin.java b/langtools/src/share/classes/com/sun/source/util/Plugin.java
index 66886aa8dec..0b500f31c84 100644
--- a/langtools/src/share/classes/com/sun/source/util/Plugin.java
+++ b/langtools/src/share/classes/com/sun/source/util/Plugin.java
@@ -56,9 +56,9 @@ public interface Plugin {
String getName();
/**
- * Invoke the plug-in for a given compilation task.
+ * Initialize the plug-in for a given compilation task.
* @param task The compilation task that has just been started
* @param args Arguments, if any, for the plug-in
*/
- void call(JavacTask task, String... args);
+ void init(JavacTask task, String... args);
}
diff --git a/langtools/src/share/classes/com/sun/source/util/TreePath.java b/langtools/src/share/classes/com/sun/source/util/TreePath.java
index eef400abc2e..a150e67e7c9 100644
--- a/langtools/src/share/classes/com/sun/source/util/TreePath.java
+++ b/langtools/src/share/classes/com/sun/source/util/TreePath.java
@@ -60,14 +60,20 @@ public class TreePath implements Iterable {
this.path = path;
}
}
+
class PathFinder extends TreePathScanner {
public TreePath scan(Tree tree, Tree target) {
- if (tree == target)
+ if (tree == target) {
throw new Result(new TreePath(getCurrentPath(), target));
+ }
return super.scan(tree, target);
}
}
+ if (path.getLeaf() == target) {
+ return path;
+ }
+
try {
new PathFinder().scan(path, target);
} catch (Result result) {
diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractMemberWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractMemberWriter.java
index 3ea59576fb6..b11d255e565 100644
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractMemberWriter.java
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractMemberWriter.java
@@ -239,7 +239,14 @@ public abstract class AbstractMemberWriter {
if ((member.isField() || member.isMethod()) &&
writer instanceof ClassWriterImpl &&
((ClassWriterImpl) writer).getClassDoc().isInterface()) {
- mod = Util.replaceText(mod, "public", "").trim();
+ // This check for isDefault() and the default modifier needs to be
+ // added for it to appear on the method details section. Once the
+ // default modifier is added to the Modifier list on DocEnv and once
+ // it is updated to use the javax.lang.model.element.Modifier, we
+ // will need to remove this.
+ mod = (member.isMethod() && ((MethodDoc)member).isDefault()) ?
+ Util.replaceText(mod, "public", "default").trim() :
+ Util.replaceText(mod, "public", "").trim();
}
if(mod.length() > 0) {
htmltree.addContent(mod);
@@ -313,8 +320,18 @@ public abstract class AbstractMemberWriter {
code.addContent(configuration.getText("doclet.Package_private"));
code.addContent(" ");
}
- if (member.isMethod() && ((MethodDoc)member).isAbstract()) {
- code.addContent("abstract ");
+ if (member.isMethod()) {
+ if (((MethodDoc)member).isAbstract()) {
+ code.addContent("abstract ");
+ }
+ // This check for isDefault() and the default modifier needs to be
+ // added for it to appear on the "Modifier and Type" column in the
+ // method summary section. Once the default modifier is added
+ // to the Modifier list on DocEnv and once it is updated to use the
+ // javax.lang.model.element.Modifier, we will need to remove this.
+ else if (((MethodDoc)member).isDefault()) {
+ code.addContent("default ");
+ }
}
if (member.isStatic()) {
code.addContent("static ");
@@ -547,6 +564,9 @@ public abstract class AbstractMemberWriter {
methodType = (classdoc.isInterface() || ((MethodDoc)member).isAbstract()) ?
methodType | MethodTypes.ABSTRACT.value() :
methodType | MethodTypes.CONCRETE.value();
+ if (((MethodDoc)member).isDefault()) {
+ methodType = methodType | MethodTypes.DEFAULT.value();
+ }
if (Util.isDeprecated(member) || Util.isDeprecated(classdoc)) {
methodType = methodType | MethodTypes.DEPRECATED.value();
}
diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassWriterImpl.java
index 06ac230dc27..809f00f8e59 100644
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassWriterImpl.java
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassWriterImpl.java
@@ -513,6 +513,20 @@ public class ClassWriterImpl extends SubWriterHolderWriter
}
}
+ /**
+ * {@inheritDoc}
+ */
+ public void addFunctionalInterfaceInfo (Content classInfoTree) {
+ if (classDoc.isFunctionalInterface()) {
+ Content dt = HtmlTree.DT(getResource("doclet.Functional_Interface"));
+ Content dl = HtmlTree.DL(dt);
+ Content dd = new HtmlTree(HtmlTag.DD);
+ dd.addContent(getResource("doclet.Functional_Interface_Message"));
+ dl.addContent(dd);
+ classInfoTree.addContent(dl);
+ }
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties
index 9dedf79fc52..7e6df8bc55c 100644
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties
@@ -90,6 +90,8 @@ doclet.in_interface=in interface
doclet.Subclasses=Direct Known Subclasses:
doclet.Subinterfaces=All Known Subinterfaces:
doclet.Implementing_Classes=All Known Implementing Classes:
+doclet.Functional_Interface=Functional Interface:
+doclet.Functional_Interface_Message=This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.
doclet.also=also
doclet.Frames=Frames
doclet.No_Frames=No Frames
diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/ClassWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/ClassWriter.java
index f5904b3aef3..c0a991e2196 100644
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/ClassWriter.java
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/ClassWriter.java
@@ -116,6 +116,13 @@ public interface ClassWriter {
*/
public void addInterfaceUsageInfo(Content classInfoTree);
+ /**
+ * If this is an functional interface, display appropriate message.
+ *
+ * @param classInfoTree content tree to which the documentation will be added
+ */
+ public void addFunctionalInterfaceInfo(Content classInfoTree);
+
/**
* If this is an inner class or interface, add the enclosing class or
* interface.
diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/ClassBuilder.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/ClassBuilder.java
index 1f2e82a10ad..efc9d563473 100644
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/ClassBuilder.java
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/ClassBuilder.java
@@ -235,6 +235,16 @@ public class ClassBuilder extends AbstractBuilder {
writer.addInterfaceUsageInfo(classInfoTree);
}
+ /**
+ * If this is an functional interface, display appropriate message.
+ *
+ * @param node the XML element that specifies which components to document
+ * @param classInfoTree the content tree to which the documentation will be added
+ */
+ public void buildFunctionalInterfaceInfo(XMLNode node, Content classInfoTree) {
+ writer.addFunctionalInterfaceInfo(classInfoTree);
+ }
+
/**
* If this class is deprecated, build the appropriate information.
*
diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclet.xml b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclet.xml
index a39cea10843..ce4472e9624 100644
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclet.xml
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclet.xml
@@ -85,6 +85,7 @@
+
diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/MethodTypes.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/MethodTypes.java
index d1211fc1c91..7b31ad81f04 100644
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/MethodTypes.java
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/MethodTypes.java
@@ -36,7 +36,8 @@ public enum MethodTypes {
INSTANCE(0x2, "Instance Methods", "t2", false),
ABSTRACT(0x4, "Abstract Methods", "t3", false),
CONCRETE(0x8, "Concrete Methods", "t4", false),
- DEPRECATED(0x10, "Deprecated Methods", "t5", false);
+ DEFAULT(0x10, "Default Methods", "t5", false),
+ DEPRECATED(0x20, "Deprecated Methods", "t6", false);
private final int value;
private final String text;
diff --git a/langtools/src/share/classes/com/sun/tools/doclint/Checker.java b/langtools/src/share/classes/com/sun/tools/doclint/Checker.java
new file mode 100644
index 00000000000..26a9cf1904d
--- /dev/null
+++ b/langtools/src/share/classes/com/sun/tools/doclint/Checker.java
@@ -0,0 +1,754 @@
+/*
+ * Copyright (c) 2012, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.doclint;
+
+import java.util.regex.Matcher;
+import com.sun.source.doctree.LinkTree;
+import java.net.URI;
+import java.util.regex.Pattern;
+import java.io.IOException;
+import com.sun.tools.javac.tree.DocPretty;
+import java.io.StringWriter;
+import java.util.Deque;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.tools.Diagnostic.Kind;
+
+import com.sun.source.doctree.AttributeTree;
+import com.sun.source.doctree.AuthorTree;
+import com.sun.source.doctree.DocCommentTree;
+import com.sun.source.doctree.DocTree;
+import com.sun.source.doctree.EndElementTree;
+import com.sun.source.doctree.EntityTree;
+import com.sun.source.doctree.ErroneousTree;
+import com.sun.source.doctree.IdentifierTree;
+import com.sun.source.doctree.InheritDocTree;
+import com.sun.source.doctree.ParamTree;
+import com.sun.source.doctree.ReferenceTree;
+import com.sun.source.doctree.ReturnTree;
+import com.sun.source.doctree.SerialDataTree;
+import com.sun.source.doctree.SerialFieldTree;
+import com.sun.source.doctree.SinceTree;
+import com.sun.source.doctree.StartElementTree;
+import com.sun.source.doctree.TextTree;
+import com.sun.source.doctree.ThrowsTree;
+import com.sun.source.doctree.VersionTree;
+import com.sun.source.util.DocTreeScanner;
+import com.sun.source.util.TreePath;
+import com.sun.tools.doclint.HtmlTag.AttrKind;
+import java.net.URISyntaxException;
+import static com.sun.tools.doclint.Messages.Group.*;
+
+
+/**
+ * Validate a doc comment.
+ *
+ *
This is NOT part of any supported API.
+ * If you write code that depends on this, you do so at your own
+ * risk. This code and its internal interfaces are subject to change
+ * or deletion without notice.
+ */
+public class Checker extends DocTreeScanner {
+ final Env env;
+
+ Set foundParams = new HashSet();
+ Set foundThrows = new HashSet();
+ Set foundAnchors = new HashSet();
+ boolean foundInheritDoc = false;
+ boolean foundReturn = false;
+
+ enum Flag {
+ TABLE_HAS_CAPTION,
+ HAS_ELEMENT,
+ HAS_TEXT
+ }
+
+ static class TagStackItem {
+ final DocTree tree; // typically, but not always, StartElementTree
+ final HtmlTag tag;
+ final Set attrs;
+ final Set flags;
+ TagStackItem(DocTree tree, HtmlTag tag) {
+ this.tree = tree;
+ this.tag = tag;
+ attrs = EnumSet.noneOf(HtmlTag.Attr.class);
+ flags = EnumSet.noneOf(Flag.class);
+ }
+ @Override
+ public String toString() {
+ return String.valueOf(tag);
+ }
+ }
+
+ private Deque tagStack; // TODO: maybe want to record starting tree as well
+ private HtmlTag currHeaderTag;
+
+ //
+
+ Checker(Env env) {
+ env.getClass();
+ this.env = env;
+ tagStack = new LinkedList();
+ }
+
+ public Void scan(DocCommentTree tree, TreePath p) {
+ env.setCurrent(p, tree);
+
+ boolean isOverridingMethod = !env.currOverriddenMethods.isEmpty();
+
+ if (tree == null) {
+ if (!isSynthetic() && !isOverridingMethod)
+ reportMissing("dc.missing.comment");
+ return null;
+ }
+
+ tagStack.clear();
+ currHeaderTag = null;
+
+ foundParams.clear();
+ foundThrows.clear();
+ foundInheritDoc = false;
+ foundReturn = false;
+
+ scan(tree, (Void) null);
+
+ if (!isOverridingMethod) {
+ switch (env.currElement.getKind()) {
+ case METHOD:
+ case CONSTRUCTOR: {
+ ExecutableElement ee = (ExecutableElement) env.currElement;
+ checkParamsDocumented(ee.getTypeParameters());
+ checkParamsDocumented(ee.getParameters());
+ switch (ee.getReturnType().getKind()) {
+ case VOID:
+ case NONE:
+ break;
+ default:
+ if (!foundReturn
+ && !foundInheritDoc
+ && !env.types.isSameType(ee.getReturnType(), env.java_lang_Void)) {
+ reportMissing("dc.missing.return");
+ }
+ }
+ checkThrowsDocumented(ee.getThrownTypes());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private void reportMissing(String code, Object... args) {
+ env.messages.report(MISSING, Kind.WARNING, env.currPath.getLeaf(), code, args);
+ }
+
+ @Override
+ public Void visitDocComment(DocCommentTree tree, Void ignore) {
+ super.visitDocComment(tree, ignore);
+ for (TagStackItem tsi: tagStack) {
+ if (tsi.tree.getKind() == DocTree.Kind.START_ELEMENT
+ && tsi.tag.endKind == HtmlTag.EndKind.REQUIRED) {
+ StartElementTree t = (StartElementTree) tsi.tree;
+ env.messages.error(HTML, t, "dc.tag.not.closed", t.getName());
+ }
+ }
+ return null;
+ }
+ //
+
+ //
+
+ @Override
+ public Void visitText(TextTree tree, Void ignore) {
+ if (!tree.getBody().trim().isEmpty()) {
+ markEnclosingTag(Flag.HAS_TEXT);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitEntity(EntityTree tree, Void ignore) {
+ markEnclosingTag(Flag.HAS_TEXT);
+ String name = tree.getName().toString();
+ if (name.startsWith("#")) {
+ int v = name.toLowerCase().startsWith("#x")
+ ? Integer.parseInt(name.substring(2), 16)
+ : Integer.parseInt(name.substring(1), 10);
+ if (!Entity.isValid(v)) {
+ env.messages.error(HTML, tree, "dc.entity.invalid", name);
+ }
+ } else if (!Entity.isValid(name)) {
+ env.messages.error(HTML, tree, "dc.entity.invalid", name);
+ }
+ return null;
+ }
+
+ //
+
+ //
+
+ @Override
+ public Void visitStartElement(StartElementTree tree, Void ignore) {
+ markEnclosingTag(Flag.HAS_ELEMENT);
+ final Name treeName = tree.getName();
+ final HtmlTag t = HtmlTag.get(treeName);
+ if (t == null) {
+ env.messages.error(HTML, tree, "dc.tag.unknown", treeName);
+ } else {
+ // tag specific checks
+ switch (t) {
+ // check for out of sequence headers, such as
...
...
+ case H1: case H2: case H3: case H4: case H5: case H6:
+ checkHeader(tree, t);
+ break;
+ //
inside
+ case P:
+ TagStackItem top = tagStack.peek();
+ if (top != null && top.tag == HtmlTag.PRE)
+ env.messages.warning(HTML, tree, "dc.tag.p.in.pre");
+ break;
+ }
+
+ // check that only block tags and inline tags are used,
+ // and that blocks tags are not used within inline tags
+ switch (t.blockType) {
+ case INLINE:
+ break;
+ case BLOCK:
+ TagStackItem top = tagStack.peek();
+ if (top != null && top.tag != null && top.tag.blockType == HtmlTag.BlockType.INLINE) {
+ switch (top.tree.getKind()) {
+ case START_ELEMENT: {
+ Name name = ((StartElementTree) top.tree).getName();
+ env.messages.error(HTML, tree, "dc.tag.not.allowed.inline.element",
+ treeName, name);
+ break;
+ }
+ case LINK:
+ case LINK_PLAIN: {
+ String name = top.tree.getKind().tagName;
+ env.messages.error(HTML, tree, "dc.tag.not.allowed.inline.tag",
+ treeName, name);
+ break;
+ }
+ default:
+ env.messages.error(HTML, tree, "dc.tag.not.allowed.inline.other",
+ treeName);
+ }
+ }
+ break;
+ case OTHER:
+ env.messages.error(HTML, tree, "dc.tag.not.allowed", treeName);
+ break;
+ default:
+ throw new AssertionError();
+ }
+
+ if (t.flags.contains(HtmlTag.Flag.NO_NEST)) {
+ for (TagStackItem i: tagStack) {
+ if (t == i.tag) {
+ env.messages.warning(HTML, tree, "dc.tag.nested.not.allowed", treeName);
+ break;
+ }
+ }
+ }
+ }
+
+ // check for self closing tags, such as
+ if (tree.isSelfClosing()) {
+ env.messages.error(HTML, tree, "dc.tag.self.closing", treeName);
+ }
+
+ try {
+ TagStackItem parent = tagStack.peek();
+ TagStackItem top = new TagStackItem(tree, t);
+ tagStack.push(top);
+
+ super.visitStartElement(tree, ignore);
+
+ // handle attributes that may or may not have been found in start element
+ if (t != null) {
+ switch (t) {
+ case CAPTION:
+ if (parent != null && parent.tag == HtmlTag.TABLE)
+ parent.flags.add(Flag.TABLE_HAS_CAPTION);
+ break;
+
+ case IMG:
+ if (!top.attrs.contains(HtmlTag.Attr.ALT))
+ env.messages.error(ACCESSIBILITY, tree, "dc.no.alt.attr.for.image");
+ break;
+ }
+ }
+
+ return null;
+ } finally {
+
+ if (t == null || t.endKind == HtmlTag.EndKind.NONE)
+ tagStack.pop();
+ }
+ }
+
+ private void checkHeader(StartElementTree tree, HtmlTag tag) {
+ // verify the new tag
+ if (getHeaderLevel(tag) > getHeaderLevel(currHeaderTag) + 1) {
+ if (currHeaderTag == null) {
+ env.messages.error(ACCESSIBILITY, tree, "dc.tag.header.sequence.1", tag);
+ } else {
+ env.messages.error(ACCESSIBILITY, tree, "dc.tag.header.sequence.2",
+ tag, currHeaderTag);
+ }
+ }
+
+ currHeaderTag = tag;
+ }
+
+ private int getHeaderLevel(HtmlTag tag) {
+ if (tag == null)
+ return 0;
+ switch (tag) {
+ case H1: return 1;
+ case H2: return 2;
+ case H3: return 3;
+ case H4: return 4;
+ case H5: return 5;
+ case H6: return 6;
+ default: throw new IllegalArgumentException();
+ }
+ }
+
+ @Override
+ public Void visitEndElement(EndElementTree tree, Void ignore) {
+ final Name treeName = tree.getName();
+ final HtmlTag t = HtmlTag.get(treeName);
+ if (t == null) {
+ env.messages.error(HTML, tree, "dc.tag.unknown", treeName);
+ } else if (t.endKind == HtmlTag.EndKind.NONE) {
+ env.messages.error(HTML, tree, "dc.tag.end.not.permitted", treeName);
+ } else if (tagStack.isEmpty()) {
+ env.messages.error(HTML, tree, "dc.tag.end.unexpected", treeName);
+ } else {
+ while (!tagStack.isEmpty()) {
+ TagStackItem top = tagStack.peek();
+ if (t == top.tag) {
+ switch (t) {
+ case TABLE:
+ if (!top.attrs.contains(HtmlTag.Attr.SUMMARY)
+ && !top.flags.contains(Flag.TABLE_HAS_CAPTION)) {
+ env.messages.error(ACCESSIBILITY, tree,
+ "dc.no.summary.or.caption.for.table");
+ }
+ }
+ if (t.flags.contains(HtmlTag.Flag.EXPECT_CONTENT)
+ && !top.flags.contains(Flag.HAS_TEXT)
+ && !top.flags.contains(Flag.HAS_ELEMENT)) {
+ env.messages.warning(HTML, tree, "dc.tag.empty", treeName);
+ }
+ if (t.flags.contains(HtmlTag.Flag.NO_TEXT)
+ && top.flags.contains(Flag.HAS_TEXT)) {
+ env.messages.error(HTML, tree, "dc.text.not.allowed", treeName);
+ }
+ tagStack.pop();
+ break;
+ } else if (top.tag == null || top.tag.endKind != HtmlTag.EndKind.REQUIRED) {
+ tagStack.pop();
+ } else {
+ boolean found = false;
+ for (TagStackItem si: tagStack) {
+ if (si.tag == t) {
+ found = true;
+ break;
+ }
+ }
+ if (found && top.tree.getKind() == DocTree.Kind.START_ELEMENT) {
+ env.messages.error(HTML, top.tree, "dc.tag.start.unmatched",
+ ((StartElementTree) top.tree).getName());
+ tagStack.pop();
+ } else {
+ env.messages.error(HTML, tree, "dc.tag.end.unexpected", treeName);
+ break;
+ }
+ }
+ }
+ }
+
+ return super.visitEndElement(tree, ignore);
+ }
+ //
+
+ //
+
+ @Override @SuppressWarnings("fallthrough")
+ public Void visitAttribute(AttributeTree tree, Void ignore) {
+ HtmlTag currTag = tagStack.peek().tag;
+ if (currTag != null) {
+ Name name = tree.getName();
+ HtmlTag.Attr attr = currTag.getAttr(name);
+ if (attr != null) {
+ boolean first = tagStack.peek().attrs.add(attr);
+ if (!first)
+ env.messages.error(HTML, tree, "dc.attr.repeated", name);
+ }
+ AttrKind k = currTag.getAttrKind(name);
+ switch (k) {
+ case OK:
+ break;
+
+ case INVALID:
+ env.messages.error(HTML, tree, "dc.attr.unknown", name);
+ break;
+
+ case OBSOLETE:
+ env.messages.warning(ACCESSIBILITY, tree, "dc.attr.obsolete", name);
+ break;
+
+ case USE_CSS:
+ env.messages.warning(ACCESSIBILITY, tree, "dc.attr.obsolete.use.css", name);
+ break;
+ }
+
+ if (attr != null) {
+ switch (attr) {
+ case NAME:
+ if (currTag != HtmlTag.A) {
+ break;
+ }
+ // fallthrough
+ case ID:
+ String value = getAttrValue(tree);
+ if (!validName.matcher(value).matches()) {
+ env.messages.error(HTML, tree, "dc.invalid.anchor", value);
+ }
+ if (!foundAnchors.add(value)) {
+ env.messages.error(HTML, tree, "dc.anchor.already.defined", value);
+ }
+ break;
+
+ case HREF:
+ if (currTag == HtmlTag.A) {
+ String v = getAttrValue(tree);
+ if (v == null || v.isEmpty()) {
+ env.messages.error(HTML, tree, "dc.attr.lacks.value");
+ } else {
+ Matcher m = docRoot.matcher(v);
+ if (m.matches()) {
+ String rest = m.group(2);
+ if (!rest.isEmpty())
+ checkURI(tree, rest);
+ } else {
+ checkURI(tree, v);
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ // TODO: basic check on value
+
+ return super.visitAttribute(tree, ignore);
+ }
+
+ // http://www.w3.org/TR/html401/types.html#type-name
+ private static final Pattern validName = Pattern.compile("[A-Za-z][A-Za-z0-9-_:.]*");
+
+ // pattern to remove leading {@docRoot}/?
+ private static final Pattern docRoot = Pattern.compile("(?i)(\\{@docRoot *\\}/?)?(.*)");
+
+ private String getAttrValue(AttributeTree tree) {
+ if (tree.getValue() == null)
+ return null;
+
+ StringWriter sw = new StringWriter();
+ try {
+ new DocPretty(sw).print(tree.getValue());
+ } catch (IOException e) {
+ // cannot happen
+ }
+ // ignore potential use of entities for now
+ return sw.toString();
+ }
+
+ private void checkURI(AttributeTree tree, String uri) {
+ try {
+ URI u = new URI(uri);
+ } catch (URISyntaxException e) {
+ env.messages.error(HTML, tree, "dc.invalid.uri", uri);
+ }
+ }
+ //
+
+ //
+
+ @Override
+ public Void visitAuthor(AuthorTree tree, Void ignore) {
+ warnIfEmpty(tree, tree.getName());
+ return super.visitAuthor(tree, ignore);
+ }
+
+ @Override
+ public Void visitInheritDoc(InheritDocTree tree, Void ignore) {
+ // TODO: verify on overridden method
+ foundInheritDoc = true;
+ return super.visitInheritDoc(tree, ignore);
+ }
+
+ @Override
+ public Void visitLink(LinkTree tree, Void ignore) {
+ // simulate inline context on tag stack
+ HtmlTag t = (tree.getKind() == DocTree.Kind.LINK)
+ ? HtmlTag.CODE : HtmlTag.SPAN;
+ tagStack.push(new TagStackItem(tree, t));
+ try {
+ return super.visitLink(tree, ignore);
+ } finally {
+ tagStack.pop();
+ }
+ }
+
+ @Override
+ public Void visitParam(ParamTree tree, Void ignore) {
+ boolean typaram = tree.isTypeParameter();
+ IdentifierTree nameTree = tree.getName();
+ Element e = env.currElement;
+ switch (e.getKind()) {
+ case METHOD: case CONSTRUCTOR: {
+ ExecutableElement ee = (ExecutableElement) e;
+ checkParamDeclared(nameTree, typaram ? ee.getTypeParameters() : ee.getParameters());
+ break;
+ }
+
+ case CLASS: case INTERFACE: {
+ TypeElement te = (TypeElement) e;
+ if (typaram) {
+ checkParamDeclared(nameTree, te.getTypeParameters());
+ } else {
+ env.messages.error(REFERENCE, tree, "dc.invalid.param");
+ }
+ break;
+ }
+
+ default:
+ env.messages.error(REFERENCE, tree, "dc.invalid.param");
+ break;
+ }
+ warnIfEmpty(tree, tree.getDescription());
+ return super.visitParam(tree, ignore);
+ }
+ // where
+ private void checkParamDeclared(IdentifierTree nameTree, List extends Element> list) {
+ Name name = nameTree.getName();
+ boolean found = false;
+ for (Element e: list) {
+ if (name.equals(e.getSimpleName())) {
+ foundParams.add(e);
+ found = true;
+ }
+ }
+ if (!found)
+ env.messages.error(REFERENCE, nameTree, "dc.param.name.not.found");
+ }
+
+ private void checkParamsDocumented(List extends Element> list) {
+ if (foundInheritDoc)
+ return;
+
+ for (Element e: list) {
+ if (!foundParams.contains(e)) {
+ CharSequence paramName = (e.getKind() == ElementKind.TYPE_PARAMETER)
+ ? "<" + e.getSimpleName() + ">"
+ : e.getSimpleName();
+ reportMissing("dc.missing.param", paramName);
+ }
+ }
+ }
+
+ @Override
+ public Void visitReference(ReferenceTree tree, Void ignore) {
+ Element e = env.trees.getElement(env.currPath, tree);
+ if (e == null)
+ env.messages.error(REFERENCE, tree, "dc.ref.not.found");
+ return super.visitReference(tree, ignore);
+ }
+
+ @Override
+ public Void visitReturn(ReturnTree tree, Void ignore) {
+ Element e = env.trees.getElement(env.currPath);
+ if (e.getKind() != ElementKind.METHOD
+ || ((ExecutableElement) e).getReturnType().getKind() == TypeKind.VOID)
+ env.messages.error(REFERENCE, tree, "dc.invalid.return");
+ foundReturn = true;
+ warnIfEmpty(tree, tree.getDescription());
+ return super.visitReturn(tree, ignore);
+ }
+
+ @Override
+ public Void visitSerialData(SerialDataTree tree, Void ignore) {
+ warnIfEmpty(tree, tree.getDescription());
+ return super.visitSerialData(tree, ignore);
+ }
+
+ @Override
+ public Void visitSerialField(SerialFieldTree tree, Void ignore) {
+ warnIfEmpty(tree, tree.getDescription());
+ return super.visitSerialField(tree, ignore);
+ }
+
+ @Override
+ public Void visitSince(SinceTree tree, Void ignore) {
+ warnIfEmpty(tree, tree.getBody());
+ return super.visitSince(tree, ignore);
+ }
+
+ @Override
+ public Void visitThrows(ThrowsTree tree, Void ignore) {
+ ReferenceTree exName = tree.getExceptionName();
+ Element ex = env.trees.getElement(env.currPath, exName);
+ if (ex == null) {
+ env.messages.error(REFERENCE, tree, "dc.ref.not.found");
+ } else if (ex.asType().getKind() == TypeKind.DECLARED
+ && env.types.isAssignable(ex.asType(), env.java_lang_Throwable)) {
+ switch (env.currElement.getKind()) {
+ case CONSTRUCTOR:
+ case METHOD:
+ if (isCheckedException(ex.asType())) {
+ ExecutableElement ee = (ExecutableElement) env.currElement;
+ checkThrowsDeclared(exName, ex.asType(), ee.getThrownTypes());
+ }
+ break;
+ default:
+ env.messages.error(REFERENCE, tree, "dc.invalid.throws");
+ }
+ } else {
+ env.messages.error(REFERENCE, tree, "dc.invalid.throws");
+ }
+ warnIfEmpty(tree, tree.getDescription());
+ return scan(tree.getDescription(), ignore);
+ }
+
+ private void checkThrowsDeclared(ReferenceTree tree, TypeMirror t, List extends TypeMirror> list) {
+ boolean found = false;
+ for (TypeMirror tl : list) {
+ if (env.types.isAssignable(t, tl)) {
+ foundThrows.add(tl);
+ found = true;
+ }
+ }
+ if (!found)
+ env.messages.error(REFERENCE, tree, "dc.exception.not.thrown", t);
+ }
+
+ private void checkThrowsDocumented(List extends TypeMirror> list) {
+ if (foundInheritDoc)
+ return;
+
+ for (TypeMirror tl: list) {
+ if (isCheckedException(tl) && !foundThrows.contains(tl))
+ reportMissing("dc.missing.throws", tl);
+ }
+ }
+
+ @Override
+ public Void visitVersion(VersionTree tree, Void ignore) {
+ warnIfEmpty(tree, tree.getBody());
+ return super.visitVersion(tree, ignore);
+ }
+
+ @Override
+ public Void visitErroneous(ErroneousTree tree, Void ignore) {
+ env.messages.error(SYNTAX, tree, null, tree.getDiagnostic().getMessage(null));
+ return null;
+ }
+ //
+
+ //
+
+ private boolean isCheckedException(TypeMirror t) {
+ return !(env.types.isAssignable(t, env.java_lang_Error)
+ || env.types.isAssignable(t, env.java_lang_RuntimeException));
+ }
+
+ private boolean isSynthetic() {
+ switch (env.currElement.getKind()) {
+ case CONSTRUCTOR:
+ // A synthetic default constructor has the same pos as the
+ // enclosing class
+ TreePath p = env.currPath;
+ return env.getPos(p) == env.getPos(p.getParentPath());
+ }
+ return false;
+ }
+
+ void markEnclosingTag(Flag flag) {
+ TagStackItem top = tagStack.peek();
+ if (top != null)
+ top.flags.add(flag);
+ }
+
+ String toString(TreePath p) {
+ StringBuilder sb = new StringBuilder("TreePath[");
+ toString(p, sb);
+ sb.append("]");
+ return sb.toString();
+ }
+
+ void toString(TreePath p, StringBuilder sb) {
+ TreePath parent = p.getParentPath();
+ if (parent != null) {
+ toString(parent, sb);
+ sb.append(",");
+ }
+ sb.append(p.getLeaf().getKind()).append(":").append(env.getPos(p)).append(":S").append(env.getStartPos(p));
+ }
+
+ void warnIfEmpty(DocTree tree, List extends DocTree> list) {
+ for (DocTree d: list) {
+ switch (d.getKind()) {
+ case TEXT:
+ if (!((TextTree) d).getBody().trim().isEmpty())
+ return;
+ break;
+ default:
+ return;
+ }
+ }
+ env.messages.warning(SYNTAX, tree, "dc.empty", tree.getKind().tagName);
+ }
+ //
+
+}
diff --git a/langtools/src/share/classes/com/sun/tools/doclint/DocLint.java b/langtools/src/share/classes/com/sun/tools/doclint/DocLint.java
new file mode 100644
index 00000000000..20813265bf8
--- /dev/null
+++ b/langtools/src/share/classes/com/sun/tools/doclint/DocLint.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 2012, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.doclint;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.lang.model.element.Name;
+import javax.tools.StandardLocation;
+
+import com.sun.source.doctree.DocCommentTree;
+import com.sun.source.tree.ClassTree;
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.VariableTree;
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.Plugin;
+import com.sun.source.util.TaskEvent;
+import com.sun.source.util.TaskListener;
+import com.sun.source.util.TreePath;
+import com.sun.source.util.TreePathScanner;
+import com.sun.tools.javac.api.JavacTaskImpl;
+import com.sun.tools.javac.api.JavacTool;
+import com.sun.tools.javac.file.JavacFileManager;
+import com.sun.tools.javac.main.JavaCompiler;
+import com.sun.tools.javac.util.Context;
+
+/**
+ * Multi-function entry point for the doc check utility.
+ *
+ * This class can be invoked in the following ways:
+ *
+ *
From the command line
+ *
From javac, as a plugin
+ *
Directly, via a simple API
+ *
+ *
+ *
This is NOT part of any supported API.
+ * If you write code that depends on this, you do so at your own
+ * risk. This code and its internal interfaces are subject to change
+ * or deletion without notice.
+ */
+public class DocLint implements Plugin {
+
+ public static final String XMSGS_OPTION = "-Xmsgs";
+ public static final String XMSGS_CUSTOM_PREFIX = "-Xmsgs:";
+ private static final String STATS = "-stats";
+
+ //
+ public static void main(String... args) {
+ try {
+ new DocLint().run(args);
+ } catch (BadArgs e) {
+ System.err.println(e.getMessage());
+ System.exit(1);
+ } catch (IOException e) {
+ System.err.println(e);
+ System.exit(2);
+ }
+ }
+
+ //
+
+ //
+
+ public static class BadArgs extends Exception {
+ private static final long serialVersionUID = 0;
+ BadArgs(String code, Object... args) {
+ this.code = code;
+ this.args = args;
+ }
+
+ final String code;
+ final Object[] args;
+ }
+
+ /**
+ * Simple API entry point.
+ */
+ public void run(String... args) throws BadArgs, IOException {
+ PrintWriter out = new PrintWriter(System.out);
+ try {
+ run(out, args);
+ } finally {
+ out.flush();
+ }
+ }
+
+ public void run(PrintWriter out, String... args) throws BadArgs, IOException {
+ env = new Env();
+ processArgs(args);
+
+ if (needHelp)
+ showHelp(out);
+
+ if (javacFiles.isEmpty()) {
+ if (!needHelp)
+ System.out.println("no files given");
+ }
+
+ JavacTool tool = JavacTool.create();
+
+ JavacFileManager fm = new JavacFileManager(new Context(), false, null);
+ fm.setSymbolFileEnabled(false);
+ fm.setLocation(StandardLocation.PLATFORM_CLASS_PATH, javacBootClassPath);
+ fm.setLocation(StandardLocation.CLASS_PATH, javacClassPath);
+ fm.setLocation(StandardLocation.SOURCE_PATH, javacSourcePath);
+
+ JavacTask task = tool.getTask(out, fm, null, javacOpts, null,
+ fm.getJavaFileObjectsFromFiles(javacFiles));
+ Iterable extends CompilationUnitTree> units = task.parse();
+ ((JavacTaskImpl) task).enter();
+
+ env.init(task);
+ checker = new Checker(env);
+
+ DeclScanner ds = new DeclScanner() {
+ @Override
+ void visitDecl(Tree tree, Name name) {
+ TreePath p = getCurrentPath();
+ DocCommentTree dc = env.trees.getDocCommentTree(p);
+
+ checker.scan(dc, p);
+ }
+ };
+
+ ds.scan(units, null);
+
+ reportStats(out);
+
+ Context ctx = ((JavacTaskImpl) task).getContext();
+ JavaCompiler c = JavaCompiler.instance(ctx);
+ c.printCount("error", c.errorCount());
+ c.printCount("warn", c.warningCount());
+ }
+
+ void processArgs(String... args) throws BadArgs {
+ javacOpts = new ArrayList();
+ javacFiles = new ArrayList();
+
+ if (args.length == 0)
+ needHelp = true;
+
+ for (int i = 0; i < args.length; i++) {
+ String arg = args[i];
+ if (arg.matches("-Xmax(errs|warns)") && i + 1 < args.length) {
+ if (args[++i].matches("[0-9]+")) {
+ javacOpts.add(arg);
+ javacOpts.add(args[i]);
+ } else {
+ throw new BadArgs("dc.bad.value.for.option", arg, args[i]);
+ }
+ } else if (arg.equals(STATS)) {
+ env.messages.setStatsEnabled(true);
+ } else if (arg.matches("-bootclasspath") && i + 1 < args.length) {
+ javacBootClassPath = splitPath(args[++i]);
+ } else if (arg.matches("-classpath") && i + 1 < args.length) {
+ javacClassPath = splitPath(args[++i]);
+ } else if (arg.matches("-sourcepath") && i + 1 < args.length) {
+ javacSourcePath = splitPath(args[++i]);
+ } else if (arg.equals(XMSGS_OPTION)) {
+ env.messages.setOptions(null);
+ } else if (arg.startsWith(XMSGS_CUSTOM_PREFIX)) {
+ env.messages.setOptions(arg.substring(arg.indexOf(":") + 1));
+ } else if (arg.equals("-h") || arg.equals("-help") || arg.equals("--help")
+ || arg.equals("-?") || arg.equals("-usage")) {
+ needHelp = true;
+ } else if (arg.startsWith("-")) {
+ throw new BadArgs("dc.bad.option", arg);
+ } else {
+ while (i < args.length)
+ javacFiles.add(new File(args[i++]));
+ }
+ }
+ }
+
+ void showHelp(PrintWriter out) {
+ out.println("Usage:");
+ out.println(" doclint [options] source-files...");
+ out.println("");
+ out.println("Options:");
+ out.println(" -Xmsgs ");
+ out.println(" Same as -Xmsgs:all");
+ out.println(" -Xmsgs:values");
+ out.println(" Specify categories of issues to be checked, where 'values'");
+ out.println(" is a comma-separated list of any of the following:");
+ out.println(" reference show places where comments contain incorrect");
+ out.println(" references to Java source code elements");
+ out.println(" syntax show basic syntax errors within comments");
+ out.println(" html show issues with HTML tags and attributes");
+ out.println(" accessibility show issues for accessibility");
+ out.println(" missing show issues with missing documentation");
+ out.println(" all all of the above");
+ out.println(" Precede a value with '-' to negate it");
+ out.println(" Categories may be qualified by one of:");
+ out.println(" /public /protected /package /private");
+ out.println(" For positive categories (not beginning with '-')");
+ out.println(" the qualifier applies to that access level and above.");
+ out.println(" For negative categories (beginning with '-')");
+ out.println(" the qualifier applies to that access level and below.");
+ out.println(" If a qualifier is missing, the category applies to");
+ out.println(" all access levels.");
+ out.println(" For example, -Xmsgs:all,-syntax/private");
+ out.println(" This will enable all messages, except syntax errors");
+ out.println(" in the doc comments of private methods.");
+ out.println(" If no -Xmsgs options are provided, the default is");
+ out.println(" equivalent to -Xmsgs:all/protected, meaning that");
+ out.println(" all messages are reported for protected and public");
+ out.println(" declarations only. ");
+ out.println(" -h -help --help -usage -?");
+ out.println(" Show this message.");
+ out.println("");
+ out.println("The following javac options are also supported");
+ out.println(" -bootclasspath, -classpath, -sourcepath, -Xmaxerrs, -Xmaxwarns");
+ out.println("");
+ out.println("To run doclint on part of a project, put the compiled classes for your");
+ out.println("project on the classpath (or bootclasspath), then specify the source files");
+ out.println("to be checked on the command line.");
+ }
+
+ List splitPath(String path) {
+ List files = new ArrayList();
+ for (String f: path.split(File.separator)) {
+ if (f.length() > 0)
+ files.add(new File(f));
+ }
+ return files;
+ }
+
+ List javacBootClassPath;
+ List javacClassPath;
+ List javacSourcePath;
+ List javacOpts;
+ List javacFiles;
+ boolean needHelp = false;
+
+ //
+
+ //
+
+ @Override
+ public String getName() {
+ return "doclint";
+ }
+
+ @Override
+ public void init(JavacTask task, String... args) {
+ init(task, args, true);
+ }
+
+ //
+
+ //
+
+ public void init(JavacTask task, String[] args, boolean addTaskListener) {
+ env = new Env();
+ for (int i = 0; i < args.length; i++) {
+ String arg = args[i];
+ if (arg.equals(XMSGS_OPTION)) {
+ env.messages.setOptions(null);
+ } else if (arg.startsWith(XMSGS_CUSTOM_PREFIX)) {
+ env.messages.setOptions(arg.substring(arg.indexOf(":") + 1));
+ } else
+ throw new IllegalArgumentException(arg);
+ }
+ env.init(task);
+
+ checker = new Checker(env);
+
+ if (addTaskListener) {
+ final DeclScanner ds = new DeclScanner() {
+ @Override
+ void visitDecl(Tree tree, Name name) {
+ TreePath p = getCurrentPath();
+ DocCommentTree dc = env.trees.getDocCommentTree(p);
+
+ checker.scan(dc, p);
+ }
+ };
+
+ TaskListener tl = new TaskListener() {
+ @Override
+ public void started(TaskEvent e) {
+ return;
+ }
+
+ @Override
+ public void finished(TaskEvent e) {
+ switch (e.getKind()) {
+ case ENTER:
+ ds.scan(e.getCompilationUnit(), null);
+ }
+ }
+ };
+
+ task.addTaskListener(tl);
+ }
+ }
+
+ public void scan(TreePath p) {
+ DocCommentTree dc = env.trees.getDocCommentTree(p);
+ checker.scan(dc, p);
+ }
+
+ public void reportStats(PrintWriter out) {
+ env.messages.reportStats(out);
+ }
+
+ //
+
+ Env env;
+ Checker checker;
+
+ public static boolean isValidOption(String opt) {
+ if (opt.equals(XMSGS_OPTION))
+ return true;
+ if (opt.startsWith(XMSGS_CUSTOM_PREFIX))
+ return Messages.Options.isValidOptions(opt.substring(XMSGS_CUSTOM_PREFIX.length()));
+ return false;
+ }
+
+ //
+
+ static abstract class DeclScanner extends TreePathScanner {
+ abstract void visitDecl(Tree tree, Name name);
+
+ @Override
+ public Void visitClass(ClassTree tree, Void ignore) {
+ visitDecl(tree, tree.getSimpleName());
+ return super.visitClass(tree, ignore);
+ }
+
+ @Override
+ public Void visitMethod(MethodTree tree, Void ignore) {
+ visitDecl(tree, tree.getName());
+ //return super.visitMethod(tree, ignore);
+ return null;
+ }
+
+ @Override
+ public Void visitVariable(VariableTree tree, Void ignore) {
+ visitDecl(tree, tree.getName());
+ return super.visitVariable(tree, ignore);
+ }
+ }
+
+ //
+
+}
diff --git a/langtools/src/share/classes/com/sun/tools/doclint/Entity.java b/langtools/src/share/classes/com/sun/tools/doclint/Entity.java
new file mode 100644
index 00000000000..24c192e8a58
--- /dev/null
+++ b/langtools/src/share/classes/com/sun/tools/doclint/Entity.java
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2012, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.doclint;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Table of entities defined in HTML 4.01.
+ *
+ *
Derived from
+ * Character entity references in HTML 4.
+ *
+ * The name of the member follows the name of the entity,
+ * except when it clashes with a keyword, in which case
+ * it is prefixed by '_'.
+ *
+ *
This is NOT part of any supported API.
+ * If you write code that depends on this, you do so at your own
+ * risk. This code and its internal interfaces are subject to change
+ * or deletion without notice.
+ */
+enum Entity {
+ nbsp(160),
+ iexcl(161),
+ cent(162),
+ pound(163),
+ curren(164),
+ yen(165),
+ brvbar(166),
+ sect(167),
+ uml(168),
+ copy(169),
+ ordf(170),
+ laquo(171),
+ not(172),
+ shy(173),
+ reg(174),
+ macr(175),
+ deg(176),
+ plusmn(177),
+ sup2(178),
+ sup3(179),
+ acute(180),
+ micro(181),
+ para(182),
+ middot(183),
+ cedil(184),
+ sup1(185),
+ ordm(186),
+ raquo(187),
+ frac14(188),
+ frac12(189),
+ frac34(190),
+ iquest(191),
+ Agrave(192),
+ Aacute(193),
+ Acirc(194),
+ Atilde(195),
+ Auml(196),
+ Aring(197),
+ AElig(198),
+ Ccedil(199),
+ Egrave(200),
+ Eacute(201),
+ Ecirc(202),
+ Euml(203),
+ Igrave(204),
+ Iacute(205),
+ Icirc(206),
+ Iuml(207),
+ ETH(208),
+ Ntilde(209),
+ Ograve(210),
+ Oacute(211),
+ Ocirc(212),
+ Otilde(213),
+ Ouml(214),
+ times(215),
+ Oslash(216),
+ Ugrave(217),
+ Uacute(218),
+ Ucirc(219),
+ Uuml(220),
+ Yacute(221),
+ THORN(222),
+ szlig(223),
+ agrave(224),
+ aacute(225),
+ acirc(226),
+ atilde(227),
+ auml(228),
+ aring(229),
+ aelig(230),
+ ccedil(231),
+ egrave(232),
+ eacute(233),
+ ecirc(234),
+ euml(235),
+ igrave(236),
+ iacute(237),
+ icirc(238),
+ iuml(239),
+ eth(240),
+ ntilde(241),
+ ograve(242),
+ oacute(243),
+ ocirc(244),
+ otilde(245),
+ ouml(246),
+ divide(247),
+ oslash(248),
+ ugrave(249),
+ uacute(250),
+ ucirc(251),
+ uuml(252),
+ yacute(253),
+ thorn(254),
+ yuml(255),
+ fnof(402),
+ Alpha(913),
+ Beta(914),
+ Gamma(915),
+ Delta(916),
+ Epsilon(917),
+ Zeta(918),
+ Eta(919),
+ Theta(920),
+ Iota(921),
+ Kappa(922),
+ Lambda(923),
+ Mu(924),
+ Nu(925),
+ Xi(926),
+ Omicron(927),
+ Pi(928),
+ Rho(929),
+ Sigma(931),
+ Tau(932),
+ Upsilon(933),
+ Phi(934),
+ Chi(935),
+ Psi(936),
+ Omega(937),
+ alpha(945),
+ beta(946),
+ gamma(947),
+ delta(948),
+ epsilon(949),
+ zeta(950),
+ eta(951),
+ theta(952),
+ iota(953),
+ kappa(954),
+ lambda(955),
+ mu(956),
+ nu(957),
+ xi(958),
+ omicron(959),
+ pi(960),
+ rho(961),
+ sigmaf(962),
+ sigma(963),
+ tau(964),
+ upsilon(965),
+ phi(966),
+ chi(967),
+ psi(968),
+ omega(969),
+ thetasym(977),
+ upsih(978),
+ piv(982),
+ bull(8226),
+ hellip(8230),
+ prime(8242),
+ Prime(8243),
+ oline(8254),
+ frasl(8260),
+ weierp(8472),
+ image(8465),
+ real(8476),
+ trade(8482),
+ alefsym(8501),
+ larr(8592),
+ uarr(8593),
+ rarr(8594),
+ darr(8595),
+ harr(8596),
+ crarr(8629),
+ lArr(8656),
+ uArr(8657),
+ rArr(8658),
+ dArr(8659),
+ hArr(8660),
+ forall(8704),
+ part(8706),
+ exist(8707),
+ empty(8709),
+ nabla(8711),
+ isin(8712),
+ notin(8713),
+ ni(8715),
+ prod(8719),
+ sum(8721),
+ minus(8722),
+ lowast(8727),
+ radic(8730),
+ prop(8733),
+ infin(8734),
+ ang(8736),
+ and(8743),
+ or(8744),
+ cap(8745),
+ cup(8746),
+ _int(8747),
+ there4(8756),
+ sim(8764),
+ cong(8773),
+ asymp(8776),
+ ne(8800),
+ equiv(8801),
+ le(8804),
+ ge(8805),
+ sub(8834),
+ sup(8835),
+ nsub(8836),
+ sube(8838),
+ supe(8839),
+ oplus(8853),
+ otimes(8855),
+ perp(8869),
+ sdot(8901),
+ lceil(8968),
+ rceil(8969),
+ lfloor(8970),
+ rfloor(8971),
+ lang(9001),
+ rang(9002),
+ loz(9674),
+ spades(9824),
+ clubs(9827),
+ hearts(9829),
+ diams(9830),
+ quot(34),
+ amp(38),
+ lt(60),
+ gt(62),
+ OElig(338),
+ oelig(339),
+ Scaron(352),
+ scaron(353),
+ Yuml(376),
+ circ(710),
+ tilde(732),
+ ensp(8194),
+ emsp(8195),
+ thinsp(8201),
+ zwnj(8204),
+ zwj(8205),
+ lrm(8206),
+ rlm(8207),
+ ndash(8211),
+ mdash(8212),
+ lsquo(8216),
+ rsquo(8217),
+ sbquo(8218),
+ ldquo(8220),
+ rdquo(8221),
+ bdquo(8222),
+ dagger(8224),
+ Dagger(8225),
+ permil(8240),
+ lsaquo(8249),
+ rsaquo(8250),
+ euro(8364);
+
+ int code;
+
+ private Entity(int code) {
+ this.code = code;
+ }
+
+ static boolean isValid(String name) {
+ return names.containsKey(name);
+ }
+
+ static boolean isValid(int code) {
+ // allow numeric codes for standard ANSI characters
+ return codes.containsKey(code) || ( 32 <= code && code < 2127);
+ }
+
+ private static final Map names = new HashMap();
+ private static final Map codes = new HashMap();
+ static {
+ for (Entity e: values()) {
+ String name = e.name();
+ int code = e.code;
+ if (name.startsWith("_")) name = name.substring(1);
+ names.put(name, e);
+ codes.put(code, e);
+ }
+ }
+}
diff --git a/langtools/src/share/classes/com/sun/tools/doclint/Env.java b/langtools/src/share/classes/com/sun/tools/doclint/Env.java
new file mode 100644
index 00000000000..12947f02b0e
--- /dev/null
+++ b/langtools/src/share/classes/com/sun/tools/doclint/Env.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2012, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.doclint;
+
+
+import java.util.Set;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+
+import com.sun.source.doctree.DocCommentTree;
+import com.sun.source.util.DocTrees;
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.SourcePositions;
+import com.sun.source.util.TreePath;
+import com.sun.tools.javac.model.JavacTypes;
+import com.sun.tools.javac.tree.JCTree;
+
+/**
+ * Utility container for current execution environment,
+ * providing the current declaration and its doc comment.
+ *
+ *
This is NOT part of any supported API.
+ * If you write code that depends on this, you do so at your own
+ * risk. This code and its internal interfaces are subject to change
+ * or deletion without notice.
+ */
+public class Env {
+ /**
+ * Access kinds for declarations.
+ */
+ public enum AccessKind {
+ PRIVATE,
+ PACKAGE,
+ PROTECTED,
+ PUBLIC;
+
+ static boolean accepts(String opt) {
+ for (AccessKind g: values())
+ if (opt.equals(g.name().toLowerCase())) return true;
+ return false;
+ }
+
+ static AccessKind of(Set mods) {
+ if (mods.contains(Modifier.PUBLIC))
+ return AccessKind.PUBLIC;
+ else if (mods.contains(Modifier.PROTECTED))
+ return AccessKind.PROTECTED;
+ else if (mods.contains(Modifier.PRIVATE))
+ return AccessKind.PRIVATE;
+ else
+ return AccessKind.PACKAGE;
+ }
+ };
+
+ /** Message handler. */
+ final Messages messages;
+
+ // Utility classes
+ DocTrees trees;
+ Elements elements;
+ Types types;
+
+ // Types used when analysing doc comments.
+ TypeMirror java_lang_Error;
+ TypeMirror java_lang_RuntimeException;
+ TypeMirror java_lang_Throwable;
+ TypeMirror java_lang_Void;
+
+ /** The path for the declaration containing the comment currently being analyzed. */
+ TreePath currPath;
+ /** The element for the declaration containing the comment currently being analyzed. */
+ Element currElement;
+ /** The comment current being analyzed. */
+ DocCommentTree currDocComment;
+ /**
+ * The access kind of the declaration containing the comment currently being analyzed.
+ * This is the minimum (most restrictive) access kind of the declaration iteself
+ * and that of its containers. For example, a public method in a private class is
+ * noted as private.
+ */
+ AccessKind currAccess;
+ /** The set of methods, if any, that the current declaration overrides. */
+ Set extends ExecutableElement> currOverriddenMethods;
+
+ Env() {
+ messages = new Messages(this);
+ }
+
+ void init(JavacTask task) {
+ init(DocTrees.instance(task), task.getElements(), task.getTypes());
+ }
+
+ void init(DocTrees trees, Elements elements, Types types) {
+ this.trees = trees;
+ this.elements = elements;
+ this.types = types;
+ java_lang_Error = elements.getTypeElement("java.lang.Error").asType();
+ java_lang_RuntimeException = elements.getTypeElement("java.lang.RuntimeException").asType();
+ java_lang_Throwable = elements.getTypeElement("java.lang.Throwable").asType();
+ java_lang_Void = elements.getTypeElement("java.lang.Void").asType();
+ }
+
+ /** Set the current declaration and its doc comment. */
+ void setCurrent(TreePath path, DocCommentTree comment) {
+ currPath = path;
+ currDocComment = comment;
+ currElement = trees.getElement(currPath);
+ currOverriddenMethods = ((JavacTypes) types).getOverriddenMethods(currElement);
+
+ AccessKind ak = null;
+ for (TreePath p = path; p != null; p = p.getParentPath()) {
+ Element e = trees.getElement(p);
+ if (e != null) {
+ ak = min(ak, AccessKind.of(e.getModifiers()));
+ }
+ }
+ currAccess = ak;
+ }
+
+ AccessKind getAccessKind() {
+ return currAccess;
+ }
+
+ long getPos(TreePath p) {
+ return ((JCTree) p.getLeaf()).pos;
+ }
+
+ long getStartPos(TreePath p) {
+ SourcePositions sp = trees.getSourcePositions();
+ return sp.getStartPosition(p.getCompilationUnit(), p.getLeaf());
+ }
+
+ private > T min(T item1, T item2) {
+ return (item1 == null) ? item2
+ : (item2 == null) ? item1
+ : item1.compareTo(item2) <= 0 ? item1 : item2;
+ }
+}
diff --git a/langtools/src/share/classes/com/sun/tools/doclint/HtmlTag.java b/langtools/src/share/classes/com/sun/tools/doclint/HtmlTag.java
new file mode 100644
index 00000000000..e21d400f067
--- /dev/null
+++ b/langtools/src/share/classes/com/sun/tools/doclint/HtmlTag.java
@@ -0,0 +1,356 @@
+/*
+ * Copyright (c) 2010, 2012, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.doclint;
+
+import java.util.Set;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.lang.model.element.Name;
+
+import static com.sun.tools.doclint.HtmlTag.Attr.*;
+
+/**
+ * Enum representing HTML tags.
+ *
+ * The intent of this class is to embody the semantics of W3C HTML 4.01
+ * to the extent supported/used by javadoc.
+ *
+ * This is derivative of com.sun.tools.doclets.formats.html.markup.HtmlTag.
+ * Eventually, these two should be merged back together, and possibly made
+ * public.
+ *
+ * @see HTML 4.01 Specification
+ * @author Bhavesh Patel
+ * @author Jonathan Gibbons (revised)
+ */
+public enum HtmlTag {
+ A(BlockType.INLINE, EndKind.REQUIRED,
+ attrs(AttrKind.OK, HREF, TARGET, NAME)),
+
+ B(BlockType.INLINE, EndKind.REQUIRED,
+ EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
+
+ BLOCKQUOTE,
+
+ BODY(BlockType.OTHER, EndKind.REQUIRED),
+
+ BR(BlockType.INLINE, EndKind.NONE,
+ attrs(AttrKind.USE_CSS, CLEAR)),
+
+ CAPTION(EnumSet.of(Flag.EXPECT_CONTENT)),
+
+ CENTER,
+
+ CITE(BlockType.INLINE, EndKind.REQUIRED,
+ EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
+
+ CODE(BlockType.INLINE, EndKind.REQUIRED,
+ EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
+
+ DD(BlockType.BLOCK, EndKind.OPTIONAL,
+ EnumSet.of(Flag.EXPECT_CONTENT)),
+
+ DIV,
+
+ DL(BlockType.BLOCK, EndKind.REQUIRED,
+ EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_TEXT),
+ attrs(AttrKind.USE_CSS, COMPACT)),
+
+ DT(BlockType.BLOCK, EndKind.OPTIONAL,
+ EnumSet.of(Flag.EXPECT_CONTENT)),
+
+ EM(BlockType.INLINE, EndKind.REQUIRED,
+ EnumSet.of(Flag.NO_NEST)),
+
+ FONT(BlockType.INLINE, EndKind.REQUIRED, // tag itself is deprecated
+ EnumSet.of(Flag.EXPECT_CONTENT),
+ attrs(AttrKind.USE_CSS, SIZE, COLOR, FACE)),
+
+ FRAME(BlockType.OTHER, EndKind.NONE),
+
+ FRAMESET(BlockType.OTHER, EndKind.REQUIRED),
+
+ H1,
+ H2,
+ H3,
+ H4,
+ H5,
+ H6,
+
+ HEAD(BlockType.OTHER, EndKind.REQUIRED),
+
+ HR(BlockType.BLOCK, EndKind.NONE),
+
+ HTML(BlockType.OTHER, EndKind.REQUIRED),
+
+ I(BlockType.INLINE, EndKind.REQUIRED,
+ EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
+
+ IMG(BlockType.INLINE, EndKind.NONE,
+ attrs(AttrKind.OK, SRC, ALT, HEIGHT, WIDTH),
+ attrs(AttrKind.OBSOLETE, NAME),
+ attrs(AttrKind.USE_CSS, ALIGN, HSPACE, VSPACE, BORDER)),
+
+ LI(BlockType.BLOCK, EndKind.OPTIONAL),
+
+ LINK(BlockType.OTHER, EndKind.NONE),
+
+ MENU,
+
+ META(BlockType.OTHER, EndKind.NONE),
+
+ NOFRAMES(BlockType.OTHER, EndKind.REQUIRED),
+
+ NOSCRIPT(BlockType.OTHER, EndKind.REQUIRED),
+
+ OL(BlockType.BLOCK, EndKind.REQUIRED,
+ EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_TEXT),
+ attrs(AttrKind.USE_CSS, START, TYPE)),
+
+ P(BlockType.BLOCK, EndKind.OPTIONAL,
+ EnumSet.of(Flag.EXPECT_CONTENT),
+ attrs(AttrKind.USE_CSS, ALIGN)),
+
+ PRE(EnumSet.of(Flag.EXPECT_CONTENT)),
+
+ SCRIPT(BlockType.OTHER, EndKind.REQUIRED),
+
+ SMALL(BlockType.INLINE, EndKind.REQUIRED),
+
+ SPAN(BlockType.INLINE, EndKind.REQUIRED,
+ EnumSet.of(Flag.EXPECT_CONTENT)),
+
+ STRONG(BlockType.INLINE, EndKind.REQUIRED,
+ EnumSet.of(Flag.EXPECT_CONTENT)),
+
+ SUB(BlockType.INLINE, EndKind.REQUIRED,
+ EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
+
+ SUP(BlockType.INLINE, EndKind.REQUIRED,
+ EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
+
+ TABLE(BlockType.BLOCK, EndKind.REQUIRED,
+ EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_TEXT),
+ attrs(AttrKind.OK, SUMMARY, Attr.FRAME, RULES, BORDER,
+ CELLPADDING, CELLSPACING),
+ attrs(AttrKind.USE_CSS, ALIGN, WIDTH, BGCOLOR)),
+
+ TBODY(BlockType.BLOCK, EndKind.REQUIRED,
+ EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_TEXT),
+ attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN)),
+
+ TD(BlockType.BLOCK, EndKind.OPTIONAL,
+ attrs(AttrKind.OK, COLSPAN, ROWSPAN, HEADERS, SCOPE, ABBR, AXIS,
+ ALIGN, CHAR, CHAROFF, VALIGN),
+ attrs(AttrKind.USE_CSS, WIDTH, BGCOLOR, HEIGHT, NOWRAP)),
+
+ TFOOT(BlockType.BLOCK, EndKind.REQUIRED,
+ attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN)),
+
+ TH(BlockType.BLOCK, EndKind.OPTIONAL,
+ attrs(AttrKind.OK, COLSPAN, ROWSPAN, HEADERS, SCOPE, ABBR, AXIS,
+ ALIGN, CHAR, CHAROFF, VALIGN),
+ attrs(AttrKind.USE_CSS, WIDTH, BGCOLOR, HEIGHT, NOWRAP)),
+
+ THEAD(BlockType.BLOCK, EndKind.REQUIRED,
+ attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN)),
+
+ TITLE(BlockType.OTHER, EndKind.REQUIRED),
+
+ TR(BlockType.BLOCK, EndKind.OPTIONAL,
+ EnumSet.of(Flag.NO_TEXT),
+ attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN),
+ attrs(AttrKind.USE_CSS, BGCOLOR)),
+
+ TT(BlockType.INLINE, EndKind.REQUIRED,
+ EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
+
+ U(BlockType.INLINE, EndKind.REQUIRED,
+ EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
+
+ UL(BlockType.BLOCK, EndKind.REQUIRED,
+ EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_TEXT),
+ attrs(AttrKind.USE_CSS, COMPACT, TYPE)),
+
+ VAR(BlockType.INLINE, EndKind.REQUIRED);
+
+ /**
+ * Enum representing the type of HTML element.
+ */
+ public static enum BlockType {
+ BLOCK,
+ INLINE,
+ OTHER;
+ }
+
+ /**
+ * Enum representing HTML end tag requirement.
+ */
+ public static enum EndKind {
+ NONE,
+ OPTIONAL,
+ REQUIRED;
+ }
+
+ public static enum Flag {
+ EXPECT_CONTENT,
+ NO_NEST,
+ NO_TEXT
+ }
+
+ public static enum Attr {
+ ABBR,
+ ALIGN,
+ ALT,
+ AXIS,
+ BGCOLOR,
+ BORDER,
+ CELLSPACING,
+ CELLPADDING,
+ CHAR,
+ CHAROFF,
+ CLEAR,
+ CLASS,
+ COLOR,
+ COLSPAN,
+ COMPACT,
+ FACE,
+ FRAME,
+ HEADERS,
+ HEIGHT,
+ HREF,
+ HSPACE,
+ ID,
+ NAME,
+ NOWRAP,
+ REVERSED,
+ ROWSPAN,
+ RULES,
+ SCOPE,
+ SIZE,
+ SPACE,
+ SRC,
+ START,
+ STYLE,
+ SUMMARY,
+ TARGET,
+ TYPE,
+ VALIGN,
+ VSPACE,
+ WIDTH;
+
+ public String getText() {
+ return name().toLowerCase();
+ }
+
+ static final Map index = new HashMap();
+ static {
+ for (Attr t: values()) {
+ index.put(t.name().toLowerCase(), t);
+ }
+ }
+ }
+
+ public static enum AttrKind {
+ INVALID,
+ OBSOLETE,
+ USE_CSS,
+ OK
+ }
+
+ // This class exists to avoid warnings from using parameterized vararg type
+ // Map in signature of HtmlTag constructor.
+ private static class AttrMap extends EnumMap {
+ private static final long serialVersionUID = 0;
+ AttrMap() {
+ super(Attr.class);
+ }
+ }
+
+
+ public final BlockType blockType;
+ public final EndKind endKind;
+ public final Set flags;
+ private final Map attrs;
+
+
+ HtmlTag() {
+ this(BlockType.BLOCK, EndKind.REQUIRED);
+ }
+
+ HtmlTag(Set flags) {
+ this(BlockType.BLOCK, EndKind.REQUIRED, flags);
+ }
+
+ HtmlTag(BlockType blockType, EndKind endKind, AttrMap... attrMaps) {
+ this(blockType, endKind, Collections.emptySet(), attrMaps);
+ }
+
+ HtmlTag(BlockType blockType, EndKind endKind, Set flags, AttrMap... attrMaps) {
+ this.blockType = blockType;
+ this.endKind = endKind;this.flags = flags;
+ this.attrs = new EnumMap(Attr.class);
+ for (Map m: attrMaps)
+ this.attrs.putAll(m);
+ attrs.put(Attr.CLASS, AttrKind.OK);
+ attrs.put(Attr.ID, AttrKind.OK);
+ attrs.put(Attr.STYLE, AttrKind.OK);
+ }
+
+ public String getText() {
+ return name().toLowerCase();
+ }
+
+ public Attr getAttr(Name attrName) {
+ return Attr.index.get(attrName.toString().toLowerCase());
+ }
+
+ public AttrKind getAttrKind(Name attrName) {
+ AttrKind k = attrs.get(getAttr(attrName)); // null-safe
+ return (k == null) ? AttrKind.INVALID : k;
+ }
+
+ private static AttrMap attrs(AttrKind k, Attr... attrs) {
+ AttrMap map = new AttrMap();
+ for (Attr a: attrs) map.put(a, k);
+ return map;
+ }
+
+ private static final Map index = new HashMap();
+ static {
+ for (HtmlTag t: values()) {
+ index.put(t.name().toLowerCase(), t);
+ }
+ }
+
+ static HtmlTag get(Name tagName) {
+ return index.get(tagName.toString().toLowerCase());
+ }
+}
diff --git a/langtools/src/share/classes/com/sun/tools/doclint/Messages.java b/langtools/src/share/classes/com/sun/tools/doclint/Messages.java
new file mode 100644
index 00000000000..cfa397d349e
--- /dev/null
+++ b/langtools/src/share/classes/com/sun/tools/doclint/Messages.java
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2012, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.doclint;
+
+import java.io.PrintWriter;
+import java.text.MessageFormat;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import javax.tools.Diagnostic;
+
+import com.sun.source.doctree.DocTree;
+import com.sun.source.tree.Tree;
+import com.sun.tools.doclint.Env.AccessKind;
+
+/**
+ * Message reporting for DocLint.
+ *
+ * Options are used to filter out messages based on group and access level.
+ * Support can be enabled for accumulating statistics of different kinds of
+ * messages.
+ *
+ *
This is NOT part of any supported API.
+ * If you write code that depends on this, you do so at your own
+ * risk. This code and its internal interfaces are subject to change
+ * or deletion without notice.
+ */
+public class Messages {
+ /**
+ * Groups used to categorize messages, so that messages in each group
+ * can be enabled or disabled via options.
+ */
+ public enum Group {
+ ACCESSIBILITY,
+ HTML,
+ MISSING,
+ SYNTAX,
+ REFERENCE;
+
+ String optName() { return name().toLowerCase(); }
+ String notOptName() { return "-" + optName(); }
+
+ static boolean accepts(String opt) {
+ for (Group g: values())
+ if (opt.equals(g.optName())) return true;
+ return false;
+ }
+ };
+
+ private final Options options;
+ private final Stats stats;
+
+ ResourceBundle bundle;
+ Env env;
+
+ Messages(Env env) {
+ this.env = env;
+ String name = getClass().getPackage().getName() + ".resources.doclint";
+ bundle = ResourceBundle.getBundle(name, Locale.ENGLISH);
+
+ stats = new Stats(bundle);
+ options = new Options(stats);
+ }
+
+ void error(Group group, DocTree tree, String code, Object... args) {
+ report(group, Diagnostic.Kind.ERROR, tree, code, args);
+ }
+
+ void warning(Group group, DocTree tree, String code, Object... args) {
+ report(group, Diagnostic.Kind.WARNING, tree, code, args);
+ }
+
+ void setOptions(String opts) {
+ options.setOptions(opts);
+ }
+
+ void setStatsEnabled(boolean b) {
+ stats.setEnabled(b);
+ }
+
+ void reportStats(PrintWriter out) {
+ stats.report(out);
+ }
+
+ protected void report(Group group, Diagnostic.Kind dkind, DocTree tree, String code, Object... args) {
+ if (options.isEnabled(group, env.currAccess)) {
+ String msg = (code == null) ? (String) args[0] : localize(code, args);
+ env.trees.printMessage(dkind, msg, tree,
+ env.currDocComment, env.currPath.getCompilationUnit());
+
+ stats.record(group, dkind, code);
+ }
+ }
+
+ protected void report(Group group, Diagnostic.Kind dkind, Tree tree, String code, Object... args) {
+ if (options.isEnabled(group, env.currAccess)) {
+ String msg = localize(code, args);
+ env.trees.printMessage(dkind, msg, tree, env.currPath.getCompilationUnit());
+
+ stats.record(group, dkind, code);
+ }
+ }
+
+ String localize(String code, Object... args) {
+ String msg = bundle.getString(code);
+ if (msg == null) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("message file broken: code=").append(code);
+ if (args.length > 0) {
+ sb.append(" arguments={0}");
+ for (int i = 1; i < args.length; i++) {
+ sb.append(", {").append(i).append("}");
+ }
+ }
+ msg = sb.toString();
+ }
+ return MessageFormat.format(msg, args);
+ }
+
+ //
+
+ /**
+ * Handler for (sub)options specific to message handling.
+ */
+ static class Options {
+ Map map = new HashMap();
+ private final Stats stats;
+
+ static boolean isValidOptions(String opts) {
+ for (String opt: opts.split(",")) {
+ if (!isValidOption(opt.trim().toLowerCase()))
+ return false;
+ }
+ return true;
+ }
+
+ private static boolean isValidOption(String opt) {
+ if (opt.equals("none") || opt.equals(Stats.OPT))
+ return true;
+
+ int begin = opt.startsWith("-") ? 1 : 0;
+ int sep = opt.indexOf("/");
+ String grp = opt.substring(begin, (sep != -1) ? sep : opt.length());
+ return ((begin == 0 && grp.equals("all")) || Group.accepts(grp))
+ && ((sep == -1) || AccessKind.accepts(opt.substring(sep + 1)));
+ }
+
+ Options(Stats stats) {
+ this.stats = stats;
+ }
+
+ /** Determine if a message group is enabled for a particular access level. */
+ boolean isEnabled(Group g, Env.AccessKind access) {
+ if (map.isEmpty())
+ map.put("all", Env.AccessKind.PROTECTED);
+
+ Env.AccessKind ak = map.get(g.optName());
+ if (ak != null && access.compareTo(ak) >= 0)
+ return true;
+
+ ak = map.get(ALL);
+ if (ak != null && access.compareTo(ak) >= 0) {
+ ak = map.get(g.notOptName());
+ if (ak == null || access.compareTo(ak) > 0) // note >, not >=
+ return true;
+ }
+
+ return false;
+ }
+
+ void setOptions(String opts) {
+ if (opts == null)
+ setOption(ALL, Env.AccessKind.PRIVATE);
+ else {
+ for (String opt: opts.split(","))
+ setOption(opt.trim().toLowerCase());
+ }
+ }
+
+ private void setOption(String arg) throws IllegalArgumentException {
+ if (arg.equals(Stats.OPT)) {
+ stats.setEnabled(true);
+ return;
+ }
+
+ int sep = arg.indexOf("/");
+ if (sep > 0) {
+ Env.AccessKind ak = Env.AccessKind.valueOf(arg.substring(sep + 1).toUpperCase());
+ setOption(arg.substring(0, sep), ak);
+ } else {
+ setOption(arg, null);
+ }
+ }
+
+ private void setOption(String opt, Env.AccessKind ak) {
+ map.put(opt, (ak != null) ? ak
+ : opt.startsWith("-") ? Env.AccessKind.PUBLIC : Env.AccessKind.PRIVATE);
+ }
+
+ private static final String ALL = "all";
+ }
+
+ //
+
+ //
+
+ /**
+ * Optionally record statistics of different kinds of message.
+ */
+ static class Stats {
+ public static final String OPT = "stats";
+ public static final String NO_CODE = "";
+ final ResourceBundle bundle;
+
+ // tables only initialized if enabled
+ int[] groupCounts;
+ int[] dkindCounts;
+ Map codeCounts;
+
+ Stats(ResourceBundle bundle) {
+ this.bundle = bundle;
+ }
+
+ void setEnabled(boolean b) {
+ if (b) {
+ groupCounts = new int[Messages.Group.values().length];
+ dkindCounts = new int[Diagnostic.Kind.values().length];
+ codeCounts = new HashMap();
+ } else {
+ groupCounts = null;
+ dkindCounts = null;
+ codeCounts = null;
+ }
+ }
+
+ void record(Messages.Group g, Diagnostic.Kind dkind, String code) {
+ if (codeCounts == null) {
+ return;
+ }
+ groupCounts[g.ordinal()]++;
+ dkindCounts[dkind.ordinal()]++;
+ if (code == null) {
+ code = NO_CODE;
+ }
+ Integer i = codeCounts.get(code);
+ codeCounts.put(code, (i == null) ? 1 : i + 1);
+ }
+
+ void report(PrintWriter out) {
+ if (codeCounts == null) {
+ return;
+ }
+ out.println("By group...");
+ Table groupTable = new Table();
+ for (Messages.Group g : Messages.Group.values()) {
+ groupTable.put(g.optName(), groupCounts[g.ordinal()]);
+ }
+ groupTable.print(out);
+ out.println();
+ out.println("By diagnostic kind...");
+ Table dkindTable = new Table();
+ for (Diagnostic.Kind k : Diagnostic.Kind.values()) {
+ dkindTable.put(k.toString().toLowerCase(), dkindCounts[k.ordinal()]);
+ }
+ dkindTable.print(out);
+ out.println();
+ out.println("By message kind...");
+ Table codeTable = new Table();
+ for (Map.Entry e : codeCounts.entrySet()) {
+ String code = e.getKey();
+ String msg;
+ try {
+ msg = code.equals(NO_CODE) ? "OTHER" : bundle.getString(code);
+ } catch (MissingResourceException ex) {
+ msg = code;
+ }
+ codeTable.put(msg, e.getValue());
+ }
+ codeTable.print(out);
+ }
+
+ /**
+ * A table of (int, String) sorted by decreasing int.
+ */
+ private static class Table {
+
+ private static final Comparator DECREASING = new Comparator() {
+
+ public int compare(Integer o1, Integer o2) {
+ return o2.compareTo(o1);
+ }
+ };
+ private final TreeMap> map = new TreeMap>(DECREASING);
+
+ void put(String label, int n) {
+ if (n == 0) {
+ return;
+ }
+ Set labels = map.get(n);
+ if (labels == null) {
+ map.put(n, labels = new TreeSet());
+ }
+ labels.add(label);
+ }
+
+ void print(PrintWriter out) {
+ for (Map.Entry> e : map.entrySet()) {
+ int count = e.getKey();
+ Set labels = e.getValue();
+ for (String label : labels) {
+ out.println(String.format("%6d: %s", count, label));
+ }
+ }
+ }
+ }
+ }
+ //
+}
diff --git a/langtools/src/share/classes/com/sun/tools/doclint/resources/doclint.properties b/langtools/src/share/classes/com/sun/tools/doclint/resources/doclint.properties
new file mode 100644
index 00000000000..e85afc92d7c
--- /dev/null
+++ b/langtools/src/share/classes/com/sun/tools/doclint/resources/doclint.properties
@@ -0,0 +1,65 @@
+#
+# Copyright (c) 2012, 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
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation. Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+dc.anchor.already.defined = anchor already defined: {0}
+dc.attr.lacks.value = attribute lacks value
+dc.attr.obsolete = attribute obsolete: {0}
+dc.attr.obsolete.use.css = attribute obsolete, use CSS instead: {0}
+dc.attr.repeated = repeated attribute: {0}
+dc.attr.unknown = unknown attribute: {0}
+dc.bad.option = bad option: {0}
+dc.bad.value.for.option = bad value for option: {0} {1}
+dc.empty = no description for @{0}
+dc.entity.invalid = invalid entity &{0};
+dc.exception.not.thrown = exception not thrown: {0}
+dc.invalid.anchor = invalid name for anchor: "{0}"
+dc.invalid.param = invalid use of @param
+dc.invalid.return = invalid use of @return
+dc.invalid.throws = invalid use of @throws
+dc.invalid.uri = invalid uri: "{0}"
+dc.missing.comment = no comment
+dc.missing.param = no @param for {0}
+dc.missing.return = no @return
+dc.missing.throws = no @throws for {0}
+dc.no.alt.attr.for.image = no "alt" attribute for image
+dc.no.summary.or.caption.for.table=no summary or caption for table
+dc.param.name.not.found = @param name not found
+dc.ref.not.found = reference not found
+dc.tag.empty = empty <{0}> tag
+dc.tag.end.not.permitted = invalid end tag: {0}>
+dc.tag.end.unexpected = unexpected end tag: {0}>
+dc.tag.header.sequence.1 = header used out of sequence: <{0}>
+dc.tag.header.sequence.2 = header used out of sequence: <{0}>
+dc.tag.nested.not.allowed=nested tag not allowed: <{0}>
+dc.tag.not.allowed = element not allowed in documentation comments: <{0}>
+dc.tag.not.allowed.inline.element = block element not allowed within inline element <{1}>: {0}
+dc.tag.not.allowed.inline.tag = block element not allowed within @{1}: {0}
+dc.tag.not.allowed.inline.other = block element not allowed here: {0}
+dc.tag.not.closed= element not closed: {0}
+dc.tag.p.in.pre= unexpected use of
inside
element
+dc.tag.self.closing = self-closing element not allowed
+dc.tag.start.unmatched = end tag missing: {0}>
+dc.tag.unknown = unknown tag: {0}
+dc.text.not.allowed = text not allowed in <{0}> element
diff --git a/langtools/src/share/classes/com/sun/tools/javac/api/BasicJavacTask.java b/langtools/src/share/classes/com/sun/tools/javac/api/BasicJavacTask.java
index 38cff74c8ca..e44bca373fc 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/api/BasicJavacTask.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/api/BasicJavacTask.java
@@ -57,6 +57,13 @@ public class BasicJavacTask extends JavacTask {
protected Context context;
private TaskListener taskListener;
+ public static JavacTask instance(Context context) {
+ JavacTask instance = context.get(JavacTask.class);
+ if (instance == null)
+ instance = new BasicJavacTask(context, true);
+ return instance;
+ }
+
public BasicJavacTask(Context c, boolean register) {
context = c;
if (register)
diff --git a/langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java b/langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java
index 4cc7075f310..fa36e1f8da7 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java
@@ -65,7 +65,6 @@ import com.sun.tools.javac.util.List;
* @author Jonathan Gibbons
*/
public class JavacTaskImpl extends BasicJavacTask {
- private ClientCodeWrapper ccw;
private Main compilerMain;
private JavaCompiler compiler;
private Locale locale;
@@ -85,7 +84,6 @@ public class JavacTaskImpl extends BasicJavacTask {
Context context,
List fileObjects) {
super(null, false);
- this.ccw = ClientCodeWrapper.instance(context);
this.compilerMain = compilerMain;
this.args = args;
this.classNames = classNames;
diff --git a/langtools/src/share/classes/com/sun/tools/javac/api/JavacTool.java b/langtools/src/share/classes/com/sun/tools/javac/api/JavacTool.java
index 0a7a4617250..d1ef9025120 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/api/JavacTool.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/api/JavacTool.java
@@ -159,7 +159,7 @@ public final class JavacTool implements JavaCompiler {
}
}
- private static void processOptions(Context context,
+ public static void processOptions(Context context,
JavaFileManager fileManager,
Iterable options)
{
diff --git a/langtools/src/share/classes/com/sun/tools/javac/api/JavacTrees.java b/langtools/src/share/classes/com/sun/tools/javac/api/JavacTrees.java
index 8a7db1f181c..490490178fb 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/api/JavacTrees.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/api/JavacTrees.java
@@ -84,6 +84,7 @@ import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.tree.TreeCopier;
import com.sun.tools.javac.tree.TreeInfo;
import com.sun.tools.javac.tree.TreeMaker;
+import com.sun.tools.javac.util.Abort;
import com.sun.tools.javac.util.Assert;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.JCDiagnostic;
@@ -236,19 +237,26 @@ public class JavacTrees extends DocTrees {
public Element getElement(TreePath path) {
JCTree tree = (JCTree) path.getLeaf();
Symbol sym = TreeInfo.symbolFor(tree);
- if (sym == null && TreeInfo.isDeclaration(tree)) {
- for (TreePath p = path; p != null; p = p.getParentPath()) {
- JCTree t = (JCTree) p.getLeaf();
- if (t.hasTag(JCTree.Tag.CLASSDEF)) {
- JCClassDecl ct = (JCClassDecl) t;
- if (ct.sym != null) {
- if ((ct.sym.flags_field & Flags.UNATTRIBUTED) != 0) {
- attr.attribClass(ct.pos(), ct.sym);
- sym = TreeInfo.symbolFor(tree);
+ if (sym == null) {
+ if (TreeInfo.isDeclaration(tree)) {
+ for (TreePath p = path; p != null; p = p.getParentPath()) {
+ JCTree t = (JCTree) p.getLeaf();
+ if (t.hasTag(JCTree.Tag.CLASSDEF)) {
+ JCClassDecl ct = (JCClassDecl) t;
+ if (ct.sym != null) {
+ if ((ct.sym.flags_field & Flags.UNATTRIBUTED) != 0) {
+ attr.attribClass(ct.pos(), ct.sym);
+ sym = TreeInfo.symbolFor(tree);
+ }
+ break;
}
- break;
}
}
+ } else if (tree.hasTag(Tag.TOPLEVEL)) {
+ JCCompilationUnit cu = (JCCompilationUnit) tree;
+ if (cu.sourcefile.isNameCompatible("package-info", JavaFileObject.Kind.SOURCE)) {
+ sym = cu.packge;
+ }
}
}
return sym;
@@ -332,6 +340,8 @@ public class JavacTrees extends DocTrees {
} else {
return msym;
}
+ } catch (Abort e) { // may be thrown by Check.completionError in case of bad class file
+ return null;
} finally {
log.popDiagnosticHandler(deferredDiagnosticHandler);
}
diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Attribute.java b/langtools/src/share/classes/com/sun/tools/javac/code/Attribute.java
index f827006a036..9ecb23d85ad 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Attribute.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Attribute.java
@@ -60,6 +60,9 @@ public abstract class Attribute implements AnnotationValue {
throw new UnsupportedOperationException();
}
+ public boolean isSynthesized() {
+ return false;
+ }
/** The value for an annotation element of primitive type or String. */
public static class Constant extends Attribute {
@@ -136,6 +139,18 @@ public abstract class Attribute implements AnnotationValue {
* access this attribute.
*/
public final List> values;
+
+ private boolean synthesized = false;
+
+ @Override
+ public boolean isSynthesized() {
+ return synthesized;
+ }
+
+ public void setSynthesized(boolean synthesized) {
+ this.synthesized = synthesized;
+ }
+
public Compound(Type type,
List> values) {
super(type);
diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java
index 2248f47e0e0..2f3f84ab054 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java
@@ -83,13 +83,13 @@ public abstract class Symbol implements Element {
* Attributes of class symbols should be accessed through the accessor
* method to make sure that the class symbol is loaded.
*/
- public List getAnnotationMirrors() {
- return Assert.checkNonNull(annotations.getAttributes());
+ public List getRawAttributes() {
+ return annotations.getAttributes();
}
/** Fetch a particular annotation from a symbol. */
public Attribute.Compound attribute(Symbol anno) {
- for (Attribute.Compound a : getAnnotationMirrors()) {
+ for (Attribute.Compound a : getRawAttributes()) {
if (a.type.tsym == anno) return a;
}
return null;
@@ -446,6 +446,14 @@ public abstract class Symbol implements Element {
return name;
}
+ /**
+ * This is the implementation for {@code
+ * javax.lang.model.element.Element.getAnnotationMirrors()}.
+ */
+ public final List getAnnotationMirrors() {
+ return getRawAttributes();
+ }
+
/**
* @deprecated this method should never be used by javac internally.
*/
@@ -662,15 +670,21 @@ public abstract class Symbol implements Element {
return flags_field;
}
- public List getAnnotationMirrors() {
+ @Override
+ public List getRawAttributes() {
if (completer != null) complete();
if (package_info != null && package_info.completer != null) {
package_info.complete();
- if (annotations.isEmpty()) {
- annotations.setAttributes(package_info.annotations);
+ mergeAttributes();
}
+ return super.getRawAttributes();
+ }
+
+ private void mergeAttributes() {
+ if (annotations.isEmpty() &&
+ !package_info.annotations.isEmpty()) {
+ annotations.setAttributes(package_info.annotations);
}
- return Assert.checkNonNull(annotations.getAttributes());
}
/** A package "exists" if a type or package that exists has
@@ -770,9 +784,10 @@ public abstract class Symbol implements Element {
return members_field;
}
- public List getAnnotationMirrors() {
+ @Override
+ public List getRawAttributes() {
if (completer != null) complete();
- return Assert.checkNonNull(annotations.getAttributes());
+ return super.getRawAttributes();
}
public Type erasure(Types types) {
@@ -1353,7 +1368,7 @@ public abstract class Symbol implements Element {
return defaultValue;
}
- public List getParameters() {
+ public List getParameters() {
return params();
}
@@ -1361,6 +1376,10 @@ public abstract class Symbol implements Element {
return (flags() & VARARGS) != 0;
}
+ public boolean isDefault() {
+ return (flags() & DEFAULT) != 0;
+ }
+
public R accept(ElementVisitor v, P p) {
return v.visitExecutable(this, p);
}
diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Type.java b/langtools/src/share/classes/com/sun/tools/javac/code/Type.java
index 80aabeeb9ba..db2685bcf07 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Type.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Type.java
@@ -302,10 +302,12 @@ public class Type implements PrimitiveType {
* never complete classes. Where isSameType would complete a
* class, equals assumes that the two types are different.
*/
+ @Override
public boolean equals(Object t) {
return super.equals(t);
}
+ @Override
public int hashCode() {
return super.hashCode();
}
@@ -996,34 +998,6 @@ public class Type implements PrimitiveType {
return "(" + argtypes + ")" + restype;
}
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (!(obj instanceof MethodType))
- return false;
- MethodType m = (MethodType)obj;
- List args1 = argtypes;
- List args2 = m.argtypes;
- while (!args1.isEmpty() && !args2.isEmpty()) {
- if (!args1.head.equals(args2.head))
- return false;
- args1 = args1.tail;
- args2 = args2.tail;
- }
- if (!args1.isEmpty() || !args2.isEmpty())
- return false;
- return restype.equals(m.restype);
- }
-
- public int hashCode() {
- int h = METHOD.ordinal();
- for (List thisargs = this.argtypes;
- thisargs.tail != null; /*inlined: thisargs.nonEmpty()*/
- thisargs = thisargs.tail)
- h = (h << 5) + thisargs.head.hashCode();
- return (h << 5) + this.restype.hashCode();
- }
-
public List getParameterTypes() { return argtypes; }
public Type getReturnType() { return restype; }
public List getThrownTypes() { return thrown; }
diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java
index 88882955b4f..a7378f8acfe 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java
@@ -1007,11 +1007,11 @@ public class Types {
if (!visit(supertype(t), supertype(s)))
return false;
- HashSet set = new HashSet();
+ HashSet set = new HashSet();
for (Type x : interfaces(t))
- set.add(new SingletonType(x));
+ set.add(new UniqueType(x, Types.this));
for (Type x : interfaces(s)) {
- if (!set.remove(new SingletonType(x)))
+ if (!set.remove(new UniqueType(x, Types.this)))
return false;
}
return (set.isEmpty());
@@ -3137,7 +3137,7 @@ public class Types {
}
@Override
public int hashCode() {
- return 127 * Types.hashCode(t1) + Types.hashCode(t2);
+ return 127 * Types.this.hashCode(t1) + Types.this.hashCode(t2);
}
@Override
public boolean equals(Object obj) {
@@ -3400,7 +3400,7 @@ public class Types {
/**
* Compute a hash code on a type.
*/
- public static int hashCode(Type t) {
+ public int hashCode(Type t) {
return hashCode.visit(t);
}
// where
@@ -3422,6 +3422,16 @@ public class Types {
return result;
}
+ @Override
+ public Integer visitMethodType(MethodType t, Void ignored) {
+ int h = METHOD.ordinal();
+ for (List thisargs = t.argtypes;
+ thisargs.tail != null;
+ thisargs = thisargs.tail)
+ h = (h << 5) + visit(thisargs.head);
+ return (h << 5) + visit(t.restype);
+ }
+
@Override
public Integer visitWildcardType(WildcardType t, Void ignored) {
int result = t.kind.hashCode();
@@ -4082,21 +4092,28 @@ public class Types {
/**
* A wrapper for a type that allows use in sets.
*/
- class SingletonType {
- final Type t;
- SingletonType(Type t) {
- this.t = t;
+ public static class UniqueType {
+ public final Type type;
+ final Types types;
+
+ public UniqueType(Type type, Types types) {
+ this.type = type;
+ this.types = types;
}
+
public int hashCode() {
- return Types.hashCode(t);
+ return types.hashCode(type);
}
+
public boolean equals(Object obj) {
- return (obj instanceof SingletonType) &&
- isSameType(t, ((SingletonType)obj).t);
+ return (obj instanceof UniqueType) &&
+ types.isSameType(type, ((UniqueType)obj).type);
}
+
public String toString() {
- return t.toString();
+ return type.toString();
}
+
}
//
diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java
index ab5d49c3166..b9807d9180c 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java
@@ -400,6 +400,7 @@ public class Annotate {
Attribute.Compound c = enterAnnotation(annoTree,
targetContainerType,
ctx.env);
+ c.setSynthesized(true);
return c;
} else {
return null; // errors should have been reported elsewhere
diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
index 23fe35ec421..da982534deb 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
@@ -1405,7 +1405,8 @@ public class Attr extends JCTree.Visitor {
Type owntype = standaloneConditional ? condType(tree, truetype, falsetype) : pt();
if (condtype.constValue() != null &&
truetype.constValue() != null &&
- falsetype.constValue() != null) {
+ falsetype.constValue() != null &&
+ !owntype.hasTag(NONE)) {
//constant folding
owntype = cfolder.coerce(condtype.isTrue() ? truetype : falsetype, owntype);
}
diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java b/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
index c737c2c36c7..6ad3da8ddae 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
@@ -692,8 +692,9 @@ public class LambdaToMethod extends TreeTranslator {
//determine the static bsm args
Type mtype = makeFunctionalDescriptorType(targetType, true);
List
+ *
+ ^
+InsertImplicit.java:14: error: block element not allowed within inline element : blockquote
+ *
abc
+ ^
+2 errors
diff --git a/langtools/test/tools/doclint/tidy/InvalidEntity.java b/langtools/test/tools/doclint/tidy/InvalidEntity.java
new file mode 100644
index 00000000000..c6ee3aa80a6
--- /dev/null
+++ b/langtools/test/tools/doclint/tidy/InvalidEntity.java
@@ -0,0 +1,22 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @library ..
+ * @build DocLintTester
+ * @run main DocLintTester -ref InvalidEntity.out InvalidEntity.java
+ */
+
+// tidy: Warning: replacing invalid numeric character reference .*
+
+// See
+// http://www.w3.org/TR/html4/sgml/entities.html
+// http://stackoverflow.com/questions/631406/what-is-the-difference-between-em-dash-151-and-8212
+
+/**
+ *
+ *
+ * &splodge;
+ *
+ */
+public class InvalidEntity { }
diff --git a/langtools/test/tools/doclint/tidy/InvalidEntity.out b/langtools/test/tools/doclint/tidy/InvalidEntity.out
new file mode 100644
index 00000000000..bd4527a55e9
--- /dev/null
+++ b/langtools/test/tools/doclint/tidy/InvalidEntity.out
@@ -0,0 +1,10 @@
+InvalidEntity.java:17: error: invalid entity
+ *
+ ^
+InvalidEntity.java:18: error: invalid entity
+ *
+ ^
+InvalidEntity.java:19: error: invalid entity &splodge;
+ * &splodge;
+ ^
+3 errors
diff --git a/langtools/test/tools/doclint/tidy/InvalidName.java b/langtools/test/tools/doclint/tidy/InvalidName.java
new file mode 100644
index 00000000000..fe87ee80916
--- /dev/null
+++ b/langtools/test/tools/doclint/tidy/InvalidName.java
@@ -0,0 +1,18 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @library ..
+ * @build DocLintTester
+ * @run main DocLintTester -ref InvalidName.out InvalidName.java
+ */
+
+// tidy: Warning: cannot copy name attribute to id
+
+/**
+ * valid
+ * valid
+ * valid
+ * invalid
+ */
+public class InvalidName { }
diff --git a/langtools/test/tools/doclint/tidy/InvalidName.out b/langtools/test/tools/doclint/tidy/InvalidName.out
new file mode 100644
index 00000000000..8b50a6f0fe1
--- /dev/null
+++ b/langtools/test/tools/doclint/tidy/InvalidName.out
@@ -0,0 +1,4 @@
+InvalidName.java:16: error: invalid name for anchor: "foo()"
+ * invalid
+ ^
+1 error
diff --git a/langtools/test/tools/doclint/tidy/InvalidTag.java b/langtools/test/tools/doclint/tidy/InvalidTag.java
new file mode 100644
index 00000000000..86513824823
--- /dev/null
+++ b/langtools/test/tools/doclint/tidy/InvalidTag.java
@@ -0,0 +1,15 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @library ..
+ * @build DocLintTester
+ * @run main DocLintTester -ref InvalidTag.out InvalidTag.java
+ */
+
+// tidy: Error: <.*> is not recognized!
+
+/**
+ * List list = new ArrayList<>();
+ */
+public class InvalidTag { }
diff --git a/langtools/test/tools/doclint/tidy/InvalidTag.out b/langtools/test/tools/doclint/tidy/InvalidTag.out
new file mode 100644
index 00000000000..5422e727b0e
--- /dev/null
+++ b/langtools/test/tools/doclint/tidy/InvalidTag.out
@@ -0,0 +1,10 @@
+InvalidTag.java:13: error: unknown tag: String
+ * List list = new ArrayList<>();
+ ^
+InvalidTag.java:13: error: malformed HTML
+ * List list = new ArrayList<>();
+ ^
+InvalidTag.java:13: error: bad use of '>'
+ * List list = new ArrayList<>();
+ ^
+3 errors
diff --git a/langtools/test/tools/doclint/tidy/InvalidURI.java b/langtools/test/tools/doclint/tidy/InvalidURI.java
new file mode 100644
index 00000000000..ba9e70a3dc9
--- /dev/null
+++ b/langtools/test/tools/doclint/tidy/InvalidURI.java
@@ -0,0 +1,21 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @library ..
+ * @build DocLintTester
+ * @run main DocLintTester -ref InvalidURI.out InvalidURI.java
+ */
+
+// tidy: Warning: escaping malformed URI reference
+// tidy: Warning: <.*> attribute ".*" lacks value
+
+/**
+ * valid
+ * valid
+ * invalid
+ * no value
+ * no value
+ * no value
+ */
+public class InvalidURI { }
diff --git a/langtools/test/tools/doclint/tidy/InvalidURI.out b/langtools/test/tools/doclint/tidy/InvalidURI.out
new file mode 100644
index 00000000000..294c592ffea
--- /dev/null
+++ b/langtools/test/tools/doclint/tidy/InvalidURI.out
@@ -0,0 +1,13 @@
+InvalidURI.java:16: error: invalid uri: "abc def"
+ * invalid
+ ^
+InvalidURI.java:17: error: attribute lacks value
+ * no value
+ ^
+InvalidURI.java:18: error: attribute lacks value
+ * no value
+ ^
+InvalidURI.java:19: error: attribute lacks value
+ * no value
+ ^
+4 errors
diff --git a/langtools/test/tools/doclint/tidy/MissingGT.java b/langtools/test/tools/doclint/tidy/MissingGT.java
new file mode 100644
index 00000000000..8e787aaa262
--- /dev/null
+++ b/langtools/test/tools/doclint/tidy/MissingGT.java
@@ -0,0 +1,16 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @library ..
+ * @build DocLintTester
+ * @run main DocLintTester -ref MissingGT.out MissingGT.java
+ */
+
+// tidy: Warning: <.*> missing '>' for end of tag
+
+/**
+ * text
+ */
+public class MissingGT { }
diff --git a/langtools/test/tools/doclint/tidy/MissingGT.out b/langtools/test/tools/doclint/tidy/MissingGT.out
new file mode 100644
index 00000000000..28455db6338
--- /dev/null
+++ b/langtools/test/tools/doclint/tidy/MissingGT.out
@@ -0,0 +1,4 @@
+MissingGT.java:13: error: malformed HTML
+ *
+// tidy: Warning: missing before
+
+/**
+ *
+ *
text
+ */
+public class MissingTag { }
diff --git a/langtools/test/tools/doclint/tidy/MissingTag.out b/langtools/test/tools/doclint/tidy/MissingTag.out
new file mode 100644
index 00000000000..152bfe36b32
--- /dev/null
+++ b/langtools/test/tools/doclint/tidy/MissingTag.out
@@ -0,0 +1,7 @@
+MissingTag.java:14: error: unexpected end tag:
+ *
+ ^
+MissingTag.java:15: error: end tag missing:
+ *
+ */
+public class ParaInPre { }
diff --git a/langtools/test/tools/doclint/tidy/ParaInPre.out b/langtools/test/tools/doclint/tidy/ParaInPre.out
new file mode 100644
index 00000000000..bafe4aa7eed
--- /dev/null
+++ b/langtools/test/tools/doclint/tidy/ParaInPre.out
@@ -0,0 +1,4 @@
+ParaInPre.java:16: warning: unexpected use of
inside
element
+ *
+ ^
+1 warning
diff --git a/langtools/test/tools/doclint/tidy/README.txt b/langtools/test/tools/doclint/tidy/README.txt
new file mode 100644
index 00000000000..662d654c13e
--- /dev/null
+++ b/langtools/test/tools/doclint/tidy/README.txt
@@ -0,0 +1,21 @@
+The utilities in this directory can be used to determine
+common issues in javadoc comments by running the standard
+"tidy" program on the output of javadoc, and analysing
+the messages that are reported.
+
+tidy.sh is a script that will run the "tidy" program on
+the files in a directory, writing the results to a new
+directroy.
+
+tidystats.Main is a Java program that can analyze the
+files produced by the tidy.sh script to generate a
+summary report about the warnings that were found.
+
+
+The tests is this directory are focussed on verifying
+that doclint detects issues in javadoc comments that will
+give rise to issues detected by "tidy" in the output
+generated by javadoc.
+
+For more information on the "tidy" program, see the HTML Tidy
+Library Project page at http://tidy.sourceforge.net/.
diff --git a/langtools/test/tools/doclint/tidy/RepeatedAttr.java b/langtools/test/tools/doclint/tidy/RepeatedAttr.java
new file mode 100644
index 00000000000..f16e7c9dd5d
--- /dev/null
+++ b/langtools/test/tools/doclint/tidy/RepeatedAttr.java
@@ -0,0 +1,15 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @library ..
+ * @build DocLintTester
+ * @run main DocLintTester -ref RepeatedAttr.out RepeatedAttr.java
+ */
+
+// tidy: Warning: <.*> dropping value ".*" for repeated attribute ".*"
+
+/**
+ *
+ */
+public class RepeatedAttr { }
diff --git a/langtools/test/tools/doclint/tidy/RepeatedAttr.out b/langtools/test/tools/doclint/tidy/RepeatedAttr.out
new file mode 100644
index 00000000000..0ed1e9f99e8
--- /dev/null
+++ b/langtools/test/tools/doclint/tidy/RepeatedAttr.out
@@ -0,0 +1,4 @@
+RepeatedAttr.java:13: error: repeated attribute: alt
+ *
+ ^
+1 error
diff --git a/langtools/test/tools/doclint/tidy/TextNotAllowed.java b/langtools/test/tools/doclint/tidy/TextNotAllowed.java
new file mode 100644
index 00000000000..c5123c5b3a2
--- /dev/null
+++ b/langtools/test/tools/doclint/tidy/TextNotAllowed.java
@@ -0,0 +1,26 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @library ..
+ * @build DocLintTester
+ * @run main DocLintTester -ref TextNotAllowed.out TextNotAllowed.java
+ */
+
+// tidy: Warning: plain text isn't allowed in <.*> elements
+
+/**
+ *
abc
+ *
abc
+ *
abc
+ *
+ *
abc
+ * abc
+ *
abc
+ *
+ *
+ *
item
+ *
item
+ *
+ */
+public class TextNotAllowed { }
diff --git a/langtools/test/tools/doclint/tidy/TextNotAllowed.out b/langtools/test/tools/doclint/tidy/TextNotAllowed.out
new file mode 100644
index 00000000000..1a2944e1b04
--- /dev/null
+++ b/langtools/test/tools/doclint/tidy/TextNotAllowed.out
@@ -0,0 +1,19 @@
+TextNotAllowed.java:13: error: text not allowed in
element
+ *
abc
+ ^
+TextNotAllowed.java:14: error: text not allowed in element
+ *
abc
+ ^
+TextNotAllowed.java:15: error: text not allowed in
element
+ *
abc
+ ^
+TextNotAllowed.java:17: error: text not allowed in
element
+ *
abc
+ ^
+TextNotAllowed.java:18: error: text not allowed in element
+ * abc
+ ^
+TextNotAllowed.java:19: error: text not allowed in