Thu, 28 Feb 2013 14:00:52 +0000
8008723: Graph Inference: bad graph calculation leads to assertion error
Summary: Dependencies are not propagated correctly through merged nodes during inference graph initialization
Reviewed-by: jjg
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)),
136 LINK(BlockType.OTHER, EndKind.NONE),
138 MENU(BlockType.BLOCK, EndKind.REQUIRED) {
139 @Override
140 public boolean accepts(HtmlTag t) {
141 return (t == LI);
142 }
143 },
145 META(BlockType.OTHER, EndKind.NONE),
147 NOFRAMES(BlockType.OTHER, EndKind.REQUIRED),
149 NOSCRIPT(BlockType.BLOCK, EndKind.REQUIRED),
151 OL(BlockType.BLOCK, EndKind.REQUIRED,
152 EnumSet.of(Flag.EXPECT_CONTENT),
153 attrs(AttrKind.USE_CSS, START, TYPE)){
154 @Override
155 public boolean accepts(HtmlTag t) {
156 return (t == LI);
157 }
158 },
160 P(BlockType.BLOCK, EndKind.OPTIONAL,
161 EnumSet.of(Flag.EXPECT_CONTENT),
162 attrs(AttrKind.USE_CSS, ALIGN)),
164 PRE(BlockType.BLOCK, EndKind.REQUIRED,
165 EnumSet.of(Flag.EXPECT_CONTENT)) {
166 @Override
167 public boolean accepts(HtmlTag t) {
168 switch (t) {
169 case IMG: case BIG: case SMALL: case SUB: case SUP:
170 return false;
171 default:
172 return (t.blockType == BlockType.INLINE);
173 }
174 }
175 },
177 SCRIPT(BlockType.OTHER, EndKind.REQUIRED),
179 SMALL(BlockType.INLINE, EndKind.REQUIRED,
180 EnumSet.of(Flag.EXPECT_CONTENT)),
182 SPAN(BlockType.INLINE, EndKind.REQUIRED,
183 EnumSet.of(Flag.EXPECT_CONTENT)),
185 STRONG(BlockType.INLINE, EndKind.REQUIRED,
186 EnumSet.of(Flag.EXPECT_CONTENT)),
188 SUB(BlockType.INLINE, EndKind.REQUIRED,
189 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
191 SUP(BlockType.INLINE, EndKind.REQUIRED,
192 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
194 TABLE(BlockType.BLOCK, EndKind.REQUIRED,
195 EnumSet.of(Flag.EXPECT_CONTENT),
196 attrs(AttrKind.OK, SUMMARY, Attr.FRAME, RULES, BORDER,
197 CELLPADDING, CELLSPACING),
198 attrs(AttrKind.USE_CSS, ALIGN, WIDTH, BGCOLOR)) {
199 @Override
200 public boolean accepts(HtmlTag t) {
201 switch (t) {
202 case CAPTION:
203 case THEAD: case TBODY: case TFOOT:
204 case TR: // HTML 3.2
205 return true;
206 default:
207 return false;
208 }
209 }
210 },
212 TBODY(BlockType.TABLE_ITEM, EndKind.REQUIRED,
213 EnumSet.of(Flag.EXPECT_CONTENT),
214 attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN)) {
215 @Override
216 public boolean accepts(HtmlTag t) {
217 return (t == TR);
218 }
219 },
221 TD(BlockType.TABLE_ITEM, EndKind.OPTIONAL,
222 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE),
223 attrs(AttrKind.OK, COLSPAN, ROWSPAN, HEADERS, SCOPE, ABBR, AXIS,
224 ALIGN, CHAR, CHAROFF, VALIGN),
225 attrs(AttrKind.USE_CSS, WIDTH, BGCOLOR, HEIGHT, NOWRAP)),
227 TFOOT(BlockType.TABLE_ITEM, EndKind.REQUIRED,
228 attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN)) {
229 @Override
230 public boolean accepts(HtmlTag t) {
231 return (t == TR);
232 }
233 },
235 TH(BlockType.TABLE_ITEM, EndKind.OPTIONAL,
236 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE),
237 attrs(AttrKind.OK, COLSPAN, ROWSPAN, HEADERS, SCOPE, ABBR, AXIS,
238 ALIGN, CHAR, CHAROFF, VALIGN),
239 attrs(AttrKind.USE_CSS, WIDTH, BGCOLOR, HEIGHT, NOWRAP)),
241 THEAD(BlockType.TABLE_ITEM, EndKind.REQUIRED,
242 attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN)) {
243 @Override
244 public boolean accepts(HtmlTag t) {
245 return (t == TR);
246 }
247 },
249 TITLE(BlockType.OTHER, EndKind.REQUIRED),
251 TR(BlockType.TABLE_ITEM, EndKind.OPTIONAL,
252 attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN),
253 attrs(AttrKind.USE_CSS, BGCOLOR)) {
254 @Override
255 public boolean accepts(HtmlTag t) {
256 return (t == TH) || (t == TD);
257 }
258 },
260 TT(BlockType.INLINE, EndKind.REQUIRED,
261 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
263 U(BlockType.INLINE, EndKind.REQUIRED,
264 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
266 UL(BlockType.BLOCK, EndKind.REQUIRED,
267 EnumSet.of(Flag.EXPECT_CONTENT),
268 attrs(AttrKind.USE_CSS, COMPACT, TYPE)){
269 @Override
270 public boolean accepts(HtmlTag t) {
271 return (t == LI);
272 }
273 },
275 VAR(BlockType.INLINE, EndKind.REQUIRED);
277 /**
278 * Enum representing the type of HTML element.
279 */
280 public static enum BlockType {
281 BLOCK,
282 INLINE,
283 LIST_ITEM,
284 TABLE_ITEM,
285 OTHER;
286 }
288 /**
289 * Enum representing HTML end tag requirement.
290 */
291 public static enum EndKind {
292 NONE,
293 OPTIONAL,
294 REQUIRED;
295 }
297 public static enum Flag {
298 ACCEPTS_BLOCK,
299 ACCEPTS_INLINE,
300 EXPECT_CONTENT,
301 NO_NEST
302 }
304 public static enum Attr {
305 ABBR,
306 ALIGN,
307 ALT,
308 AXIS,
309 BGCOLOR,
310 BORDER,
311 CELLSPACING,
312 CELLPADDING,
313 CHAR,
314 CHAROFF,
315 CLEAR,
316 CLASS,
317 COLOR,
318 COLSPAN,
319 COMPACT,
320 FACE,
321 FRAME,
322 HEADERS,
323 HEIGHT,
324 HREF,
325 HSPACE,
326 ID,
327 NAME,
328 NOWRAP,
329 REVERSED,
330 ROWSPAN,
331 RULES,
332 SCOPE,
333 SIZE,
334 SPACE,
335 SRC,
336 START,
337 STYLE,
338 SUMMARY,
339 TARGET,
340 TYPE,
341 VALIGN,
342 VSPACE,
343 WIDTH;
345 public String getText() {
346 return name().toLowerCase();
347 }
349 static final Map<String,Attr> index = new HashMap<String,Attr>();
350 static {
351 for (Attr t: values()) {
352 index.put(t.getText(), t);
353 }
354 }
355 }
357 public static enum AttrKind {
358 INVALID,
359 OBSOLETE,
360 USE_CSS,
361 OK
362 }
364 // This class exists to avoid warnings from using parameterized vararg type
365 // Map<Attr,AttrKind> in signature of HtmlTag constructor.
366 private static class AttrMap extends EnumMap<Attr,AttrKind> {
367 private static final long serialVersionUID = 0;
368 AttrMap() {
369 super(Attr.class);
370 }
371 }
374 public final BlockType blockType;
375 public final EndKind endKind;
376 public final Set<Flag> flags;
377 private final Map<Attr,AttrKind> attrs;
379 HtmlTag(BlockType blockType, EndKind endKind, AttrMap... attrMaps) {
380 this(blockType, endKind, Collections.<Flag>emptySet(), attrMaps);
381 }
383 HtmlTag(BlockType blockType, EndKind endKind, Set<Flag> flags, AttrMap... attrMaps) {
384 this.blockType = blockType;
385 this.endKind = endKind;
386 this.flags = flags;
387 this.attrs = new EnumMap<Attr,AttrKind>(Attr.class);
388 for (Map<Attr,AttrKind> m: attrMaps)
389 this.attrs.putAll(m);
390 attrs.put(Attr.CLASS, AttrKind.OK);
391 attrs.put(Attr.ID, AttrKind.OK);
392 attrs.put(Attr.STYLE, AttrKind.OK);
393 }
395 public boolean accepts(HtmlTag t) {
396 if (flags.contains(Flag.ACCEPTS_BLOCK) && flags.contains(Flag.ACCEPTS_INLINE)) {
397 return (t.blockType == BlockType.BLOCK) || (t.blockType == BlockType.INLINE);
398 } else if (flags.contains(Flag.ACCEPTS_BLOCK)) {
399 return (t.blockType == BlockType.BLOCK);
400 } else if (flags.contains(Flag.ACCEPTS_INLINE)) {
401 return (t.blockType == BlockType.INLINE);
402 } else
403 switch (blockType) {
404 case BLOCK:
405 case INLINE:
406 return (t.blockType == BlockType.INLINE);
407 case OTHER:
408 // OTHER tags are invalid in doc comments, and will be
409 // reported separately, so silently accept/ignore any content
410 return true;
411 default:
412 // any combination which could otherwise arrive here
413 // ought to have been handled in an overriding method
414 throw new AssertionError(this + ":" + t);
415 }
416 }
418 public boolean acceptsText() {
419 // generally, anywhere we can put text we can also put inline tag
420 // so check if a typical inline tag is allowed
421 return accepts(B);
422 }
424 public String getText() {
425 return name().toLowerCase();
426 }
428 public Attr getAttr(Name attrName) {
429 return Attr.index.get(attrName.toString().toLowerCase());
430 }
432 public AttrKind getAttrKind(Name attrName) {
433 AttrKind k = attrs.get(getAttr(attrName)); // null-safe
434 return (k == null) ? AttrKind.INVALID : k;
435 }
437 private static AttrMap attrs(AttrKind k, Attr... attrs) {
438 AttrMap map = new AttrMap();
439 for (Attr a: attrs) map.put(a, k);
440 return map;
441 }
443 private static final Map<String,HtmlTag> index = new HashMap<String,HtmlTag>();
444 static {
445 for (HtmlTag t: values()) {
446 index.put(t.getText(), t);
447 }
448 }
450 static HtmlTag get(Name tagName) {
451 return index.get(tagName.toString().toLowerCase());
452 }
453 }