src/share/classes/com/sun/tools/doclint/HtmlTag.java

Fri, 12 Jul 2013 13:11:12 -0700

author
jjg
date
Fri, 12 Jul 2013 13:11:12 -0700
changeset 1895
37031963493e
parent 1793
391f97e270c2
child 1964
79e341614c50
permissions
-rw-r--r--

8020278: NPE in javadoc
Reviewed-by: mcimadamore, vromero

     1 /*
     2  * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package com.sun.tools.doclint;
    28 import java.util.Set;
    29 import java.util.Collections;
    30 import java.util.EnumMap;
    31 import java.util.EnumSet;
    32 import java.util.HashMap;
    33 import java.util.Map;
    35 import javax.lang.model.element.Name;
    37 import static com.sun.tools.doclint.HtmlTag.Attr.*;
    39 /**
    40  * Enum representing HTML tags.
    41  *
    42  * The intent of this class is to embody the semantics of W3C HTML 4.01
    43  * to the extent supported/used by javadoc.
    44  *
    45  * This is derivative of com.sun.tools.doclets.formats.html.markup.HtmlTag.
    46  * Eventually, these two should be merged back together, and possibly made
    47  * public.
    48  *
    49  * @see <a href="http://www.w3.org/TR/REC-html40/">HTML 4.01 Specification</a>
    50  * @author Bhavesh Patel
    51  * @author Jonathan Gibbons (revised)
    52  */
    53 public enum HtmlTag {
    54     A(BlockType.INLINE, EndKind.REQUIRED,
    55             attrs(AttrKind.OK, HREF, TARGET, NAME)),
    57     B(BlockType.INLINE, EndKind.REQUIRED,
    58             EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
    60     BIG(BlockType.INLINE, EndKind.REQUIRED,
    61             EnumSet.of(Flag.EXPECT_CONTENT)),
    63     BLOCKQUOTE(BlockType.BLOCK, EndKind.REQUIRED,
    64             EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)),
    66     BODY(BlockType.OTHER, EndKind.REQUIRED),
    68     BR(BlockType.INLINE, EndKind.NONE,
    69             attrs(AttrKind.USE_CSS, CLEAR)),
    71     CAPTION(BlockType.TABLE_ITEM, EndKind.REQUIRED,
    72             EnumSet.of(Flag.ACCEPTS_INLINE, Flag.EXPECT_CONTENT)),
    74     CENTER(BlockType.BLOCK, EndKind.REQUIRED,
    75             EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)),
    77     CITE(BlockType.INLINE, EndKind.REQUIRED,
    78             EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
    80     CODE(BlockType.INLINE, EndKind.REQUIRED,
    81             EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
    83     DD(BlockType.LIST_ITEM, EndKind.OPTIONAL,
    84             EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE, Flag.EXPECT_CONTENT)),
    86     DIV(BlockType.BLOCK, EndKind.REQUIRED,
    87             EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)),
    89     DL(BlockType.BLOCK, EndKind.REQUIRED,
    90             EnumSet.of(Flag.EXPECT_CONTENT),
    91             attrs(AttrKind.USE_CSS, COMPACT)) {
    92         @Override
    93         public boolean accepts(HtmlTag t) {
    94             return (t == DT) || (t == DD);
    95         }
    96     },
    98     DT(BlockType.LIST_ITEM, EndKind.OPTIONAL,
    99             EnumSet.of(Flag.ACCEPTS_INLINE, Flag.EXPECT_CONTENT)),
   101     EM(BlockType.INLINE, EndKind.REQUIRED,
   102             EnumSet.of(Flag.NO_NEST)),
   104     FONT(BlockType.INLINE, EndKind.REQUIRED, // tag itself is deprecated
   105             EnumSet.of(Flag.EXPECT_CONTENT),
   106             attrs(AttrKind.USE_CSS, SIZE, COLOR, FACE)),
   108     FRAME(BlockType.OTHER, EndKind.NONE),
   110     FRAMESET(BlockType.OTHER, EndKind.REQUIRED),
   112     H1(BlockType.BLOCK, EndKind.REQUIRED),
   113     H2(BlockType.BLOCK, EndKind.REQUIRED),
   114     H3(BlockType.BLOCK, EndKind.REQUIRED),
   115     H4(BlockType.BLOCK, EndKind.REQUIRED),
   116     H5(BlockType.BLOCK, EndKind.REQUIRED),
   117     H6(BlockType.BLOCK, EndKind.REQUIRED),
   119     HEAD(BlockType.OTHER, EndKind.REQUIRED),
   121     HR(BlockType.BLOCK, EndKind.NONE),
   123     HTML(BlockType.OTHER, EndKind.REQUIRED),
   125     I(BlockType.INLINE, EndKind.REQUIRED,
   126             EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
   128     IMG(BlockType.INLINE, EndKind.NONE,
   129             attrs(AttrKind.OK, SRC, ALT, HEIGHT, WIDTH),
   130             attrs(AttrKind.OBSOLETE, NAME),
   131             attrs(AttrKind.USE_CSS, ALIGN, HSPACE, VSPACE, BORDER)),
   133     LI(BlockType.LIST_ITEM, EndKind.OPTIONAL,
   134             EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE),
   135             attrs(AttrKind.OK, VALUE)),
   137     LINK(BlockType.OTHER, EndKind.NONE),
   139     MENU(BlockType.BLOCK, EndKind.REQUIRED) {
   140         @Override
   141         public boolean accepts(HtmlTag t) {
   142             return (t == LI);
   143         }
   144     },
   146     META(BlockType.OTHER, EndKind.NONE),
   148     NOFRAMES(BlockType.OTHER, EndKind.REQUIRED),
   150     NOSCRIPT(BlockType.BLOCK, EndKind.REQUIRED),
   152     OL(BlockType.BLOCK, EndKind.REQUIRED,
   153             EnumSet.of(Flag.EXPECT_CONTENT),
   154             attrs(AttrKind.USE_CSS, START, TYPE)){
   155         @Override
   156         public boolean accepts(HtmlTag t) {
   157             return (t == LI);
   158         }
   159     },
   161     P(BlockType.BLOCK, EndKind.OPTIONAL,
   162             EnumSet.of(Flag.EXPECT_CONTENT),
   163             attrs(AttrKind.USE_CSS, ALIGN)),
   165     PRE(BlockType.BLOCK, EndKind.REQUIRED,
   166             EnumSet.of(Flag.EXPECT_CONTENT)) {
   167         @Override
   168         public boolean accepts(HtmlTag t) {
   169             switch (t) {
   170                 case IMG: case BIG: case SMALL: case SUB: case SUP:
   171                     return false;
   172                 default:
   173                     return (t.blockType == BlockType.INLINE);
   174             }
   175         }
   176     },
   178     SCRIPT(BlockType.OTHER, EndKind.REQUIRED),
   180     SMALL(BlockType.INLINE, EndKind.REQUIRED,
   181             EnumSet.of(Flag.EXPECT_CONTENT)),
   183     SPAN(BlockType.INLINE, EndKind.REQUIRED,
   184             EnumSet.of(Flag.EXPECT_CONTENT)),
   186     STRONG(BlockType.INLINE, EndKind.REQUIRED,
   187             EnumSet.of(Flag.EXPECT_CONTENT)),
   189     SUB(BlockType.INLINE, EndKind.REQUIRED,
   190             EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
   192     SUP(BlockType.INLINE, EndKind.REQUIRED,
   193             EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
   195     TABLE(BlockType.BLOCK, EndKind.REQUIRED,
   196             EnumSet.of(Flag.EXPECT_CONTENT),
   197             attrs(AttrKind.OK, SUMMARY, Attr.FRAME, RULES, BORDER,
   198                 CELLPADDING, CELLSPACING),
   199             attrs(AttrKind.USE_CSS, ALIGN, WIDTH, BGCOLOR)) {
   200         @Override
   201         public boolean accepts(HtmlTag t) {
   202             switch (t) {
   203                 case CAPTION:
   204                 case THEAD: case TBODY: case TFOOT:
   205                 case TR: // HTML 3.2
   206                     return true;
   207                 default:
   208                     return false;
   209             }
   210         }
   211     },
   213     TBODY(BlockType.TABLE_ITEM, EndKind.REQUIRED,
   214             EnumSet.of(Flag.EXPECT_CONTENT),
   215             attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN)) {
   216         @Override
   217         public boolean accepts(HtmlTag t) {
   218             return (t == TR);
   219         }
   220     },
   222     TD(BlockType.TABLE_ITEM, EndKind.OPTIONAL,
   223             EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE),
   224             attrs(AttrKind.OK, COLSPAN, ROWSPAN, HEADERS, SCOPE, ABBR, AXIS,
   225                 ALIGN, CHAR, CHAROFF, VALIGN),
   226             attrs(AttrKind.USE_CSS, WIDTH, BGCOLOR, HEIGHT, NOWRAP)),
   228     TFOOT(BlockType.TABLE_ITEM, EndKind.REQUIRED,
   229             attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN)) {
   230         @Override
   231         public boolean accepts(HtmlTag t) {
   232             return (t == TR);
   233         }
   234     },
   236     TH(BlockType.TABLE_ITEM, EndKind.OPTIONAL,
   237             EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE),
   238             attrs(AttrKind.OK, COLSPAN, ROWSPAN, HEADERS, SCOPE, ABBR, AXIS,
   239                 ALIGN, CHAR, CHAROFF, VALIGN),
   240             attrs(AttrKind.USE_CSS, WIDTH, BGCOLOR, HEIGHT, NOWRAP)),
   242     THEAD(BlockType.TABLE_ITEM, EndKind.REQUIRED,
   243             attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN)) {
   244         @Override
   245         public boolean accepts(HtmlTag t) {
   246             return (t == TR);
   247         }
   248     },
   250     TITLE(BlockType.OTHER, EndKind.REQUIRED),
   252     TR(BlockType.TABLE_ITEM, EndKind.OPTIONAL,
   253             attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN),
   254             attrs(AttrKind.USE_CSS, BGCOLOR)) {
   255         @Override
   256         public boolean accepts(HtmlTag t) {
   257             return (t == TH) || (t == TD);
   258         }
   259     },
   261     TT(BlockType.INLINE, EndKind.REQUIRED,
   262             EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
   264     U(BlockType.INLINE, EndKind.REQUIRED,
   265             EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
   267     UL(BlockType.BLOCK, EndKind.REQUIRED,
   268             EnumSet.of(Flag.EXPECT_CONTENT),
   269             attrs(AttrKind.USE_CSS, COMPACT, TYPE)){
   270         @Override
   271         public boolean accepts(HtmlTag t) {
   272             return (t == LI);
   273         }
   274     },
   276     VAR(BlockType.INLINE, EndKind.REQUIRED);
   278     /**
   279      * Enum representing the type of HTML element.
   280      */
   281     public static enum BlockType {
   282         BLOCK,
   283         INLINE,
   284         LIST_ITEM,
   285         TABLE_ITEM,
   286         OTHER;
   287     }
   289     /**
   290      * Enum representing HTML end tag requirement.
   291      */
   292     public static enum EndKind {
   293         NONE,
   294         OPTIONAL,
   295         REQUIRED;
   296     }
   298     public static enum Flag {
   299         ACCEPTS_BLOCK,
   300         ACCEPTS_INLINE,
   301         EXPECT_CONTENT,
   302         NO_NEST
   303     }
   305     public static enum Attr {
   306         ABBR,
   307         ALIGN,
   308         ALT,
   309         AXIS,
   310         BGCOLOR,
   311         BORDER,
   312         CELLSPACING,
   313         CELLPADDING,
   314         CHAR,
   315         CHAROFF,
   316         CLEAR,
   317         CLASS,
   318         COLOR,
   319         COLSPAN,
   320         COMPACT,
   321         FACE,
   322         FRAME,
   323         HEADERS,
   324         HEIGHT,
   325         HREF,
   326         HSPACE,
   327         ID,
   328         NAME,
   329         NOWRAP,
   330         REVERSED,
   331         ROWSPAN,
   332         RULES,
   333         SCOPE,
   334         SIZE,
   335         SPACE,
   336         SRC,
   337         START,
   338         STYLE,
   339         SUMMARY,
   340         TARGET,
   341         TYPE,
   342         VALIGN,
   343         VALUE,
   344         VSPACE,
   345         WIDTH;
   347         public String getText() {
   348             return name().toLowerCase();
   349         }
   351         static final Map<String,Attr> index = new HashMap<String,Attr>();
   352         static {
   353             for (Attr t: values()) {
   354                 index.put(t.getText(), t);
   355             }
   356         }
   357     }
   359     public static enum AttrKind {
   360         INVALID,
   361         OBSOLETE,
   362         USE_CSS,
   363         OK
   364     }
   366     // This class exists to avoid warnings from using parameterized vararg type
   367     // Map<Attr,AttrKind> in signature of HtmlTag constructor.
   368     private static class AttrMap extends EnumMap<Attr,AttrKind>  {
   369         private static final long serialVersionUID = 0;
   370         AttrMap() {
   371             super(Attr.class);
   372         }
   373     }
   376     public final BlockType blockType;
   377     public final EndKind endKind;
   378     public final Set<Flag> flags;
   379     private final Map<Attr,AttrKind> attrs;
   381     HtmlTag(BlockType blockType, EndKind endKind, AttrMap... attrMaps) {
   382         this(blockType, endKind, Collections.<Flag>emptySet(), attrMaps);
   383     }
   385     HtmlTag(BlockType blockType, EndKind endKind, Set<Flag> flags, AttrMap... attrMaps) {
   386         this.blockType = blockType;
   387         this.endKind = endKind;
   388         this.flags = flags;
   389         this.attrs = new EnumMap<Attr,AttrKind>(Attr.class);
   390         for (Map<Attr,AttrKind> m: attrMaps)
   391             this.attrs.putAll(m);
   392         attrs.put(Attr.CLASS, AttrKind.OK);
   393         attrs.put(Attr.ID, AttrKind.OK);
   394         attrs.put(Attr.STYLE, AttrKind.OK);
   395     }
   397     public boolean accepts(HtmlTag t) {
   398         if (flags.contains(Flag.ACCEPTS_BLOCK) && flags.contains(Flag.ACCEPTS_INLINE)) {
   399             return (t.blockType == BlockType.BLOCK) || (t.blockType == BlockType.INLINE);
   400         } else if (flags.contains(Flag.ACCEPTS_BLOCK)) {
   401             return (t.blockType == BlockType.BLOCK);
   402         } else if (flags.contains(Flag.ACCEPTS_INLINE)) {
   403             return (t.blockType == BlockType.INLINE);
   404         } else
   405             switch (blockType) {
   406                 case BLOCK:
   407                 case INLINE:
   408                     return (t.blockType == BlockType.INLINE);
   409                 case OTHER:
   410                     // OTHER tags are invalid in doc comments, and will be
   411                     // reported separately, so silently accept/ignore any content
   412                     return true;
   413                 default:
   414                     // any combination which could otherwise arrive here
   415                     // ought to have been handled in an overriding method
   416                     throw new AssertionError(this + ":" + t);
   417             }
   418     }
   420     public boolean acceptsText() {
   421         // generally, anywhere we can put text we can also put inline tag
   422         // so check if a typical inline tag is allowed
   423         return accepts(B);
   424     }
   426     public String getText() {
   427         return name().toLowerCase();
   428     }
   430     public Attr getAttr(Name attrName) {
   431         return Attr.index.get(attrName.toString().toLowerCase());
   432     }
   434     public AttrKind getAttrKind(Name attrName) {
   435         AttrKind k = attrs.get(getAttr(attrName)); // null-safe
   436         return (k == null) ? AttrKind.INVALID : k;
   437     }
   439     private static AttrMap attrs(AttrKind k, Attr... attrs) {
   440         AttrMap map = new AttrMap();
   441         for (Attr a: attrs) map.put(a, k);
   442         return map;
   443     }
   445     private static final Map<String,HtmlTag> index = new HashMap<String,HtmlTag>();
   446     static {
   447         for (HtmlTag t: values()) {
   448             index.put(t.getText(), t);
   449         }
   450     }
   452     static HtmlTag get(Name tagName) {
   453         return index.get(tagName.toString().toLowerCase());
   454     }
   455 }

mercurial