211 |
211 |
212 @Override |
212 @Override |
213 public Void visitDocComment(DocCommentTree tree, Void ignore) { |
213 public Void visitDocComment(DocCommentTree tree, Void ignore) { |
214 super.visitDocComment(tree, ignore); |
214 super.visitDocComment(tree, ignore); |
215 for (TagStackItem tsi: tagStack) { |
215 for (TagStackItem tsi: tagStack) { |
|
216 warnIfEmpty(tsi, null); |
216 if (tsi.tree.getKind() == DocTree.Kind.START_ELEMENT |
217 if (tsi.tree.getKind() == DocTree.Kind.START_ELEMENT |
217 && tsi.tag.endKind == HtmlTag.EndKind.REQUIRED) { |
218 && tsi.tag.endKind == HtmlTag.EndKind.REQUIRED) { |
218 StartElementTree t = (StartElementTree) tsi.tree; |
219 StartElementTree t = (StartElementTree) tsi.tree; |
219 env.messages.error(HTML, t, "dc.tag.not.closed", t.getName()); |
220 env.messages.error(HTML, t, "dc.tag.not.closed", t.getName()); |
220 } |
221 } |
268 |
269 |
269 // <editor-fold defaultstate="collapsed" desc="HTML elements"> |
270 // <editor-fold defaultstate="collapsed" desc="HTML elements"> |
270 |
271 |
271 @Override |
272 @Override |
272 public Void visitStartElement(StartElementTree tree, Void ignore) { |
273 public Void visitStartElement(StartElementTree tree, Void ignore) { |
273 markEnclosingTag(Flag.HAS_ELEMENT); |
|
274 final Name treeName = tree.getName(); |
274 final Name treeName = tree.getName(); |
275 final HtmlTag t = HtmlTag.get(treeName); |
275 final HtmlTag t = HtmlTag.get(treeName); |
276 if (t == null) { |
276 if (t == null) { |
277 env.messages.error(HTML, tree, "dc.tag.unknown", treeName); |
277 env.messages.error(HTML, tree, "dc.tag.unknown", treeName); |
278 } else { |
278 } else { |
279 boolean done = false; |
279 boolean done = false; |
280 for (TagStackItem tsi: tagStack) { |
280 for (TagStackItem tsi: tagStack) { |
281 if (tsi.tag.accepts(t)) { |
281 if (tsi.tag.accepts(t)) { |
282 while (tagStack.peek() != tsi) tagStack.pop(); |
282 while (tagStack.peek() != tsi) { |
|
283 warnIfEmpty(tagStack.peek(), null); |
|
284 tagStack.pop(); |
|
285 } |
283 done = true; |
286 done = true; |
284 break; |
287 break; |
285 } else if (tsi.tag.endKind != HtmlTag.EndKind.OPTIONAL) { |
288 } else if (tsi.tag.endKind != HtmlTag.EndKind.OPTIONAL) { |
286 done = true; |
289 done = true; |
287 break; |
290 break; |
288 } |
291 } |
289 } |
292 } |
290 if (!done && HtmlTag.BODY.accepts(t)) { |
293 if (!done && HtmlTag.BODY.accepts(t)) { |
291 tagStack.clear(); |
294 while (!tagStack.isEmpty()) { |
292 } |
295 warnIfEmpty(tagStack.peek(), null); |
293 |
296 tagStack.pop(); |
|
297 } |
|
298 } |
|
299 |
|
300 markEnclosingTag(Flag.HAS_ELEMENT); |
294 checkStructure(tree, t); |
301 checkStructure(tree, t); |
295 |
302 |
296 // tag specific checks |
303 // tag specific checks |
297 switch (t) { |
304 switch (t) { |
298 // check for out of sequence headers, such as <h1>...</h1> <h3>...</h3> |
305 // check for out of sequence headers, such as <h1>...</h1> <h3>...</h3> |
445 && !top.flags.contains(Flag.TABLE_HAS_CAPTION)) { |
452 && !top.flags.contains(Flag.TABLE_HAS_CAPTION)) { |
446 env.messages.error(ACCESSIBILITY, tree, |
453 env.messages.error(ACCESSIBILITY, tree, |
447 "dc.no.summary.or.caption.for.table"); |
454 "dc.no.summary.or.caption.for.table"); |
448 } |
455 } |
449 } |
456 } |
450 if (t.flags.contains(HtmlTag.Flag.EXPECT_CONTENT) |
457 warnIfEmpty(top, tree); |
451 && !top.flags.contains(Flag.HAS_TEXT) |
|
452 && !top.flags.contains(Flag.HAS_ELEMENT) |
|
453 && !top.flags.contains(Flag.HAS_INLINE_TAG)) { |
|
454 env.messages.warning(HTML, tree, "dc.tag.empty", treeName); |
|
455 } |
|
456 tagStack.pop(); |
458 tagStack.pop(); |
457 done = true; |
459 done = true; |
458 break; |
460 break; |
459 } else if (top.tag == null || top.tag.endKind != HtmlTag.EndKind.REQUIRED) { |
461 } else if (top.tag == null || top.tag.endKind != HtmlTag.EndKind.REQUIRED) { |
460 tagStack.pop(); |
462 tagStack.pop(); |
483 } |
485 } |
484 } |
486 } |
485 |
487 |
486 return super.visitEndElement(tree, ignore); |
488 return super.visitEndElement(tree, ignore); |
487 } |
489 } |
|
490 |
|
491 void warnIfEmpty(TagStackItem tsi, DocTree endTree) { |
|
492 if (tsi.tag != null && tsi.tree instanceof StartElementTree) { |
|
493 if (tsi.tag.flags.contains(HtmlTag.Flag.EXPECT_CONTENT) |
|
494 && !tsi.flags.contains(Flag.HAS_TEXT) |
|
495 && !tsi.flags.contains(Flag.HAS_ELEMENT) |
|
496 && !tsi.flags.contains(Flag.HAS_INLINE_TAG)) { |
|
497 DocTree tree = (endTree != null) ? endTree : tsi.tree; |
|
498 Name treeName = ((StartElementTree) tsi.tree).getName(); |
|
499 env.messages.warning(HTML, tree, "dc.tag.empty", treeName); |
|
500 } |
|
501 } |
|
502 } |
|
503 |
488 // </editor-fold> |
504 // </editor-fold> |
489 |
505 |
490 // <editor-fold defaultstate="collapsed" desc="HTML attributes"> |
506 // <editor-fold defaultstate="collapsed" desc="HTML attributes"> |
491 |
507 |
492 @Override @SuppressWarnings("fallthrough") |
508 @Override @SuppressWarnings("fallthrough") |