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

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.
*
* This code is free software; you can redistribute it and/or modify it
@ -65,6 +65,12 @@ public interface ClassDoc extends ProgramElementDoc, Type {
*/
boolean isExternalizable();
/**
* Return true if this class can be used as a target type of a lambda expression
* or method reference.
*/
boolean isFunctionalInterface();
/**
* Return the serialization methods for this class or
* interface.

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

View File

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

View File

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

View File

@ -56,9 +56,9 @@ public interface Plugin {
String getName();
/**
* Invoke the plug-in for a given compilation task.
* Initialize the plug-in for a given compilation task.
* @param task The compilation task that has just been started
* @param args Arguments, if any, for the plug-in
*/
void call(JavacTask task, String... args);
void init(JavacTask task, String... args);
}

View File

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

View File

@ -239,7 +239,14 @@ public abstract class AbstractMemberWriter {
if ((member.isField() || member.isMethod()) &&
writer instanceof ClassWriterImpl &&
((ClassWriterImpl) writer).getClassDoc().isInterface()) {
mod = Util.replaceText(mod, "public", "").trim();
// This check for isDefault() and the default modifier needs to be
// added for it to appear on the method details section. Once the
// default modifier is added to the Modifier list on DocEnv and once
// it is updated to use the javax.lang.model.element.Modifier, we
// will need to remove this.
mod = (member.isMethod() && ((MethodDoc)member).isDefault()) ?
Util.replaceText(mod, "public", "default").trim() :
Util.replaceText(mod, "public", "").trim();
}
if(mod.length() > 0) {
htmltree.addContent(mod);
@ -313,8 +320,18 @@ public abstract class AbstractMemberWriter {
code.addContent(configuration.getText("doclet.Package_private"));
code.addContent(" ");
}
if (member.isMethod() && ((MethodDoc)member).isAbstract()) {
code.addContent("abstract ");
if (member.isMethod()) {
if (((MethodDoc)member).isAbstract()) {
code.addContent("abstract ");
}
// This check for isDefault() and the default modifier needs to be
// added for it to appear on the "Modifier and Type" column in the
// method summary section. Once the default modifier is added
// to the Modifier list on DocEnv and once it is updated to use the
// javax.lang.model.element.Modifier, we will need to remove this.
else if (((MethodDoc)member).isDefault()) {
code.addContent("default ");
}
}
if (member.isStatic()) {
code.addContent("static ");
@ -547,6 +564,9 @@ public abstract class AbstractMemberWriter {
methodType = (classdoc.isInterface() || ((MethodDoc)member).isAbstract()) ?
methodType | MethodTypes.ABSTRACT.value() :
methodType | MethodTypes.CONCRETE.value();
if (((MethodDoc)member).isDefault()) {
methodType = methodType | MethodTypes.DEFAULT.value();
}
if (Util.isDeprecated(member) || Util.isDeprecated(classdoc)) {
methodType = methodType | MethodTypes.DEPRECATED.value();
}

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}
*/

View File

@ -90,6 +90,8 @@ doclet.in_interface=in interface
doclet.Subclasses=Direct Known Subclasses:
doclet.Subinterfaces=All Known Subinterfaces:
doclet.Implementing_Classes=All Known Implementing Classes:
doclet.Functional_Interface=Functional Interface:
doclet.Functional_Interface_Message=This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.
doclet.also=also
doclet.Frames=Frames
doclet.No_Frames=No Frames

View File

@ -116,6 +116,13 @@ public interface ClassWriter {
*/
public void addInterfaceUsageInfo(Content classInfoTree);
/**
* If this is an functional interface, display appropriate message.
*
* @param classInfoTree content tree to which the documentation will be added
*/
public void addFunctionalInterfaceInfo(Content classInfoTree);
/**
* If this is an inner class or interface, add the enclosing class or
* interface.

View File

@ -235,6 +235,16 @@ public class ClassBuilder extends AbstractBuilder {
writer.addInterfaceUsageInfo(classInfoTree);
}
/**
* If this is an functional interface, display appropriate message.
*
* @param node the XML element that specifies which components to document
* @param classInfoTree the content tree to which the documentation will be added
*/
public void buildFunctionalInterfaceInfo(XMLNode node, Content classInfoTree) {
writer.addFunctionalInterfaceInfo(classInfoTree);
}
/**
* If this class is deprecated, build the appropriate information.
*

View File

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

View File

@ -36,7 +36,8 @@ public enum MethodTypes {
INSTANCE(0x2, "Instance Methods", "t2", false),
ABSTRACT(0x4, "Abstract Methods", "t3", false),
CONCRETE(0x8, "Concrete Methods", "t4", false),
DEPRECATED(0x10, "Deprecated Methods", "t5", false);
DEFAULT(0x10, "Default Methods", "t5", false),
DEPRECATED(0x20, "Deprecated Methods", "t6", false);
private final int value;
private final String text;

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;
private TaskListener taskListener;
public static JavacTask instance(Context context) {
JavacTask instance = context.get(JavacTask.class);
if (instance == null)
instance = new BasicJavacTask(context, true);
return instance;
}
public BasicJavacTask(Context c, boolean register) {
context = c;
if (register)

View File

@ -65,7 +65,6 @@ import com.sun.tools.javac.util.List;
* @author Jonathan Gibbons
*/
public class JavacTaskImpl extends BasicJavacTask {
private ClientCodeWrapper ccw;
private Main compilerMain;
private JavaCompiler compiler;
private Locale locale;
@ -85,7 +84,6 @@ public class JavacTaskImpl extends BasicJavacTask {
Context context,
List<JavaFileObject> fileObjects) {
super(null, false);
this.ccw = ClientCodeWrapper.instance(context);
this.compilerMain = compilerMain;
this.args = args;
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,
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.TreeInfo;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.util.Abort;
import com.sun.tools.javac.util.Assert;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.JCDiagnostic;
@ -236,19 +237,26 @@ public class JavacTrees extends DocTrees {
public Element getElement(TreePath path) {
JCTree tree = (JCTree) path.getLeaf();
Symbol sym = TreeInfo.symbolFor(tree);
if (sym == null && TreeInfo.isDeclaration(tree)) {
for (TreePath p = path; p != null; p = p.getParentPath()) {
JCTree t = (JCTree) p.getLeaf();
if (t.hasTag(JCTree.Tag.CLASSDEF)) {
JCClassDecl ct = (JCClassDecl) t;
if (ct.sym != null) {
if ((ct.sym.flags_field & Flags.UNATTRIBUTED) != 0) {
attr.attribClass(ct.pos(), ct.sym);
sym = TreeInfo.symbolFor(tree);
if (sym == null) {
if (TreeInfo.isDeclaration(tree)) {
for (TreePath p = path; p != null; p = p.getParentPath()) {
JCTree t = (JCTree) p.getLeaf();
if (t.hasTag(JCTree.Tag.CLASSDEF)) {
JCClassDecl ct = (JCClassDecl) t;
if (ct.sym != null) {
if ((ct.sym.flags_field & Flags.UNATTRIBUTED) != 0) {
attr.attribClass(ct.pos(), ct.sym);
sym = TreeInfo.symbolFor(tree);
}
break;
}
break;
}
}
} else if (tree.hasTag(Tag.TOPLEVEL)) {
JCCompilationUnit cu = (JCCompilationUnit) tree;
if (cu.sourcefile.isNameCompatible("package-info", JavaFileObject.Kind.SOURCE)) {
sym = cu.packge;
}
}
}
return sym;
@ -332,6 +340,8 @@ public class JavacTrees extends DocTrees {
} else {
return msym;
}
} catch (Abort e) { // may be thrown by Check.completionError in case of bad class file
return null;
} finally {
log.popDiagnosticHandler(deferredDiagnosticHandler);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1798,6 +1798,9 @@ public class Resolve {
if ((kind & TYP) != 0) {
sym = findType(env, name);
if (sym.kind==TYP) {
reportDependence(env.enclClass.sym, sym);
}
if (sym.exists()) return sym;
else if (sym.kind < bestSoFar.kind) bestSoFar = sym;
}
@ -1806,6 +1809,14 @@ public class Resolve {
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.
* @param env The current environment.
* @param name The identifier's name.
@ -3064,16 +3075,20 @@ public class Resolve {
if (hasLocation) {
return diags.create(dkind, log.currentSource(), pos,
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
}
else {
return diags.create(dkind, log.currentSource(), pos,
errKey, kindname, idname, //symbol kindname, name
typeargtypes, argtypes); //type parameters and arguments (if any)
typeargtypes, args(argtypes)); //type parameters and arguments (if any)
}
}
//where
private Object args(List<Type> args) {
return args.isEmpty() ? args : methodArguments(args);
}
private String getErrorKey(KindName kindname, boolean hasTypeArgs, boolean hasLocation) {
String key = "cant.resolve";
String suffix = hasLocation ? ".location" : "";

View File

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

View File

@ -26,6 +26,8 @@
package com.sun.tools.javac.jvm;
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;
@ -166,22 +168,29 @@ public class ClassFile {
*/
public static class NameAndType {
Name name;
Type type;
UniqueType uniqueType;
Types types;
NameAndType(Name name, Type type) {
NameAndType(Name name, Type type, Types types) {
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) {
return
other instanceof NameAndType &&
name == ((NameAndType) other).name &&
type.equals(((NameAndType) other).type);
return (other instanceof NameAndType &&
name == ((NameAndType) other).name &&
uniqueType.equals(((NameAndType) other).uniqueType));
}
@Override
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: {
ClassSymbol owner = readClassSymbol(getChar(index + 1));
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;
}
case CONSTANT_Methodref:
case CONSTANT_InterfaceMethodref: {
ClassSymbol owner = readClassSymbol(getChar(index + 1));
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;
}
case CONSTANT_NameandType:
poolObj[i] = new NameAndType(
readName(getChar(index + 1)),
readType(getChar(index + 3)));
readType(getChar(index + 3)), types);
break;
case CONSTANT_Integer:
poolObj[i] = getInt(index + 1);
@ -1224,7 +1224,7 @@ public class ClassReader implements Completer {
if (nt == 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())
if (e.sym.kind == MTH && isSameBinaryType(e.sym.type.asMethodType(), type))
@ -1236,16 +1236,16 @@ public class ClassReader implements Completer {
if ((flags & INTERFACE) != 0)
// no enclosing instance
return null;
if (nt.type.getParameterTypes().isEmpty())
if (nt.uniqueType.type.getParameterTypes().isEmpty())
// no parameters
return null;
// A constructor of an inner class.
// Remove the first argument (the enclosing instance)
nt.type = new MethodType(nt.type.getParameterTypes().tail,
nt.type.getReturnType(),
nt.type.getThrownTypes(),
syms.methodClass);
nt.setType(new MethodType(nt.uniqueType.type.getParameterTypes().tail,
nt.uniqueType.type.getReturnType(),
nt.uniqueType.type.getThrownTypes(),
syms.methodClass));
// Try searching again
return findMethod(nt, scope, flags);
}
@ -1959,7 +1959,7 @@ public class ClassReader implements Completer {
if (readAllOfClassFile) {
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

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

View File

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

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.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.Assert;
@ -60,11 +63,14 @@ public class Pool {
*/
Map<Object,Integer> indices;
Types types;
/** 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.pool = pool;
this.types = types;
this.indices = new HashMap<Object,Integer>(pool.length);
for (int i = 1; i < pp; i++) {
if (pool[i] != null) indices.put(pool[i], i);
@ -73,8 +79,8 @@ public class Pool {
/** Construct an empty pool.
*/
public Pool() {
this(1, new Object[64]);
public Pool(Types types) {
this(1, new Object[64], types);
}
/** Return the number of entries in the constant pool.
@ -114,11 +120,13 @@ public class Pool {
Object makePoolValue(Object o) {
if (o instanceof DynamicMethodSymbol) {
return new DynamicMethod((DynamicMethodSymbol)o);
return new DynamicMethod((DynamicMethodSymbol)o, types);
} else if (o instanceof MethodSymbol) {
return new Method((MethodSymbol)o);
return new Method((MethodSymbol)o, types);
} 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 {
return o;
}
@ -134,9 +142,11 @@ public class Pool {
static class Method extends DelegatedSymbol {
MethodSymbol m;
Method(MethodSymbol m) {
UniqueType uniqueType;
Method(MethodSymbol m, Types types) {
super(m);
this.m = m;
this.uniqueType = new UniqueType(m.type, types);
}
public boolean equals(Object other) {
if (!(other instanceof Method)) return false;
@ -144,20 +154,22 @@ public class Pool {
return
o.name == m.name &&
o.owner == m.owner &&
o.type.equals(m.type);
((Method)other).uniqueType.equals(uniqueType);
}
public int hashCode() {
return
m.name.hashCode() * 33 +
m.owner.hashCode() * 9 +
m.type.hashCode();
uniqueType.hashCode();
}
}
static class DynamicMethod extends Method {
public Object[] uniqueStaticArgs;
DynamicMethod(DynamicMethodSymbol m) {
super(m);
DynamicMethod(DynamicMethodSymbol m, Types types) {
super(m, types);
uniqueStaticArgs = getUniqueTypeArray(m.staticArgs, types);
}
@Override
@ -168,7 +180,8 @@ public class Pool {
DynamicMethodSymbol dm2 = (DynamicMethodSymbol)((DynamicMethod)other).m;
return dm1.bsm == dm2.bsm &&
dm1.bsmKind == dm2.bsmKind &&
Arrays.equals(dm1.staticArgs, dm2.staticArgs);
Arrays.equals(uniqueStaticArgs,
((DynamicMethod)other).uniqueStaticArgs);
}
@Override
@ -178,17 +191,31 @@ public class Pool {
hash += dm.bsmKind * 7 +
dm.bsm.hashCode() * 11;
for (int i = 0; i < dm.staticArgs.length; i++) {
hash += (dm.staticArgs[i].hashCode() * 23);
hash += (uniqueStaticArgs[i].hashCode() * 23);
}
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 {
VarSymbol v;
Variable(VarSymbol v) {
UniqueType uniqueType;
Variable(VarSymbol v, Types types) {
super(v);
this.v = v;
this.uniqueType = new UniqueType(v.type, types);
}
public boolean equals(Object other) {
if (!(other instanceof Variable)) return false;
@ -196,13 +223,13 @@ public class Pool {
return
o.name == v.name &&
o.owner == v.owner &&
o.type.equals(v.type);
((Variable)other).uniqueType.equals(uniqueType);
}
public int hashCode() {
return
v.name.hashCode() * 33 +
v.owner.hashCode() * 9 +
v.type.hashCode();
uniqueType.hashCode();
}
}
@ -214,9 +241,12 @@ public class Pool {
/** Reference symbol */
Symbol refSym;
public MethodHandle(int refKind, Symbol refSym) {
UniqueType uniqueType;
public MethodHandle(int refKind, Symbol refSym, Types types) {
this.refKind = refKind;
this.refSym = refSym;
this.uniqueType = new UniqueType(this.refSym.type, types);
checkConsistent();
}
public boolean equals(Object other) {
@ -227,14 +257,14 @@ public class Pool {
return
o.name == refSym.name &&
o.owner == refSym.owner &&
o.type.equals(refSym.type);
((MethodHandle)other).uniqueType.equals(uniqueType);
}
public int hashCode() {
return
refKind * 65 +
refSym.name.hashCode() * 33 +
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;
/**
@ -984,9 +994,10 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
}
}
//If generating source, remember the classes declared in
//the original compilation units listed on the command line.
if (sourceOutput || stubOutput) {
// If generating source, or if tracking public apis,
// then remember the classes declared in
// the original compilation units listed on the command line.
if (needRootClasses || sourceOutput || stubOutput) {
ListBuffer<JCClassDecl> cdefs = lb();
for (JCCompilationUnit unit : roots) {
for (List<JCTree> defs = unit.defs;
@ -1247,6 +1258,12 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
attr.postAttr(env.tree);
}
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 {
log.useSource(prev);
@ -1255,6 +1272,14 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
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.
* 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.
*/
protected void printCount(String kind, int count) {
public void printCount(String kind, int count) {
if (count != 0) {
String key;
if (count == 1)

View File

@ -44,6 +44,8 @@ import javax.tools.JavaFileObject;
import com.sun.source.util.JavacTask;
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.file.CacheFSInfo;
import com.sun.tools.javac.file.JavacFileManager;
@ -428,6 +430,7 @@ public class Main {
if (batchMode)
CacheFSInfo.preRegister(context);
// FIXME: this code will not be invoked if using JavacTask.parse/analyze/generate
// invoke any available plugins
String plugins = options.get(PLUGIN);
if (plugins != null) {
@ -448,7 +451,7 @@ public class Main {
try {
if (task == null)
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) {
if (apiMode)
throw new RuntimeException(ex);
@ -464,10 +467,31 @@ public class Main {
}
}
fileManager = context.get(JavaFileManager.class);
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()) {
// add filenames to fileObjects

View File

@ -25,28 +25,30 @@
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.FileWriter;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.EnumSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
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.OptionKind.*;
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
@ -79,6 +81,24 @@ public enum Option {
XLINT_CUSTOM("-Xlint:", "opt.Xlint.suboptlist",
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("-nowarn", "opt.nowarn", STANDARD, BASIC) {
@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.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,11 +25,16 @@
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.Set;
import java.util.EnumSet;
import javax.lang.model.element.*;
import javax.lang.model.type.*;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.util.*;
@ -301,4 +306,31 @@ public class JavacTypes implements javax.lang.model.util.Types {
throw new IllegalArgumentException(o.toString());
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;
import com.sun.tools.javac.util.Filter;
import java.text.BreakIterator;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Locale;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
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.JCTree;
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.ListBuffer;
import com.sun.tools.javac.util.Log;
@ -736,7 +732,9 @@ public class DocCommentParser {
nextChar();
return m.at(p).Entity(names.fromChars(buf, namep, bp - namep - 1));
} else {
String code = checkSemi ? "dc.missing.semicolon" : "dc.bad.entity";
String code = checkSemi
? "dc.missing.semicolon"
: "dc.bad.entity";
return erroneous(code, p);
}
}
@ -888,8 +886,10 @@ public class DocCommentParser {
}
protected void addPendingText(ListBuffer<DCTree> list, int textEnd) {
if (textStart != -1 && textStart <= textEnd) {
list.add(m.at(textStart).Text(newString(textStart, textEnd + 1)));
if (textStart != -1) {
if (textStart <= textEnd) {
list.add(m.at(textStart).Text(newString(textStart, textEnd + 1)));
}
textStart = -1;
}
}
@ -1196,6 +1196,16 @@ public class DocCommentParser {
return m.at(pos).See(html);
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:
if (isJavaIdentifierStart(ch) || ch == '#') {
DCReference ref = reference(true);

View File

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

View File

@ -138,6 +138,14 @@ javac.opt.Xlint=\
Enable recommended warnings
javac.opt.Xlint.suboptlist=\
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=\
Redirect standard output
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.Symtab;
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.ClassWriter;
import com.sun.tools.javac.jvm.Pool;
@ -173,7 +174,8 @@ public class CreateSymbols extends AbstractProcessor {
List.<Pair<Symbol.MethodSymbol,Attribute>>nil());
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)) {
String className = fm.inferBinaryName(jarLocation, file);
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.List;
import com.sun.tools.javac.util.Name;
import java.io.IOException;
import java.io.StringWriter;
import javax.tools.JavaFileObject;
/**
@ -65,6 +67,21 @@ public abstract class DCTree implements DocTree {
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 {
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.
*/
protected void print(List<? extends DocTree> list) throws IOException {
public void print(List<? extends DocTree> list) throws IOException {
for (DocTree t: list) {
print(t);
}

View File

@ -26,6 +26,7 @@
package com.sun.tools.javac.tree;
import com.sun.source.tree.Tree;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.comp.AttrContext;
@ -330,6 +331,13 @@ public class TreeInfo {
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 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) {
return (JCVariableDecl)
new JCVariableDecl(
Modifiers(v.flags(), Annotations(v.getAnnotationMirrors())),
Modifiers(v.flags(), Annotations(v.getRawAttributes())),
v.name,
Type(v.type),
init,
@ -800,7 +800,7 @@ public class TreeMaker implements JCTree.Factory {
public JCMethodDecl MethodDef(MethodSymbol m, Type mtype, JCBlock body) {
return (JCMethodDecl)
new JCMethodDecl(
Modifiers(m.flags(), Annotations(m.getAnnotationMirrors())),
Modifiers(m.flags(), Annotations(m.getRawAttributes())),
m.name,
Type(mtype.getReturnType()),
TypeParams(mtype.getTypeArguments()),

View File

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

View File

@ -75,6 +75,13 @@ public class MethodDocImpl
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
*/

View File

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

View File

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

View File

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

View File

@ -77,6 +77,16 @@ public interface ExecutableElement extends Element, Parameterizable {
*/
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
* 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.
*
* 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>" +
"<span id=\"t4\" class=\"tableTab\"><span><a href=\"javascript:show(8);\">" +
"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>" +
"</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>" +
"<span id=\"t4\" class=\"tableTab\"><span><a href=\"javascript:show(8);\">" +
"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>" +
"</caption>"
},
@ -87,7 +87,7 @@ public class TestMethodTypes extends JavadocTester {
"Abstract Methods</a></span><span class=\"tabEnd\">&nbsp;</span></span>" +
"<span id=\"t4\" class=\"tableTab\"><span><a href=\"javascript:show(8);\">" +
"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>" +
"</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