Copyright (c) 2000, 2019 IBM Corporation and others. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: IBM Corporation - initial API and implementation
/******************************************************************************* * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/
package org.eclipse.jdt.internal.core.util; import java.util.Arrays; import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.parser.Parser; import org.eclipse.jdt.internal.compiler.parser.Scanner; import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
Internal parser used for parsing source to create DOM AST nodes.
Since:3.0
/** * Internal parser used for parsing source to create DOM AST nodes. * * @since 3.0 */
public class CommentRecorderParser extends Parser { // support for comments int[] commentStops = new int[10]; int[] commentStarts = new int[10]; int commentPtr = -1; // no comment test with commentPtr value -1 protected final static int CommentIncrement = 100;
Params:
  • problemReporter –
  • optimizeStringLiterals –
/** * @param problemReporter * @param optimizeStringLiterals */
public CommentRecorderParser(ProblemReporter problemReporter, boolean optimizeStringLiterals) { super(problemReporter, optimizeStringLiterals); } // old javadoc style check which doesn't include all leading comments into declaration // for backward compatibility with 2.1 DOM @Override public void checkComment() { // discard obsolete comments while inside methods or fields initializer (see bug 74369) if (!(this.diet && this.dietInt==0) && this.scanner.commentPtr >= 0) { flushCommentsDefinedPriorTo(this.endStatementPosition); } boolean deprecated = false; boolean checkDeprecated = false; int lastCommentIndex = -1; //since jdk1.2 look only in the last java doc comment... nextComment : for (lastCommentIndex = this.scanner.commentPtr; lastCommentIndex >= 0; lastCommentIndex--){ //look for @deprecated into the first javadoc comment preceeding the declaration int commentSourceStart = this.scanner.commentStarts[lastCommentIndex]; // javadoc only (non javadoc comment have negative start and/or end positions.) if ((commentSourceStart < 0) || (this.modifiersSourceStart != -1 && this.modifiersSourceStart < commentSourceStart) || (this.scanner.commentStops[lastCommentIndex] < 0)) { continue nextComment; } checkDeprecated = true; int commentSourceEnd = this.scanner.commentStops[lastCommentIndex] - 1; //stop is one over // do not report problem before last parsed comment while recovering code... if (this.javadocParser.shouldReportProblems) { this.javadocParser.reportProblems = this.currentElement == null || commentSourceEnd > this.lastJavadocEnd; } else { this.javadocParser.reportProblems = false; } deprecated = this.javadocParser.checkDeprecation(lastCommentIndex); this.javadoc = this.javadocParser.docComment; if (this.currentElement == null) this.lastJavadocEnd = commentSourceEnd; break nextComment; } if (deprecated) { checkAndSetModifiers(ClassFileConstants.AccDeprecated); } // modify the modifier source start to point at the first comment if (lastCommentIndex >= 0 && checkDeprecated) { int lastCommentStart = this.scanner.commentStarts[lastCommentIndex]; if (lastCommentStart < 0) lastCommentStart = -lastCommentStart; if (this.forStartPosition == 0 || this.forStartPosition < lastCommentStart) {// only if there is no "for" in between this.modifiersSourceStart = lastCommentStart; } } } @Override protected void consumeAnnotationTypeDeclarationHeader() { pushOnCommentsStack(0, this.scanner.commentPtr); super.consumeAnnotationTypeDeclarationHeader(); } @Override protected void consumeClassHeader() { pushOnCommentsStack(0, this.scanner.commentPtr); super.consumeClassHeader(); } @Override protected void consumeEmptyTypeDeclaration() { pushOnCommentsStack(0, this.scanner.commentPtr); super.consumeEmptyTypeDeclaration(); } @Override protected void consumeEnterAnonymousClassBody(boolean qualified) { pushOnCommentsStack(0, this.scanner.commentPtr); super.consumeEnterAnonymousClassBody(qualified); } @Override protected void consumeEnumHeader() { pushOnCommentsStack(0, this.scanner.commentPtr); super.consumeEnumHeader(); } @Override protected void consumeInterfaceHeader() { pushOnCommentsStack(0, this.scanner.commentPtr); super.consumeInterfaceHeader(); } @Override protected CompilationUnitDeclaration endParse(int act) { CompilationUnitDeclaration unit = super.endParse(act); if (unit.comments == null) { pushOnCommentsStack(0, this.scanner.commentPtr); unit.comments = getCommentsPositions(); } return unit; } /* (non-Javadoc) * Save all source comments currently stored before flushing them. * @see org.eclipse.jdt.internal.compiler.parser.Parser#flushCommentsDefinedPriorTo(int) */ @Override public int flushCommentsDefinedPriorTo(int position) { int lastCommentIndex = getCommentPtr(); if (lastCommentIndex < 0) return position; // no comment // compute the index of the first obsolete comment int index = lastCommentIndex; int validCount = 0; while (index >= 0){ int commentEnd = this.scanner.commentStops[index]; if (commentEnd < 0) commentEnd = -commentEnd; // negative end position for non-javadoc comments if (commentEnd <= position){ break; } index--; validCount++; } // if the source at <position> is immediately followed by a line comment, then // flush this comment and shift <position> to the comment end. if (validCount > 0){ int immediateCommentEnd = 0; while (index<lastCommentIndex && (immediateCommentEnd = -this.scanner.commentStops[index+1]) > 0){ // only tolerating non-javadoc comments (non-javadoc comment end positions are negative) // is there any line break until the end of the immediate comment ? (thus only tolerating line comment) immediateCommentEnd--; // comment end in one char too far if (org.eclipse.jdt.internal.compiler.util.Util.getLineNumber(position, this.scanner.lineEnds, 0, this.scanner.linePtr) != org.eclipse.jdt.internal.compiler.util.Util.getLineNumber(immediateCommentEnd, this.scanner.lineEnds, 0, this.scanner.linePtr)) break; position = immediateCommentEnd; validCount--; // flush this comment index++; } } if (index < 0) return position; // no obsolete comment pushOnCommentsStack(0, index); // store comment before flushing them switch (validCount) { case 0: // do nothing break; // move valid comment infos, overriding obsolete comment infos case 2: this.scanner.commentStarts[0] = this.scanner.commentStarts[index+1]; this.scanner.commentStops[0] = this.scanner.commentStops[index+1]; this.scanner.commentTagStarts[0] = this.scanner.commentTagStarts[index+1]; this.scanner.commentStarts[1] = this.scanner.commentStarts[index+2]; this.scanner.commentStops[1] = this.scanner.commentStops[index+2]; this.scanner.commentTagStarts[1] = this.scanner.commentTagStarts[index+2]; break; case 1: this.scanner.commentStarts[0] = this.scanner.commentStarts[index+1]; this.scanner.commentStops[0] = this.scanner.commentStops[index+1]; this.scanner.commentTagStarts[0] = this.scanner.commentTagStarts[index+1]; break; default: System.arraycopy(this.scanner.commentStarts, index + 1, this.scanner.commentStarts, 0, validCount); System.arraycopy(this.scanner.commentStops, index + 1, this.scanner.commentStops, 0, validCount); System.arraycopy(this.scanner.commentTagStarts, index + 1, this.scanner.commentTagStarts, 0, validCount); } this.scanner.commentPtr = validCount - 1; return position; } protected int getCommentPtr() { int lastComment = this.scanner.commentPtr; if (lastComment == -1 && this.currentElement != null) { // during recovery reuse comments from initial scan ... lastComment = this.commentPtr; if (lastComment >= 0) { // ... but ignore if not suitable ... if (lastComment >= this.scanner.commentStarts.length) { return -1; } else { int start = this.scanner.commentStarts[lastComment]; // ... unsuitable if: // - unknown to the scanner (start == 0) // - line comment (start < 0) if (start <= 0) return -1; // - past the current position, or start of previous recovered element int currentStart = this.currentElement.getLastStart(); if (currentStart == -1) currentStart = this.scanner.currentPosition; if (start > currentStart) return -1; } } } return lastComment; } /* * Build a n*2 matrix of comments positions. * For each position, 0 is for start position and 1 for end position of the comment. */ public int[][] getCommentsPositions() { int[][] positions = new int[this.commentPtr+1][2]; for (int i = 0, max = this.commentPtr; i <= max; i++){ positions[i][0] = this.commentStarts[i]; positions[i][1] = this.commentStops[i]; } return positions; } @Override public void initialize(boolean parsingCompilationUnit) { super.initialize(parsingCompilationUnit); this.commentPtr = -1; } @Override public void initialize() { super.initialize(); this.commentPtr = -1; } /* (non-Javadoc) * Create and store a specific comment recorder scanner. * @see org.eclipse.jdt.internal.compiler.parser.Parser#initializeScanner() */ @Override public void initializeScanner() { this.scanner = new Scanner( false /*comment*/, false /*whitespace*/, this.options.getSeverity(CompilerOptions.NonExternalizedString) != ProblemSeverities.Ignore /*nls*/, this.options.sourceLevel /*sourceLevel*/, this.options.taskTags/*taskTags*/, this.options.taskPriorities/*taskPriorities*/, this.options.isTaskCaseSensitive/*taskCaseSensitive*/, this.options.enablePreviewFeatures /*isPreviewEnabled*/); } /* * Push all stored comments in stack. */ private void pushOnCommentsStack(int start, int end) { for (int i=start; i<=end; i++) { if (this.scanner.commentPtr < i) break; // First see if comment hasn't been already stored int scannerStart = this.scanner.commentStarts[i]<0 ? -this.scanner.commentStarts[i] : this.scanner.commentStarts[i]; int commentStart = this.commentPtr == -1 ? -1 : (this.commentStarts[this.commentPtr]<0 ? -this.commentStarts[this.commentPtr] : this.commentStarts[this.commentPtr]); if (commentStart == -1 || scannerStart > commentStart) { int stackLength = this.commentStarts.length; if (++this.commentPtr >= stackLength) { System.arraycopy( this.commentStarts, 0, this.commentStarts = new int[stackLength + CommentIncrement], 0, stackLength); System.arraycopy( this.commentStops, 0, this.commentStops = new int[stackLength + CommentIncrement], 0, stackLength); } this.commentStarts[this.commentPtr] = this.scanner.commentStarts[i]; this.commentStops[this.commentPtr] = this.scanner.commentStops[i]; } } } /* (non-Javadoc) * Save all source comments currently stored before flushing them. * this.scanner.commentPtr is expected *not* yet being reset before calling this method. * @see org.eclipse.jdt.internal.compiler.parser.Parser#resetModifiers() */ @Override protected void resetModifiers() { pushOnCommentsStack(0, this.scanner.commentPtr); super.resetModifiers(); } public void resetComments() { this.commentPtr = -1; Arrays.fill(this.commentStarts, 0); Arrays.fill(this.commentStops, 0); Arrays.fill(this.scanner.commentStops, 0); Arrays.fill(this.scanner.commentStarts, 0); Arrays.fill(this.scanner.commentTagStarts, 0); this.scanner.commentPtr = -1; // no comment test with commentPtr value -1 this.scanner.lastCommentLinePosition = -1; } }