/******************************************************************************* * Copyright (c) 2000, 2004 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package net.sourceforge.phpdt.internal.core.util; import net.sourceforge.phpdt.internal.compiler.ast.CompilationUnitDeclaration; import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions; import net.sourceforge.phpdt.internal.compiler.parser.UnitParser; import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter; import net.sourceforge.phpdt.internal.compiler.problem.ProblemSeverities; /** * Internal parser used for parsing source to create DOM AST nodes. * * @since 3.0 */ public class CommentRecorderParser extends UnitParser { // 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; /** * @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 // public void checkComment() { // // if (this.currentElement != null && this.scanner.commentPtr >= 0) { // flushCommentsDefinedPriorTo(this.endStatementPosition); // discard // obsolete comments // } // 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 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 // // deprecated = this.javadocParser.checkDeprecation(commentSourceStart, // commentSourceEnd); // this.javadoc = this.javadocParser.docComment; // break nextComment; // } // if (deprecated) { // checkAndSetModifiers(AccDeprecated); // } // // modify the modifier source start to point at the first comment // if (lastCommentIndex >= 0 && checkDeprecated) { // this.modifiersSourceStart = this.scanner.commentStarts[lastCommentIndex]; // if (this.modifiersSourceStart < 0) { // this.modifiersSourceStart = -this.modifiersSourceStart; // } // } // // } // /* (non-Javadoc) // * @see // net.sourceforge.phpdt.internal.compiler.parser.Parser#consumeClassHeader() // */ // protected void consumeClassHeader() { // pushOnCommentsStack(0, this.scanner.commentPtr); // super.consumeClassHeader(); // } // /* (non-Javadoc) // * @see // net.sourceforge.phpdt.internal.compiler.parser.Parser#consumeEmptyClassMemberDeclaration() // */ // protected void consumeEmptyClassMemberDeclaration() { // pushOnCommentsStack(0, this.scanner.commentPtr); // super.consumeEmptyClassMemberDeclaration(); // } // /* (non-Javadoc) // * @see // net.sourceforge.phpdt.internal.compiler.parser.Parser#consumeEmptyTypeDeclaration() // */ // protected void consumeEmptyTypeDeclaration() { // pushOnCommentsStack(0, this.scanner.commentPtr); // super.consumeEmptyTypeDeclaration(); // } // /* (non-Javadoc) // * @see // net.sourceforge.phpdt.internal.compiler.parser.Parser#consumeInterfaceHeader() // */ // protected void consumeInterfaceHeader() { // pushOnCommentsStack(0, this.scanner.commentPtr); // super.consumeInterfaceHeader(); // } /** * Insure that start position is always positive. * * @see net.sourceforge.phpdt.internal.compiler.parser.Parser#containsComment(int, * int) */ public boolean containsComment(int sourceStart, int sourceEnd) { int iComment = this.scanner.commentPtr; for (; iComment >= 0; iComment--) { int commentStart = this.scanner.commentStarts[iComment]; if (commentStart < 0) { commentStart = -commentStart; } // ignore comments before start if (commentStart < sourceStart) continue; // ignore comments after end if (commentStart > sourceEnd) continue; return true; } return false; } /* * (non-Javadoc) * * @see net.sourceforge.phpdt.internal.compiler.parser.Parser#endParse(int) */ 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 net.sourceforge.phpdt.internal.compiler.parser.Parser#flushCommentsDefinedPriorTo(int) */ public int flushCommentsDefinedPriorTo(int position) { int lastCommentIndex = this.scanner.commentPtr; 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 is immediately followed by a line // comment, then // flush this comment and shift 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 (this.scanner.getLineNumber(position) != this.scanner .getLineNumber(immediateCommentEnd)) break; position = immediateCommentEnd; validCount--; // flush this comment index++; } } if (index < 0) return position; // no obsolete comment pushOnCommentsStack(0, index); // store comment before flushing them if (validCount > 0) { // move valid comment infos, overriding obsolete // comment infos System.arraycopy(this.scanner.commentStarts, index + 1, this.scanner.commentStarts, 0, validCount); System.arraycopy(this.scanner.commentStops, index + 1, this.scanner.commentStops, 0, validCount); } this.scanner.commentPtr = validCount - 1; return position; } /* * 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; } /* * (non-Javadoc) * * @see net.sourceforge.phpdt.internal.compiler.parser.Parser#initialize() */ public void initialize(boolean phpMode) { super.initialize(phpMode); this.commentPtr = -1; } /* * (non-Javadoc) Create and store a specific comment recorder scanner. * * @see net.sourceforge.phpdt.internal.compiler.parser.Parser#initializeScanner() */ public void initializeScanner() { this.scanner = new CommentRecorderScanner( false /* comment */, false /* whitespace */, this.options.getSeverity(CompilerOptions.NonExternalizedString) != ProblemSeverities.Ignore /* nls */, // this.options.sourceLevel /*sourceLevel*/, this.options.taskTags/* taskTags */, this.options.taskPriorites);/* taskPriorities */ // this.options.isTaskCaseSensitive/*taskCaseSensitive*/); } /* * Push all stored comments in stack. */ private void pushOnCommentsStack(int start, int end) { for (int i = start; i <= end; i++) { // 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) { try { this.commentPtr++; this.commentStarts[this.commentPtr] = this.scanner.commentStarts[i]; this.commentStops[this.commentPtr] = this.scanner.commentStops[i]; } catch (IndexOutOfBoundsException e) { // this.commentPtr is still correct int oldStackLength = this.commentStarts.length; int oldCommentStarts[] = this.commentStarts; this.commentStarts = new int[oldStackLength + CommentIncrement]; System.arraycopy(oldCommentStarts, 0, this.commentStarts, 0, oldStackLength); this.commentStarts[this.commentPtr] = this.scanner.commentStarts[i]; int oldCommentStops[] = this.commentStops; this.commentStops = new int[oldStackLength + CommentIncrement]; System.arraycopy(oldCommentStops, 0, this.commentStops, 0, oldStackLength); this.commentStops[this.commentPtr] = this.scanner.commentStops[i]; } } } } /* * (non-Javadoc) Save all source comments currently stored before flushing * them. * * @see net.sourceforge.phpdt.internal.compiler.parser.Parser#resetModifiers() */ protected void resetModifiers() { pushOnCommentsStack(0, this.scanner.commentPtr); super.resetModifiers(); } }