1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core.util;
13 import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions;
14 import net.sourceforge.phpdt.internal.compiler.parser.UnitParser;
15 import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter;
16 import net.sourceforge.phpdt.internal.compiler.problem.ProblemSeverities;
17 import net.sourceforge.phpeclipse.internal.compiler.ast.CompilationUnitDeclaration;
19 import org.eclipse.core.resources.IResource;
22 * Internal parser used for parsing source to create DOM AST nodes.
26 public class CommentRecorderParser extends UnitParser {
28 // support for comments
29 int[] commentStops = new int[10];
30 int[] commentStarts = new int[10];
31 int commentPtr = -1; // no comment test with commentPtr value -1
32 protected final static int CommentIncrement = 100;
35 * @param problemReporter
36 * @param optimizeStringLiterals
38 public CommentRecorderParser(ProblemReporter problemReporter) { // , boolean optimizeStringLiterals) {
39 super(problemReporter); //, optimizeStringLiterals);
42 // old javadoc style check which doesn't include all leading comments into declaration
43 // for backward compatibility with 2.1 DOM
44 // public void checkComment() {
46 // if (this.currentElement != null && this.scanner.commentPtr >= 0) {
47 // flushCommentsDefinedPriorTo(this.endStatementPosition); // discard obsolete comments
49 // boolean deprecated = false;
50 // boolean checkDeprecated = false;
51 // int lastCommentIndex = -1;
55 // //since jdk1.2 look only in the last java doc comment...
56 // nextComment : for (lastCommentIndex = this.scanner.commentPtr; lastCommentIndex >= 0; lastCommentIndex--){
57 // //look for @deprecated into the first javadoc comment preceeding the declaration
58 // int commentSourceStart = this.scanner.commentStarts[lastCommentIndex];
59 // // javadoc only (non javadoc comment have negative end positions.)
60 // if ((commentSourceStart < 0) ||
61 // (this.modifiersSourceStart != -1 && this.modifiersSourceStart < commentSourceStart) ||
62 // (this.scanner.commentStops[lastCommentIndex] < 0))
64 // continue nextComment;
66 // checkDeprecated = true;
67 // int commentSourceEnd = this.scanner.commentStops[lastCommentIndex] - 1; //stop is one over
69 // deprecated = this.javadocParser.checkDeprecation(commentSourceStart, commentSourceEnd);
70 // this.javadoc = this.javadocParser.docComment;
74 // checkAndSetModifiers(AccDeprecated);
76 // // modify the modifier source start to point at the first comment
77 // if (lastCommentIndex >= 0 && checkDeprecated) {
78 // this.modifiersSourceStart = this.scanner.commentStarts[lastCommentIndex];
79 // if (this.modifiersSourceStart < 0) {
80 // this.modifiersSourceStart = -this.modifiersSourceStart;
87 // * @see org.eclipse.jdt.internal.compiler.parser.Parser#consumeClassHeader()
89 // protected void consumeClassHeader() {
90 // pushOnCommentsStack(0, this.scanner.commentPtr);
91 // super.consumeClassHeader();
94 // * @see org.eclipse.jdt.internal.compiler.parser.Parser#consumeEmptyClassMemberDeclaration()
96 // protected void consumeEmptyClassMemberDeclaration() {
97 // pushOnCommentsStack(0, this.scanner.commentPtr);
98 // super.consumeEmptyClassMemberDeclaration();
101 // * @see org.eclipse.jdt.internal.compiler.parser.Parser#consumeEmptyTypeDeclaration()
103 // protected void consumeEmptyTypeDeclaration() {
104 // pushOnCommentsStack(0, this.scanner.commentPtr);
105 // super.consumeEmptyTypeDeclaration();
108 // * @see org.eclipse.jdt.internal.compiler.parser.Parser#consumeInterfaceHeader()
110 // protected void consumeInterfaceHeader() {
111 // pushOnCommentsStack(0, this.scanner.commentPtr);
112 // super.consumeInterfaceHeader();
116 * Insure that start position is always positive.
117 * @see org.eclipse.jdt.internal.compiler.parser.Parser#containsComment(int, int)
119 public boolean containsComment(int sourceStart, int sourceEnd) {
120 int iComment = this.scanner.commentPtr;
121 for (; iComment >= 0; iComment--) {
122 int commentStart = this.scanner.commentStarts[iComment];
123 if (commentStart < 0) {
124 commentStart = -commentStart;
126 // ignore comments before start
127 if (commentStart < sourceStart) continue;
128 // ignore comments after end
129 if (commentStart > sourceEnd) continue;
136 * @see org.eclipse.jdt.internal.compiler.parser.Parser#endParse(int)
138 protected CompilationUnitDeclaration endParse(int act) {
139 CompilationUnitDeclaration unit = super.endParse(act);
140 if (unit.comments == null) {
141 pushOnCommentsStack(0, this.scanner.commentPtr);
142 unit.comments = getCommentsPositions();
148 * Save all source comments currently stored before flushing them.
149 * @see org.eclipse.jdt.internal.compiler.parser.Parser#flushCommentsDefinedPriorTo(int)
151 public int flushCommentsDefinedPriorTo(int position) {
153 int lastCommentIndex = this.scanner.commentPtr;
154 if (lastCommentIndex < 0) return position; // no comment
156 // compute the index of the first obsolete comment
157 int index = lastCommentIndex;
160 int commentEnd = this.scanner.commentStops[index];
161 if (commentEnd < 0) commentEnd = -commentEnd; // negative end position for non-javadoc comments
162 if (commentEnd <= position){
168 // if the source at <position> is immediately followed by a line comment, then
169 // flush this comment and shift <position> to the comment end.
171 int immediateCommentEnd = 0;
172 while (index<lastCommentIndex && (immediateCommentEnd = -this.scanner.commentStops[index+1]) > 0){ // only tolerating non-javadoc comments (non-javadoc comment end positions are negative)
173 // is there any line break until the end of the immediate comment ? (thus only tolerating line comment)
174 immediateCommentEnd--; // comment end in one char too far
175 if (this.scanner.getLineNumber(position) != this.scanner.getLineNumber(immediateCommentEnd)) break;
176 position = immediateCommentEnd;
177 validCount--; // flush this comment
182 if (index < 0) return position; // no obsolete comment
183 pushOnCommentsStack(0, index); // store comment before flushing them
185 if (validCount > 0){ // move valid comment infos, overriding obsolete comment infos
186 System.arraycopy(this.scanner.commentStarts, index + 1, this.scanner.commentStarts, 0, validCount);
187 System.arraycopy(this.scanner.commentStops, index + 1, this.scanner.commentStops, 0, validCount);
189 this.scanner.commentPtr = validCount - 1;
194 * Build a n*2 matrix of comments positions.
195 * For each position, 0 is for start position and 1 for end position of the comment.
197 public int[][] getCommentsPositions() {
198 int[][] positions = new int[this.commentPtr+1][2];
199 for (int i = 0, max = this.commentPtr; i <= max; i++){
200 positions[i][0] = this.commentStarts[i];
201 positions[i][1] = this.commentStops[i];
207 * @see org.eclipse.jdt.internal.compiler.parser.Parser#initialize()
209 public void initialize(boolean phpMode) {
210 super.initialize(phpMode);
211 this.commentPtr = -1;
215 * Create and store a specific comment recorder scanner.
216 * @see org.eclipse.jdt.internal.compiler.parser.Parser#initializeScanner()
218 public void initializeScanner() {
219 this.scanner = new CommentRecorderScanner(
221 false /*whitespace*/,
222 this.options.getSeverity(CompilerOptions.NonExternalizedString) != ProblemSeverities.Ignore /*nls*/,
223 // this.options.sourceLevel /*sourceLevel*/,
224 this.options.taskTags/*taskTags*/,
225 this.options.taskPriorites);/*taskPriorities*/
226 // this.options.isTaskCaseSensitive/*taskCaseSensitive*/);
230 * Push all stored comments in stack.
232 private void pushOnCommentsStack(int start, int end) {
234 for (int i=start; i<=end; i++) {
235 // First see if comment hasn't been already stored
236 int scannerStart = this.scanner.commentStarts[i]<0 ? -this.scanner.commentStarts[i] : this.scanner.commentStarts[i];
237 int commentStart = this.commentPtr == -1 ? -1 : (this.commentStarts[this.commentPtr]<0 ? -this.commentStarts[this.commentPtr] : this.commentStarts[this.commentPtr]);
238 if (commentStart == -1 || scannerStart > commentStart) {
241 this.commentStarts[this.commentPtr] = this.scanner.commentStarts[i];
242 this.commentStops[this.commentPtr] = this.scanner.commentStops[i];
243 } catch (IndexOutOfBoundsException e) {
244 // this.commentPtr is still correct
245 int oldStackLength = this.commentStarts.length;
246 int oldCommentStarts[] = this.commentStarts;
247 this.commentStarts = new int[oldStackLength + CommentIncrement];
248 System.arraycopy(oldCommentStarts, 0, this.commentStarts, 0, oldStackLength);
249 this.commentStarts[this.commentPtr] = this.scanner.commentStarts[i];
250 int oldCommentStops[] = this.commentStops;
251 this.commentStops = new int[oldStackLength + CommentIncrement];
252 System.arraycopy(oldCommentStops, 0, this.commentStops, 0, oldStackLength);
253 this.commentStops[this.commentPtr] = this.scanner.commentStops[i];
259 * Save all source comments currently stored before flushing them.
260 * @see org.eclipse.jdt.internal.compiler.parser.Parser#resetModifiers()
262 protected void resetModifiers() {
263 pushOnCommentsStack(0, this.scanner.commentPtr);
264 super.resetModifiers();