### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core.tests.compiler Index: src/org/eclipse/jdt/core/tests/compiler/regression/JavadocBugsTest.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/JavadocBugsTest.java,v retrieving revision 1.48 diff -u -r1.48 JavadocBugsTest.java --- src/org/eclipse/jdt/core/tests/compiler/regression/JavadocBugsTest.java 9 Jul 2008 09:28:43 -0000 1.48 +++ src/org/eclipse/jdt/core/tests/compiler/regression/JavadocBugsTest.java 1 Sep 2008 16:03:12 -0000 @@ -7227,6 +7227,95 @@ null, null, JavacTestOptions.Excuse.EclipseHasSomeMoreWarnings); } + +/** + * @bug 222900: [Javadoc] Missing description is warned if valid description is on a new line + * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=222900" + */ +public void testBug222900a() { + String[] units = new String[] { + "X.java", + "/**\n" + + "* @since\n" + + "* description\n" + + "* @author\n" + + "* description\n" + + "* @version\n" + + "* description\n" + + "*/\n" + + "public class X {\n" + + " /**\n" + + " * @param aParam\n" + + " * description\n" + + " * @return\n" + + " * description\n" + + " * @since\n" + + " * description\n" + + " * @throws NullPointerException\n" + + " * description\n" + + " * @exception NullPointerException\n" + + " * description\n" + + " * @serial\n" + + " * description\n" + + " * @serialData\n" + + " * description\n" + + " * @serialField\n" + + " * description\n" + + " * @deprecated\n" + + " * description\n" + + " */\n" + + " public String foo(String aParam) {\n" + + " return new String();\n" + + " }\n" + + "}\n" + }; + this.reportMissingJavadocDescription = CompilerOptions.ALL_STANDARD_TAGS; + runConformTest(units); +} +public void testBug222900b() { + String[] units = new String[] { + "X.java", + "/**\n" + + " * {@code\n" + + " * description}\n" + + " * {@literal\n" + + " * description}\n" + + "*/\n" + + "public class X {\n" + + "}\n" + }; + this.reportMissingJavadocDescription = CompilerOptions.ALL_STANDARD_TAGS; + runConformTest(units); +} +public void testBug222900c() { + String[] units = new String[] { + "X.java", + "/**\n" + + " * Test the {@code} missing description\n" + + " * Test the {@code\n" + + " * } missing description\n" + + " * Test the {@code X} with description\n" + + " * Test the {@code\n" + + " * public class X} with description\n" + + "*/\n" + + "public class X {\n" + + "}\n" + }; + this.reportMissingJavadocDescription = CompilerOptions.ALL_STANDARD_TAGS; + runNegativeTest(units, + "----------\n" + + "1. ERROR in X.java (at line 2)\n" + + " * Test the {@code} missing description\n" + + " ^^^^\n" + + "Javadoc: Description expected after @code\n" + + "----------\n" + + "2. ERROR in X.java (at line 3)\n" + + " * Test the {@code\n" + + " ^^^^\n" + + "Javadoc: Description expected after @code\n" + + "----------\n" + ); +} /** * @bug 222902: [Javadoc] Missing description should not be warned in some cases * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=222902" @@ -7336,6 +7425,7 @@ JavacTestOptions.Excuse.EclipseHasSomeMoreWarnings ); } + /** * @bug 227730: [Javadoc] Missing description should not be warned for @inheritDoc * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=227730" #P org.eclipse.jdt.core Index: compiler/org/eclipse/jdt/internal/compiler/parser/JavadocParser.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/JavadocParser.java,v retrieving revision 1.71 diff -u -r1.71 JavadocParser.java --- compiler/org/eclipse/jdt/internal/compiler/parser/JavadocParser.java 27 Jun 2008 16:03:51 -0000 1.71 +++ compiler/org/eclipse/jdt/internal/compiler/parser/JavadocParser.java 1 Sep 2008 16:03:13 -0000 @@ -38,6 +38,10 @@ // returns whether this JavadocParser should report errors or not (overrides reportProblems) // see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=192449" public boolean shouldReportProblems = true; + + // flag to let the parser know that the current tag is waiting for a description + // see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=222900" + private int tagWaitingForDescription; public JavadocParser(Parser sourceParser) { super(sourceParser); @@ -58,6 +62,7 @@ this.firstTagPosition = this.sourceParser.scanner.commentTagStarts[commentPtr]; this.validValuePositions = -1; this.invalidValuePositions = -1; + this.tagWaitingForDescription = NO_TAG_VALUE; // Init javadoc if necessary if (this.checkDocComment) { @@ -339,13 +344,7 @@ */ protected boolean parseThrows() { boolean valid = super.parseThrows(); - if (valid && this.reportProblems && verifyEndLine(this.scanner.currentPosition)) { - // retrieve last identifier position (valid as, in the super method, we already parsed an identifier) - int start = (int) (this.identifierPositionStack[0] >>> 32); - int end = (int) this.identifierPositionStack[this.identifierPtr]; - this.sourceParser.problemReporter().javadocMissingTagDescriptionAfterReference(start, end, this.sourceParser.modifiers); - return false; - } + this.tagWaitingForDescription = valid && this.reportProblems ? TAG_THROWS_VALUE : NO_TAG_VALUE; return valid; } @@ -408,6 +407,22 @@ protected boolean parseTag(int previousPosition) throws InvalidInputException { + // Signal tag missing description if necessary + switch (this.tagWaitingForDescription) { + case TAG_PARAM_VALUE: + case TAG_THROWS_VALUE: + int start = (int) (this.identifierPositionStack[0] >>> 32); + int end = (int) this.identifierPositionStack[this.identifierPtr]; + this.sourceParser.problemReporter().javadocMissingTagDescriptionAfterReference(start, end, this.sourceParser.modifiers); + break; + case NO_TAG_VALUE: + break; + default: + this.sourceParser.problemReporter().javadocMissingTagDescription(TAG_NAMES[this.tagWaitingForDescription], this.tagSourceStart, this.tagSourceEnd, this.sourceParser.modifiers); + break; + } + this.tagWaitingForDescription = NO_TAG_VALUE; + // Read tag name int currentPosition = this.index; int token = readTokenAndConsume(); @@ -486,7 +501,6 @@ // Decide which parse to perform depending on tag name this.tagValue = TAG_OTHERS_VALUE; - boolean alreadyParsedTag = false; boolean valid = false; switch (token) { case TerminalTokens.TokenNameIdentifier : @@ -494,6 +508,7 @@ case 'a': if (length == TAG_AUTHOR_LENGTH && CharOperation.equals(TAG_AUTHOR, tagName)) { this.tagValue = TAG_AUTHOR_VALUE; + this.tagWaitingForDescription = this.tagValue; } break; case 'c': @@ -502,6 +517,7 @@ valid = parseIdentifierTag(false); // TODO (frederic) reconsider parameter value when @category will be significant in spec } else if (length == TAG_CODE_LENGTH && this.inlineTagStarted && CharOperation.equals(TAG_CODE, tagName)) { this.tagValue = TAG_CODE_VALUE; + this.tagWaitingForDescription = this.tagValue; } break; case 'd': @@ -509,19 +525,18 @@ this.deprecated = true; valid = true; this.tagValue = TAG_DEPRECATED_VALUE; + this.tagWaitingForDescription = this.tagValue; } else if (length == TAG_DOC_ROOT_LENGTH && CharOperation.equals(TAG_DOC_ROOT, tagName)) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=227730 // identify @docRoot tag as a base tag that does not expect any argument valid = true; this.tagValue = TAG_DOC_ROOT_VALUE; - alreadyParsedTag = true; } break; case 'e': if (length == TAG_EXCEPTION_LENGTH && CharOperation.equals(TAG_EXCEPTION, tagName)) { this.tagValue = TAG_EXCEPTION_VALUE; valid = parseThrows(); - alreadyParsedTag = true; } break; case 'i': @@ -536,9 +551,6 @@ } valid = true; this.tagValue = TAG_INHERITDOC_VALUE; - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=227730 - // no argument expected for @inheritedDoc tag - alreadyParsedTag = true; } break; case 'l': @@ -554,7 +566,6 @@ this.sourceParser.problemReporter().javadocUnexpectedTag(this.tagSourceStart, this.tagSourceEnd); } } - alreadyParsedTag = true; } else if (length == TAG_LINKPLAIN_LENGTH && CharOperation.equals(TAG_LINKPLAIN, tagName)) { this.tagValue = TAG_LINKPLAIN_VALUE; if (this.inlineTagStarted) { @@ -565,16 +576,15 @@ this.sourceParser.problemReporter().javadocUnexpectedTag(this.tagSourceStart, this.tagSourceEnd); } } - alreadyParsedTag = true; } else if (length == TAG_LITERAL_LENGTH && this.inlineTagStarted && CharOperation.equals(TAG_LITERAL, tagName)) { this.tagValue = TAG_LITERAL_VALUE; + this.tagWaitingForDescription = this.tagValue; } break; case 'p': if (length == TAG_PARAM_LENGTH && CharOperation.equals(TAG_PARAM, tagName)) { this.tagValue = TAG_PARAM_VALUE; valid = parseParam(); - alreadyParsedTag = true; } break; case 's': @@ -590,15 +600,18 @@ this.tagValue = TAG_SEE_VALUE; valid = parseReference(); } - alreadyParsedTag = true; } else if (length == TAG_SERIAL_LENGTH && CharOperation.equals(TAG_SERIAL, tagName)) { this.tagValue = TAG_SERIAL_VALUE; + this.tagWaitingForDescription = this.tagValue; } else if (length == TAG_SERIAL_DATA_LENGTH && CharOperation.equals(TAG_SERIAL_DATA, tagName)) { this.tagValue = TAG_SERIAL_DATA_VALUE; + this.tagWaitingForDescription = this.tagValue; } else if (length == TAG_SERIAL_FIELD_LENGTH && CharOperation.equals(TAG_SERIAL_FIELD, tagName)) { this.tagValue = TAG_SERIAL_FIELD_VALUE; + this.tagWaitingForDescription = this.tagValue; } else if (length == TAG_SINCE_LENGTH && CharOperation.equals(TAG_SINCE, tagName)) { this.tagValue = TAG_SINCE_VALUE; + this.tagWaitingForDescription = this.tagValue; } break; case 'v': @@ -626,9 +639,9 @@ if (this.reportProblems) this.sourceParser.problemReporter().javadocUnexpectedTag(this.tagSourceStart, this.tagSourceEnd); } } - alreadyParsedTag = true; } else if (length == TAG_VERSION_LENGTH && CharOperation.equals(TAG_VERSION, tagName)) { this.tagValue = TAG_VERSION_VALUE; + this.tagWaitingForDescription = this.tagValue; } else { createTag(); } @@ -641,27 +654,13 @@ case TerminalTokens.TokenNamereturn : this.tagValue = TAG_RETURN_VALUE; valid = parseReturn(); - alreadyParsedTag = true; - /* verify characters after return tag (we're expecting text description) - if(!verifyCharsAfterReturnTag(this.index)) { - if (this.sourceParser != null) { - int end = this.starPosition == -1 || this.lineEnd>> 32); - int end = (int) this.identifierPositionStack[this.identifierPtr]; - this.sourceParser.problemReporter().javadocMissingTagDescriptionAfterReference(start, end, this.sourceParser.modifiers); - return false; - } + this.tagWaitingForDescription = valid && this.reportProblems ? TAG_PARAM_VALUE : NO_TAG_VALUE; return valid; } @@ -771,6 +764,14 @@ return true; } + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#pushText(int, int) + */ + protected void pushText(int start, int end) { + // The tag gets its description => clear the flag + this.tagWaitingForDescription = NO_TAG_VALUE; + } + /* * Push a throws type ref in ast node stack. */ @@ -800,6 +801,18 @@ return true; } + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#refreshInlineTagPosition(int) + */ + protected void refreshInlineTagPosition(int previousPosition) { + + // Signal tag missing description if necessary + if (this.tagWaitingForDescription!= NO_TAG_VALUE) { + this.sourceParser.problemReporter().javadocMissingTagDescription(TAG_NAMES[this.tagWaitingForDescription], this.tagSourceStart, this.tagSourceEnd, this.sourceParser.modifiers); + this.tagWaitingForDescription = NO_TAG_VALUE; + } + } + /* * Refresh return statement */ @@ -820,6 +833,22 @@ */ protected void updateDocComment() { + // Signal tag missing description if necessary + switch (this.tagWaitingForDescription) { + case TAG_PARAM_VALUE: + case TAG_THROWS_VALUE: + int start = (int) (this.identifierPositionStack[0] >>> 32); + int end = (int) this.identifierPositionStack[this.identifierPtr]; + this.sourceParser.problemReporter().javadocMissingTagDescriptionAfterReference(start, end, this.sourceParser.modifiers); + break; + case NO_TAG_VALUE: + break; + default: + this.sourceParser.problemReporter().javadocMissingTagDescription(TAG_NAMES[this.tagWaitingForDescription], this.tagSourceStart, this.tagSourceEnd, this.sourceParser.modifiers); + break; + } + this.tagWaitingForDescription = NO_TAG_VALUE; + // Set positions this.docComment.inheritedPositions = this.inheritedPositions; this.docComment.valuePositions = this.validValuePositions != -1 ? this.validValuePositions : this.invalidValuePositions; Index: compiler/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java,v retrieving revision 1.80 diff -u -r1.80 AbstractCommentParser.java --- compiler/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java 20 Aug 2008 16:33:17 -0000 1.80 +++ compiler/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java 1 Sep 2008 16:03:13 -0000 @@ -137,7 +137,6 @@ int invalidTagLineEnd = -1; int invalidInlineTagLineEnd = -1; boolean lineHasStar = true; - boolean pushText = (this.kind & TEXT_PARSE) != 0; boolean verifText = (this.kind & TEXT_VERIF) != 0; boolean isDomParser = (this.kind & DOM_PARSER) != 0; boolean isFormatterParser = (this.kind & FORMATTER_COMMENT_PARSER) != 0; @@ -210,7 +209,7 @@ } validComment = false; if (this.textStart != -1 && this.textStart < textEndPosition) { - if (pushText) pushText(this.textStart, textEndPosition); + pushText(this.textStart, textEndPosition); } if (isDomParser || isFormatterParser) { refreshInlineTagPosition(textEndPosition); @@ -219,13 +218,13 @@ if (previousChar == '{') { if (this.textStart != -1) { if (this.textStart < textEndPosition) { - if (pushText) pushText(this.textStart, textEndPosition); + pushText(this.textStart, textEndPosition); } } this.inlineTagStarted = true; invalidInlineTagLineEnd = this.lineEnd; } else if (this.textStart != -1 && this.textStart < invalidTagLineEnd) { - if (pushText) pushText(this.textStart, invalidTagLineEnd); + pushText(this.textStart, invalidTagLineEnd); } this.scanner.resetTo(this.index, this.javadocEnd); this.currentTokenType = -1; // flush token cache at line begin @@ -263,7 +262,7 @@ textEndPosition = previousPosition; } if (this.textStart != -1 && this.textStart < textEndPosition) { - if (pushText) pushText(this.textStart, textEndPosition); + pushText(this.textStart, textEndPosition); } } this.lineStarted = false; @@ -276,12 +275,10 @@ refreshReturnStatement(); } if (this.inlineTagStarted) { - if (pushText) { - if (this.lineStarted && this.textStart != -1 && this.textStart < textEndPosition) { - pushText(this.textStart, textEndPosition); - } - refreshInlineTagPosition(previousPosition); + if (this.lineStarted && this.textStart != -1 && this.textStart < textEndPosition) { + pushText(this.textStart, textEndPosition); } + refreshInlineTagPosition(previousPosition); if (!isFormatterParser) this.textStart = this.index; this.inlineTagStarted = false; } else { @@ -304,12 +301,10 @@ int end = previousPosition= this.javadocEnd) end = invalidInlineTagLineEnd; this.sourceParser.problemReporter().javadocUnterminatedInlineTag(this.inlineTagStart, end); } - if (pushText) { - if (this.lineStarted && this.textStart != -1 && this.textStart < textEndPosition) { - pushText(this.textStart, textEndPosition); - } - refreshInlineTagPosition(textEndPosition); + if (this.lineStarted && this.textStart != -1 && this.textStart < textEndPosition) { + pushText(this.textStart, textEndPosition); } + refreshInlineTagPosition(textEndPosition); this.inlineTagStarted = false; - } else if (pushText && this.lineStarted && this.textStart != -1 && this.textStart <= textEndPosition) { + } else if (this.lineStarted && this.textStart != -1 && this.textStart <= textEndPosition) { pushText(this.textStart, textEndPosition); } updateDocComment(); Index: compiler/org/eclipse/jdt/internal/compiler/parser/JavadocTagConstants.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/JavadocTagConstants.java,v retrieving revision 1.17 diff -u -r1.17 JavadocTagConstants.java --- compiler/org/eclipse/jdt/internal/compiler/parser/JavadocTagConstants.java 27 Jun 2008 16:03:54 -0000 1.17 +++ compiler/org/eclipse/jdt/internal/compiler/parser/JavadocTagConstants.java 1 Sep 2008 16:03:14 -0000 @@ -11,6 +11,8 @@ package org.eclipse.jdt.internal.compiler.parser; +import org.eclipse.jdt.core.compiler.CharOperation; + /** * Javadoc tag constants. * @@ -62,7 +64,6 @@ public static final int TAG_LITERAL_LENGTH = TAG_LITERAL.length; public static final int TAG_DOC_ROOT_LENGTH = TAG_DOC_ROOT.length; - // tags value public static final int NO_TAG_VALUE = 0; public static final int TAG_DEPRECATED_VALUE = 1; @@ -86,6 +87,31 @@ public static final int TAG_LITERAL_VALUE = 19; public static final int TAG_DOC_ROOT_VALUE = 20; public static final int TAG_OTHERS_VALUE = 100; + + // Tag names array + public static final char[][] TAG_NAMES = { + CharOperation.NO_CHAR, + TAG_DEPRECATED, /* 1 */ + TAG_PARAM, /* 2 */ + TAG_RETURN, /* 3 */ + TAG_THROWS, /* 4 */ + TAG_EXCEPTION, /* 5 */ + TAG_SEE, /* 6 */ + TAG_LINK, /* 7 */ + TAG_LINKPLAIN, /* 8 */ + TAG_INHERITDOC, /* 9 */ + TAG_VALUE, /* 10 */ + TAG_CATEGORY, /* 11 */ + TAG_AUTHOR, /* 12 */ + TAG_SERIAL, /* 13 */ + TAG_SERIAL_DATA, /* 14 */ + TAG_SERIAL_FIELD, /* 15 */ + TAG_SINCE, /* 16 */ + TAG_VERSION, /* 17 */ + TAG_CODE, /* 18 */ + TAG_LITERAL, /* 19 */ + TAG_DOC_ROOT, /* 20 */ + }; // tags expected positions public final static int ORDERED_TAGS_NUMBER = 3;