This commit is contained in:
Lana Steuck 2012-12-28 18:39:09 -08:00
commit f2c7a7867a
234 changed files with 5907 additions and 315 deletions

View File

@ -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 # set the following to -version to verify the versions of javac being used
javac.version.opt = javac.version.opt =
# in time, there should be no exceptions to -Xlint:all # 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 <javadoc> task for javac # options for the <javadoc> task for javac
#javadoc.jls3.url=http://java.sun.com/docs/books/jls/ #javadoc.jls3.url=http://java.sun.com/docs/books/jls/
@ -117,7 +117,8 @@ javac.includes = \
javax/lang/model/ \ javax/lang/model/ \
javax/tools/ \ javax/tools/ \
com/sun/source/ \ com/sun/source/ \
com/sun/tools/javac/ com/sun/tools/javac/ \
com/sun/tools/doclint/
javac.tests = \ javac.tests = \
tools/javac tools/javac

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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(); 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 * Return the serialization methods for this class or
* interface. * interface.

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -38,6 +38,11 @@ public interface MethodDoc extends ExecutableMemberDoc {
*/ */
boolean isAbstract(); boolean isAbstract();
/**
* Return true if this method is default
*/
boolean isDefault();
/** /**
* Get return type. * Get return type.
* *

View File

@ -45,9 +45,7 @@ public abstract class DocTrees extends Trees {
* @throws IllegalArgumentException if the task does not support the Trees API. * @throws IllegalArgumentException if the task does not support the Trees API.
*/ */
public static DocTrees instance(CompilationTask task) { public static DocTrees instance(CompilationTask task) {
if (!task.getClass().getName().equals("com.sun.tools.javac.api.JavacTaskImpl")) return (DocTrees) Trees.instance(task);
throw new IllegalArgumentException();
return (DocTrees) getJavacTrees(CompilationTask.class, task);
} }
/** /**

View File

@ -139,6 +139,7 @@ public abstract class JavacTask implements CompilationTask {
* @see com.sun.source.util.Trees#getTypeMirror * @see com.sun.source.util.Trees#getTypeMirror
*/ */
public abstract TypeMirror getTypeMirror(Iterable<? extends Tree> path); public abstract TypeMirror getTypeMirror(Iterable<? extends Tree> path);
/** /**
* Get a utility object for dealing with program elements. * Get a utility object for dealing with program elements.
*/ */

View File

@ -56,9 +56,9 @@ public interface Plugin {
String getName(); 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 task The compilation task that has just been started
* @param args Arguments, if any, for the plug-in * @param args Arguments, if any, for the plug-in
*/ */
void call(JavacTask task, String... args); void init(JavacTask task, String... args);
} }

View File

@ -60,14 +60,20 @@ public class TreePath implements Iterable<Tree> {
this.path = path; this.path = path;
} }
} }
class PathFinder extends TreePathScanner<TreePath,Tree> { class PathFinder extends TreePathScanner<TreePath,Tree> {
public TreePath scan(Tree tree, Tree target) { public TreePath scan(Tree tree, Tree target) {
if (tree == target) if (tree == target) {
throw new Result(new TreePath(getCurrentPath(), target)); throw new Result(new TreePath(getCurrentPath(), target));
}
return super.scan(tree, target); return super.scan(tree, target);
} }
} }
if (path.getLeaf() == target) {
return path;
}
try { try {
new PathFinder().scan(path, target); new PathFinder().scan(path, target);
} catch (Result result) { } catch (Result result) {

View File

@ -239,7 +239,14 @@ public abstract class AbstractMemberWriter {
if ((member.isField() || member.isMethod()) && if ((member.isField() || member.isMethod()) &&
writer instanceof ClassWriterImpl && writer instanceof ClassWriterImpl &&
((ClassWriterImpl) writer).getClassDoc().isInterface()) { ((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) { if(mod.length() > 0) {
htmltree.addContent(mod); htmltree.addContent(mod);
@ -313,8 +320,18 @@ public abstract class AbstractMemberWriter {
code.addContent(configuration.getText("doclet.Package_private")); code.addContent(configuration.getText("doclet.Package_private"));
code.addContent(" "); code.addContent(" ");
} }
if (member.isMethod() && ((MethodDoc)member).isAbstract()) { if (member.isMethod()) {
code.addContent("abstract "); 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()) { if (member.isStatic()) {
code.addContent("static "); code.addContent("static ");
@ -547,6 +564,9 @@ public abstract class AbstractMemberWriter {
methodType = (classdoc.isInterface() || ((MethodDoc)member).isAbstract()) ? methodType = (classdoc.isInterface() || ((MethodDoc)member).isAbstract()) ?
methodType | MethodTypes.ABSTRACT.value() : methodType | MethodTypes.ABSTRACT.value() :
methodType | MethodTypes.CONCRETE.value(); methodType | MethodTypes.CONCRETE.value();
if (((MethodDoc)member).isDefault()) {
methodType = methodType | MethodTypes.DEFAULT.value();
}
if (Util.isDeprecated(member) || Util.isDeprecated(classdoc)) { if (Util.isDeprecated(member) || Util.isDeprecated(classdoc)) {
methodType = methodType | MethodTypes.DEPRECATED.value(); methodType = methodType | MethodTypes.DEPRECATED.value();
} }

View File

@ -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} * {@inheritDoc}
*/ */

View File

@ -90,6 +90,8 @@ doclet.in_interface=in interface
doclet.Subclasses=Direct Known Subclasses: doclet.Subclasses=Direct Known Subclasses:
doclet.Subinterfaces=All Known Subinterfaces: doclet.Subinterfaces=All Known Subinterfaces:
doclet.Implementing_Classes=All Known Implementing Classes: 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.also=also
doclet.Frames=Frames doclet.Frames=Frames
doclet.No_Frames=No Frames doclet.No_Frames=No Frames

View File

@ -116,6 +116,13 @@ public interface ClassWriter {
*/ */
public void addInterfaceUsageInfo(Content classInfoTree); 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 * If this is an inner class or interface, add the enclosing class or
* interface. * interface.

View File

@ -235,6 +235,16 @@ public class ClassBuilder extends AbstractBuilder {
writer.addInterfaceUsageInfo(classInfoTree); 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. * If this class is deprecated, build the appropriate information.
* *

View File

@ -85,6 +85,7 @@
<SubInterfacesInfo/> <SubInterfacesInfo/>
<InterfaceUsageInfo/> <InterfaceUsageInfo/>
<NestedClassInfo/> <NestedClassInfo/>
<FunctionalInterfaceInfo/>
<DeprecationInfo/> <DeprecationInfo/>
<ClassSignature/> <ClassSignature/>
<ClassDescription/> <ClassDescription/>

View File

@ -36,7 +36,8 @@ public enum MethodTypes {
INSTANCE(0x2, "Instance Methods", "t2", false), INSTANCE(0x2, "Instance Methods", "t2", false),
ABSTRACT(0x4, "Abstract Methods", "t3", false), ABSTRACT(0x4, "Abstract Methods", "t3", false),
CONCRETE(0x8, "Concrete Methods", "t4", 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 int value;
private final String text; private final String text;

View File

@ -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.
*
* <p><b>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.</b></p>
*/
public class Checker extends DocTreeScanner<Void, Void> {
final Env env;
Set<Element> foundParams = new HashSet<Element>();
Set<TypeMirror> foundThrows = new HashSet<TypeMirror>();
Set<String> foundAnchors = new HashSet<String>();
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<HtmlTag.Attr> attrs;
final Set<Flag> 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<TagStackItem> tagStack; // TODO: maybe want to record starting tree as well
private HtmlTag currHeaderTag;
// <editor-fold defaultstate="collapsed" desc="Top level">
Checker(Env env) {
env.getClass();
this.env = env;
tagStack = new LinkedList<TagStackItem>();
}
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;
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Text and entities.">
@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;
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="HTML elements">
@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 <h1>...</h1> <h3>...</h3>
case H1: case H2: case H3: case H4: case H5: case H6:
checkHeader(tree, t);
break;
// <p> inside <pre>
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 <a id="name"/>
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);
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="HTML attributes">
@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);
}
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="javadoc tags">
@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;
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Utility methods">
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);
}
// </editor-fold>
}

View File

@ -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:
* <ul>
* <li>From the command line
* <li>From javac, as a plugin
* <li>Directly, via a simple API
* </ul>
*
* <p><b>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.</b></p>
*/
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";
// <editor-fold defaultstate="collapsed" desc="Command-line entry point">
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);
}
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Simple API">
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<String>();
javacFiles = new ArrayList<File>();
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<File> splitPath(String path) {
List<File> files = new ArrayList<File>();
for (String f: path.split(File.separator)) {
if (f.length() > 0)
files.add(new File(f));
}
return files;
}
List<File> javacBootClassPath;
List<File> javacClassPath;
List<File> javacSourcePath;
List<String> javacOpts;
List<File> javacFiles;
boolean needHelp = false;
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="javac Plugin">
@Override
public String getName() {
return "doclint";
}
@Override
public void init(JavacTask task, String... args) {
init(task, args, true);
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Embedding API">
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);
}
// </editor-fold>
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;
}
// <editor-fold defaultstate="collapsed" desc="DeclScanner">
static abstract class DeclScanner extends TreePathScanner<Void, Void> {
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);
}
}
// </editor-fold>
}

View File

@ -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.
*
* <p> Derived from
* <a href="http://www.w3.org/TR/html4/sgml/entities.html">Character entity references in HTML 4</a>.
*
* 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 '_'.
*
* <p><b>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.</b></p>
*/
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<String,Entity> names = new HashMap<String,Entity>();
private static final Map<Integer,Entity> codes = new HashMap<Integer,Entity>();
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);
}
}
}

View File

@ -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.
*
* <p><b>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.</b></p>
*/
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<Modifier> 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 extends Comparable<T>> T min(T item1, T item2) {
return (item1 == null) ? item2
: (item2 == null) ? item1
: item1.compareTo(item2) <= 0 ? item1 : item2;
}
}

View File

@ -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 <a href="http://www.w3.org/TR/REC-html40/">HTML 4.01 Specification</a>
* @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<String,Attr> index = new HashMap<String,Attr>();
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<Attr,AttrKind> in signature of HtmlTag constructor.
private static class AttrMap extends EnumMap<Attr,AttrKind> {
private static final long serialVersionUID = 0;
AttrMap() {
super(Attr.class);
}
}
public final BlockType blockType;
public final EndKind endKind;
public final Set<Flag> flags;
private final Map<Attr,AttrKind> attrs;
HtmlTag() {
this(BlockType.BLOCK, EndKind.REQUIRED);
}
HtmlTag(Set<Flag> flags) {
this(BlockType.BLOCK, EndKind.REQUIRED, flags);
}
HtmlTag(BlockType blockType, EndKind endKind, AttrMap... attrMaps) {
this(blockType, endKind, Collections.<Flag>emptySet(), attrMaps);
}
HtmlTag(BlockType blockType, EndKind endKind, Set<Flag> flags, AttrMap... attrMaps) {
this.blockType = blockType;
this.endKind = endKind;this.flags = flags;
this.attrs = new EnumMap<Attr,AttrKind>(Attr.class);
for (Map<Attr,AttrKind> 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<String,HtmlTag> index = new HashMap<String,HtmlTag>();
static {
for (HtmlTag t: values()) {
index.put(t.name().toLowerCase(), t);
}
}
static HtmlTag get(Name tagName) {
return index.get(tagName.toString().toLowerCase());
}
}

View File

@ -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.
*
* <p><b>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.</b></p>
*/
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);
}
// <editor-fold defaultstate="collapsed" desc="Options">
/**
* Handler for (sub)options specific to message handling.
*/
static class Options {
Map<String, Env.AccessKind> map = new HashMap<String, Env.AccessKind>();
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";
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Statistics">
/**
* 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<String, Integer> 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<String, Integer>();
} 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<String, Integer> 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<Integer> DECREASING = new Comparator<Integer>() {
public int compare(Integer o1, Integer o2) {
return o2.compareTo(o1);
}
};
private final TreeMap<Integer, Set<String>> map = new TreeMap<Integer, Set<String>>(DECREASING);
void put(String label, int n) {
if (n == 0) {
return;
}
Set<String> labels = map.get(n);
if (labels == null) {
map.put(n, labels = new TreeSet<String>());
}
labels.add(label);
}
void print(PrintWriter out) {
for (Map.Entry<Integer, Set<String>> e : map.entrySet()) {
int count = e.getKey();
Set<String> labels = e.getValue();
for (String label : labels) {
out.println(String.format("%6d: %s", count, label));
}
}
}
}
}
// </editor-fold>
}

View File

@ -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 <p> inside <pre> 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

View File

@ -57,6 +57,13 @@ public class BasicJavacTask extends JavacTask {
protected Context context; protected Context context;
private TaskListener taskListener; 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) { public BasicJavacTask(Context c, boolean register) {
context = c; context = c;
if (register) if (register)

View File

@ -65,7 +65,6 @@ import com.sun.tools.javac.util.List;
* @author Jonathan Gibbons * @author Jonathan Gibbons
*/ */
public class JavacTaskImpl extends BasicJavacTask { public class JavacTaskImpl extends BasicJavacTask {
private ClientCodeWrapper ccw;
private Main compilerMain; private Main compilerMain;
private JavaCompiler compiler; private JavaCompiler compiler;
private Locale locale; private Locale locale;
@ -85,7 +84,6 @@ public class JavacTaskImpl extends BasicJavacTask {
Context context, Context context,
List<JavaFileObject> fileObjects) { List<JavaFileObject> fileObjects) {
super(null, false); super(null, false);
this.ccw = ClientCodeWrapper.instance(context);
this.compilerMain = compilerMain; this.compilerMain = compilerMain;
this.args = args; this.args = args;
this.classNames = classNames; this.classNames = classNames;

View File

@ -159,7 +159,7 @@ public final class JavacTool implements JavaCompiler {
} }
} }
private static void processOptions(Context context, public static void processOptions(Context context,
JavaFileManager fileManager, JavaFileManager fileManager,
Iterable<String> options) Iterable<String> options)
{ {

View File

@ -84,6 +84,7 @@ import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.tree.TreeCopier; import com.sun.tools.javac.tree.TreeCopier;
import com.sun.tools.javac.tree.TreeInfo; import com.sun.tools.javac.tree.TreeInfo;
import com.sun.tools.javac.tree.TreeMaker; 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.Assert;
import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.JCDiagnostic; import com.sun.tools.javac.util.JCDiagnostic;
@ -236,19 +237,26 @@ public class JavacTrees extends DocTrees {
public Element getElement(TreePath path) { public Element getElement(TreePath path) {
JCTree tree = (JCTree) path.getLeaf(); JCTree tree = (JCTree) path.getLeaf();
Symbol sym = TreeInfo.symbolFor(tree); Symbol sym = TreeInfo.symbolFor(tree);
if (sym == null && TreeInfo.isDeclaration(tree)) { if (sym == null) {
for (TreePath p = path; p != null; p = p.getParentPath()) { if (TreeInfo.isDeclaration(tree)) {
JCTree t = (JCTree) p.getLeaf(); for (TreePath p = path; p != null; p = p.getParentPath()) {
if (t.hasTag(JCTree.Tag.CLASSDEF)) { JCTree t = (JCTree) p.getLeaf();
JCClassDecl ct = (JCClassDecl) t; if (t.hasTag(JCTree.Tag.CLASSDEF)) {
if (ct.sym != null) { JCClassDecl ct = (JCClassDecl) t;
if ((ct.sym.flags_field & Flags.UNATTRIBUTED) != 0) { if (ct.sym != null) {
attr.attribClass(ct.pos(), ct.sym); if ((ct.sym.flags_field & Flags.UNATTRIBUTED) != 0) {
sym = TreeInfo.symbolFor(tree); 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; return sym;
@ -332,6 +340,8 @@ public class JavacTrees extends DocTrees {
} else { } else {
return msym; return msym;
} }
} catch (Abort e) { // may be thrown by Check.completionError in case of bad class file
return null;
} finally { } finally {
log.popDiagnosticHandler(deferredDiagnosticHandler); log.popDiagnosticHandler(deferredDiagnosticHandler);
} }

View File

@ -60,6 +60,9 @@ public abstract class Attribute implements AnnotationValue {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
public boolean isSynthesized() {
return false;
}
/** The value for an annotation element of primitive type or String. */ /** The value for an annotation element of primitive type or String. */
public static class Constant extends Attribute { public static class Constant extends Attribute {
@ -136,6 +139,18 @@ public abstract class Attribute implements AnnotationValue {
* access this attribute. * access this attribute.
*/ */
public final List<Pair<MethodSymbol,Attribute>> values; public final List<Pair<MethodSymbol,Attribute>> values;
private boolean synthesized = false;
@Override
public boolean isSynthesized() {
return synthesized;
}
public void setSynthesized(boolean synthesized) {
this.synthesized = synthesized;
}
public Compound(Type type, public Compound(Type type,
List<Pair<MethodSymbol,Attribute>> values) { List<Pair<MethodSymbol,Attribute>> values) {
super(type); super(type);

View File

@ -83,13 +83,13 @@ public abstract class Symbol implements Element {
* Attributes of class symbols should be accessed through the accessor * Attributes of class symbols should be accessed through the accessor
* method to make sure that the class symbol is loaded. * method to make sure that the class symbol is loaded.
*/ */
public List<Attribute.Compound> getAnnotationMirrors() { public List<Attribute.Compound> getRawAttributes() {
return Assert.checkNonNull(annotations.getAttributes()); return annotations.getAttributes();
} }
/** Fetch a particular annotation from a symbol. */ /** Fetch a particular annotation from a symbol. */
public Attribute.Compound attribute(Symbol anno) { public Attribute.Compound attribute(Symbol anno) {
for (Attribute.Compound a : getAnnotationMirrors()) { for (Attribute.Compound a : getRawAttributes()) {
if (a.type.tsym == anno) return a; if (a.type.tsym == anno) return a;
} }
return null; return null;
@ -446,6 +446,14 @@ public abstract class Symbol implements Element {
return name; return name;
} }
/**
* This is the implementation for {@code
* javax.lang.model.element.Element.getAnnotationMirrors()}.
*/
public final List<Attribute.Compound> getAnnotationMirrors() {
return getRawAttributes();
}
/** /**
* @deprecated this method should never be used by javac internally. * @deprecated this method should never be used by javac internally.
*/ */
@ -662,15 +670,21 @@ public abstract class Symbol implements Element {
return flags_field; return flags_field;
} }
public List<Attribute.Compound> getAnnotationMirrors() { @Override
public List<Attribute.Compound> getRawAttributes() {
if (completer != null) complete(); if (completer != null) complete();
if (package_info != null && package_info.completer != null) { if (package_info != null && package_info.completer != null) {
package_info.complete(); package_info.complete();
if (annotations.isEmpty()) { mergeAttributes();
annotations.setAttributes(package_info.annotations);
} }
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 /** A package "exists" if a type or package that exists has
@ -770,9 +784,10 @@ public abstract class Symbol implements Element {
return members_field; return members_field;
} }
public List<Attribute.Compound> getAnnotationMirrors() { @Override
public List<Attribute.Compound> getRawAttributes() {
if (completer != null) complete(); if (completer != null) complete();
return Assert.checkNonNull(annotations.getAttributes()); return super.getRawAttributes();
} }
public Type erasure(Types types) { public Type erasure(Types types) {
@ -1353,7 +1368,7 @@ public abstract class Symbol implements Element {
return defaultValue; return defaultValue;
} }
public List<VarSymbol> getParameters() { public List<VarSymbol> getParameters() {
return params(); return params();
} }
@ -1361,6 +1376,10 @@ public abstract class Symbol implements Element {
return (flags() & VARARGS) != 0; return (flags() & VARARGS) != 0;
} }
public boolean isDefault() {
return (flags() & DEFAULT) != 0;
}
public <R, P> R accept(ElementVisitor<R, P> v, P p) { public <R, P> R accept(ElementVisitor<R, P> v, P p) {
return v.visitExecutable(this, p); return v.visitExecutable(this, p);
} }

View File

@ -302,10 +302,12 @@ public class Type implements PrimitiveType {
* never complete classes. Where isSameType would complete a * never complete classes. Where isSameType would complete a
* class, equals assumes that the two types are different. * class, equals assumes that the two types are different.
*/ */
@Override
public boolean equals(Object t) { public boolean equals(Object t) {
return super.equals(t); return super.equals(t);
} }
@Override
public int hashCode() { public int hashCode() {
return super.hashCode(); return super.hashCode();
} }
@ -996,34 +998,6 @@ public class Type implements PrimitiveType {
return "(" + argtypes + ")" + restype; return "(" + argtypes + ")" + restype;
} }
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof MethodType))
return false;
MethodType m = (MethodType)obj;
List<Type> args1 = argtypes;
List<Type> 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<Type> 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<Type> getParameterTypes() { return argtypes; } public List<Type> getParameterTypes() { return argtypes; }
public Type getReturnType() { return restype; } public Type getReturnType() { return restype; }
public List<Type> getThrownTypes() { return thrown; } public List<Type> getThrownTypes() { return thrown; }

View File

@ -1007,11 +1007,11 @@ public class Types {
if (!visit(supertype(t), supertype(s))) if (!visit(supertype(t), supertype(s)))
return false; return false;
HashSet<SingletonType> set = new HashSet<SingletonType>(); HashSet<UniqueType> set = new HashSet<UniqueType>();
for (Type x : interfaces(t)) for (Type x : interfaces(t))
set.add(new SingletonType(x)); set.add(new UniqueType(x, Types.this));
for (Type x : interfaces(s)) { for (Type x : interfaces(s)) {
if (!set.remove(new SingletonType(x))) if (!set.remove(new UniqueType(x, Types.this)))
return false; return false;
} }
return (set.isEmpty()); return (set.isEmpty());
@ -3137,7 +3137,7 @@ public class Types {
} }
@Override @Override
public int hashCode() { public int hashCode() {
return 127 * Types.hashCode(t1) + Types.hashCode(t2); return 127 * Types.this.hashCode(t1) + Types.this.hashCode(t2);
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
@ -3400,7 +3400,7 @@ public class Types {
/** /**
* Compute a hash code on a type. * Compute a hash code on a type.
*/ */
public static int hashCode(Type t) { public int hashCode(Type t) {
return hashCode.visit(t); return hashCode.visit(t);
} }
// where // where
@ -3422,6 +3422,16 @@ public class Types {
return result; return result;
} }
@Override
public Integer visitMethodType(MethodType t, Void ignored) {
int h = METHOD.ordinal();
for (List<Type> thisargs = t.argtypes;
thisargs.tail != null;
thisargs = thisargs.tail)
h = (h << 5) + visit(thisargs.head);
return (h << 5) + visit(t.restype);
}
@Override @Override
public Integer visitWildcardType(WildcardType t, Void ignored) { public Integer visitWildcardType(WildcardType t, Void ignored) {
int result = t.kind.hashCode(); int result = t.kind.hashCode();
@ -4082,21 +4092,28 @@ public class Types {
/** /**
* A wrapper for a type that allows use in sets. * A wrapper for a type that allows use in sets.
*/ */
class SingletonType { public static class UniqueType {
final Type t; public final Type type;
SingletonType(Type t) { final Types types;
this.t = t;
public UniqueType(Type type, Types types) {
this.type = type;
this.types = types;
} }
public int hashCode() { public int hashCode() {
return Types.hashCode(t); return types.hashCode(type);
} }
public boolean equals(Object obj) { public boolean equals(Object obj) {
return (obj instanceof SingletonType) && return (obj instanceof UniqueType) &&
isSameType(t, ((SingletonType)obj).t); types.isSameType(type, ((UniqueType)obj).type);
} }
public String toString() { public String toString() {
return t.toString(); return type.toString();
} }
} }
// </editor-fold> // </editor-fold>

View File

@ -400,6 +400,7 @@ public class Annotate {
Attribute.Compound c = enterAnnotation(annoTree, Attribute.Compound c = enterAnnotation(annoTree,
targetContainerType, targetContainerType,
ctx.env); ctx.env);
c.setSynthesized(true);
return c; return c;
} else { } else {
return null; // errors should have been reported elsewhere return null; // errors should have been reported elsewhere

View File

@ -1405,7 +1405,8 @@ public class Attr extends JCTree.Visitor {
Type owntype = standaloneConditional ? condType(tree, truetype, falsetype) : pt(); Type owntype = standaloneConditional ? condType(tree, truetype, falsetype) : pt();
if (condtype.constValue() != null && if (condtype.constValue() != null &&
truetype.constValue() != null && truetype.constValue() != null &&
falsetype.constValue() != null) { falsetype.constValue() != null &&
!owntype.hasTag(NONE)) {
//constant folding //constant folding
owntype = cfolder.coerce(condtype.isTrue() ? truetype : falsetype, owntype); owntype = cfolder.coerce(condtype.isTrue() ? truetype : falsetype, owntype);
} }

View File

@ -692,8 +692,9 @@ public class LambdaToMethod extends TreeTranslator {
//determine the static bsm args //determine the static bsm args
Type mtype = makeFunctionalDescriptorType(targetType, true); Type mtype = makeFunctionalDescriptorType(targetType, true);
List<Object> staticArgs = List.<Object>of( List<Object> staticArgs = List.<Object>of(
new Pool.MethodHandle(ClassFile.REF_invokeInterface, types.findDescriptorSymbol(targetType.tsym)), new Pool.MethodHandle(ClassFile.REF_invokeInterface,
new Pool.MethodHandle(refKind, refSym), types.findDescriptorSymbol(targetType.tsym), types),
new Pool.MethodHandle(refKind, refSym, types),
new MethodType(mtype.getParameterTypes(), new MethodType(mtype.getParameterTypes(),
mtype.getReturnType(), mtype.getReturnType(),
mtype.getThrownTypes(), mtype.getThrownTypes(),

View File

@ -1798,6 +1798,9 @@ public class Resolve {
if ((kind & TYP) != 0) { if ((kind & TYP) != 0) {
sym = findType(env, name); sym = findType(env, name);
if (sym.kind==TYP) {
reportDependence(env.enclClass.sym, sym);
}
if (sym.exists()) return sym; if (sym.exists()) return sym;
else if (sym.kind < bestSoFar.kind) bestSoFar = sym; else if (sym.kind < bestSoFar.kind) bestSoFar = sym;
} }
@ -1806,6 +1809,14 @@ public class Resolve {
else return bestSoFar; else return bestSoFar;
} }
/** Report dependencies.
* @param from The enclosing class sym
* @param to The found identifier that the class depends on.
*/
public void reportDependence(Symbol from, Symbol to) {
// Override if you want to collect the reported dependencies.
}
/** Find an identifier in a package which matches a specified kind set. /** Find an identifier in a package which matches a specified kind set.
* @param env The current environment. * @param env The current environment.
* @param name The identifier's name. * @param name The identifier's name.
@ -3064,16 +3075,20 @@ public class Resolve {
if (hasLocation) { if (hasLocation) {
return diags.create(dkind, log.currentSource(), pos, return diags.create(dkind, log.currentSource(), pos,
errKey, kindname, idname, //symbol kindname, name errKey, kindname, idname, //symbol kindname, name
typeargtypes, argtypes, //type parameters and arguments (if any) typeargtypes, args(argtypes), //type parameters and arguments (if any)
getLocationDiag(location, site)); //location kindname, type getLocationDiag(location, site)); //location kindname, type
} }
else { else {
return diags.create(dkind, log.currentSource(), pos, return diags.create(dkind, log.currentSource(), pos,
errKey, kindname, idname, //symbol kindname, name errKey, kindname, idname, //symbol kindname, name
typeargtypes, argtypes); //type parameters and arguments (if any) typeargtypes, args(argtypes)); //type parameters and arguments (if any)
} }
} }
//where //where
private Object args(List<Type> args) {
return args.isEmpty() ? args : methodArguments(args);
}
private String getErrorKey(KindName kindname, boolean hasTypeArgs, boolean hasLocation) { private String getErrorKey(KindName kindname, boolean hasTypeArgs, boolean hasLocation) {
String key = "cant.resolve"; String key = "cant.resolve";
String suffix = hasLocation ? ".location" : ""; String suffix = hasLocation ? ".location" : "";

View File

@ -548,17 +548,15 @@ public class ZipFileIndex {
} }
if (i >= 0) { if (i >= 0) {
zipDir = new byte[get4ByteLittleEndian(endbuf, i + 12) + 2]; zipDir = new byte[get4ByteLittleEndian(endbuf, i + 12)];
zipDir[0] = endbuf[i + 10];
zipDir[1] = endbuf[i + 11];
int sz = get4ByteLittleEndian(endbuf, i + 16); int sz = get4ByteLittleEndian(endbuf, i + 16);
// a negative offset or the entries field indicates a // a negative offset or the entries field indicates a
// potential zip64 archive // potential zip64 archive
if (sz < 0 || get2ByteLittleEndian(zipDir, 0) == 0xffff) { if (sz < 0 || get2ByteLittleEndian(endbuf, i + 10) == 0xffff) {
throw new ZipFormatException("detected a zip64 archive"); throw new ZipFormatException("detected a zip64 archive");
} }
zipRandomFile.seek(start + sz); zipRandomFile.seek(start + sz);
zipRandomFile.readFully(zipDir, 2, zipDir.length - 2); zipRandomFile.readFully(zipDir, 0, zipDir.length);
return; return;
} else { } else {
endbufend = endbufpos + 21; endbufend = endbufpos + 21;
@ -568,14 +566,13 @@ public class ZipFileIndex {
} }
private void buildIndex() throws IOException { private void buildIndex() throws IOException {
int entryCount = get2ByteLittleEndian(zipDir, 0); int len = zipDir.length;
// Add each of the files // Add each of the files
if (entryCount > 0) { if (len > 0) {
directories = new LinkedHashMap<RelativeDirectory, DirectoryEntry>(); directories = new LinkedHashMap<RelativeDirectory, DirectoryEntry>();
ArrayList<Entry> entryList = new ArrayList<Entry>(); ArrayList<Entry> entryList = new ArrayList<Entry>();
int pos = 2; for (int pos = 0; pos < len; ) {
for (int i = 0; i < entryCount; i++) {
pos = readEntry(pos, entryList, directories); pos = readEntry(pos, entryList, directories);
} }

View File

@ -26,6 +26,8 @@
package com.sun.tools.javac.jvm; package com.sun.tools.javac.jvm;
import com.sun.tools.javac.code.Type; import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Types;
import com.sun.tools.javac.code.Types.UniqueType;
import com.sun.tools.javac.util.Name; import com.sun.tools.javac.util.Name;
@ -166,22 +168,29 @@ public class ClassFile {
*/ */
public static class NameAndType { public static class NameAndType {
Name name; Name name;
Type type; UniqueType uniqueType;
Types types;
NameAndType(Name name, Type type) { NameAndType(Name name, Type type, Types types) {
this.name = name; this.name = name;
this.type = type; this.uniqueType = new UniqueType(type, types);
this.types = types;
} }
void setType(Type type) {
this.uniqueType = new UniqueType(type, types);
}
@Override
public boolean equals(Object other) { public boolean equals(Object other) {
return return (other instanceof NameAndType &&
other instanceof NameAndType && name == ((NameAndType) other).name &&
name == ((NameAndType) other).name && uniqueType.equals(((NameAndType) other).uniqueType));
type.equals(((NameAndType) other).type);
} }
@Override
public int hashCode() { public int hashCode() {
return name.hashCode() * type.hashCode(); return name.hashCode() * uniqueType.hashCode();
} }
} }
} }

View File

@ -488,20 +488,20 @@ public class ClassReader implements Completer {
case CONSTANT_Fieldref: { case CONSTANT_Fieldref: {
ClassSymbol owner = readClassSymbol(getChar(index + 1)); ClassSymbol owner = readClassSymbol(getChar(index + 1));
NameAndType nt = (NameAndType)readPool(getChar(index + 3)); NameAndType nt = (NameAndType)readPool(getChar(index + 3));
poolObj[i] = new VarSymbol(0, nt.name, nt.type, owner); poolObj[i] = new VarSymbol(0, nt.name, nt.uniqueType.type, owner);
break; break;
} }
case CONSTANT_Methodref: case CONSTANT_Methodref:
case CONSTANT_InterfaceMethodref: { case CONSTANT_InterfaceMethodref: {
ClassSymbol owner = readClassSymbol(getChar(index + 1)); ClassSymbol owner = readClassSymbol(getChar(index + 1));
NameAndType nt = (NameAndType)readPool(getChar(index + 3)); NameAndType nt = (NameAndType)readPool(getChar(index + 3));
poolObj[i] = new MethodSymbol(0, nt.name, nt.type, owner); poolObj[i] = new MethodSymbol(0, nt.name, nt.uniqueType.type, owner);
break; break;
} }
case CONSTANT_NameandType: case CONSTANT_NameandType:
poolObj[i] = new NameAndType( poolObj[i] = new NameAndType(
readName(getChar(index + 1)), readName(getChar(index + 1)),
readType(getChar(index + 3))); readType(getChar(index + 3)), types);
break; break;
case CONSTANT_Integer: case CONSTANT_Integer:
poolObj[i] = getInt(index + 1); poolObj[i] = getInt(index + 1);
@ -1224,7 +1224,7 @@ public class ClassReader implements Completer {
if (nt == null) if (nt == null)
return null; return null;
MethodType type = nt.type.asMethodType(); MethodType type = nt.uniqueType.type.asMethodType();
for (Scope.Entry e = scope.lookup(nt.name); e.scope != null; e = e.next()) for (Scope.Entry e = scope.lookup(nt.name); e.scope != null; e = e.next())
if (e.sym.kind == MTH && isSameBinaryType(e.sym.type.asMethodType(), type)) if (e.sym.kind == MTH && isSameBinaryType(e.sym.type.asMethodType(), type))
@ -1236,16 +1236,16 @@ public class ClassReader implements Completer {
if ((flags & INTERFACE) != 0) if ((flags & INTERFACE) != 0)
// no enclosing instance // no enclosing instance
return null; return null;
if (nt.type.getParameterTypes().isEmpty()) if (nt.uniqueType.type.getParameterTypes().isEmpty())
// no parameters // no parameters
return null; return null;
// A constructor of an inner class. // A constructor of an inner class.
// Remove the first argument (the enclosing instance) // Remove the first argument (the enclosing instance)
nt.type = new MethodType(nt.type.getParameterTypes().tail, nt.setType(new MethodType(nt.uniqueType.type.getParameterTypes().tail,
nt.type.getReturnType(), nt.uniqueType.type.getReturnType(),
nt.type.getThrownTypes(), nt.uniqueType.type.getThrownTypes(),
syms.methodClass); syms.methodClass));
// Try searching again // Try searching again
return findMethod(nt, scope, flags); return findMethod(nt, scope, flags);
} }
@ -1959,7 +1959,7 @@ public class ClassReader implements Completer {
if (readAllOfClassFile) { if (readAllOfClassFile) {
for (int i = 1; i < poolObj.length; i++) readPool(i); for (int i = 1; i < poolObj.length; i++) readPool(i);
c.pool = new Pool(poolObj.length, poolObj); c.pool = new Pool(poolObj.length, poolObj, types);
} }
// reset and read rest of classinfo // reset and read rest of classinfo

View File

@ -39,7 +39,12 @@ import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Attribute.RetentionPolicy; import com.sun.tools.javac.code.Attribute.RetentionPolicy;
import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.Type.*; import com.sun.tools.javac.code.Type.*;
import com.sun.tools.javac.code.Types.UniqueType;
import com.sun.tools.javac.file.BaseFileObject; import com.sun.tools.javac.file.BaseFileObject;
import com.sun.tools.javac.jvm.Pool.DynamicMethod;
import com.sun.tools.javac.jvm.Pool.Method;
import com.sun.tools.javac.jvm.Pool.MethodHandle;
import com.sun.tools.javac.jvm.Pool.Variable;
import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.*;
import static com.sun.tools.javac.code.BoundKind.*; import static com.sun.tools.javac.code.BoundKind.*;
@ -142,7 +147,7 @@ public class ClassWriter extends ClassFile {
/** The bootstrap methods to be written in the corresponding class attribute /** The bootstrap methods to be written in the corresponding class attribute
* (one for each invokedynamic) * (one for each invokedynamic)
*/ */
Map<MethodSymbol, Pool.MethodHandle> bootstrapMethods; Map<DynamicMethod, MethodHandle> bootstrapMethods;
/** The log to use for verbose output. /** The log to use for verbose output.
*/ */
@ -477,10 +482,10 @@ public class ClassWriter extends ClassFile {
while (i < pool.pp) { while (i < pool.pp) {
Object value = pool.pool[i]; Object value = pool.pool[i];
Assert.checkNonNull(value); Assert.checkNonNull(value);
if (value instanceof Pool.Method) if (value instanceof Method)
value = ((Pool.Method)value).m; value = ((Method)value).m;
else if (value instanceof Pool.Variable) else if (value instanceof Variable)
value = ((Pool.Variable)value).v; value = ((Variable)value).v;
if (value instanceof MethodSymbol) { if (value instanceof MethodSymbol) {
MethodSymbol m = (MethodSymbol)value; MethodSymbol m = (MethodSymbol)value;
@ -493,8 +498,9 @@ public class ClassWriter extends ClassFile {
} else { } else {
//invokedynamic //invokedynamic
DynamicMethodSymbol dynSym = (DynamicMethodSymbol)m; DynamicMethodSymbol dynSym = (DynamicMethodSymbol)m;
Pool.MethodHandle handle = new Pool.MethodHandle(dynSym.bsmKind, dynSym.bsm); MethodHandle handle = new MethodHandle(dynSym.bsmKind, dynSym.bsm, types);
bootstrapMethods.put(dynSym, handle); DynamicMethod dynMeth = new DynamicMethod(dynSym, types);
bootstrapMethods.put(dynMeth, handle);
//init cp entries //init cp entries
pool.put(names.BootstrapMethods); pool.put(names.BootstrapMethods);
pool.put(handle); pool.put(handle);
@ -531,7 +537,7 @@ public class ClassWriter extends ClassFile {
NameAndType nt = (NameAndType)value; NameAndType nt = (NameAndType)value;
poolbuf.appendByte(CONSTANT_NameandType); poolbuf.appendByte(CONSTANT_NameandType);
poolbuf.appendChar(pool.put(nt.name)); poolbuf.appendChar(pool.put(nt.name));
poolbuf.appendChar(pool.put(typeSig(nt.type))); poolbuf.appendChar(pool.put(typeSig(nt.uniqueType.type)));
} else if (value instanceof Integer) { } else if (value instanceof Integer) {
poolbuf.appendByte(CONSTANT_Integer); poolbuf.appendByte(CONSTANT_Integer);
poolbuf.appendInt(((Integer)value).intValue()); poolbuf.appendInt(((Integer)value).intValue());
@ -549,17 +555,18 @@ public class ClassWriter extends ClassFile {
} else if (value instanceof String) { } else if (value instanceof String) {
poolbuf.appendByte(CONSTANT_String); poolbuf.appendByte(CONSTANT_String);
poolbuf.appendChar(pool.put(names.fromString((String)value))); poolbuf.appendChar(pool.put(names.fromString((String)value)));
} else if (value instanceof MethodType) { } else if (value instanceof UniqueType) {
MethodType mtype = (MethodType)value; Type type = ((UniqueType)value).type;
poolbuf.appendByte(CONSTANT_MethodType); if (type instanceof MethodType) {
poolbuf.appendChar(pool.put(typeSig(mtype))); poolbuf.appendByte(CONSTANT_MethodType);
} else if (value instanceof Type) { poolbuf.appendChar(pool.put(typeSig((MethodType)type)));
Type type = (Type)value; } else {
if (type.hasTag(CLASS)) enterInner((ClassSymbol)type.tsym); if (type.hasTag(CLASS)) enterInner((ClassSymbol)type.tsym);
poolbuf.appendByte(CONSTANT_Class); poolbuf.appendByte(CONSTANT_Class);
poolbuf.appendChar(pool.put(xClassName(type))); poolbuf.appendChar(pool.put(xClassName(type)));
} else if (value instanceof Pool.MethodHandle) { }
Pool.MethodHandle ref = (Pool.MethodHandle)value; } else if (value instanceof MethodHandle) {
MethodHandle ref = (MethodHandle)value;
poolbuf.appendByte(CONSTANT_MethodHandle); poolbuf.appendByte(CONSTANT_MethodHandle);
poolbuf.appendByte(ref.refKind); poolbuf.appendByte(ref.refKind);
poolbuf.appendChar(pool.put(ref.refSym)); poolbuf.appendChar(pool.put(ref.refSym));
@ -589,7 +596,7 @@ public class ClassWriter extends ClassFile {
return new NameAndType(fieldName(sym), return new NameAndType(fieldName(sym),
retrofit retrofit
? sym.erasure(types) ? sym.erasure(types)
: sym.externalType(types)); : sym.externalType(types), types);
// if we retrofit, then the NameAndType has been read in as is // if we retrofit, then the NameAndType has been read in as is
// and no change is necessary. If we compile normally, the // and no change is necessary. If we compile normally, the
// NameAndType is generated from a symbol reference, and the // NameAndType is generated from a symbol reference, and the
@ -714,7 +721,7 @@ public class ClassWriter extends ClassFile {
endAttr(alenIdx); endAttr(alenIdx);
acount++; acount++;
} }
acount += writeJavaAnnotations(sym.getAnnotationMirrors()); acount += writeJavaAnnotations(sym.getRawAttributes());
return acount; return acount;
} }
@ -725,7 +732,7 @@ public class ClassWriter extends ClassFile {
boolean hasVisible = false; boolean hasVisible = false;
boolean hasInvisible = false; boolean hasInvisible = false;
if (m.params != null) for (VarSymbol s : m.params) { if (m.params != null) for (VarSymbol s : m.params) {
for (Attribute.Compound a : s.getAnnotationMirrors()) { for (Attribute.Compound a : s.getRawAttributes()) {
switch (types.getRetention(a)) { switch (types.getRetention(a)) {
case SOURCE: break; case SOURCE: break;
case CLASS: hasInvisible = true; break; case CLASS: hasInvisible = true; break;
@ -741,7 +748,7 @@ public class ClassWriter extends ClassFile {
databuf.appendByte(m.params.length()); databuf.appendByte(m.params.length());
for (VarSymbol s : m.params) { for (VarSymbol s : m.params) {
ListBuffer<Attribute.Compound> buf = new ListBuffer<Attribute.Compound>(); ListBuffer<Attribute.Compound> buf = new ListBuffer<Attribute.Compound>();
for (Attribute.Compound a : s.getAnnotationMirrors()) for (Attribute.Compound a : s.getRawAttributes())
if (types.getRetention(a) == RetentionPolicy.RUNTIME) if (types.getRetention(a) == RetentionPolicy.RUNTIME)
buf.append(a); buf.append(a);
databuf.appendChar(buf.length()); databuf.appendChar(buf.length());
@ -756,7 +763,7 @@ public class ClassWriter extends ClassFile {
databuf.appendByte(m.params.length()); databuf.appendByte(m.params.length());
for (VarSymbol s : m.params) { for (VarSymbol s : m.params) {
ListBuffer<Attribute.Compound> buf = new ListBuffer<Attribute.Compound>(); ListBuffer<Attribute.Compound> buf = new ListBuffer<Attribute.Compound>();
for (Attribute.Compound a : s.getAnnotationMirrors()) for (Attribute.Compound a : s.getRawAttributes())
if (types.getRetention(a) == RetentionPolicy.CLASS) if (types.getRetention(a) == RetentionPolicy.CLASS)
buf.append(a); buf.append(a);
databuf.appendChar(buf.length()); databuf.appendChar(buf.length());
@ -951,14 +958,16 @@ public class ClassWriter extends ClassFile {
void writeBootstrapMethods() { void writeBootstrapMethods() {
int alenIdx = writeAttr(names.BootstrapMethods); int alenIdx = writeAttr(names.BootstrapMethods);
databuf.appendChar(bootstrapMethods.size()); databuf.appendChar(bootstrapMethods.size());
for (Map.Entry<MethodSymbol, Pool.MethodHandle> entry : bootstrapMethods.entrySet()) { for (Map.Entry<DynamicMethod, MethodHandle> entry : bootstrapMethods.entrySet()) {
DynamicMethodSymbol dsym = (DynamicMethodSymbol)entry.getKey(); DynamicMethod dmeth = entry.getKey();
DynamicMethodSymbol dsym = (DynamicMethodSymbol)dmeth.baseSymbol();
//write BSM handle //write BSM handle
databuf.appendChar(pool.get(entry.getValue())); databuf.appendChar(pool.get(entry.getValue()));
//write static args length //write static args length
databuf.appendChar(dsym.staticArgs.length); databuf.appendChar(dsym.staticArgs.length);
//write static args array //write static args array
for (Object o : dsym.staticArgs) { Object[] uniqueArgs = dmeth.uniqueStaticArgs;
for (Object o : uniqueArgs) {
databuf.appendChar(pool.get(o)); databuf.appendChar(pool.get(o));
} }
} }
@ -1534,7 +1543,7 @@ public class ClassWriter extends ClassFile {
pool = c.pool; pool = c.pool;
innerClasses = null; innerClasses = null;
innerClassesQueue = null; innerClassesQueue = null;
bootstrapMethods = new LinkedHashMap<MethodSymbol, Pool.MethodHandle>(); bootstrapMethods = new LinkedHashMap<DynamicMethod, MethodHandle>();
Type supertype = types.supertype(c.type); Type supertype = types.supertype(c.type);
List<Type> interfaces = types.interfaces(c.type); List<Type> interfaces = types.interfaces(c.type);
@ -1627,7 +1636,7 @@ public class ClassWriter extends ClassFile {
} }
acount += writeFlagAttrs(c.flags()); acount += writeFlagAttrs(c.flags());
acount += writeJavaAnnotations(c.getAnnotationMirrors()); acount += writeJavaAnnotations(c.getRawAttributes());
acount += writeEnclosingMethodAttribute(c); acount += writeEnclosingMethodAttribute(c);
acount += writeExtraClassAttributes(c); acount += writeExtraClassAttributes(c);

View File

@ -27,6 +27,7 @@ package com.sun.tools.javac.jvm;
import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.Types.UniqueType;
import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
@ -901,6 +902,7 @@ public class Code {
if (o instanceof ClassSymbol) return syms.classType; if (o instanceof ClassSymbol) return syms.classType;
if (o instanceof Type.ArrayType) return syms.classType; if (o instanceof Type.ArrayType) return syms.classType;
if (o instanceof Type.MethodType) return syms.methodTypeType; if (o instanceof Type.MethodType) return syms.methodTypeType;
if (o instanceof UniqueType) return typeForPool(((UniqueType)o).type);
if (o instanceof Pool.MethodHandle) return syms.methodHandleType; if (o instanceof Pool.MethodHandle) return syms.methodHandleType;
throw new AssertionError(o); throw new AssertionError(o);
} }
@ -1030,7 +1032,7 @@ public class Code {
Object o = pool.pool[od]; Object o = pool.pool[od];
Type t = (o instanceof Symbol) Type t = (o instanceof Symbol)
? ((Symbol)o).erasure(types) ? ((Symbol)o).erasure(types)
: types.erasure(((Type)o)); : types.erasure((((UniqueType)o).type));
state.push(t); state.push(t);
break; } break; }
case ldc2w: case ldc2w:

View File

@ -94,6 +94,10 @@ public class Gen extends JCTree.Visitor {
return instance; return instance;
} }
/* Constant pool, reset by genClass.
*/
private Pool pool;
protected Gen(Context context) { protected Gen(Context context) {
context.put(genKey, this); context.put(genKey, this);
@ -126,6 +130,7 @@ public class Gen extends JCTree.Visitor {
genCrt = options.isSet(XJCOV); genCrt = options.isSet(XJCOV);
debugCode = options.isSet("debugcode"); debugCode = options.isSet("debugcode");
allowInvokedynamic = target.hasInvokedynamic() || options.isSet("invokedynamic"); allowInvokedynamic = target.hasInvokedynamic() || options.isSet("invokedynamic");
pool = new Pool(types);
generateIproxies = generateIproxies =
target.requiresIproxy() || target.requiresIproxy() ||
@ -174,10 +179,6 @@ public class Gen extends JCTree.Visitor {
*/ */
private boolean useJsrLocally; private boolean useJsrLocally;
/* Constant pool, reset by genClass.
*/
private Pool pool = new Pool();
/** Code buffer, set by genMethod. /** Code buffer, set by genMethod.
*/ */
private Code code; private Code code;
@ -705,7 +706,7 @@ public class Gen extends JCTree.Visitor {
} }
int startpc = code.curPc(); int startpc = code.curPc();
genStat(tree, env); genStat(tree, env);
if (tree.hasTag(BLOCK)) crtFlags |= CRT_BLOCK; if (tree.hasTag(Tag.BLOCK)) crtFlags |= CRT_BLOCK;
code.crt.put(tree, crtFlags, startpc, code.curPc()); code.crt.put(tree, crtFlags, startpc, code.curPc());
} }

View File

@ -28,6 +28,9 @@ package com.sun.tools.javac.jvm;
import com.sun.tools.javac.code.Kinds; import com.sun.tools.javac.code.Kinds;
import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Types;
import com.sun.tools.javac.code.Types.UniqueType;
import com.sun.tools.javac.util.ArrayUtils; import com.sun.tools.javac.util.ArrayUtils;
import com.sun.tools.javac.util.Assert; import com.sun.tools.javac.util.Assert;
@ -60,11 +63,14 @@ public class Pool {
*/ */
Map<Object,Integer> indices; Map<Object,Integer> indices;
Types types;
/** Construct a pool with given number of elements and element array. /** Construct a pool with given number of elements and element array.
*/ */
public Pool(int pp, Object[] pool) { public Pool(int pp, Object[] pool, Types types) {
this.pp = pp; this.pp = pp;
this.pool = pool; this.pool = pool;
this.types = types;
this.indices = new HashMap<Object,Integer>(pool.length); this.indices = new HashMap<Object,Integer>(pool.length);
for (int i = 1; i < pp; i++) { for (int i = 1; i < pp; i++) {
if (pool[i] != null) indices.put(pool[i], i); if (pool[i] != null) indices.put(pool[i], i);
@ -73,8 +79,8 @@ public class Pool {
/** Construct an empty pool. /** Construct an empty pool.
*/ */
public Pool() { public Pool(Types types) {
this(1, new Object[64]); this(1, new Object[64], types);
} }
/** Return the number of entries in the constant pool. /** Return the number of entries in the constant pool.
@ -114,11 +120,13 @@ public class Pool {
Object makePoolValue(Object o) { Object makePoolValue(Object o) {
if (o instanceof DynamicMethodSymbol) { if (o instanceof DynamicMethodSymbol) {
return new DynamicMethod((DynamicMethodSymbol)o); return new DynamicMethod((DynamicMethodSymbol)o, types);
} else if (o instanceof MethodSymbol) { } else if (o instanceof MethodSymbol) {
return new Method((MethodSymbol)o); return new Method((MethodSymbol)o, types);
} else if (o instanceof VarSymbol) { } else if (o instanceof VarSymbol) {
return new Variable((VarSymbol)o); return new Variable((VarSymbol)o, types);
} else if (o instanceof Type) {
return new UniqueType((Type)o, types);
} else { } else {
return o; return o;
} }
@ -134,9 +142,11 @@ public class Pool {
static class Method extends DelegatedSymbol { static class Method extends DelegatedSymbol {
MethodSymbol m; MethodSymbol m;
Method(MethodSymbol m) { UniqueType uniqueType;
Method(MethodSymbol m, Types types) {
super(m); super(m);
this.m = m; this.m = m;
this.uniqueType = new UniqueType(m.type, types);
} }
public boolean equals(Object other) { public boolean equals(Object other) {
if (!(other instanceof Method)) return false; if (!(other instanceof Method)) return false;
@ -144,20 +154,22 @@ public class Pool {
return return
o.name == m.name && o.name == m.name &&
o.owner == m.owner && o.owner == m.owner &&
o.type.equals(m.type); ((Method)other).uniqueType.equals(uniqueType);
} }
public int hashCode() { public int hashCode() {
return return
m.name.hashCode() * 33 + m.name.hashCode() * 33 +
m.owner.hashCode() * 9 + m.owner.hashCode() * 9 +
m.type.hashCode(); uniqueType.hashCode();
} }
} }
static class DynamicMethod extends Method { static class DynamicMethod extends Method {
public Object[] uniqueStaticArgs;
DynamicMethod(DynamicMethodSymbol m) { DynamicMethod(DynamicMethodSymbol m, Types types) {
super(m); super(m, types);
uniqueStaticArgs = getUniqueTypeArray(m.staticArgs, types);
} }
@Override @Override
@ -168,7 +180,8 @@ public class Pool {
DynamicMethodSymbol dm2 = (DynamicMethodSymbol)((DynamicMethod)other).m; DynamicMethodSymbol dm2 = (DynamicMethodSymbol)((DynamicMethod)other).m;
return dm1.bsm == dm2.bsm && return dm1.bsm == dm2.bsm &&
dm1.bsmKind == dm2.bsmKind && dm1.bsmKind == dm2.bsmKind &&
Arrays.equals(dm1.staticArgs, dm2.staticArgs); Arrays.equals(uniqueStaticArgs,
((DynamicMethod)other).uniqueStaticArgs);
} }
@Override @Override
@ -178,17 +191,31 @@ public class Pool {
hash += dm.bsmKind * 7 + hash += dm.bsmKind * 7 +
dm.bsm.hashCode() * 11; dm.bsm.hashCode() * 11;
for (int i = 0; i < dm.staticArgs.length; i++) { for (int i = 0; i < dm.staticArgs.length; i++) {
hash += (dm.staticArgs[i].hashCode() * 23); hash += (uniqueStaticArgs[i].hashCode() * 23);
} }
return hash; return hash;
} }
private Object[] getUniqueTypeArray(Object[] objects, Types types) {
Object[] result = new Object[objects.length];
for (int i = 0; i < objects.length; i++) {
if (objects[i] instanceof Type) {
result[i] = new UniqueType((Type)objects[i], types);
} else {
result[i] = objects[i];
}
}
return result;
}
} }
static class Variable extends DelegatedSymbol { static class Variable extends DelegatedSymbol {
VarSymbol v; VarSymbol v;
Variable(VarSymbol v) { UniqueType uniqueType;
Variable(VarSymbol v, Types types) {
super(v); super(v);
this.v = v; this.v = v;
this.uniqueType = new UniqueType(v.type, types);
} }
public boolean equals(Object other) { public boolean equals(Object other) {
if (!(other instanceof Variable)) return false; if (!(other instanceof Variable)) return false;
@ -196,13 +223,13 @@ public class Pool {
return return
o.name == v.name && o.name == v.name &&
o.owner == v.owner && o.owner == v.owner &&
o.type.equals(v.type); ((Variable)other).uniqueType.equals(uniqueType);
} }
public int hashCode() { public int hashCode() {
return return
v.name.hashCode() * 33 + v.name.hashCode() * 33 +
v.owner.hashCode() * 9 + v.owner.hashCode() * 9 +
v.type.hashCode(); uniqueType.hashCode();
} }
} }
@ -214,9 +241,12 @@ public class Pool {
/** Reference symbol */ /** Reference symbol */
Symbol refSym; Symbol refSym;
public MethodHandle(int refKind, Symbol refSym) { UniqueType uniqueType;
public MethodHandle(int refKind, Symbol refSym, Types types) {
this.refKind = refKind; this.refKind = refKind;
this.refSym = refSym; this.refSym = refSym;
this.uniqueType = new UniqueType(this.refSym.type, types);
checkConsistent(); checkConsistent();
} }
public boolean equals(Object other) { public boolean equals(Object other) {
@ -227,14 +257,14 @@ public class Pool {
return return
o.name == refSym.name && o.name == refSym.name &&
o.owner == refSym.owner && o.owner == refSym.owner &&
o.type.equals(refSym.type); ((MethodHandle)other).uniqueType.equals(uniqueType);
} }
public int hashCode() { public int hashCode() {
return return
refKind * 65 + refKind * 65 +
refSym.name.hashCode() * 33 + refSym.name.hashCode() * 33 +
refSym.owner.hashCode() * 9 + refSym.owner.hashCode() * 9 +
refSym.type.hashCode(); uniqueType.hashCode();
} }
/** /**

View File

@ -928,6 +928,16 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
} }
} }
/**
* Set needRootClasses to true, in JavaCompiler subclass constructor
* that want to collect public apis of classes supplied on the command line.
*/
protected boolean needRootClasses = false;
/**
* The list of classes explicitly supplied on the command line for compilation.
* Not always populated.
*/
private List<JCClassDecl> rootClasses; private List<JCClassDecl> rootClasses;
/** /**
@ -984,9 +994,10 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
} }
} }
//If generating source, remember the classes declared in // If generating source, or if tracking public apis,
//the original compilation units listed on the command line. // then remember the classes declared in
if (sourceOutput || stubOutput) { // the original compilation units listed on the command line.
if (needRootClasses || sourceOutput || stubOutput) {
ListBuffer<JCClassDecl> cdefs = lb(); ListBuffer<JCClassDecl> cdefs = lb();
for (JCCompilationUnit unit : roots) { for (JCCompilationUnit unit : roots) {
for (List<JCTree> defs = unit.defs; for (List<JCTree> defs = unit.defs;
@ -1247,6 +1258,12 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
attr.postAttr(env.tree); attr.postAttr(env.tree);
} }
compileStates.put(env, CompileState.ATTR); compileStates.put(env, CompileState.ATTR);
if (rootClasses != null && rootClasses.contains(env.enclClass)) {
// This was a class that was explicitly supplied for compilation.
// If we want to capture the public api of this class,
// then now is a good time to do it.
reportPublicApi(env.enclClass.sym);
}
} }
finally { finally {
log.useSource(prev); log.useSource(prev);
@ -1255,6 +1272,14 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
return env; return env;
} }
/** Report the public api of a class that was supplied explicitly for compilation,
* for example on the command line to javac.
* @param sym The symbol of the class.
*/
public void reportPublicApi(ClassSymbol sym) {
// Override to collect the reported public api.
}
/** /**
* Perform dataflow checks on attributed parse trees. * Perform dataflow checks on attributed parse trees.
* These include checks for definite assignment and unreachable statements. * These include checks for definite assignment and unreachable statements.
@ -1675,7 +1700,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
/** Print numbers of errors and warnings. /** Print numbers of errors and warnings.
*/ */
protected void printCount(String kind, int count) { public void printCount(String kind, int count) {
if (count != 0) { if (count != 0) {
String key; String key;
if (count == 1) if (count == 1)

View File

@ -44,6 +44,8 @@ import javax.tools.JavaFileObject;
import com.sun.source.util.JavacTask; import com.sun.source.util.JavacTask;
import com.sun.source.util.Plugin; import com.sun.source.util.Plugin;
import com.sun.tools.doclint.DocLint;
import com.sun.tools.javac.api.BasicJavacTask;
import com.sun.tools.javac.code.Source; import com.sun.tools.javac.code.Source;
import com.sun.tools.javac.file.CacheFSInfo; import com.sun.tools.javac.file.CacheFSInfo;
import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.file.JavacFileManager;
@ -428,6 +430,7 @@ public class Main {
if (batchMode) if (batchMode)
CacheFSInfo.preRegister(context); CacheFSInfo.preRegister(context);
// FIXME: this code will not be invoked if using JavacTask.parse/analyze/generate
// invoke any available plugins // invoke any available plugins
String plugins = options.get(PLUGIN); String plugins = options.get(PLUGIN);
if (plugins != null) { if (plugins != null) {
@ -448,7 +451,7 @@ public class Main {
try { try {
if (task == null) if (task == null)
task = JavacTask.instance(pEnv); task = JavacTask.instance(pEnv);
plugin.call(task, p.tail.toArray(new String[p.tail.size()])); plugin.init(task, p.tail.toArray(new String[p.tail.size()]));
} catch (Throwable ex) { } catch (Throwable ex) {
if (apiMode) if (apiMode)
throw new RuntimeException(ex); throw new RuntimeException(ex);
@ -464,10 +467,31 @@ public class Main {
} }
} }
fileManager = context.get(JavaFileManager.class);
comp = JavaCompiler.instance(context); comp = JavaCompiler.instance(context);
if (comp == null) return Result.SYSERR;
// FIXME: this code will not be invoked if using JavacTask.parse/analyze/generate
String xdoclint = options.get(XDOCLINT);
String xdoclintCustom = options.get(XDOCLINT_CUSTOM);
if (xdoclint != null || xdoclintCustom != null) {
Set<String> doclintOpts = new LinkedHashSet<String>();
if (xdoclint != null)
doclintOpts.add(DocLint.XMSGS_OPTION);
if (xdoclintCustom != null) {
for (String s: xdoclintCustom.split("\\s+")) {
if (s.isEmpty())
continue;
doclintOpts.add(s.replace(XDOCLINT_CUSTOM.text, DocLint.XMSGS_CUSTOM_PREFIX));
}
}
if (!(doclintOpts.size() == 1
&& doclintOpts.iterator().next().equals(DocLint.XMSGS_CUSTOM_PREFIX + "none"))) {
JavacTask t = BasicJavacTask.instance(context);
new DocLint().init(t, doclintOpts.toArray(new String[doclintOpts.size()]));
comp.keepComments = true;
}
}
fileManager = context.get(JavaFileManager.class);
if (!files.isEmpty()) { if (!files.isEmpty()) {
// add filenames to fileObjects // add filenames to fileObjects

View File

@ -25,28 +25,30 @@
package com.sun.tools.javac.main; package com.sun.tools.javac.main;
import java.util.Collections;
import com.sun.tools.javac.util.Log.PrefixKind;
import com.sun.tools.javac.util.Log.WriterKind;
import com.sun.tools.javac.util.Log;
import com.sun.tools.javac.code.Lint;
import com.sun.tools.javac.code.Source;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.jvm.Target;
import com.sun.tools.javac.util.Options;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import java.io.File; import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.lang.model.SourceVersion; import javax.lang.model.SourceVersion;
import com.sun.tools.doclint.DocLint;
import com.sun.tools.javac.code.Lint;
import com.sun.tools.javac.code.Source;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.jvm.Target;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.util.Log;
import com.sun.tools.javac.util.Log.PrefixKind;
import com.sun.tools.javac.util.Log.WriterKind;
import com.sun.tools.javac.util.Options;
import static com.sun.tools.javac.main.Option.ChoiceKind.*; import static com.sun.tools.javac.main.Option.ChoiceKind.*;
import static com.sun.tools.javac.main.Option.OptionKind.*;
import static com.sun.tools.javac.main.Option.OptionGroup.*; import static com.sun.tools.javac.main.Option.OptionGroup.*;
import static com.sun.tools.javac.main.Option.OptionKind.*;
/** /**
* Options for javac. The specific Option to handle a command-line option * Options for javac. The specific Option to handle a command-line option
@ -79,6 +81,24 @@ public enum Option {
XLINT_CUSTOM("-Xlint:", "opt.Xlint.suboptlist", XLINT_CUSTOM("-Xlint:", "opt.Xlint.suboptlist",
EXTENDED, BASIC, ANYOF, getXLintChoices()), EXTENDED, BASIC, ANYOF, getXLintChoices()),
XDOCLINT("-Xdoclint", "opt.Xdoclint", EXTENDED, BASIC),
XDOCLINT_CUSTOM("-Xdoclint:", "opt.Xdoclint.subopts", "opt.Xdoclint.custom", EXTENDED, BASIC) {
@Override
public boolean matches(String option) {
return DocLint.isValidOption(
option.replace(XDOCLINT_CUSTOM.text, DocLint.XMSGS_CUSTOM_PREFIX));
}
@Override
public boolean process(OptionHelper helper, String option) {
String prev = helper.get(XDOCLINT_CUSTOM);
String next = (prev == null) ? option : (prev + " " + option);
helper.put(XDOCLINT_CUSTOM.text, next);
return false;
}
},
// -nowarn is retained for command-line backward compatibility // -nowarn is retained for command-line backward compatibility
NOWARN("-nowarn", "opt.nowarn", STANDARD, BASIC) { NOWARN("-nowarn", "opt.nowarn", STANDARD, BASIC) {
@Override @Override

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -25,11 +25,16 @@
package com.sun.tools.javac.model; package com.sun.tools.javac.model;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.EnumSet;
import javax.lang.model.element.*; import javax.lang.model.element.*;
import javax.lang.model.type.*; import javax.lang.model.type.*;
import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.*;
@ -301,4 +306,31 @@ public class JavacTypes implements javax.lang.model.util.Types {
throw new IllegalArgumentException(o.toString()); throw new IllegalArgumentException(o.toString());
return clazz.cast(o); return clazz.cast(o);
} }
public Set<MethodSymbol> getOverriddenMethods(Element elem) {
if (elem.getKind() != ElementKind.METHOD
|| elem.getModifiers().contains(Modifier.STATIC)
|| elem.getModifiers().contains(Modifier.PRIVATE))
return Collections.emptySet();
if (!(elem instanceof MethodSymbol))
throw new IllegalArgumentException();
MethodSymbol m = (MethodSymbol) elem;
ClassSymbol origin = (ClassSymbol) m.owner;
Set<MethodSymbol> results = new LinkedHashSet<MethodSymbol>();
for (Type t : types.closure(origin.type)) {
if (t != origin.type) {
ClassSymbol c = (ClassSymbol) t.tsym;
for (Scope.Entry e = c.members().lookup(m.name); e.scope != null; e = e.next()) {
if (e.sym.kind == Kinds.MTH && m.overrides(e.sym, origin, types, true)) {
results.add((MethodSymbol) e.sym);
}
}
}
}
return results;
}
} }

View File

@ -25,15 +25,12 @@
package com.sun.tools.javac.parser; package com.sun.tools.javac.parser;
import com.sun.tools.javac.util.Filter;
import java.text.BreakIterator; import java.text.BreakIterator;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Queue;
import java.util.Set; import java.util.Set;
import com.sun.source.doctree.AttributeTree.ValueKind; import com.sun.source.doctree.AttributeTree.ValueKind;
@ -52,7 +49,6 @@ import com.sun.tools.javac.tree.DCTree.DCText;
import com.sun.tools.javac.tree.DocTreeMaker; import com.sun.tools.javac.tree.DocTreeMaker;
import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.util.DiagnosticSource; import com.sun.tools.javac.util.DiagnosticSource;
import com.sun.tools.javac.util.JCDiagnostic;
import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Log; import com.sun.tools.javac.util.Log;
@ -736,7 +732,9 @@ public class DocCommentParser {
nextChar(); nextChar();
return m.at(p).Entity(names.fromChars(buf, namep, bp - namep - 1)); return m.at(p).Entity(names.fromChars(buf, namep, bp - namep - 1));
} else { } else {
String code = checkSemi ? "dc.missing.semicolon" : "dc.bad.entity"; String code = checkSemi
? "dc.missing.semicolon"
: "dc.bad.entity";
return erroneous(code, p); return erroneous(code, p);
} }
} }
@ -888,8 +886,10 @@ public class DocCommentParser {
} }
protected void addPendingText(ListBuffer<DCTree> list, int textEnd) { protected void addPendingText(ListBuffer<DCTree> list, int textEnd) {
if (textStart != -1 && textStart <= textEnd) { if (textStart != -1) {
list.add(m.at(textStart).Text(newString(textStart, textEnd + 1))); if (textStart <= textEnd) {
list.add(m.at(textStart).Text(newString(textStart, textEnd + 1)));
}
textStart = -1; textStart = -1;
} }
} }
@ -1196,6 +1196,16 @@ public class DocCommentParser {
return m.at(pos).See(html); return m.at(pos).See(html);
break; break;
case '@':
if (newline)
throw new ParseException("dc.no.content");
break;
case EOI:
if (bp == buf.length - 1)
throw new ParseException("dc.no.content");
break;
default: default:
if (isJavaIdentifierStart(ch) || ch == '#') { if (isJavaIdentifierStart(ch) || ch == '#') {
DCReference ref = reference(true); DCReference ref = reference(true);

View File

@ -2364,6 +2364,9 @@ compiler.err.dc.malformed.html=\
compiler.err.dc.missing.semicolon=\ compiler.err.dc.missing.semicolon=\
semicolon missing semicolon missing
compiler.err.dc.no.content=\
no content
compiler.err.dc.no.tag.name=\ compiler.err.dc.no.tag.name=\
no tag name after '@' no tag name after '@'

View File

@ -138,6 +138,14 @@ javac.opt.Xlint=\
Enable recommended warnings Enable recommended warnings
javac.opt.Xlint.suboptlist=\ javac.opt.Xlint.suboptlist=\
Enable or disable specific warnings Enable or disable specific warnings
javac.opt.Xdoclint=\
Enable recommended checks for problems in javadoc comments
javac.opt.Xdoclint.subopts = \
(all|[-]<group>)[/<access>]
javac.opt.Xdoclint.custom=\n\
\ Enable or disable specific checks for problems in javadoc comments,\n\
\ where <group> is one of accessibility, html, reference, or syntax,\n\
\ and <access> is one of public, protected, package, or private.
javac.opt.Xstdout=\ javac.opt.Xstdout=\
Redirect standard output Redirect standard output
javac.opt.X=\ javac.opt.X=\

View File

@ -33,6 +33,7 @@ import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.Attribute;
import com.sun.tools.javac.code.Symtab; import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.code.Type; import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Types;
import com.sun.tools.javac.jvm.ClassReader; import com.sun.tools.javac.jvm.ClassReader;
import com.sun.tools.javac.jvm.ClassWriter; import com.sun.tools.javac.jvm.ClassWriter;
import com.sun.tools.javac.jvm.Pool; import com.sun.tools.javac.jvm.Pool;
@ -173,7 +174,8 @@ public class CreateSymbols extends AbstractProcessor {
List.<Pair<Symbol.MethodSymbol,Attribute>>nil()); List.<Pair<Symbol.MethodSymbol,Attribute>>nil());
Type.moreInfo = true; Type.moreInfo = true;
Pool pool = new Pool(); Types types = Types.instance(task.getContext());
Pool pool = new Pool(types);
for (JavaFileObject file : fm.list(jarLocation, "", EnumSet.of(CLASS), true)) { for (JavaFileObject file : fm.list(jarLocation, "", EnumSet.of(CLASS), true)) {
String className = fm.inferBinaryName(jarLocation, file); String className = fm.inferBinaryName(jarLocation, file);
int index = className.lastIndexOf('.'); int index = className.lastIndexOf('.');

View File

@ -36,6 +36,8 @@ import com.sun.tools.javac.util.JCDiagnostic;
import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition; import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition;
import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Name; import com.sun.tools.javac.util.Name;
import java.io.IOException;
import java.io.StringWriter;
import javax.tools.JavaFileObject; import javax.tools.JavaFileObject;
/** /**
@ -65,6 +67,21 @@ public abstract class DCTree implements DocTree {
return new SimpleDiagnosticPosition(dc.comment.getSourcePos(pos)); return new SimpleDiagnosticPosition(dc.comment.getSourcePos(pos));
} }
/** Convert a tree to a pretty-printed string. */
@Override
public String toString() {
StringWriter s = new StringWriter();
try {
new DocPretty(s).print(this);
}
catch (IOException e) {
// should never happen, because StringWriter is defined
// never to throw any IOExceptions
throw new AssertionError(e);
}
return s.toString();
}
public static class DCDocComment extends DCTree implements DocCommentTree { public static class DCDocComment extends DCTree implements DocCommentTree {
final Comment comment; // required for the implicit source pos table final Comment comment; // required for the implicit source pos table

View File

@ -81,7 +81,7 @@ public class DocPretty implements DocTreeVisitor<Void,Void> {
/** /**
* Print list. * Print list.
*/ */
protected void print(List<? extends DocTree> list) throws IOException { public void print(List<? extends DocTree> list) throws IOException {
for (DocTree t: list) { for (DocTree t: list) {
print(t); print(t);
} }

View File

@ -26,6 +26,7 @@
package com.sun.tools.javac.tree; package com.sun.tools.javac.tree;
import com.sun.source.tree.Tree; import com.sun.source.tree.Tree;
import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.*;
import com.sun.tools.javac.comp.AttrContext; import com.sun.tools.javac.comp.AttrContext;
@ -330,6 +331,13 @@ public class TreeInfo {
return (docComments == null) ? null : docComments.getCommentText(tree); return (docComments == null) ? null : docComments.getCommentText(tree);
} }
public static DCTree.DCDocComment getCommentTree(Env<?> env, JCTree tree) {
DocCommentTable docComments = (tree.hasTag(JCTree.Tag.TOPLEVEL))
? ((JCCompilationUnit) tree).docComments
: env.toplevel.docComments;
return (docComments == null) ? null : docComments.getCommentTree(tree);
}
/** The position of the first statement in a block, or the position of /** The position of the first statement in a block, or the position of
* the block itself if it is empty. * the block itself if it is empty.
*/ */

View File

@ -684,7 +684,7 @@ public class TreeMaker implements JCTree.Factory {
public JCVariableDecl VarDef(VarSymbol v, JCExpression init) { public JCVariableDecl VarDef(VarSymbol v, JCExpression init) {
return (JCVariableDecl) return (JCVariableDecl)
new JCVariableDecl( new JCVariableDecl(
Modifiers(v.flags(), Annotations(v.getAnnotationMirrors())), Modifiers(v.flags(), Annotations(v.getRawAttributes())),
v.name, v.name,
Type(v.type), Type(v.type),
init, init,
@ -800,7 +800,7 @@ public class TreeMaker implements JCTree.Factory {
public JCMethodDecl MethodDef(MethodSymbol m, Type mtype, JCBlock body) { public JCMethodDecl MethodDef(MethodSymbol m, Type mtype, JCBlock body) {
return (JCMethodDecl) return (JCMethodDecl)
new JCMethodDecl( new JCMethodDecl(
Modifiers(m.flags(), Annotations(m.getAnnotationMirrors())), Modifiers(m.flags(), Annotations(m.getRawAttributes())),
m.name, m.name,
Type(mtype.getReturnType()), Type(mtype.getReturnType()),
TypeParams(mtype.getTypeArguments()), TypeParams(mtype.getTypeArguments()),

View File

@ -276,6 +276,10 @@ public class ClassDocImpl extends ProgramElementDocImpl implements ClassDoc {
return false; return false;
} }
public boolean isFunctionalInterface() {
return env.types.isFunctionalInterface(tsym);
}
/** /**
* Return the package that this class is contained in. * Return the package that this class is contained in.
*/ */

View File

@ -75,6 +75,13 @@ public class MethodDocImpl
return true; return true;
} }
/**
* Return true if this method is default
*/
public boolean isDefault() {
return (sym.flags() & Flags.DEFAULT) != 0;
}
/** /**
* Return true if this method is abstract * Return true if this method is abstract
*/ */

View File

@ -288,9 +288,9 @@ public class PackageDocImpl extends DocImpl implements PackageDoc {
* Return an empty array if there are none. * Return an empty array if there are none.
*/ */
public AnnotationDesc[] annotations() { public AnnotationDesc[] annotations() {
AnnotationDesc res[] = new AnnotationDesc[sym.getAnnotationMirrors().length()]; AnnotationDesc res[] = new AnnotationDesc[sym.getRawAttributes().length()];
int i = 0; int i = 0;
for (Attribute.Compound a : sym.getAnnotationMirrors()) { for (Attribute.Compound a : sym.getRawAttributes()) {
res[i++] = new AnnotationDescImpl(env, a); res[i++] = new AnnotationDescImpl(env, a);
} }
return res; return res;

View File

@ -99,9 +99,9 @@ class ParameterImpl implements Parameter {
* Return an empty array if there are none. * Return an empty array if there are none.
*/ */
public AnnotationDesc[] annotations() { public AnnotationDesc[] annotations() {
AnnotationDesc res[] = new AnnotationDesc[sym.getAnnotationMirrors().length()]; AnnotationDesc res[] = new AnnotationDesc[sym.getRawAttributes().length()];
int i = 0; int i = 0;
for (Attribute.Compound a : sym.getAnnotationMirrors()) { for (Attribute.Compound a : sym.getRawAttributes()) {
res[i++] = new AnnotationDescImpl(env, a); res[i++] = new AnnotationDescImpl(env, a);
} }
return res; return res;

View File

@ -164,9 +164,9 @@ public abstract class ProgramElementDocImpl
* Return an empty array if there are none. * Return an empty array if there are none.
*/ */
public AnnotationDesc[] annotations() { public AnnotationDesc[] annotations() {
AnnotationDesc res[] = new AnnotationDesc[sym.getAnnotationMirrors().length()]; AnnotationDesc res[] = new AnnotationDesc[sym.getRawAttributes().length()];
int i = 0; int i = 0;
for (Attribute.Compound a : sym.getAnnotationMirrors()) { for (Attribute.Compound a : sym.getRawAttributes()) {
res[i++] = new AnnotationDescImpl(env, a); res[i++] = new AnnotationDescImpl(env, a);
} }
return res; return res;

View File

@ -77,6 +77,16 @@ public interface ExecutableElement extends Element, Parameterizable {
*/ */
boolean isVarArgs(); boolean isVarArgs();
/**
* Returns {@code true} if this method is a default method and
* returns {@code false} otherwise.
*
* @return {@code true} if this method is a default method and
* {@code false} otherwise
* @since 1.8
*/
boolean isDefault();
/** /**
* Returns the exceptions and other throwables listed in this * Returns the exceptions and other throwables listed in this
* method or constructor's {@code throws} clause in declaration * method or constructor's {@code throws} clause in declaration

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -207,7 +207,7 @@ public class TestHtmlTableTags extends JavadocTester {
"Instance Methods</a></span><span class=\"tabEnd\">&nbsp;</span></span>" + "Instance Methods</a></span><span class=\"tabEnd\">&nbsp;</span></span>" +
"<span id=\"t4\" class=\"tableTab\"><span><a href=\"javascript:show(8);\">" + "<span id=\"t4\" class=\"tableTab\"><span><a href=\"javascript:show(8);\">" +
"Concrete Methods</a></span><span class=\"tabEnd\">&nbsp;</span></span>" + "Concrete Methods</a></span><span class=\"tabEnd\">&nbsp;</span></span>" +
"<span id=\"t5\" class=\"tableTab\"><span><a href=\"javascript:show(16);\">" + "<span id=\"t6\" class=\"tableTab\"><span><a href=\"javascript:show(32);\">" +
"Deprecated Methods</a></span><span class=\"tabEnd\">&nbsp;</span></span>" + "Deprecated Methods</a></span><span class=\"tabEnd\">&nbsp;</span></span>" +
"</caption>" "</caption>"
}, },

View File

@ -0,0 +1,102 @@
/*
* 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.
*
* 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.
*/
/*
* @test
* @bug 8004893
* @summary Make sure that the lambda feature changes work fine in
* javadoc.
* @author bpatel
* @library ../lib/
* @build JavadocTester TestLambdaFeature
* @run main TestLambdaFeature
*/
public class TestLambdaFeature extends JavadocTester {
//Test information.
private static final String BUG_ID = "8004893";
//Javadoc arguments.
private static final String[] ARGS = new String[] {
"-d", BUG_ID, "-sourcepath", SRC_DIR, "pkg"
};
//Input for string search tests.
private static final String[][] TEST = {
{BUG_ID + FS + "pkg" + FS + "A.html",
"<td class=\"colFirst\"><code>default void</code></td>"},
{BUG_ID + FS + "pkg" + FS + "A.html",
"<pre>default&nbsp;void&nbsp;defaultMethod()</pre>"},
{BUG_ID + FS + "pkg" + FS + "A.html",
"<caption><span id=\"t0\" class=\"activeTableTab\"><span>" +
"All Methods</span><span class=\"tabEnd\">&nbsp;</span></span>" +
"<span id=\"t2\" class=\"tableTab\"><span>" +
"<a href=\"javascript:show(2);\">Instance Methods</a></span>" +
"<span class=\"tabEnd\">&nbsp;</span></span><span id=\"t3\" " +
"class=\"tableTab\"><span><a href=\"javascript:show(4);\">" +
"Abstract Methods</a></span><span class=\"tabEnd\">&nbsp;</span>" +
"</span><span id=\"t5\" class=\"tableTab\"><span>" +
"<a href=\"javascript:show(16);\">Default Methods</a></span>" +
"<span class=\"tabEnd\">&nbsp;</span></span></caption>"},
{BUG_ID + FS + "pkg" + FS + "A.html",
"<dl>" + NL + "<dt>Functional Interface:</dt>" + NL +
"<dd>This is a functional interface and can therefore be used as " +
"the assignment target for a lambda expression or method " +
"reference. </dd>" + NL + "</dl>"}
};
private static final String[][] NEGATED_TEST = {
{BUG_ID + FS + "pkg" + FS + "A.html",
"<td class=\"colFirst\"><code>default default void</code></td>"},
{BUG_ID + FS + "pkg" + FS + "A.html",
"<pre>default&nbsp;default&nbsp;void&nbsp;defaultMethod()</pre>"},
{BUG_ID + FS + "pkg" + FS + "B.html",
"<td class=\"colFirst\"><code>default void</code></td>"},
{BUG_ID + FS + "pkg" + FS + "B.html",
"<dl>" + NL + "<dt>Functional Interface:</dt>"}
};
/**
* The entry point of the test.
* @param args the array of command line arguments.
*/
public static void main(String[] args) {
TestLambdaFeature tester = new TestLambdaFeature();
run(tester, ARGS, TEST, NEGATED_TEST);
tester.printSummary();
}
/**
* {@inheritDoc}
*/
public String getBugId() {
return BUG_ID;
}
/**
* {@inheritDoc}
*/
public String getBugName() {
return getClass().getName();
}
}

View File

@ -0,0 +1,31 @@
/*
* 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.
*
* 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 pkg;
public interface A {
public void method1();
public default void defaultMethod() { }
}

View File

@ -0,0 +1,31 @@
/*
* 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.
*
* 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 pkg;
public abstract class B {
public abstract void method1();
public void method2() { }
}

View File

@ -55,7 +55,7 @@ public class TestMethodTypes extends JavadocTester {
"Instance Methods</a></span><span class=\"tabEnd\">&nbsp;</span></span>" + "Instance Methods</a></span><span class=\"tabEnd\">&nbsp;</span></span>" +
"<span id=\"t4\" class=\"tableTab\"><span><a href=\"javascript:show(8);\">" + "<span id=\"t4\" class=\"tableTab\"><span><a href=\"javascript:show(8);\">" +
"Concrete Methods</a></span><span class=\"tabEnd\">&nbsp;</span></span>" + "Concrete Methods</a></span><span class=\"tabEnd\">&nbsp;</span></span>" +
"<span id=\"t5\" class=\"tableTab\"><span><a href=\"javascript:show(16);\">" + "<span id=\"t6\" class=\"tableTab\"><span><a href=\"javascript:show(32);\">" +
"Deprecated Methods</a></span><span class=\"tabEnd\">&nbsp;</span></span>" + "Deprecated Methods</a></span><span class=\"tabEnd\">&nbsp;</span></span>" +
"</caption>" "</caption>"
}, },
@ -87,7 +87,7 @@ public class TestMethodTypes extends JavadocTester {
"Abstract Methods</a></span><span class=\"tabEnd\">&nbsp;</span></span>" + "Abstract Methods</a></span><span class=\"tabEnd\">&nbsp;</span></span>" +
"<span id=\"t4\" class=\"tableTab\"><span><a href=\"javascript:show(8);\">" + "<span id=\"t4\" class=\"tableTab\"><span><a href=\"javascript:show(8);\">" +
"Concrete Methods</a></span><span class=\"tabEnd\">&nbsp;</span></span>" + "Concrete Methods</a></span><span class=\"tabEnd\">&nbsp;</span></span>" +
"<span id=\"t5\" class=\"tableTab\"><span><a href=\"javascript:show(16);\">" + "<span id=\"t6\" class=\"tableTab\"><span><a href=\"javascript:show(32);\">" +
"Deprecated Methods</a></span><span class=\"tabEnd\">&nbsp;</span></span>" + "Deprecated Methods</a></span><span class=\"tabEnd\">&nbsp;</span></span>" +
"</caption>" "</caption>"
}, },

View File

@ -0,0 +1,65 @@
/*
* @test /nodynamiccopyright/
* @bug 8004832
* @summary Add new doclint package
* @build DocLintTester
* @run main DocLintTester -ref AccessTest.protected.out AccessTest.java
* @run main DocLintTester -Xmsgs -ref AccessTest.private.out AccessTest.java
* @run main DocLintTester -Xmsgs:syntax -ref AccessTest.private.out AccessTest.java
* @run main DocLintTester -Xmsgs:syntax/public -ref AccessTest.public.out AccessTest.java
* @run main DocLintTester -Xmsgs:syntax/protected -ref AccessTest.protected.out AccessTest.java
* @run main DocLintTester -Xmsgs:syntax/package -ref AccessTest.package.out AccessTest.java
* @run main DocLintTester -Xmsgs:syntax/private -ref AccessTest.private.out AccessTest.java
* @run main DocLintTester -Xmsgs:all,-syntax AccessTest.java
* @run main DocLintTester -Xmsgs:all,-syntax/public AccessTest.java
* @run main DocLintTester -Xmsgs:all,-syntax/protected -ref AccessTest.public.out AccessTest.java
* @run main DocLintTester -Xmsgs:all,-syntax/package -ref AccessTest.protected.out AccessTest.java
* @run main DocLintTester -Xmsgs:all,-syntax/private -ref AccessTest.package.out AccessTest.java
*/
/** */
public class AccessTest {
/**
* public a < b
*/
public void public_syntax_error() { }
/**
* protected a < b
*/
protected void protected_syntax_error() { }
/**
* package-private a < b
*/
void syntax_error() { }
/**
* private a < b
*/
private void private_syntax_error() { }
}
/** */
class AccessTest2 {
/**
* public a < b
*/
public void public_syntax_error() { }
/**
* protected a < b
*/
protected void protected_syntax_error() { }
/**
* package-private a < b
*/
void syntax_error() { }
/**
* private a < b
*/
private void private_syntax_error() { }
}

View File

@ -0,0 +1,20 @@
AccessTest.java:23: error: malformed HTML
* public a < b
^
AccessTest.java:28: error: malformed HTML
* protected a < b
^
AccessTest.java:33: error: malformed HTML
* package-private a < b
^
AccessTest.java:46: error: malformed HTML
* public a < b
^
AccessTest.java:51: error: malformed HTML
* protected a < b
^
AccessTest.java:56: error: malformed HTML
* package-private a < b
^
6 errors

View File

@ -0,0 +1,27 @@
AccessTest.java:23: error: malformed HTML
* public a < b
^
AccessTest.java:28: error: malformed HTML
* protected a < b
^
AccessTest.java:33: error: malformed HTML
* package-private a < b
^
AccessTest.java:38: error: malformed HTML
* private a < b
^
AccessTest.java:46: error: malformed HTML
* public a < b
^
AccessTest.java:51: error: malformed HTML
* protected a < b
^
AccessTest.java:56: error: malformed HTML
* package-private a < b
^
AccessTest.java:61: error: malformed HTML
* private a < b
^
8 errors

View File

@ -0,0 +1,8 @@
AccessTest.java:23: error: malformed HTML
* public a < b
^
AccessTest.java:28: error: malformed HTML
* protected a < b
^
2 errors

View File

@ -0,0 +1,5 @@
AccessTest.java:23: error: malformed HTML
* public a < b
^
1 error

View File

@ -0,0 +1,44 @@
/*
* @test /nodynamiccopyright/
* @bug 8004832
* @summary Add new doclint package
* @build DocLintTester
* @run main DocLintTester -Xmsgs:-accessibility AccessibilityTest.java
* @run main DocLintTester -ref AccessibilityTest.out AccessibilityTest.java
*/
/** */
public class AccessibilityTest {
/**
* <h2> ... </h2>
*/
public void missing_h1() { }
/**
* <h1> ... </h1>
* <h3> ... </h3>
*/
public void missing_h2() { }
/**
* <img src="x.jpg">
*/
public void missing_alt() { }
/**
* <table summary="ok"><tr><th>head<tr><td>data</table>
*/
public void table_with_summary() { }
/**
* <table><caption>ok</caption><tr><th>head<tr><td>data</table>
*/
public void table_with_caption() { }
/**
* <table><tr><th>head<tr><td>data</table>
*/
public void table_without_summary_and_caption() { }
}

View File

@ -0,0 +1,13 @@
AccessibilityTest.java:14: error: header used out of sequence: <H2>
* <h2> ... </h2>
^
AccessibilityTest.java:20: error: header used out of sequence: <H3>
* <h3> ... </h3>
^
AccessibilityTest.java:25: error: no "alt" attribute for image
* <img src="x.jpg">
^
AccessibilityTest.java:40: error: no summary or caption for table
* <table><tr><th>head<tr><td>data</table>
^
4 errors

View File

@ -0,0 +1,135 @@
/*
* 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.
*
* 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.
*/
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import com.sun.tools.doclint.DocLint;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringWriter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class DocLintTester {
public static void main(String... args) throws Exception {
new DocLintTester().run(args);
}
public void run(String... args) throws Exception {
String testSrc = System.getProperty("test.src");
File refFile = null;
List<String> opts = new ArrayList<String>();
List<File> files = new ArrayList<File>();
for (int i = 0; i < args.length; i++) {
String arg = args[i];
if (arg.equals("-ref")) {
refFile = new File(testSrc, args[++i]);
} else if (arg.startsWith("-Xmsgs")) {
opts.add(arg);
} else
files.add(new File(testSrc, arg));
}
check(opts, files, refFile);
if (errors > 0)
throw new Exception(errors + " errors occurred");
}
void check(List<String> opts, List<File> files, File refFile) throws Exception {
List<String> args = new ArrayList<String>();
args.addAll(opts);
for (File file: files)
args.add(file.getPath());
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
new DocLint().run(pw, args.toArray(new String[args.size()]));
pw.flush();
String out = normalizeNewlines(removeFileNames(sw.toString())).trim();
if (out != null)
System.err.println("Output:\n" + out);
if (refFile == null) {
if (!out.isEmpty())
error("unexpected output");
} else {
String expect = readFile(refFile);
if (!expect.equals(out)) {
error("expected output not found");
System.err.println("EXPECT>>" + expect + "<<");
System.err.println(" FOUND>>" + out + "<<");
}
}
}
String readFile(File file) throws IOException {
StringBuilder sb = new StringBuilder();
Reader in = new BufferedReader(new FileReader(file));
try {
char[] buf = new char[1024];
int n;
while ((n = in.read(buf)) != -1)
sb.append(buf, 0, n);
} finally {
in.close();
}
return sb.toString().trim();
}
private static final Pattern dirFileLine = Pattern.compile(
"(?m)" // multi-line mode
+ "^([^: ]+?)" // directory part of file name
+ "([A-Za-z0-9.]+:[0-9]+:)"); // file name and line number
String removeFileNames(String s) {
Matcher m = dirFileLine.matcher(s);
StringBuffer sb = new StringBuffer();
while (m.find()) {
m.appendReplacement(sb, "$2");
}
m.appendTail(sb);
return sb.toString();
}
private static final String nl = System.getProperty("line.separator");
String normalizeNewlines(String s) {
return (nl.equals("\n") ? s : s.replace(nl, "\n"));
}
void error(String msg) {
System.err.println("Error: " + msg);
errors++;
}
int errors;
}

View File

@ -0,0 +1,12 @@
/*
* @test /nodynamiccopyright/
* @bug 8004832
* @summary Add new doclint package
* @build DocLintTester
* @run main DocLintTester -Xmsgs:-syntax EmptyAuthorTest.java
* @run main DocLintTester -Xmsgs:syntax -ref EmptyAuthorTest.out EmptyAuthorTest.java
*/
/** @author */
public class EmptyAuthorTest {
}

View File

@ -0,0 +1,5 @@
EmptyAuthorTest.java:10: warning: no description for @author
/** @author */
^
1 warning

View File

@ -0,0 +1,14 @@
/*
* @test /nodynamiccopyright/
* @bug 8004832
* @summary Add new doclint package
* @build DocLintTester
* @run main DocLintTester -Xmsgs:-syntax EmptyExceptionTest.java
* @run main DocLintTester -Xmsgs:syntax -ref EmptyExceptionTest.out EmptyExceptionTest.java
*/
/** . */
public class EmptyExceptionTest {
/** @exception NullPointerException */
int emptyException() throws NullPointerException { }
}

View File

@ -0,0 +1,4 @@
EmptyExceptionTest.java:12: warning: no description for @exception
/** @exception NullPointerException */
^
1 warning

View File

@ -0,0 +1,14 @@
/*
* @test /nodynamiccopyright/
* @bug 8004832
* @summary Add new doclint package
* @build DocLintTester
* @run main DocLintTester -Xmsgs:-syntax EmptyParamTest.java
* @run main DocLintTester -Xmsgs:syntax -ref EmptyParamTest.out EmptyParamTest.java
*/
/** . */
public class EmptyParamTest {
/** @param i */
int emptyParam(int i) { }
}

View File

@ -0,0 +1,5 @@
EmptyParamTest.java:12: warning: no description for @param
/** @param i */
^
1 warning

View File

@ -0,0 +1,14 @@
/*
* @test /nodynamiccopyright/
* @bug 8004832
* @summary Add new doclint package
* @build DocLintTester
* @run main DocLintTester -Xmsgs:-syntax EmptyReturnTest.java
* @run main DocLintTester -Xmsgs:syntax -ref EmptyReturnTest.out EmptyReturnTest.java
*/
/** . */
public class EmptyReturnTest {
/** @return */
int emptyReturn() { }
}

View File

@ -0,0 +1,5 @@
EmptyReturnTest.java:12: warning: no description for @return
/** @return */
^
1 warning

View File

@ -0,0 +1,17 @@
/*
* @test /nodynamiccopyright/
* @bug 8004832
* @summary Add new doclint package
* @build DocLintTester
* @run main DocLintTester -Xmsgs:-syntax EmptySerialDataTest.java
* @run main DocLintTester -Xmsgs:syntax -ref EmptySerialDataTest.out EmptySerialDataTest.java
*/
import java.io.ObjectOutputStream;
import java.io.Serializable;
/** . */
public class EmptySerialDataTest implements Serializable {
/** @serialData */
private void writeObject(ObjectOutputStream s) { }
}

View File

@ -0,0 +1,5 @@
EmptySerialDataTest.java:15: warning: no description for @serialData
/** @serialData */
^
1 warning

View File

@ -0,0 +1,22 @@
/*
* @test /nodynamiccopyright/
* @bug 8004832
* @summary Add new doclint package
* @build DocLintTester
* @run main DocLintTester -Xmsgs:-syntax EmptySerialFieldTest.java
* @run main DocLintTester -Xmsgs:syntax -ref EmptySerialFieldTest.out EmptySerialFieldTest.java
*/
import java.io.ObjectStreamField;
import java.io.Serializable;
/** . */
public class EmptySerialFieldTest implements Serializable {
/**
* @serialField empty String
*/
private static final ObjectStreamField[] serialPersistentFields = {
new ObjectStreamField("empty", String.class),
};
}

View File

@ -0,0 +1,5 @@
EmptySerialFieldTest.java:17: warning: no description for @serialField
* @serialField empty String
^
1 warning

View File

@ -0,0 +1,14 @@
/*
* @test /nodynamiccopyright/
* @bug 8004832
* @summary Add new doclint package
* @build DocLintTester
* @run main DocLintTester -Xmsgs:-syntax EmptySinceTest.java
* @run main DocLintTester -Xmsgs:syntax -ref EmptySinceTest.out EmptySinceTest.java
*/
/** . */
public class EmptySinceTest {
/** @since */
int emptySince() { }
}

View File

@ -0,0 +1,5 @@
EmptySinceTest.java:12: warning: no description for @since
/** @since */
^
1 warning

View File

@ -0,0 +1,14 @@
/*
* @test /nodynamiccopyright/
* @bug 8004832
* @summary Add new doclint package
* @build DocLintTester
* @run main DocLintTester -Xmsgs:-syntax EmptyVersionTest.java
* @run main DocLintTester -Xmsgs:syntax -ref EmptyVersionTest.out EmptyVersionTest.java
*/
/** . */
public class EmptyVersionTest {
/** @version */
int missingVersion() { }
}

View File

@ -0,0 +1,4 @@
EmptyVersionTest.java:12: warning: no description for @version
/** @version */
^
1 warning

View File

@ -0,0 +1,27 @@
/*
* @test /nodynamiccopyright/
* @bug 8004832
* @summary Add new doclint package
* @build DocLintTester
* @run main DocLintTester -Xmsgs:-html HtmlAttrsTest.java
* @run main DocLintTester -ref HtmlAttrsTest.out HtmlAttrsTest.java
*/
/** */
public class HtmlAttrsTest {
/**
* <p xyz>
*/
public void unknown() { }
/**
* <img name="x" alt="alt">
*/
public void obsolete() { }
/**
* <font size="3"> text </font>
*/
public void obsolete_use_css() { }
}

View File

@ -0,0 +1,12 @@
HtmlAttrsTest.java:13: error: unknown attribute: xyz
* <p xyz>
^
HtmlAttrsTest.java:18: warning: attribute obsolete: name
* <img name="x" alt="alt">
^
HtmlAttrsTest.java:23: warning: attribute obsolete, use CSS instead: size
* <font size="3"> text </font>
^
1 error
2 warnings

View File

@ -0,0 +1,58 @@
/*
* @test /nodynamiccopyright/
* @bug 8004832
* @summary Add new doclint package
* @build DocLintTester
* @run main DocLintTester -Xmsgs:-html HtmlTagsTest.java
* @run main DocLintTester -ref HtmlTagsTest.out HtmlTagsTest.java
*/
/** */
public class HtmlTagsTest {
/**
* <xyz> ... </xyz>
*/
public void unknownTag1() { }
/**
* <div> <xyz> </div>
*/
public void unknownTag2() { }
/**
* <br/>
*/
public void selfClosingTag() { }
/**
* <html>
*/
public void not_allowed() { }
/**
* <span> <p> </span>
*/
public void not_allowed_inline() { }
/**
* {@link java.lang.String <p> }
* {@link java.lang.String <p> }
*/
public void not_allowed_inline_2() { }
/**
* <img src="any.jpg" alt="alt"> </img>
*/
public void end_not_allowed() { }
/**
* <i> <b> </i>
*/
public void start_not_matched() { }
/**
* <i> </b> </i>
*/
public void end_unexpected() { }
}

View File

@ -0,0 +1,38 @@
HtmlTagsTest.java:13: error: unknown tag: xyz
* <xyz> ... </xyz>
^
HtmlTagsTest.java:13: error: unknown tag: xyz
* <xyz> ... </xyz>
^
HtmlTagsTest.java:18: error: unknown tag: xyz
* <div> <xyz> </div>
^
HtmlTagsTest.java:23: error: self-closing element not allowed
* <br/>
^
HtmlTagsTest.java:28: error: element not allowed in documentation comments: <html>
* <html>
^
HtmlTagsTest.java:33: error: block element not allowed within inline element <span>: p
* <span> <p> </span>
^
HtmlTagsTest.java:38: error: block element not allowed within @link: p
* {@link java.lang.String <p> }
^
HtmlTagsTest.java:39: error: block element not allowed within @link: p
* {@link java.lang.String <p> }
^
HtmlTagsTest.java:44: error: invalid end tag: </img>
* <img src="any.jpg" alt="alt"> </img>
^
HtmlTagsTest.java:49: error: end tag missing: </b>
* <i> <b> </i>
^
HtmlTagsTest.java:54: error: unexpected end tag: </b>
* <i> </b> </i>
^
HtmlTagsTest.java:54: warning: empty <i> tag
* <i> </b> </i>
^
11 errors
1 warning

View File

@ -0,0 +1,14 @@
/*
* @test /nodynamiccopyright/
* @build DocLintTester
* @run main DocLintTester -Xmsgs:-missing MissingCommentTest.java
* @run main DocLintTester -Xmsgs:missing -ref MissingCommentTest.out MissingCommentTest.java
*/
public class MissingCommentTest {
MissingCommentTest() { }
int missingComment;
void missingComment() { }
}

View File

@ -0,0 +1,14 @@
MissingCommentTest.java:8: warning: no comment
public class MissingCommentTest {
^
MissingCommentTest.java:9: warning: no comment
MissingCommentTest() { }
^
MissingCommentTest.java:11: warning: no comment
int missingComment;
^
MissingCommentTest.java:13: warning: no comment
void missingComment() { }
^
4 warnings

View File

@ -0,0 +1,23 @@
/*
* @test /nodynamiccopyright/
* @bug 8004832
* @summary Add new doclint package
* @build DocLintTester
* @run main DocLintTester -Xmsgs:-missing MissingParamsTest.java
* @run main DocLintTester -Xmsgs:missing -ref MissingParamsTest.out MissingParamsTest.java
*/
/** . */
public class MissingParamsTest {
/** */
MissingParamsTest(int param) { }
/** */
<T> MissingParamsTest() { }
/** */
void missingParam(int param) { }
/** */
<T> void missingTyparam() { }
}

View File

@ -0,0 +1,14 @@
MissingParamsTest.java:13: warning: no @param for param
MissingParamsTest(int param) { }
^
MissingParamsTest.java:16: warning: no @param for <T>
<T> MissingParamsTest() { }
^
MissingParamsTest.java:19: warning: no @param for param
void missingParam(int param) { }
^
MissingParamsTest.java:22: warning: no @param for <T>
<T> void missingTyparam() { }
^
4 warnings

View File

@ -0,0 +1,23 @@
/*
* @test /nodynamiccopyright/
* @bug 8004832
* @summary Add new doclint package
* @build DocLintTester
* @run main DocLintTester -Xmsgs:-missing MissingReturnTest.java
* @run main DocLintTester -Xmsgs:missing -ref MissingReturnTest.out MissingReturnTest.java
*/
/** . */
public class MissingReturnTest {
/** no return allowed */
MissingReturnTest() { }
/** no return allowed */
void return_void() { }
/** no return required */
Void return_Void() { }
/** */
int missingReturn() { }
}

View File

@ -0,0 +1,5 @@
MissingReturnTest.java:22: warning: no @return
int missingReturn() { }
^
1 warning

View File

@ -0,0 +1,14 @@
/*
* @test /nodynamiccopyright/
* @bug 8004832
* @summary Add new doclint package
* @build DocLintTester
* @run main DocLintTester -Xmsgs:-missing MissingThrowsTest.java
* @run main DocLintTester -Xmsgs:missing -ref MissingThrowsTest.out MissingThrowsTest.java
*/
/** */
public class MissingThrowsTest {
/** */
void missingThrows() throws Exception { }
}

View File

@ -0,0 +1,4 @@
MissingThrowsTest.java:13: warning: no @throws for java.lang.Exception
void missingThrows() throws Exception { }
^
1 warning

View File

@ -0,0 +1,96 @@
/*
* 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.
*
* 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.
*/
/*
* @test
* @bug 8004832
* @summary Add new doclint package
*/
import com.sun.tools.doclint.DocLint;
public class OptionTest {
public static void main(String... args) throws Exception {
new OptionTest().run();
}
String[] positiveTests = {
"-Xmsgs",
"-Xmsgs:all",
"-Xmsgs:none",
"-Xmsgs:accessibility",
"-Xmsgs:html",
"-Xmsgs:missing",
"-Xmsgs:reference",
"-Xmsgs:syntax",
"-Xmsgs:html/public",
"-Xmsgs:html/protected",
"-Xmsgs:html/package",
"-Xmsgs:html/private",
"-Xmsgs:-html/public",
"-Xmsgs:-html/protected",
"-Xmsgs:-html/package",
"-Xmsgs:-html/private",
"-Xmsgs:html,syntax",
"-Xmsgs:html,-syntax",
"-Xmsgs:-html,syntax",
"-Xmsgs:-html,-syntax",
"-Xmsgs:html/public,syntax",
"-Xmsgs:html,syntax/public",
"-Xmsgs:-html/public,syntax/public"
};
String[] negativeTests = {
"-typo",
"-Xmsgs:-all",
"-Xmsgs:-none",
"-Xmsgs:typo",
"-Xmsgs:html/typo",
"-Xmsgs:html/public,typo",
"-Xmsgs:html/public,syntax/typo",
};
void run() throws Exception {
test(positiveTests, true);
test(negativeTests, false);
if (errors > 0)
throw new Exception(errors + " errors occurred");
}
void test(String[] tests, boolean expect) {
for (String test: tests) {
System.err.println("test: " + test);
boolean found = DocLint.isValidOption(test);
if (found != expect)
error("Unexpected result: " + found + ",expected: " + expect);
}
}
void error(String msg) {
System.err.println("Error: " + msg);
errors++;
}
int errors;
}

Some files were not shown because too many files have changed in this diff Show More