Tue, 26 Nov 2013 15:27:19 +0100
8026374: javac accepts void as a method parameter
Summary: Changing Check.validate to reject void types.
Reviewed-by: jjg, 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.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 DFN(BlockType.INLINE, EndKind.REQUIRED,
90 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
92 DIV(BlockType.BLOCK, EndKind.REQUIRED,
93 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)),
95 DL(BlockType.BLOCK, EndKind.REQUIRED,
96 EnumSet.of(Flag.EXPECT_CONTENT),
97 attrs(AttrKind.USE_CSS, COMPACT)) {
98 @Override
99 public boolean accepts(HtmlTag t) {
100 return (t == DT) || (t == DD);
101 }
102 },
104 DT(BlockType.LIST_ITEM, EndKind.OPTIONAL,
105 EnumSet.of(Flag.ACCEPTS_INLINE, Flag.EXPECT_CONTENT)),
107 EM(BlockType.INLINE, EndKind.REQUIRED,
108 EnumSet.of(Flag.NO_NEST)),
110 FONT(BlockType.INLINE, EndKind.REQUIRED, // tag itself is deprecated
111 EnumSet.of(Flag.EXPECT_CONTENT),
112 attrs(AttrKind.USE_CSS, SIZE, COLOR, FACE)),
114 FRAME(BlockType.OTHER, EndKind.NONE),
116 FRAMESET(BlockType.OTHER, EndKind.REQUIRED),
118 H1(BlockType.BLOCK, EndKind.REQUIRED),
119 H2(BlockType.BLOCK, EndKind.REQUIRED),
120 H3(BlockType.BLOCK, EndKind.REQUIRED),
121 H4(BlockType.BLOCK, EndKind.REQUIRED),
122 H5(BlockType.BLOCK, EndKind.REQUIRED),
123 H6(BlockType.BLOCK, EndKind.REQUIRED),
125 HEAD(BlockType.OTHER, EndKind.REQUIRED),
127 HR(BlockType.BLOCK, EndKind.NONE,
128 attrs(AttrKind.OK, WIDTH)), // OK in 4.01; not allowed in 5
130 HTML(BlockType.OTHER, EndKind.REQUIRED),
132 I(BlockType.INLINE, EndKind.REQUIRED,
133 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
135 IMG(BlockType.INLINE, EndKind.NONE,
136 attrs(AttrKind.OK, SRC, ALT, HEIGHT, WIDTH),
137 attrs(AttrKind.OBSOLETE, NAME),
138 attrs(AttrKind.USE_CSS, ALIGN, HSPACE, VSPACE, BORDER)),
140 LI(BlockType.LIST_ITEM, EndKind.OPTIONAL,
141 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE),
142 attrs(AttrKind.OK, VALUE)),
144 LINK(BlockType.OTHER, EndKind.NONE),
146 MENU(BlockType.BLOCK, EndKind.REQUIRED) {
147 @Override
148 public boolean accepts(HtmlTag t) {
149 return (t == LI);
150 }
151 },
153 META(BlockType.OTHER, EndKind.NONE),
155 NOFRAMES(BlockType.OTHER, EndKind.REQUIRED),
157 NOSCRIPT(BlockType.BLOCK, EndKind.REQUIRED),
159 OL(BlockType.BLOCK, EndKind.REQUIRED,
160 EnumSet.of(Flag.EXPECT_CONTENT),
161 attrs(AttrKind.OK, START, TYPE)) {
162 @Override
163 public boolean accepts(HtmlTag t) {
164 return (t == LI);
165 }
166 },
168 P(BlockType.BLOCK, EndKind.OPTIONAL,
169 EnumSet.of(Flag.EXPECT_CONTENT),
170 attrs(AttrKind.USE_CSS, ALIGN)),
172 PRE(BlockType.BLOCK, EndKind.REQUIRED,
173 EnumSet.of(Flag.EXPECT_CONTENT)) {
174 @Override
175 public boolean accepts(HtmlTag t) {
176 switch (t) {
177 case IMG: case BIG: case SMALL: case SUB: case SUP:
178 return false;
179 default:
180 return (t.blockType == BlockType.INLINE);
181 }
182 }
183 },
185 SCRIPT(BlockType.OTHER, EndKind.REQUIRED),
187 SMALL(BlockType.INLINE, EndKind.REQUIRED,
188 EnumSet.of(Flag.EXPECT_CONTENT)),
190 SPAN(BlockType.INLINE, EndKind.REQUIRED,
191 EnumSet.of(Flag.EXPECT_CONTENT)),
193 STRONG(BlockType.INLINE, EndKind.REQUIRED,
194 EnumSet.of(Flag.EXPECT_CONTENT)),
196 SUB(BlockType.INLINE, EndKind.REQUIRED,
197 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
199 SUP(BlockType.INLINE, EndKind.REQUIRED,
200 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
202 TABLE(BlockType.BLOCK, EndKind.REQUIRED,
203 EnumSet.of(Flag.EXPECT_CONTENT),
204 attrs(AttrKind.OK, SUMMARY, Attr.FRAME, RULES, BORDER,
205 CELLPADDING, CELLSPACING, WIDTH), // width OK in 4.01; not allowed in 5
206 attrs(AttrKind.USE_CSS, ALIGN, BGCOLOR)) {
207 @Override
208 public boolean accepts(HtmlTag t) {
209 switch (t) {
210 case CAPTION:
211 case THEAD: case TBODY: case TFOOT:
212 case TR: // HTML 3.2
213 return true;
214 default:
215 return false;
216 }
217 }
218 },
220 TBODY(BlockType.TABLE_ITEM, EndKind.REQUIRED,
221 EnumSet.of(Flag.EXPECT_CONTENT),
222 attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN)) {
223 @Override
224 public boolean accepts(HtmlTag t) {
225 return (t == TR);
226 }
227 },
229 TD(BlockType.TABLE_ITEM, EndKind.OPTIONAL,
230 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE),
231 attrs(AttrKind.OK, COLSPAN, ROWSPAN, HEADERS, SCOPE, ABBR, AXIS,
232 ALIGN, CHAR, CHAROFF, VALIGN),
233 attrs(AttrKind.USE_CSS, WIDTH, BGCOLOR, HEIGHT, NOWRAP)),
235 TFOOT(BlockType.TABLE_ITEM, EndKind.REQUIRED,
236 attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN)) {
237 @Override
238 public boolean accepts(HtmlTag t) {
239 return (t == TR);
240 }
241 },
243 TH(BlockType.TABLE_ITEM, EndKind.OPTIONAL,
244 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE),
245 attrs(AttrKind.OK, COLSPAN, ROWSPAN, HEADERS, SCOPE, ABBR, AXIS,
246 ALIGN, CHAR, CHAROFF, VALIGN),
247 attrs(AttrKind.USE_CSS, WIDTH, BGCOLOR, HEIGHT, NOWRAP)),
249 THEAD(BlockType.TABLE_ITEM, EndKind.REQUIRED,
250 attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN)) {
251 @Override
252 public boolean accepts(HtmlTag t) {
253 return (t == TR);
254 }
255 },
257 TITLE(BlockType.OTHER, EndKind.REQUIRED),
259 TR(BlockType.TABLE_ITEM, EndKind.OPTIONAL,
260 attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN),
261 attrs(AttrKind.USE_CSS, BGCOLOR)) {
262 @Override
263 public boolean accepts(HtmlTag t) {
264 return (t == TH) || (t == TD);
265 }
266 },
268 TT(BlockType.INLINE, EndKind.REQUIRED,
269 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
271 U(BlockType.INLINE, EndKind.REQUIRED,
272 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
274 UL(BlockType.BLOCK, EndKind.REQUIRED,
275 EnumSet.of(Flag.EXPECT_CONTENT),
276 attrs(AttrKind.OK, COMPACT, TYPE)) { // OK in 4.01; not allowed in 5
277 @Override
278 public boolean accepts(HtmlTag t) {
279 return (t == LI);
280 }
281 },
283 VAR(BlockType.INLINE, EndKind.REQUIRED);
285 /**
286 * Enum representing the type of HTML element.
287 */
288 public static enum BlockType {
289 BLOCK,
290 INLINE,
291 LIST_ITEM,
292 TABLE_ITEM,
293 OTHER;
294 }
296 /**
297 * Enum representing HTML end tag requirement.
298 */
299 public static enum EndKind {
300 NONE,
301 OPTIONAL,
302 REQUIRED;
303 }
305 public static enum Flag {
306 ACCEPTS_BLOCK,
307 ACCEPTS_INLINE,
308 EXPECT_CONTENT,
309 NO_NEST
310 }
312 public static enum Attr {
313 ABBR,
314 ALIGN,
315 ALT,
316 AXIS,
317 BGCOLOR,
318 BORDER,
319 CELLSPACING,
320 CELLPADDING,
321 CHAR,
322 CHAROFF,
323 CLEAR,
324 CLASS,
325 COLOR,
326 COLSPAN,
327 COMPACT,
328 FACE,
329 FRAME,
330 HEADERS,
331 HEIGHT,
332 HREF,
333 HSPACE,
334 ID,
335 NAME,
336 NOWRAP,
337 REVERSED,
338 ROWSPAN,
339 RULES,
340 SCOPE,
341 SIZE,
342 SPACE,
343 SRC,
344 START,
345 STYLE,
346 SUMMARY,
347 TARGET,
348 TYPE,
349 VALIGN,
350 VALUE,
351 VSPACE,
352 WIDTH;
354 public String getText() {
355 return toLowerCase(name());
356 }
358 static final Map<String,Attr> index = new HashMap<String,Attr>();
359 static {
360 for (Attr t: values()) {
361 index.put(t.getText(), t);
362 }
363 }
364 }
366 public static enum AttrKind {
367 INVALID,
368 OBSOLETE,
369 USE_CSS,
370 OK
371 }
373 // This class exists to avoid warnings from using parameterized vararg type
374 // Map<Attr,AttrKind> in signature of HtmlTag constructor.
375 private static class AttrMap extends EnumMap<Attr,AttrKind> {
376 private static final long serialVersionUID = 0;
377 AttrMap() {
378 super(Attr.class);
379 }
380 }
383 public final BlockType blockType;
384 public final EndKind endKind;
385 public final Set<Flag> flags;
386 private final Map<Attr,AttrKind> attrs;
388 HtmlTag(BlockType blockType, EndKind endKind, AttrMap... attrMaps) {
389 this(blockType, endKind, Collections.<Flag>emptySet(), attrMaps);
390 }
392 HtmlTag(BlockType blockType, EndKind endKind, Set<Flag> flags, AttrMap... attrMaps) {
393 this.blockType = blockType;
394 this.endKind = endKind;
395 this.flags = flags;
396 this.attrs = new EnumMap<Attr,AttrKind>(Attr.class);
397 for (Map<Attr,AttrKind> m: attrMaps)
398 this.attrs.putAll(m);
399 attrs.put(Attr.CLASS, AttrKind.OK);
400 attrs.put(Attr.ID, AttrKind.OK);
401 attrs.put(Attr.STYLE, AttrKind.OK);
402 }
404 public boolean accepts(HtmlTag t) {
405 if (flags.contains(Flag.ACCEPTS_BLOCK) && flags.contains(Flag.ACCEPTS_INLINE)) {
406 return (t.blockType == BlockType.BLOCK) || (t.blockType == BlockType.INLINE);
407 } else if (flags.contains(Flag.ACCEPTS_BLOCK)) {
408 return (t.blockType == BlockType.BLOCK);
409 } else if (flags.contains(Flag.ACCEPTS_INLINE)) {
410 return (t.blockType == BlockType.INLINE);
411 } else
412 switch (blockType) {
413 case BLOCK:
414 case INLINE:
415 return (t.blockType == BlockType.INLINE);
416 case OTHER:
417 // OTHER tags are invalid in doc comments, and will be
418 // reported separately, so silently accept/ignore any content
419 return true;
420 default:
421 // any combination which could otherwise arrive here
422 // ought to have been handled in an overriding method
423 throw new AssertionError(this + ":" + t);
424 }
425 }
427 public boolean acceptsText() {
428 // generally, anywhere we can put text we can also put inline tag
429 // so check if a typical inline tag is allowed
430 return accepts(B);
431 }
433 public String getText() {
434 return toLowerCase(name());
435 }
437 public Attr getAttr(Name attrName) {
438 return Attr.index.get(toLowerCase(attrName.toString()));
439 }
441 public AttrKind getAttrKind(Name attrName) {
442 AttrKind k = attrs.get(getAttr(attrName)); // null-safe
443 return (k == null) ? AttrKind.INVALID : k;
444 }
446 private static AttrMap attrs(AttrKind k, Attr... attrs) {
447 AttrMap map = new AttrMap();
448 for (Attr a: attrs) map.put(a, k);
449 return map;
450 }
452 private static final Map<String,HtmlTag> index = new HashMap<String,HtmlTag>();
453 static {
454 for (HtmlTag t: values()) {
455 index.put(t.getText(), t);
456 }
457 }
459 static HtmlTag get(Name tagName) {
460 return index.get(toLowerCase(tagName.toString()));
461 }
463 private static String toLowerCase(String s) {
464 return s.toLowerCase(Locale.US);
465 }
466 }