KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > codeassist > complete > CompletionJavadocParser


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.codeassist.complete;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.List JavaDoc;
15
16 import org.eclipse.jdt.core.compiler.CharOperation;
17 import org.eclipse.jdt.core.compiler.InvalidInputException;
18 import org.eclipse.jdt.internal.codeassist.CompletionEngine;
19 import org.eclipse.jdt.internal.compiler.ast.*;
20 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
21 import org.eclipse.jdt.internal.compiler.parser.JavadocParser;
22 import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
23 import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
24
25 /**
26  * Parser specialized for decoding javadoc comments which includes cursor location for code completion.
27  */

28 public class CompletionJavadocParser extends JavadocParser {
29     
30     // Initialize lengthes for block and inline tags tables
31
public final static int INLINE_ALL_TAGS_LENGTH;
32     public final static int BLOCK_ALL_TAGS_LENGTH;
33     static {
34         int length = 0;
35         for (int i=0; i<INLINE_TAGS_LENGTH; i++) {
36             length += INLINE_TAGS[i].length;
37         }
38         INLINE_ALL_TAGS_LENGTH = length;
39         length = 0;
40         for (int i=0; i<BLOCK_TAGS_LENGTH; i++) {
41             length += BLOCK_TAGS[i].length;
42         }
43         BLOCK_ALL_TAGS_LENGTH = length;
44     }
45     
46     // Level tags are array of inline/block tags depending on compilation source level
47
char[][][] levelTags = new char[2][][];
48     int[] levelTagsLength = new int[2];
49     
50     // Completion specific info
51
int cursorLocation;
52     CompletionOnJavadoc completionNode = null;
53     boolean pushText = false;
54     boolean allPossibleTags = false;
55
56     public CompletionJavadocParser(CompletionParser sourceParser) {
57         super(sourceParser);
58         this.scanner = new CompletionScanner(ClassFileConstants.JDK1_3);
59         this.kind = COMPLETION_PARSER | TEXT_PARSE;
60         this.reportProblems = false;
61         initLevelTags();
62     }
63
64     /*
65      * Do not parse comment if completion location is not included.
66      */

67     public boolean checkDeprecation(int commentPtr) {
68         this.cursorLocation = ((CompletionParser)sourceParser).cursorLocation;
69         CompletionScanner completionScanner = (CompletionScanner)this.scanner;
70         completionScanner.cursorLocation = this.cursorLocation;
71         this.javadocStart = this.sourceParser.scanner.commentStarts[commentPtr];
72         this.javadocEnd = this.sourceParser.scanner.commentStops[commentPtr];
73         if (this.javadocStart <= this.cursorLocation && this.cursorLocation <= this.javadocEnd) {
74             if (CompletionEngine.DEBUG) {
75                 System.out.println("COMPLETION in Javadoc:"); //$NON-NLS-1$
76
}
77             completionScanner.completionIdentifier = null;
78             this.firstTagPosition = 1;
79             super.checkDeprecation(commentPtr);
80         } else {
81             this.docComment = null;
82         }
83         return false;
84     }
85
86     /*
87      * Replace stored Javadoc node with specific completion one.
88      */

89     protected boolean commentParse() {
90         this.docComment = new CompletionJavadoc(this.javadocStart, this.javadocEnd);
91         return super.commentParse();
92     }
93
94     /*
95      * Create argument expression. If it includes completion location, create and store completion node.
96      */

97     protected Object JavaDoc createArgumentReference(char[] name, int dim, boolean isVarargs, Object JavaDoc typeRef, long[] dimPositions, long argNamePos) throws InvalidInputException {
98         // Create argument as we may need it after
99
char[] argName = name==null ? CharOperation.NO_CHAR : name;
100         Expression expression = (Expression) super.createArgumentReference(argName, dim, isVarargs, typeRef, dimPositions, argNamePos);
101         // See if completion location is in argument
102
int refStart = ((TypeReference)typeRef).sourceStart;
103         int refEnd = ((TypeReference)typeRef).sourceEnd;
104         boolean inCompletion = (refStart <= this.cursorLocation && this.cursorLocation <= refEnd) // completion cursor is between first and last stacked identifiers
105
|| ((refStart == (refEnd+1) && refEnd == this.cursorLocation)); // or it's a completion on empty token
106
if (this.completionNode == null && inCompletion) {
107             JavadocArgumentExpression javadocArgument = (JavadocArgumentExpression) expression;
108             TypeReference expressionType = javadocArgument.argument.type;
109             if (expressionType instanceof JavadocSingleTypeReference) {
110                 this.completionNode = new CompletionOnJavadocSingleTypeReference((JavadocSingleTypeReference) expressionType);
111             } else if (expressionType instanceof JavadocQualifiedTypeReference) {
112                 this.completionNode = new CompletionOnJavadocQualifiedTypeReference((JavadocQualifiedTypeReference) expressionType);
113             }
114             if (CompletionEngine.DEBUG) {
115                 System.out.println(" completion argument="+completionNode); //$NON-NLS-1$
116
}
117             return this.completionNode;
118         }
119         return expression;
120     }
121
122     /*
123      * Create field reference. If it includes completion location, create and store completion node.
124      */

125     protected Object JavaDoc createFieldReference(Object JavaDoc receiver) throws InvalidInputException {
126         int refStart = (int) (this.identifierPositionStack[0] >>> 32);
127         int refEnd = (int) this.identifierPositionStack[0];
128         boolean inCompletion = (refStart <= (this.cursorLocation+1) && this.cursorLocation <= refEnd) // completion cursor is between first and last stacked identifiers
129
|| ((refStart == (refEnd+1) && refEnd == this.cursorLocation)) // or it's a completion on empty token
130
|| (this.memberStart == this.cursorLocation); // or it's a completion just after the member separator with an identifier after the cursor
131
if (inCompletion) {
132             JavadocFieldReference fieldRef = (JavadocFieldReference) super.createFieldReference(receiver);
133             char[] name = this.sourceParser.compilationUnit.getMainTypeName();
134             TypeDeclaration typeDecl = getParsedTypeDeclaration();
135             if (typeDecl != null) {
136                 name = typeDecl.name;
137             }
138             this.completionNode = new CompletionOnJavadocFieldReference(fieldRef, this.memberStart, name);
139             if (CompletionEngine.DEBUG) {
140                 System.out.println(" completion field="+completionNode); //$NON-NLS-1$
141
}
142             return this.completionNode;
143         }
144         return super.createFieldReference(receiver);
145     }
146
147     /*
148      * Verify if method identifier positions include completion location.
149      * If so, create method reference and store it.
150      * Otherwise return null as we do not need this reference.
151      */

152     protected Object JavaDoc createMethodReference(Object JavaDoc receiver, List JavaDoc arguments) throws InvalidInputException {
153         int memberPtr = this.identifierLengthStack[0] - 1; // may be > 0 for inner class constructor reference
154
int refStart = (int) (this.identifierPositionStack[memberPtr] >>> 32);
155         int refEnd = (int) this.identifierPositionStack[memberPtr];
156         boolean inCompletion = (refStart <= (this.cursorLocation+1) && this.cursorLocation <= refEnd) // completion cursor is between first and last stacked identifiers
157
|| ((refStart == (refEnd+1) && refEnd == this.cursorLocation)) // or it's a completion on empty token
158
|| (this.memberStart == this.cursorLocation); // or it's a completion just after the member separator with an identifier after the cursor
159
if (inCompletion) {
160             ASTNode node = (ASTNode) super.createMethodReference(receiver, arguments);
161             if (node instanceof JavadocMessageSend) {
162                 JavadocMessageSend messageSend = (JavadocMessageSend) node;
163                 int nameStart = (int) (messageSend.nameSourcePosition >>> 32);
164                 int nameEnd = (int) messageSend.nameSourcePosition;
165                 if ((nameStart <= (this.cursorLocation+1) && this.cursorLocation <= nameEnd)) {
166                     this.completionNode = new CompletionOnJavadocFieldReference(messageSend, this.memberStart);
167                 } else {
168                     this.completionNode = new CompletionOnJavadocMessageSend(messageSend, this.memberStart);
169                 }
170             } else if (node instanceof JavadocAllocationExpression) {
171                 this.completionNode = new CompletionOnJavadocAllocationExpression((JavadocAllocationExpression)node, this.memberStart);
172             }
173             if (CompletionEngine.DEBUG) {
174                 System.out.println(" completion method="+completionNode); //$NON-NLS-1$
175
}
176             return this.completionNode;
177         }
178         return super.createMethodReference(receiver, arguments);
179     }
180
181     /*
182      * Create type reference. If it includes completion location, create and store completion node.
183      */

184     protected Object JavaDoc createTypeReference(int primitiveToken) {
185         // Need to create type ref in case it was needed by members
186
int nbIdentifiers = this.identifierLengthStack[this.identifierLengthPtr];
187         int startPtr = this.identifierPtr - (nbIdentifiers-1);
188         int refStart = (int) (this.identifierPositionStack[startPtr] >>> 32);
189         int refEnd = (int) this.identifierPositionStack[this.identifierPtr];
190         boolean inCompletion = (refStart <= (this.cursorLocation+1) && this.cursorLocation <= refEnd) // completion cursor is between first and last stacked identifiers
191
|| ((refStart == (refEnd+1) && refEnd == this.cursorLocation)); // or it's a completion on empty token
192
if (!inCompletion) {
193             return super.createTypeReference(primitiveToken);
194         }
195         this.identifierLengthPtr--;
196         if (nbIdentifiers == 1) { // Single Type ref
197
this.completionNode = new CompletionOnJavadocSingleTypeReference(
198                         this.identifierStack[this.identifierPtr],
199                         this.identifierPositionStack[this.identifierPtr],
200                         this.tagSourceStart,
201                         this.tagSourceEnd);
202         } else if (nbIdentifiers > 1) { // Qualified Type ref
203
for (int i=startPtr; i<this.identifierPtr; i++) {
204                 int start = (int) (this.identifierPositionStack[i] >>> 32);
205                 int end = (int) this.identifierPositionStack[i];
206                 if (start <= this.cursorLocation && this.cursorLocation <= end) {
207                     if (i == startPtr) {
208                         this.completionNode = new CompletionOnJavadocSingleTypeReference(
209                                     this.identifierStack[startPtr],
210                                     this.identifierPositionStack[startPtr],
211                                     this.tagSourceStart,
212                                     this.tagSourceEnd);
213                     } else {
214                         char[][] tokens = new char[i][];
215                         System.arraycopy(this.identifierStack, startPtr, tokens, 0, i);
216                         long[] positions = new long[i+1];
217                         System.arraycopy(this.identifierPositionStack, startPtr, positions, 0, i+1);
218                         this.completionNode = new CompletionOnJavadocQualifiedTypeReference(tokens, this.identifierStack[i], positions, this.tagSourceStart, this.tagSourceEnd);
219                     }
220                     break;
221                 }
222             }
223             if (this.completionNode == null) {
224                 char[][] tokens = new char[nbIdentifiers-1][];
225                 System.arraycopy(this.identifierStack, startPtr, tokens, 0, nbIdentifiers-1);
226                 long[] positions = new long[nbIdentifiers];
227                 System.arraycopy(this.identifierPositionStack, startPtr, positions, 0, nbIdentifiers);
228                 this.completionNode = new CompletionOnJavadocQualifiedTypeReference(tokens, this.identifierStack[this.identifierPtr], positions, this.tagSourceStart, this.tagSourceEnd);
229             }
230         }
231
232         if (CompletionEngine.DEBUG) {
233             System.out.println(" completion partial qualified type="+completionNode); //$NON-NLS-1$
234
}
235         return this.completionNode;
236     }
237
238     /*
239      * Get possible tags for a given prefix.
240      */

241     private char[][][] possibleTags(char[] prefix, boolean newLine) {
242         char[][][] possibleTags = new char[2][][];
243         if (newLine) {
244             System.arraycopy(this.levelTags[BLOCK_IDX], 0, possibleTags[BLOCK_IDX] = new char[this.levelTagsLength[BLOCK_IDX]][], 0, this.levelTagsLength[BLOCK_IDX]);
245         } else {
246             possibleTags[BLOCK_IDX] = CharOperation.NO_CHAR_CHAR;
247         }
248         System.arraycopy(this.levelTags[INLINE_IDX], 0, possibleTags[INLINE_IDX] = new char[this.levelTagsLength[INLINE_IDX]][], 0, this.levelTagsLength[INLINE_IDX]);
249         if (prefix == null || prefix.length == 0) return possibleTags;
250         int kinds = levelTags.length;
251         for (int k=0; k<kinds; k++) {
252             int length = possibleTags[k].length, size = 0;
253             int indexes[] = new int[length];
254             for (int i=0; i<length; i++) {
255                 if (CharOperation.prefixEquals(prefix, possibleTags[k][i], false)) {
256                     indexes[size++] = i;
257                 }
258             }
259             char[][] tags = new char[size][];
260             for (int i=0; i<size; i++) {
261                 tags[i] = possibleTags[k][indexes[i]];
262             }
263             possibleTags[k] = tags;
264         }
265         return possibleTags;
266     }
267
268     private CompletionJavadoc getCompletionJavadoc() {
269         return (CompletionJavadoc)this.docComment;
270     }
271
272     private CompletionParser getCompletionParser() {
273         return (CompletionParser)this.sourceParser;
274     }
275
276     /*
277      * Init tags arrays for current source level.
278      */

279     private void initLevelTags() {
280         int level = ((int)(this.complianceLevel >>> 16)) - ClassFileConstants.MAJOR_VERSION_1_1 + 1;
281         // Init block tags
282
this.levelTags[BLOCK_IDX] = new char[BLOCK_ALL_TAGS_LENGTH][];
283         this.levelTagsLength[BLOCK_IDX] = 0;
284         for (int i=0; i<=level; i++) {
285             int length = BLOCK_TAGS[i].length;
286             System.arraycopy(BLOCK_TAGS[i], 0, this.levelTags[BLOCK_IDX], this.levelTagsLength[BLOCK_IDX], length);
287             this.levelTagsLength[BLOCK_IDX] += length;
288         }
289         if (this.levelTagsLength[BLOCK_IDX] < BLOCK_ALL_TAGS_LENGTH) {
290             System.arraycopy(this.levelTags[BLOCK_IDX], 0, this.levelTags[BLOCK_IDX] = new char[this.levelTagsLength[BLOCK_IDX]][], 0, this.levelTagsLength[BLOCK_IDX]);
291         }
292         // Init inline tags
293
this.levelTags[INLINE_IDX] = new char[INLINE_ALL_TAGS_LENGTH][];
294         this.levelTagsLength[INLINE_IDX]= 0;
295         for (int i=0; i<=level; i++) {
296             int length = INLINE_TAGS[i].length;
297             System.arraycopy(INLINE_TAGS[i], 0, this.levelTags[INLINE_IDX], this.levelTagsLength[INLINE_IDX], length);
298             this.levelTagsLength[INLINE_IDX] += length;
299         }
300         if (this.levelTagsLength[INLINE_IDX] < INLINE_ALL_TAGS_LENGTH) {
301             System.arraycopy(this.levelTags[INLINE_IDX], 0, this.levelTags[INLINE_IDX] = new char[this.levelTagsLength[INLINE_IDX]][], 0, this.levelTagsLength[INLINE_IDX]);
302         }
303     }
304     /*
305      * Parse argument in @see tag method reference
306      */

307     protected Object JavaDoc parseArguments(Object JavaDoc receiver) throws InvalidInputException {
308         
309         if (this.tagSourceStart>this.cursorLocation) {
310             return super.parseArguments(receiver);
311         }
312
313         // Init
314
int modulo = 0; // should be 2 for (Type,Type,...) or 3 for (Type arg,Type arg,...)
315
int iToken = 0;
316         char[] argName = null;
317         List JavaDoc arguments = new ArrayList JavaDoc(10);
318         Object JavaDoc typeRef = null;
319         int dim = 0;
320         boolean isVarargs = false;
321         long[] dimPositions = new long[20]; // assume that there won't be more than 20 dimensions...
322
char[] name = null;
323         long argNamePos = -1;
324         
325         // Parse arguments declaration if method reference
326
nextArg : while (this.index < this.scanner.eofPosition) {
327
328             // Read argument type reference
329
try {
330                 typeRef = parseQualifiedName(false);
331                 if (this.abort) return null; // May be aborted by specialized parser
332
} catch (InvalidInputException e) {
333                 break nextArg;
334             }
335             boolean firstArg = modulo == 0;
336             if (firstArg) { // verify position
337
if (iToken != 0)
338                     break nextArg;
339             } else if ((iToken % modulo) != 0) {
340                     break nextArg;
341             }
342             if (typeRef == null) {
343                 if (firstArg && getCurrentTokenType() == TerminalTokens.TokenNameRPAREN) {
344                     this.lineStarted = true;
345                     return createMethodReference(receiver, null);
346                 }
347                 Object JavaDoc methodRef = createMethodReference(receiver, arguments);
348                 return syntaxRecoverEmptyArgumentType(methodRef);
349             }
350             if (this.index >= this.scanner.eofPosition) {
351                 int argumentStart = ((ASTNode)typeRef).sourceStart;
352                 Object JavaDoc argument = createArgumentReference(this.scanner.getCurrentIdentifierSource(), 0, false, typeRef, null, (((long)argumentStart)<<32)+this.tokenPreviousPosition-1);
353                 return syntaxRecoverArgumentType(receiver, arguments, argument);
354             }
355             if (this.index >= this.cursorLocation) {
356                 if (this.completionNode instanceof CompletionOnJavadocSingleTypeReference) {
357                     CompletionOnJavadocSingleTypeReference singleTypeReference = (CompletionOnJavadocSingleTypeReference) this.completionNode;
358                     if (singleTypeReference.token == null || singleTypeReference.token.length == 0) {
359                         Object JavaDoc methodRef = createMethodReference(receiver, arguments);
360                         return syntaxRecoverEmptyArgumentType(methodRef);
361                     }
362                 }
363                 if (this.completionNode instanceof CompletionOnJavadocQualifiedTypeReference) {
364                     CompletionOnJavadocQualifiedTypeReference qualifiedTypeReference = (CompletionOnJavadocQualifiedTypeReference) this.completionNode;
365                     if (qualifiedTypeReference.tokens == null || qualifiedTypeReference.tokens.length < qualifiedTypeReference.sourcePositions.length) {
366                         Object JavaDoc methodRef = createMethodReference(receiver, arguments);
367                         return syntaxRecoverEmptyArgumentType(methodRef);
368                     }
369                 }
370             }
371             iToken++;
372
373             // Read possible additional type info
374
dim = 0;
375             isVarargs = false;
376             if (readToken() == TerminalTokens.TokenNameLBRACKET) {
377                 // array declaration
378
int dimStart = this.scanner.getCurrentTokenStartPosition();
379                 while (readToken() == TerminalTokens.TokenNameLBRACKET) {
380                     consumeToken();
381                     if (readToken() != TerminalTokens.TokenNameRBRACKET) {
382                         break nextArg;
383                     }
384                     consumeToken();
385                     dimPositions[dim++] = (((long) dimStart) << 32) + this.scanner.getCurrentTokenEndPosition();
386                 }
387             } else if (readToken() == TerminalTokens.TokenNameELLIPSIS) {
388                 // ellipsis declaration
389
int dimStart = this.scanner.getCurrentTokenStartPosition();
390                 dimPositions[dim++] = (((long) dimStart) << 32) + this.scanner.getCurrentTokenEndPosition();
391                 consumeToken();
392                 isVarargs = true;
393             }
394
395             // Read argument name
396
argNamePos = -1;
397             if (readToken() == TerminalTokens.TokenNameIdentifier) {
398                 consumeToken();
399                 if (firstArg) { // verify position
400
if (iToken != 1)
401                         break nextArg;
402                 } else if ((iToken % modulo) != 1) {
403                         break nextArg;
404                 }
405                 if (argName == null) { // verify that all arguments name are declared
406
if (!firstArg) {
407                         break nextArg;
408                     }
409                 }
410                 argName = this.scanner.getCurrentIdentifierSource();
411                 argNamePos = (((long)this.scanner.getCurrentTokenStartPosition())<<32)+this.scanner.getCurrentTokenEndPosition();
412                 iToken++;
413             } else if (argName != null) { // verify that no argument name is declared
414
break nextArg;
415             }
416             
417             // Verify token position
418
if (firstArg) {
419                 modulo = iToken + 1;
420             } else {
421                 if ((iToken % modulo) != (modulo - 1)) {
422                     break nextArg;
423                 }
424             }
425
426             // Read separator or end arguments declaration
427
int token = readToken();
428             name = argName == null ? CharOperation.NO_CHAR : argName;
429             if (token == TerminalTokens.TokenNameCOMMA) {
430                 // Create new argument
431
Object JavaDoc argument = createArgumentReference(name, dim, isVarargs, typeRef, dimPositions, argNamePos);
432                 if (this.abort) return null; // May be aborted by specialized parser
433
arguments.add(argument);
434                 consumeToken();
435                 iToken++;
436             } else if (token == TerminalTokens.TokenNameRPAREN) {
437                 // Create new argument
438
Object JavaDoc argument = createArgumentReference(name, dim, isVarargs, typeRef, dimPositions, argNamePos);
439                 if (this.abort) return null; // May be aborted by specialized parser
440
arguments.add(argument);
441                 consumeToken();
442                 return createMethodReference(receiver, arguments);
443             } else {
444                 Object JavaDoc argument = createArgumentReference(name, dim, isVarargs, typeRef, dimPositions, argNamePos);
445                 return syntaxRecoverArgumentType(receiver, arguments, argument);
446             }
447         }
448
449         // Something wrong happened => Invalid input
450
throw new InvalidInputException();
451     }
452
453         protected boolean parseParam() throws InvalidInputException {
454             int startPosition = this.index;
455             int endPosition = this.index;
456             long namePosition = (((long)startPosition)<<32) + endPosition;
457             this.identifierPtr = -1;
458             boolean valid = super.parseParam();
459             if (this.identifierPtr > 2) return valid;
460             // See if expression is concerned by completion
461
char[] name = null;
462             CompletionScanner completionScanner = (CompletionScanner) this.scanner;
463             boolean isTypeParam = false;
464             if (this.identifierPtr >= 0) {
465                 char[] identifier = null;
466                 switch (this.identifierPtr) {
467                     case 2:
468                         if (!valid && completionScanner.completionIdentifier != null && completionScanner.completionIdentifier.length == 0) {
469                             valid = pushParamName(true);
470                         }
471                     case 1:
472                         isTypeParam = this.identifierStack[0][0] == '<';
473                         identifier = this.identifierStack[1];
474                         namePosition = this.identifierPositionStack[1];
475                         break;
476                     case 0:
477                         identifier = this.identifierStack[0];
478                         namePosition = this.identifierPositionStack[0];
479                         isTypeParam = identifier.length > 0 && identifier[0] == '<';
480                         break;
481                 }
482                 if (identifier != null && identifier.length > 0 && ScannerHelper.isJavaIdentifierPart(identifier[0])) {
483                     name = identifier;
484                 }
485                 startPosition = (int)(this.identifierPositionStack[0]>>32);
486                 endPosition = (int)this.identifierPositionStack[this.identifierPtr];
487             }
488             boolean inCompletion = (startPosition <= (this.cursorLocation+1) && this.cursorLocation <= endPosition) // completion cursor is between first and last stacked identifiers
489
|| ((startPosition == (endPosition+1) && endPosition == this.cursorLocation)); // or it's a completion on empty token
490
if (inCompletion) {
491                 if (this.completionNode == null) {
492                     if (isTypeParam) {
493                         this.completionNode = new CompletionOnJavadocTypeParamReference(name, namePosition, startPosition, endPosition);
494                     } else {
495                         this.completionNode = new CompletionOnJavadocParamNameReference(name, namePosition, startPosition, endPosition);
496                     }
497                     if (CompletionEngine.DEBUG) {
498                         System.out.println(" completion param="+completionNode); //$NON-NLS-1$
499
}
500                 } else if (this.completionNode instanceof CompletionOnJavadocParamNameReference) {
501                     CompletionOnJavadocParamNameReference paramNameRef = (CompletionOnJavadocParamNameReference)this.completionNode;
502                     int nameStart = (int) (namePosition>>32);
503                     paramNameRef.sourceStart = nameStart;
504                     int nameEnd = (int) namePosition;
505                     if (nameStart<this.cursorLocation && this.cursorLocation<nameEnd) {
506                         paramNameRef.sourceEnd = this.cursorLocation + 1;
507                     } else {
508                         paramNameRef.sourceEnd = nameEnd;
509                     }
510                     paramNameRef.tagSourceStart = startPosition;
511                     paramNameRef.tagSourceEnd = endPosition;
512                 } else if (this.completionNode instanceof CompletionOnJavadocTypeParamReference) {
513                     CompletionOnJavadocTypeParamReference typeParamRef = (CompletionOnJavadocTypeParamReference)this.completionNode;
514                     int nameStart = (int) (namePosition>>32);
515                     typeParamRef.sourceStart = nameStart;
516                     int nameEnd = (int) namePosition;
517                     if (nameStart<this.cursorLocation && this.cursorLocation<nameEnd) {
518                         typeParamRef.sourceEnd = this.cursorLocation + 1;
519                     } else {
520                         typeParamRef.sourceEnd = nameEnd;
521                     }
522                     typeParamRef.tagSourceStart = startPosition;
523                     typeParamRef.tagSourceEnd = endPosition;
524                 }
525             }
526             return valid;
527         }
528
529     /* (non-Javadoc)
530          * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#parseReference()
531          */

532         protected boolean parseReference() throws InvalidInputException {
533             boolean completed = this.completionNode != null;
534             boolean valid = super.parseReference();
535             if (!completed && this.completionNode != null) {
536                 this.completionNode.addCompletionFlags(CompletionOnJavadoc.FORMAL_REFERENCE);
537             }
538             return valid;
539         }
540
541     /*(non-Javadoc)
542      * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#parseTag(int)
543      */

544     protected boolean parseTag(int previousPosition) throws InvalidInputException {
545         int startPosition = this.inlineTagStarted ? this.inlineTagStart : previousPosition;
546         boolean newLine = !this.lineStarted;
547         boolean valid = super.parseTag(previousPosition);
548         boolean inCompletion = (this.tagSourceStart <= (this.cursorLocation+1) && this.cursorLocation <= this.tagSourceEnd) // completion cursor is between first and last stacked identifiers
549
|| ((this.tagSourceStart == (this.tagSourceEnd+1) && this.tagSourceEnd == this.cursorLocation)); // or it's a completion on empty token
550
if (inCompletion) {
551             int end = this.tagSourceEnd;
552             if (this.inlineTagStarted && this.scanner.currentCharacter == '}') {
553                 end = this.scanner.currentPosition;
554             }
555             long position = (((long)startPosition)<<32) + end;
556             int length = this.cursorLocation+1-tagSourceStart;
557             char[] tag = new char[length];
558             System.arraycopy(this.source, this.tagSourceStart, tag, 0, length);
559             char[][][] tags = possibleTags(tag, newLine);
560             if (tags != null) {
561                 this.completionNode = new CompletionOnJavadocTag(tag, position, startPosition, end, tags, this.allPossibleTags);
562             }
563         }
564         return valid;
565     }
566
567     /* (non-Javadoc)
568      * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#parseThrows()
569      */

570     protected boolean parseThrows() {
571         try {
572             Object JavaDoc typeRef = parseQualifiedName(true);
573             if (this.completionNode != null) {
574                 this.completionNode.addCompletionFlags(CompletionOnJavadoc.EXCEPTION);
575             }
576             return pushThrowName(typeRef);
577         } catch (InvalidInputException ex) {
578             // ignore
579
}
580         return false;
581     }
582
583     /*
584      * Push param name reference. If it includes completion location, create and store completion node.
585      */

586     protected boolean pushParamName(boolean isTypeParam) {
587         if (super.pushParamName(isTypeParam)) {
588             Expression expression = (Expression) astStack[astPtr];
589             // See if expression is concerned by completion
590
if (expression.sourceStart <= (this.cursorLocation+1) && this.cursorLocation <= expression.sourceEnd) {
591                 if (isTypeParam) {
592                     this.completionNode = new CompletionOnJavadocTypeParamReference((JavadocSingleTypeReference)expression);
593                 } else {
594                     this.completionNode = new CompletionOnJavadocParamNameReference((JavadocSingleNameReference)expression);
595                 }
596                 if (CompletionEngine.DEBUG) {
597                     System.out.println(" completion param="+completionNode); //$NON-NLS-1$
598
}
599             }
600             return true;
601         }
602         return false;
603     }
604
605     /**
606      * Push text. If it includes completion location, then rescan line to see if there's a possible
607      * reference under the cursor location.
608      *
609      * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#pushText(int, int)
610      */

611     protected void pushText(int start, int end) {
612         if (start <= this.cursorLocation && this.cursorLocation <= end) {
613             this.scanner.resetTo(start, end);
614             boolean tokenizeWhiteSpace = this.scanner.tokenizeWhiteSpace;
615             this.scanner.tokenizeWhiteSpace = true;
616             try {
617                 Object JavaDoc typeRef = null;
618                 this.pushText = true;
619
620                 // Get reference tokens
621
int previousToken = TerminalTokens.TokenNameWHITESPACE;
622                 while (!this.scanner.atEnd() && this.completionNode == null && !this.abort) {
623                     int token = readTokenSafely();
624                     switch (token) {
625                         case TerminalTokens.TokenNameStringLiteral :
626                             int strStart = 0, strEnd = 0;
627                             if ((strStart=this.scanner.getCurrentTokenStartPosition()+1) <= this.cursorLocation &&
628                                 this.cursorLocation <= (strEnd=this.scanner.getCurrentTokenEndPosition()-1))
629                             {
630                                 this.scanner.resetTo(strStart, strEnd);
631                             }
632                             consumeToken();
633                             break;
634                         case TerminalTokens.TokenNameERROR :
635                             consumeToken();
636                             if (this.scanner.currentCharacter == '#') { // @see ...#member
637
Object JavaDoc member = null;
638                                 try {
639                                     this.scanner.tokenizeWhiteSpace = false;
640                                     member = parseMember(typeRef);
641                                 } catch (InvalidInputException e) {
642                                     consumeToken();
643                                 }
644                                 this.scanner.tokenizeWhiteSpace = true;
645                                 if (this.completionNode != null) {
646                                     int flags = this.inlineTagStarted ? 0 : CompletionOnJavadoc.TEXT|CompletionOnJavadoc.ONLY_INLINE_TAG;
647                                     if (member instanceof JavadocMessageSend) {
648                                         JavadocMessageSend msgSend = (JavadocMessageSend) member;
649                                         this.completionNode = new CompletionOnJavadocMessageSend(msgSend, this.memberStart, flags);
650                                         if (CompletionEngine.DEBUG) {
651                                             System.out.println(" new completion method="+completionNode); //$NON-NLS-1$
652
}
653                                     } else if (member instanceof JavadocAllocationExpression) {
654                                         JavadocAllocationExpression alloc = (JavadocAllocationExpression) member;
655                                         this.completionNode = new CompletionOnJavadocAllocationExpression(alloc, this.memberStart, flags);
656                                         if (CompletionEngine.DEBUG) {
657                                             System.out.println(" new completion method="+completionNode); //$NON-NLS-1$
658
}
659                                     } else {
660                                         this.completionNode.addCompletionFlags(flags);
661                                     }
662                                 }
663                             }
664                             break;
665                         case TerminalTokens.TokenNameIdentifier :
666                             try {
667                                 this.scanner.tokenizeWhiteSpace = false;
668                                 typeRef = parseQualifiedName(true);
669                                 if (this.completionNode == null) {
670                                     consumeToken();
671                                     this.scanner.resetTo(this.tokenPreviousPosition, end);
672                                     this.index = this.tokenPreviousPosition;
673                                 }
674                             }
675                             catch (InvalidInputException e) {
676                                 consumeToken();
677                             }
678                             finally {
679                                 this.scanner.tokenizeWhiteSpace = true;
680                             }
681                             if (previousToken != TerminalTokens.TokenNameWHITESPACE) {
682                                 typeRef = null;
683                                 this.completionNode = null;
684                             }
685                             break;
686                         case TerminalTokens.TokenNameAT:
687                             consumeToken();
688                             try {
689                                 this.scanner.tokenizeWhiteSpace = false;
690                                 int startPosition = this.scanner.getCurrentTokenStartPosition();
691                                 parseTag(startPosition);
692                                 if (this.completionNode != null) {
693                                     if (this.inlineTagStarted) {
694                                         /* May be to replace invalid @value tag inside text?
695                                         if (this.completionNode instanceof CompletionOnJavadocSingleTypeReference) {
696                                             CompletionOnJavadocSingleTypeReference singleTypeReference = (CompletionOnJavadocSingleTypeReference) this.completionNode;
697                                             singleTypeReference.tagSourceStart = startPosition;
698                                             switch (this.tagValue) {
699                                                 case TAG_VALUE_VALUE:
700 // singleTypeReference.completionFlags |= ONLY_INLINE_TAG;
701                                                     if (this.sourceLevel < ClassFileConstants.JDK1_5) singleTypeReference.completionFlags |= REPLACE_TAG;
702                                                     break;
703                                             }
704                                         } else if (this.completionNode instanceof CompletionOnJavadocQualifiedTypeReference) {
705                                             CompletionOnJavadocQualifiedTypeReference qualifiedTypeRef = (CompletionOnJavadocQualifiedTypeReference) this.completionNode;
706                                             qualifiedTypeRef.tagSourceStart = startPosition;
707                                             switch (this.tagValue) {
708                                                 case TAG_VALUE_VALUE:
709                                                     singleTypeReference.completionFlags |= ONLY_INLINE_TAG;
710                                                     if (this.sourceLevel < ClassFileConstants.JDK1_5) qualifiedTypeRef.completionFlags |= REPLACE_TAG;
711                                                     break;
712                                             }
713                                         }
714 // */

715                                     } else {
716                                         /* May be to replace non-inline tag inside text?
717                                         if (this.completionNode instanceof CompletionOnJavadocSingleTypeReference) {
718                                             CompletionOnJavadocSingleTypeReference singleTypeReference = (CompletionOnJavadocSingleTypeReference) this.completionNode;
719                                             singleTypeReference.tagSourceStart = startPosition;
720                                             switch (this.tagValue) {
721                                                 case TAG_LINK_VALUE:
722                                                 case TAG_LINKPLAIN_VALUE:
723                                                     singleTypeReference.completionFlags |= ONLY_INLINE_TAG;
724                                                 case TAG_SEE_VALUE:
725                                                     singleTypeReference.completionFlags |= REPLACE_TAG;
726                                                     break;
727                                             }
728                                         } else if (this.completionNode instanceof CompletionOnJavadocQualifiedTypeReference) {
729                                             CompletionOnJavadocQualifiedTypeReference qualifiedTypeRef = (CompletionOnJavadocQualifiedTypeReference) this.completionNode;
730                                             qualifiedTypeRef.tagSourceStart = startPosition;
731                                             switch (this.tagValue) {
732                                                 case TAG_LINK_VALUE:
733                                                 case TAG_LINKPLAIN_VALUE:
734                                                     qualifiedTypeRef.completionFlags |= ONLY_INLINE_TAG;
735                                                 case TAG_SEE_VALUE:
736                                                     qualifiedTypeRef.completionFlags |= REPLACE_TAG;
737                                                     break;
738                                             }
739                                         }
740 // */

741                                     }
742                                 }
743                             } catch (InvalidInputException e) {
744                                 consumeToken();
745                             }
746                             this.scanner.tokenizeWhiteSpace = true;
747                             break;
748                         default :
749                             consumeToken();
750                             typeRef = null;
751                             break;
752                     }
753                     previousToken = token;
754                 }
755             }
756             finally {
757                 this.scanner.tokenizeWhiteSpace = tokenizeWhiteSpace;
758                 this.pushText = false;
759             }
760
761             // Reset position to avoid missing tokens when new line was encountered
762
this.index = end;
763             this.scanner.currentPosition = end;
764             consumeToken();
765
766             if (this.completionNode != null) {
767                 if (this.inlineTagStarted) {
768                     this.completionNode.addCompletionFlags(CompletionOnJavadoc.FORMAL_REFERENCE);
769                 } else {
770                     this.completionNode.addCompletionFlags(CompletionOnJavadoc.TEXT);
771                 }
772             }
773         }
774     }
775
776     /* (non-Javadoc)
777      * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#readToken()
778      */

779     protected int readToken() throws InvalidInputException {
780         int token = super.readToken();
781         if (token == TerminalTokens.TokenNameIdentifier && this.scanner.currentPosition == this.scanner.startPosition) {
782             // Scanner is looping on empty token => read it...
783
this.scanner.getCurrentIdentifierSource();
784         }
785         return token;
786     }
787
788     /*
789      * Recover syntax on invalid qualified name.
790      */

791     protected Object JavaDoc syntaxRecoverQualifiedName(int primitiveToken) throws InvalidInputException {
792         if (this.cursorLocation == ((int)this.identifierPositionStack[this.identifierPtr])) {
793             // special case of completion just before the dot.
794
return createTypeReference(primitiveToken);
795         }
796         int idLength = this.identifierLengthStack[this.identifierLengthPtr];
797         char[][] tokens = new char[idLength][];
798         int startPtr = this.identifierPtr-idLength+1;
799         System.arraycopy(this.identifierStack, startPtr, tokens, 0, idLength);
800         long[] positions = new long[idLength+1];
801         System.arraycopy(this.identifierPositionStack, startPtr, positions, 0, idLength);
802         positions[idLength] = (((long)this.tokenPreviousPosition)<<32) + this.tokenPreviousPosition;
803         this.completionNode = new CompletionOnJavadocQualifiedTypeReference(tokens, CharOperation.NO_CHAR, positions, this.tagSourceStart, this.tagSourceEnd);
804
805         if (CompletionEngine.DEBUG) {
806             System.out.println(" completion partial qualified type="+completionNode); //$NON-NLS-1$
807
}
808         return this.completionNode;
809     }
810
811     /*
812      * Recover syntax on type argument in invalid method/constructor reference
813      */

814     protected Object JavaDoc syntaxRecoverArgumentType(Object JavaDoc receiver, List JavaDoc arguments, Object JavaDoc argument) throws InvalidInputException {
815         if (this.completionNode != null && !this.pushText) {
816             this.completionNode.addCompletionFlags(CompletionOnJavadoc.BASE_TYPES);
817             if (this.completionNode instanceof CompletionOnJavadocSingleTypeReference) {
818                 char[] token = ((CompletionOnJavadocSingleTypeReference)this.completionNode).token;
819                 if (token != null && token.length > 0) {
820                     return this.completionNode;
821                 }
822             } else {
823                 return this.completionNode;
824             }
825         }
826         // Filter empty token
827
if (this.completionNode instanceof CompletionOnJavadocSingleTypeReference) {
828             CompletionOnJavadocSingleTypeReference singleTypeReference = (CompletionOnJavadocSingleTypeReference) this.completionNode;
829             if (singleTypeReference.token != null && singleTypeReference.token.length > 0) {
830                 arguments.add(argument);
831             }
832         } else if (this.completionNode instanceof CompletionOnJavadocQualifiedTypeReference) {
833             CompletionOnJavadocQualifiedTypeReference qualifiedTypeReference = (CompletionOnJavadocQualifiedTypeReference) this.completionNode;
834             if (qualifiedTypeReference.tokens != null && qualifiedTypeReference.tokens.length == qualifiedTypeReference.sourcePositions.length) {
835                 arguments.add(argument);
836             }
837         } else {
838             arguments.add(argument);
839         }
840         Object JavaDoc methodRef = super.createMethodReference(receiver, arguments);
841         if (methodRef instanceof JavadocMessageSend) {
842             JavadocMessageSend msgSend = (JavadocMessageSend) methodRef;
843             if (this.index > this.cursorLocation) {
844                 msgSend.sourceEnd = this.tokenPreviousPosition-1;
845             }
846             int nameStart = (int) (msgSend.nameSourcePosition >>> 32);
847             int nameEnd = (int) msgSend.nameSourcePosition;
848             if ((nameStart <= (this.cursorLocation+1) && this.cursorLocation <= nameEnd)) {
849                 this.completionNode = new CompletionOnJavadocFieldReference(msgSend, this.memberStart);
850             } else {
851                 this.completionNode = new CompletionOnJavadocMessageSend(msgSend, this.memberStart);
852             }
853         } else if (methodRef instanceof JavadocAllocationExpression) {
854             JavadocAllocationExpression allocExp = (JavadocAllocationExpression) methodRef;
855             if (this.index > this.cursorLocation) {
856                 allocExp.sourceEnd = this.tokenPreviousPosition-1;
857             }
858             this.completionNode = new CompletionOnJavadocAllocationExpression(allocExp, this.memberStart);
859         }
860         if (CompletionEngine.DEBUG) {
861             System.out.println(" completion method="+completionNode); //$NON-NLS-1$
862
}
863         return this.completionNode;
864     }
865
866     /*
867      * Recover syntax on empty type argument in invalid method/constructor reference
868      */

869     protected Object JavaDoc syntaxRecoverEmptyArgumentType(Object JavaDoc methodRef) throws InvalidInputException {
870         if (methodRef instanceof JavadocMessageSend) {
871             JavadocMessageSend msgSend = (JavadocMessageSend) methodRef;
872             if (this.index > this.cursorLocation) {
873                 msgSend.sourceEnd = this.tokenPreviousPosition-1;
874             }
875             this.completionNode = new CompletionOnJavadocMessageSend(msgSend, this.memberStart);
876         } else if (methodRef instanceof JavadocAllocationExpression) {
877             JavadocAllocationExpression allocExp = (JavadocAllocationExpression) methodRef;
878             if (this.index > this.cursorLocation) {
879                 allocExp.sourceEnd = this.tokenPreviousPosition-1;
880             }
881             this.completionNode = new CompletionOnJavadocAllocationExpression(allocExp, this.memberStart);
882         }
883         if (CompletionEngine.DEBUG) {
884             System.out.println(" completion method="+completionNode); //$NON-NLS-1$
885
}
886         return this.completionNode;
887     }
888
889     /*
890      * Store completion node into doc comment.
891      */

892     protected void updateDocComment() {
893         super.updateDocComment();
894         if (completionNode instanceof Expression) {
895             getCompletionParser().assistNodeParent = this.docComment;
896             getCompletionParser().assistNode = (ASTNode) this.completionNode;
897             getCompletionJavadoc().completionNode = (Expression) completionNode;
898         }
899     }
900
901     /* (non-Javadoc)
902      * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#verifySpaceOrEndComment()
903      */

904     protected boolean verifySpaceOrEndComment() {
905         CompletionScanner completionScanner = (CompletionScanner) this.scanner;
906         if (completionScanner.completionIdentifier != null && completionScanner.completedIdentifierStart <= this.cursorLocation && this.cursorLocation <= completionScanner.completedIdentifierEnd) {
907             // if we're on completion location do not verify end...
908
return true;
909         }
910         return super.verifySpaceOrEndComment();
911     }
912     
913 }
914
Popular Tags