1.1 --- a/src/share/classes/com/sun/tools/doclint/Checker.java Mon Jan 21 10:00:46 2013 -0800 1.2 +++ b/src/share/classes/com/sun/tools/doclint/Checker.java Mon Jan 21 10:07:37 2013 -0800 1.3 @@ -95,7 +95,8 @@ 1.4 public enum Flag { 1.5 TABLE_HAS_CAPTION, 1.6 HAS_ELEMENT, 1.7 - HAS_TEXT 1.8 + HAS_TEXT, 1.9 + REPORTED_BAD_INLINE 1.10 } 1.11 1.12 static class TagStackItem { 1.13 @@ -195,7 +196,8 @@ 1.14 1.15 @Override 1.16 public Void visitText(TextTree tree, Void ignore) { 1.17 - if (!tree.getBody().trim().isEmpty()) { 1.18 + if (hasNonWhitespace(tree)) { 1.19 + checkAllowsText(tree); 1.20 markEnclosingTag(Flag.HAS_TEXT); 1.21 } 1.22 return null; 1.23 @@ -203,6 +205,7 @@ 1.24 1.25 @Override 1.26 public Void visitEntity(EntityTree tree, Void ignore) { 1.27 + checkAllowsText(tree); 1.28 markEnclosingTag(Flag.HAS_TEXT); 1.29 String name = tree.getName().toString(); 1.30 if (name.startsWith("#")) { 1.31 @@ -218,6 +221,18 @@ 1.32 return null; 1.33 } 1.34 1.35 + void checkAllowsText(DocTree tree) { 1.36 + TagStackItem top = tagStack.peek(); 1.37 + if (top != null 1.38 + && top.tree.getKind() == DocTree.Kind.START_ELEMENT 1.39 + && !top.tag.acceptsText()) { 1.40 + if (top.flags.add(Flag.REPORTED_BAD_INLINE)) { 1.41 + env.messages.error(HTML, tree, "dc.text.not.allowed", 1.42 + ((StartElementTree) top.tree).getName()); 1.43 + } 1.44 + } 1.45 + } 1.46 + 1.47 // </editor-fold> 1.48 1.49 // <editor-fold defaultstate="collapsed" desc="HTML elements"> 1.50 @@ -230,53 +245,22 @@ 1.51 if (t == null) { 1.52 env.messages.error(HTML, tree, "dc.tag.unknown", treeName); 1.53 } else { 1.54 + for (TagStackItem tsi: tagStack) { 1.55 + if (tsi.tag.accepts(t)) { 1.56 + while (tagStack.peek() != tsi) tagStack.pop(); 1.57 + break; 1.58 + } else if (tsi.tag.endKind != HtmlTag.EndKind.OPTIONAL) 1.59 + break; 1.60 + } 1.61 + 1.62 + checkStructure(tree, t); 1.63 + 1.64 // tag specific checks 1.65 switch (t) { 1.66 // check for out of sequence headers, such as <h1>...</h1> <h3>...</h3> 1.67 case H1: case H2: case H3: case H4: case H5: case H6: 1.68 checkHeader(tree, t); 1.69 break; 1.70 - // <p> inside <pre> 1.71 - case P: 1.72 - TagStackItem top = tagStack.peek(); 1.73 - if (top != null && top.tag == HtmlTag.PRE) 1.74 - env.messages.warning(HTML, tree, "dc.tag.p.in.pre"); 1.75 - break; 1.76 - } 1.77 - 1.78 - // check that only block tags and inline tags are used, 1.79 - // and that blocks tags are not used within inline tags 1.80 - switch (t.blockType) { 1.81 - case INLINE: 1.82 - break; 1.83 - case BLOCK: 1.84 - TagStackItem top = tagStack.peek(); 1.85 - if (top != null && top.tag != null && top.tag.blockType == HtmlTag.BlockType.INLINE) { 1.86 - switch (top.tree.getKind()) { 1.87 - case START_ELEMENT: { 1.88 - Name name = ((StartElementTree) top.tree).getName(); 1.89 - env.messages.error(HTML, tree, "dc.tag.not.allowed.inline.element", 1.90 - treeName, name); 1.91 - break; 1.92 - } 1.93 - case LINK: 1.94 - case LINK_PLAIN: { 1.95 - String name = top.tree.getKind().tagName; 1.96 - env.messages.error(HTML, tree, "dc.tag.not.allowed.inline.tag", 1.97 - treeName, name); 1.98 - break; 1.99 - } 1.100 - default: 1.101 - env.messages.error(HTML, tree, "dc.tag.not.allowed.inline.other", 1.102 - treeName); 1.103 - } 1.104 - } 1.105 - break; 1.106 - case OTHER: 1.107 - env.messages.error(HTML, tree, "dc.tag.not.allowed", treeName); 1.108 - break; 1.109 - default: 1.110 - throw new AssertionError(); 1.111 } 1.112 1.113 if (t.flags.contains(HtmlTag.Flag.NO_NEST)) { 1.114 @@ -324,6 +308,58 @@ 1.115 } 1.116 } 1.117 1.118 + private void checkStructure(StartElementTree tree, HtmlTag t) { 1.119 + Name treeName = tree.getName(); 1.120 + TagStackItem top = tagStack.peek(); 1.121 + switch (t.blockType) { 1.122 + case BLOCK: 1.123 + if (top == null || top.tag.accepts(t)) 1.124 + return; 1.125 + 1.126 + switch (top.tree.getKind()) { 1.127 + case START_ELEMENT: { 1.128 + if (top.tag.blockType == HtmlTag.BlockType.INLINE) { 1.129 + Name name = ((StartElementTree) top.tree).getName(); 1.130 + env.messages.error(HTML, tree, "dc.tag.not.allowed.inline.element", 1.131 + treeName, name); 1.132 + return; 1.133 + } 1.134 + } 1.135 + break; 1.136 + 1.137 + case LINK: 1.138 + case LINK_PLAIN: { 1.139 + String name = top.tree.getKind().tagName; 1.140 + env.messages.error(HTML, tree, "dc.tag.not.allowed.inline.tag", 1.141 + treeName, name); 1.142 + return; 1.143 + } 1.144 + } 1.145 + break; 1.146 + 1.147 + case INLINE: 1.148 + if (top == null || top.tag.accepts(t)) 1.149 + return; 1.150 + break; 1.151 + 1.152 + case LIST_ITEM: 1.153 + case TABLE_ITEM: 1.154 + if (top != null) { 1.155 + // reset this flag so subsequent bad inline content gets reported 1.156 + top.flags.remove(Flag.REPORTED_BAD_INLINE); 1.157 + if (top.tag.accepts(t)) 1.158 + return; 1.159 + } 1.160 + break; 1.161 + 1.162 + case OTHER: 1.163 + env.messages.error(HTML, tree, "dc.tag.not.allowed", treeName); 1.164 + return; 1.165 + } 1.166 + 1.167 + env.messages.error(HTML, tree, "dc.tag.not.allowed.here", treeName); 1.168 + } 1.169 + 1.170 private void checkHeader(StartElementTree tree, HtmlTag tag) { 1.171 // verify the new tag 1.172 if (getHeaderLevel(tag) > getHeaderLevel(currHeaderTag) + 1) { 1.173 @@ -378,10 +414,6 @@ 1.174 && !top.flags.contains(Flag.HAS_ELEMENT)) { 1.175 env.messages.warning(HTML, tree, "dc.tag.empty", treeName); 1.176 } 1.177 - if (t.flags.contains(HtmlTag.Flag.NO_TEXT) 1.178 - && top.flags.contains(Flag.HAS_TEXT)) { 1.179 - env.messages.error(HTML, tree, "dc.text.not.allowed", treeName); 1.180 - } 1.181 tagStack.pop(); 1.182 done = true; 1.183 break; 1.184 @@ -763,7 +795,7 @@ 1.185 for (DocTree d: list) { 1.186 switch (d.getKind()) { 1.187 case TEXT: 1.188 - if (!((TextTree) d).getBody().trim().isEmpty()) 1.189 + if (hasNonWhitespace((TextTree) d)) 1.190 return; 1.191 break; 1.192 default: 1.193 @@ -772,6 +804,16 @@ 1.194 } 1.195 env.messages.warning(SYNTAX, tree, "dc.empty", tree.getKind().tagName); 1.196 } 1.197 + 1.198 + boolean hasNonWhitespace(TextTree tree) { 1.199 + String s = tree.getBody(); 1.200 + for (int i = 0; i < s.length(); i++) { 1.201 + if (!Character.isWhitespace(s.charAt(i))) 1.202 + return true; 1.203 + } 1.204 + return false; 1.205 + } 1.206 + 1.207 // </editor-fold> 1.208 1.209 }