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

Tue, 17 Sep 2013 14:17:13 -0700

author
jjg
date
Tue, 17 Sep 2013 14:17:13 -0700
changeset 2033
fdfbc5f0c4ed
parent 1976
b77381d99056
child 2051
96dcb66e6b0a
permissions
-rw-r--r--

8024538: -Xdoclint + -Xprefer:source + incremental compilation == FAIL
Reviewed-by: darcy

     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.Locale;
    34 import java.util.Map;
    36 import javax.lang.model.element.Name;
    38 import static com.sun.tools.doclint.HtmlTag.Attr.*;
    40 /**
    41  * Enum representing HTML tags.
    42  *
    43  * The intent of this class is to embody the semantics of W3C HTML 4.01
    44  * to the extent supported/used by javadoc.
    45  * In time, we may wish to transition javadoc and doclint to using HTML 5.
    46  *
    47  * This is derivative of com.sun.tools.doclets.formats.html.markup.HtmlTag.
    48  * Eventually, these two should be merged back together, and possibly made
    49  * public.
    50  *
    51  * @see <a href="http://www.w3.org/TR/REC-html40/">HTML 4.01 Specification</a>
    52  * @see <a href="http://www.w3.org/TR/html5/">HTML 5 Specification</a>
    53  * @author Bhavesh Patel
    54  * @author Jonathan Gibbons (revised)
    55  */
    56 public enum HtmlTag {
    57     A(BlockType.INLINE, EndKind.REQUIRED,
    58             attrs(AttrKind.OK, HREF, TARGET, NAME)),
    60     B(BlockType.INLINE, EndKind.REQUIRED,
    61             EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
    63     BIG(BlockType.INLINE, EndKind.REQUIRED,
    64             EnumSet.of(Flag.EXPECT_CONTENT)),
    66     BLOCKQUOTE(BlockType.BLOCK, EndKind.REQUIRED,
    67             EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)),
    69     BODY(BlockType.OTHER, EndKind.REQUIRED),
    71     BR(BlockType.INLINE, EndKind.NONE,
    72             attrs(AttrKind.USE_CSS, CLEAR)),
    74     CAPTION(BlockType.TABLE_ITEM, EndKind.REQUIRED,
    75             EnumSet.of(Flag.ACCEPTS_INLINE, Flag.EXPECT_CONTENT)),
    77     CENTER(BlockType.BLOCK, EndKind.REQUIRED,
    78             EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)),
    80     CITE(BlockType.INLINE, EndKind.REQUIRED,
    81             EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
    83     CODE(BlockType.INLINE, EndKind.REQUIRED,
    84             EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
    86     DD(BlockType.LIST_ITEM, EndKind.OPTIONAL,
    87             EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE, Flag.EXPECT_CONTENT)),
    89     DIV(BlockType.BLOCK, EndKind.REQUIRED,
    90             EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)),
    92     DL(BlockType.BLOCK, EndKind.REQUIRED,
    93             EnumSet.of(Flag.EXPECT_CONTENT),
    94             attrs(AttrKind.USE_CSS, COMPACT)) {
    95         @Override
    96         public boolean accepts(HtmlTag t) {
    97             return (t == DT) || (t == DD);
    98         }
    99     },
   101     DT(BlockType.LIST_ITEM, EndKind.OPTIONAL,
   102             EnumSet.of(Flag.ACCEPTS_INLINE, Flag.EXPECT_CONTENT)),
   104     EM(BlockType.INLINE, EndKind.REQUIRED,
   105             EnumSet.of(Flag.NO_NEST)),
   107     FONT(BlockType.INLINE, EndKind.REQUIRED, // tag itself is deprecated
   108             EnumSet.of(Flag.EXPECT_CONTENT),
   109             attrs(AttrKind.USE_CSS, SIZE, COLOR, FACE)),
   111     FRAME(BlockType.OTHER, EndKind.NONE),
   113     FRAMESET(BlockType.OTHER, EndKind.REQUIRED),
   115     H1(BlockType.BLOCK, EndKind.REQUIRED),
   116     H2(BlockType.BLOCK, EndKind.REQUIRED),
   117     H3(BlockType.BLOCK, EndKind.REQUIRED),
   118     H4(BlockType.BLOCK, EndKind.REQUIRED),
   119     H5(BlockType.BLOCK, EndKind.REQUIRED),
   120     H6(BlockType.BLOCK, EndKind.REQUIRED),
   122     HEAD(BlockType.OTHER, EndKind.REQUIRED),
   124     HR(BlockType.BLOCK, EndKind.NONE,
   125             attrs(AttrKind.OK, WIDTH)), // OK in 4.01; not allowed in 5
   127     HTML(BlockType.OTHER, EndKind.REQUIRED),
   129     I(BlockType.INLINE, EndKind.REQUIRED,
   130             EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
   132     IMG(BlockType.INLINE, EndKind.NONE,
   133             attrs(AttrKind.OK, SRC, ALT, HEIGHT, WIDTH),
   134             attrs(AttrKind.OBSOLETE, NAME),
   135             attrs(AttrKind.USE_CSS, ALIGN, HSPACE, VSPACE, BORDER)),
   137     LI(BlockType.LIST_ITEM, EndKind.OPTIONAL,
   138             EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE),
   139             attrs(AttrKind.OK, VALUE)),
   141     LINK(BlockType.OTHER, EndKind.NONE),
   143     MENU(BlockType.BLOCK, EndKind.REQUIRED) {
   144         @Override
   145         public boolean accepts(HtmlTag t) {
   146             return (t == LI);
   147         }
   148     },
   150     META(BlockType.OTHER, EndKind.NONE),
   152     NOFRAMES(BlockType.OTHER, EndKind.REQUIRED),
   154     NOSCRIPT(BlockType.BLOCK, EndKind.REQUIRED),
   156     OL(BlockType.BLOCK, EndKind.REQUIRED,
   157             EnumSet.of(Flag.EXPECT_CONTENT),
   158             attrs(AttrKind.OK, START, TYPE)) {
   159         @Override
   160         public boolean accepts(HtmlTag t) {
   161             return (t == LI);
   162         }
   163     },
   165     P(BlockType.BLOCK, EndKind.OPTIONAL,
   166             EnumSet.of(Flag.EXPECT_CONTENT),
   167             attrs(AttrKind.USE_CSS, ALIGN)),
   169     PRE(BlockType.BLOCK, EndKind.REQUIRED,
   170             EnumSet.of(Flag.EXPECT_CONTENT)) {
   171         @Override
   172         public boolean accepts(HtmlTag t) {
   173             switch (t) {
   174                 case IMG: case BIG: case SMALL: case SUB: case SUP:
   175                     return false;
   176                 default:
   177                     return (t.blockType == BlockType.INLINE);
   178             }
   179         }
   180     },
   182     SCRIPT(BlockType.OTHER, EndKind.REQUIRED),
   184     SMALL(BlockType.INLINE, EndKind.REQUIRED,
   185             EnumSet.of(Flag.EXPECT_CONTENT)),
   187     SPAN(BlockType.INLINE, EndKind.REQUIRED,
   188             EnumSet.of(Flag.EXPECT_CONTENT)),
   190     STRONG(BlockType.INLINE, EndKind.REQUIRED,
   191             EnumSet.of(Flag.EXPECT_CONTENT)),
   193     SUB(BlockType.INLINE, EndKind.REQUIRED,
   194             EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
   196     SUP(BlockType.INLINE, EndKind.REQUIRED,
   197             EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
   199     TABLE(BlockType.BLOCK, EndKind.REQUIRED,
   200             EnumSet.of(Flag.EXPECT_CONTENT),
   201             attrs(AttrKind.OK, SUMMARY, Attr.FRAME, RULES, BORDER,
   202                 CELLPADDING, CELLSPACING, WIDTH), // width OK in 4.01; not allowed in 5
   203             attrs(AttrKind.USE_CSS, ALIGN, BGCOLOR)) {
   204         @Override
   205         public boolean accepts(HtmlTag t) {
   206             switch (t) {
   207                 case CAPTION:
   208                 case THEAD: case TBODY: case TFOOT:
   209                 case TR: // HTML 3.2
   210                     return true;
   211                 default:
   212                     return false;
   213             }
   214         }
   215     },
   217     TBODY(BlockType.TABLE_ITEM, EndKind.REQUIRED,
   218             EnumSet.of(Flag.EXPECT_CONTENT),
   219             attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN)) {
   220         @Override
   221         public boolean accepts(HtmlTag t) {
   222             return (t == TR);
   223         }
   224     },
   226     TD(BlockType.TABLE_ITEM, EndKind.OPTIONAL,
   227             EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE),
   228             attrs(AttrKind.OK, COLSPAN, ROWSPAN, HEADERS, SCOPE, ABBR, AXIS,
   229                 ALIGN, CHAR, CHAROFF, VALIGN),
   230             attrs(AttrKind.USE_CSS, WIDTH, BGCOLOR, HEIGHT, NOWRAP)),
   232     TFOOT(BlockType.TABLE_ITEM, EndKind.REQUIRED,
   233             attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN)) {
   234         @Override
   235         public boolean accepts(HtmlTag t) {
   236             return (t == TR);
   237         }
   238     },
   240     TH(BlockType.TABLE_ITEM, EndKind.OPTIONAL,
   241             EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE),
   242             attrs(AttrKind.OK, COLSPAN, ROWSPAN, HEADERS, SCOPE, ABBR, AXIS,
   243                 ALIGN, CHAR, CHAROFF, VALIGN),
   244             attrs(AttrKind.USE_CSS, WIDTH, BGCOLOR, HEIGHT, NOWRAP)),
   246     THEAD(BlockType.TABLE_ITEM, EndKind.REQUIRED,
   247             attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN)) {
   248         @Override
   249         public boolean accepts(HtmlTag t) {
   250             return (t == TR);
   251         }
   252     },
   254     TITLE(BlockType.OTHER, EndKind.REQUIRED),
   256     TR(BlockType.TABLE_ITEM, EndKind.OPTIONAL,
   257             attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN),
   258             attrs(AttrKind.USE_CSS, BGCOLOR)) {
   259         @Override
   260         public boolean accepts(HtmlTag t) {
   261             return (t == TH) || (t == TD);
   262         }
   263     },
   265     TT(BlockType.INLINE, EndKind.REQUIRED,
   266             EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
   268     U(BlockType.INLINE, EndKind.REQUIRED,
   269             EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
   271     UL(BlockType.BLOCK, EndKind.REQUIRED,
   272             EnumSet.of(Flag.EXPECT_CONTENT),
   273             attrs(AttrKind.OK, COMPACT, TYPE)) { // OK in 4.01; not allowed in 5
   274         @Override
   275         public boolean accepts(HtmlTag t) {
   276             return (t == LI);
   277         }
   278     },
   280     VAR(BlockType.INLINE, EndKind.REQUIRED);
   282     /**
   283      * Enum representing the type of HTML element.
   284      */
   285     public static enum BlockType {
   286         BLOCK,
   287         INLINE,
   288         LIST_ITEM,
   289         TABLE_ITEM,
   290         OTHER;
   291     }
   293     /**
   294      * Enum representing HTML end tag requirement.
   295      */
   296     public static enum EndKind {
   297         NONE,
   298         OPTIONAL,
   299         REQUIRED;
   300     }
   302     public static enum Flag {
   303         ACCEPTS_BLOCK,
   304         ACCEPTS_INLINE,
   305         EXPECT_CONTENT,
   306         NO_NEST
   307     }
   309     public static enum Attr {
   310         ABBR,
   311         ALIGN,
   312         ALT,
   313         AXIS,
   314         BGCOLOR,
   315         BORDER,
   316         CELLSPACING,
   317         CELLPADDING,
   318         CHAR,
   319         CHAROFF,
   320         CLEAR,
   321         CLASS,
   322         COLOR,
   323         COLSPAN,
   324         COMPACT,
   325         FACE,
   326         FRAME,
   327         HEADERS,
   328         HEIGHT,
   329         HREF,
   330         HSPACE,
   331         ID,
   332         NAME,
   333         NOWRAP,
   334         REVERSED,
   335         ROWSPAN,
   336         RULES,
   337         SCOPE,
   338         SIZE,
   339         SPACE,
   340         SRC,
   341         START,
   342         STYLE,
   343         SUMMARY,
   344         TARGET,
   345         TYPE,
   346         VALIGN,
   347         VALUE,
   348         VSPACE,
   349         WIDTH;
   351         public String getText() {
   352             return toLowerCase(name());
   353         }
   355         static final Map<String,Attr> index = new HashMap<String,Attr>();
   356         static {
   357             for (Attr t: values()) {
   358                 index.put(t.getText(), t);
   359             }
   360         }
   361     }
   363     public static enum AttrKind {
   364         INVALID,
   365         OBSOLETE,
   366         USE_CSS,
   367         OK
   368     }
   370     // This class exists to avoid warnings from using parameterized vararg type
   371     // Map<Attr,AttrKind> in signature of HtmlTag constructor.
   372     private static class AttrMap extends EnumMap<Attr,AttrKind>  {
   373         private static final long serialVersionUID = 0;
   374         AttrMap() {
   375             super(Attr.class);
   376         }
   377     }
   380     public final BlockType blockType;
   381     public final EndKind endKind;
   382     public final Set<Flag> flags;
   383     private final Map<Attr,AttrKind> attrs;
   385     HtmlTag(BlockType blockType, EndKind endKind, AttrMap... attrMaps) {
   386         this(blockType, endKind, Collections.<Flag>emptySet(), attrMaps);
   387     }
   389     HtmlTag(BlockType blockType, EndKind endKind, Set<Flag> flags, AttrMap... attrMaps) {
   390         this.blockType = blockType;
   391         this.endKind = endKind;
   392         this.flags = flags;
   393         this.attrs = new EnumMap<Attr,AttrKind>(Attr.class);
   394         for (Map<Attr,AttrKind> m: attrMaps)
   395             this.attrs.putAll(m);
   396         attrs.put(Attr.CLASS, AttrKind.OK);
   397         attrs.put(Attr.ID, AttrKind.OK);
   398         attrs.put(Attr.STYLE, AttrKind.OK);
   399     }
   401     public boolean accepts(HtmlTag t) {
   402         if (flags.contains(Flag.ACCEPTS_BLOCK) && flags.contains(Flag.ACCEPTS_INLINE)) {
   403             return (t.blockType == BlockType.BLOCK) || (t.blockType == BlockType.INLINE);
   404         } else if (flags.contains(Flag.ACCEPTS_BLOCK)) {
   405             return (t.blockType == BlockType.BLOCK);
   406         } else if (flags.contains(Flag.ACCEPTS_INLINE)) {
   407             return (t.blockType == BlockType.INLINE);
   408         } else
   409             switch (blockType) {
   410                 case BLOCK:
   411                 case INLINE:
   412                     return (t.blockType == BlockType.INLINE);
   413                 case OTHER:
   414                     // OTHER tags are invalid in doc comments, and will be
   415                     // reported separately, so silently accept/ignore any content
   416                     return true;
   417                 default:
   418                     // any combination which could otherwise arrive here
   419                     // ought to have been handled in an overriding method
   420                     throw new AssertionError(this + ":" + t);
   421             }
   422     }
   424     public boolean acceptsText() {
   425         // generally, anywhere we can put text we can also put inline tag
   426         // so check if a typical inline tag is allowed
   427         return accepts(B);
   428     }
   430     public String getText() {
   431         return toLowerCase(name());
   432     }
   434     public Attr getAttr(Name attrName) {
   435         return Attr.index.get(toLowerCase(attrName.toString()));
   436     }
   438     public AttrKind getAttrKind(Name attrName) {
   439         AttrKind k = attrs.get(getAttr(attrName)); // null-safe
   440         return (k == null) ? AttrKind.INVALID : k;
   441     }
   443     private static AttrMap attrs(AttrKind k, Attr... attrs) {
   444         AttrMap map = new AttrMap();
   445         for (Attr a: attrs) map.put(a, k);
   446         return map;
   447     }
   449     private static final Map<String,HtmlTag> index = new HashMap<String,HtmlTag>();
   450     static {
   451         for (HtmlTag t: values()) {
   452             index.put(t.getText(), t);
   453         }
   454     }
   456     static HtmlTag get(Name tagName) {
   457         return index.get(toLowerCase(tagName.toString()));
   458     }
   460     private static String toLowerCase(String s) {
   461         return s.toLowerCase(Locale.US);
   462     }
   463 }

mercurial