EclipseJDT Source Viewer

Home|eclipse_jdt/src/org/eclipse/jdt/core/dom/DocCommentParser.java
1/*******************************************************************************
2 * Copyright (c) 2004, 2022 IBM Corporation and others.
3 *
4 * This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License 2.0
6 * which accompanies this distribution, and is available at
7 * https://www.eclipse.org/legal/epl-2.0/
8 *
9 * SPDX-License-Identifier: EPL-2.0
10 *
11 * Contributors:
12 *     IBM Corporation - initial API and implementation
13 *******************************************************************************/
14package org.eclipse.jdt.core.dom;
15
16import java.util.ArrayList;
17import java.util.Iterator;
18import java.util.List;
19import java.util.Map;
20
21import org.eclipse.jdt.core.compiler.CharOperation;
22import org.eclipse.jdt.core.compiler.InvalidInputException;
23import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
24import org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser;
25import org.eclipse.jdt.internal.compiler.parser.Scanner;
26import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
27import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
28
29/**
30 * Internal parser used for decoding doc comments.
31 *
32 * @since 3.0
33 */
34@SuppressWarnings({ "rawtypes""unchecked" })
35class DocCommentParser extends AbstractCommentParser {
36
37    private Javadoc docComment;
38    private AST ast;
39
40    DocCommentParser(AST astScanner scannerboolean check) {
41        super(null);
42        this.ast = ast;
43        this.scanner = scanner;
44        switch(this.ast.apiLevel()) {
45            case AST.JLS2_INTERNAL :
46                this.sourceLevel = ClassFileConstants.JDK1_3;
47                break;
48            case AST.JLS3_INTERNAL:
49                this.sourceLevel = ClassFileConstants.JDK1_5;
50                break;
51            default:
52                // AST.JLS4 for now
53                this.sourceLevel = ClassFileConstants.JDK1_7;
54        }
55        this.checkDocComment = check;
56        this.kind = DOM_PARSER | TEXT_PARSE;
57    }
58
59    /* (non-Javadoc)
60     * Returns true if tag @deprecated is present in annotation.
61     *
62     * If annotation checking is enabled, will also construct an Annotation node, which will be stored into Parser.annotation
63     * slot for being consumed later on.
64     */
65    public Javadoc parse(int[] positions) {
66        return parse(positions[0], positions[1]-positions[0]);
67    }
68    public Javadoc parse(int startint length) {
69
70        // Init
71        this.source = this.scanner.source;
72        this.lineEnds = this.scanner.lineEnds;
73        this.docComment = new Javadoc(this.ast);
74
75        // Parse
76        if (this.checkDocComment) {
77            this.javadocStart = start;
78            this.javadocEnd = start+length-1;
79            this.firstTagPosition = this.javadocStart;
80            commentParse();
81        }
82        this.docComment.setSourceRange(startlength);
83        if (this.ast.apiLevel == AST.JLS2_INTERNAL) {
84            setComment(startlength);  // backward compatibility
85        }
86        return this.docComment;
87    }
88
89    /**
90     * Sets the comment starting at the given position and with the given length.
91     * <p>
92     * Note the only purpose of this method is to hide deprecated warnings.
93     * @deprecated mark deprecated to hide deprecated usage
94     */
95    private void setComment(int startint length) {
96        this.docComment.setComment(new String(this.sourcestartlength));
97    }
98
99    @Override
100    public String toString() {
101        StringBuilder buffer = new StringBuilder();
102        buffer.append("javadoc: ").append(this.docComment).append("\n");    //$NON-NLS-1$ //$NON-NLS-2$
103        buffer.append(super.toString());
104        return buffer.toString();
105    }
106
107    @Override
108    protected Object createArgumentReference(char[] nameint dimboolean isVarargsObject typeReflong[] dimPositionslong argNamePos) throws InvalidInputException {
109        try {
110            MethodRefParameter argument = this.ast.newMethodRefParameter();
111            ASTNode node = (ASTNodetypeRef;
112            int argStart = node.getStartPosition();
113            int argEnd = node.getStartPosition()+node.getLength()-1;
114            if (dim > 0argEnd = (intdimPositions[dim-1];
115            if (argNamePos >= 0argEnd = (intargNamePos;
116            if (name.length != 0) {
117                final SimpleName argName = new SimpleName(this.ast);
118                argName.internalSetIdentifier(new String(name));
119                argument.setName(argName);
120                int argNameStart = (int) (argNamePos >>> 32);
121                argName.setSourceRange(argNameStartargEnd-argNameStart+1);
122            }
123            Type argType = null;
124            if (node.getNodeType() == ASTNode.PRIMITIVE_TYPE) {
125                argType = (PrimitiveTypenode;
126            } else {
127                Name argTypeName = (Namenode;
128                argType = this.ast.newSimpleType(argTypeName);
129                argType.setSourceRange(argStartnode.getLength());
130            }
131            if (dim > 0 && !isVarargs) {
132                if (this.ast.apiLevel <= AST.JLS4_INTERNAL) {
133                    for (int i=0i<dimi++) {
134                        argType = this.ast.newArrayType(argType);
135                        argType.setSourceRange(argStart, ((intdimPositions[i])-argStart+1);
136                    }
137                } else {
138                    ArrayType argArrayType = this.ast.newArrayType(argType0);
139                    argType = argArrayType;
140                    argType.setSourceRange(argStart, ((intdimPositions[dim-1])-argStart+1);
141                    for (int i=0i<dimi++) {
142                        Dimension dimension = this.ast.newDimension();
143                        int dimStart = (int) (dimPositions[i] >>> 32);
144                        int dimEnd = (intdimPositions[i];
145                        dimension.setSourceRange(dimStartdimEnd-dimStart+1);
146                        argArrayType.dimensions().add(dimension);
147                    }
148                }
149            }
150            argument.setType(argType);
151            if (this.ast.apiLevel > AST.JLS8_INTERNAL) {
152                argument.setVarargs(isVarargs);
153            }
154            argument.setSourceRange(argStartargEnd - argStart + 1);
155            return argument;
156        }
157        catch (ClassCastException ex) {
158                throw new InvalidInputException();
159        }
160    }
161
162    @Override
163    protected Object createFieldReference(Object receiver) throws InvalidInputException {
164        try {
165            MemberRef fieldRef = this.ast.newMemberRef();
166            SimpleName fieldName = new SimpleName(this.ast);
167            fieldName.internalSetIdentifier(new String(this.identifierStack[0]));
168            fieldRef.setName(fieldName);
169            int start = (int) (this.identifierPositionStack[0] >>> 32);
170            int end = (int) this.identifierPositionStack[0];
171            fieldName.setSourceRange(startend - start + 1);
172            if (receiver == null) {
173                start = this.memberStart;
174                fieldRef.setSourceRange(startend - start + 1);
175            } else {
176                Name typeRef = (Namereceiver;
177                fieldRef.setQualifier(typeRef);
178                start = typeRef.getStartPosition();
179                end = fieldName.getStartPosition()+fieldName.getLength()-1;
180                fieldRef.setSourceRange(startend-start+1);
181            }
182            return fieldRef;
183        }
184        catch (ClassCastException ex) {
185                throw new InvalidInputException();
186        }
187    }
188
189    @Override
190    protected Object createMethodReference(Object receiverList arguments) throws InvalidInputException {
191        try {
192            // Create method ref
193            MethodRef methodRef = this.ast.newMethodRef();
194            SimpleName methodName = new SimpleName(this.ast);
195            int length = this.identifierLengthStack[0] - 1// may be > 0 for member class constructor reference
196            methodName.internalSetIdentifier(new String(this.identifierStack[length]));
197            methodRef.setName(methodName);
198            int start = (int) (this.identifierPositionStack[length] >>> 32);
199            int end = (int) this.identifierPositionStack[length];
200            methodName.setSourceRange(startend - start + 1);
201            // Set qualifier
202            if (receiver == null) {
203                start = this.memberStart;
204                methodRef.setSourceRange(startend - start + 1);
205            } else {
206                Name typeRef = (Namereceiver;
207                methodRef.setQualifier(typeRef);
208                start = typeRef.getStartPosition();
209            }
210            // Add arguments
211            if (arguments != null) {
212                Iterator parameters = arguments.listIterator();
213                while (parameters.hasNext()) {
214                    MethodRefParameter param = (MethodRefParameterparameters.next();
215                    methodRef.parameters().add(param);
216                }
217            }
218            methodRef.setSourceRange(start, this.scanner.getCurrentTokenEndPosition()-start+1);
219            return methodRef;
220        }
221        catch (ClassCastException ex) {
222                throw new InvalidInputException();
223        }
224    }
225
226    @Override
227    protected void createTag() {
228        int position = this.scanner.currentPosition;
229        this.scanner.resetTo(this.tagSourceStart, this.tagSourceEnd);
230        StringBuilder tagName = new StringBuilder();
231        int start = this.tagSourceStart;
232        this.scanner.getNextChar();
233        while (this.scanner.currentPosition <= (this.tagSourceEnd+1)) {
234            tagName.append(this.scanner.currentCharacter);
235            this.scanner.getNextChar();
236        }
237        if (TagElement.TAG_SNIPPET.equals(tagName.toString())) {
238            this.tagSourceEnd = this.index;
239            // need to use createSnippetTag to create @snippet
240            return;
241        }
242        TagElement tagElement = this.ast.newTagElement();
243        tagElement.setTagName(tagName.toString());
244        if (this.inlineTagStarted) {
245            start = this.inlineTagStart;
246            TagElement previousTag = null;
247            if (this.astPtr == -1) {
248                previousTag = this.ast.newTagElement();
249                previousTag.setSourceRange(start, this.tagSourceEnd-start+1);
250                pushOnAstStack(previousTagtrue);
251            } else {
252                previousTag = (TagElement) this.astStack[this.astPtr];
253            }
254            int previousStart = previousTag.getStartPosition();
255            previousTag.fragments().add(tagElement);
256            previousTag.setSourceRange(previousStart, this.tagSourceEnd-previousStart+1);
257        } else {
258            pushOnAstStack(tagElementtrue);
259        }
260        tagElement.setSourceRange(start, this.tagSourceEnd-start+1);
261        this.scanner.resetTo(position, this.javadocEnd);
262    }
263
264    @Override
265    protected Object createSnippetTag() {
266        TagElement tagElement = this.ast.newTagElement();
267        int position = this.scanner.currentPosition;
268        this.scanner.resetTo(this.tagSourceStart, this.tagSourceEnd);
269        StringBuilder tagName = new StringBuilder();
270        int start = this.tagSourceStart;
271        this.scanner.getNextChar();
272        while (this.scanner.currentPosition <= (this.tagSourceEnd+1)) {
273            tagName.append(this.scanner.currentCharacter);
274            this.scanner.getNextChar();
275        }
276        tagElement.setTagName(tagName.toString());
277        if (this.inlineTagStarted) {
278            start = this.inlineTagStart;
279            TagElement previousTag = null;
280            if (this.astPtr == -1) {
281                previousTag = this.ast.newTagElement();
282                previousTag.setSourceRange(start, this.tagSourceEnd-start+1);
283                pushOnAstStack(previousTagtrue);
284            } else {
285                previousTag = (TagElement) this.astStack[this.astPtr];
286            }
287            int previousStart = previousTag.getStartPosition();
288            previousTag.fragments().add(tagElement);
289            previousTag.setSourceRange(previousStart, this.tagSourceEnd-previousStart+1);
290        } else {
291            pushOnAstStack(tagElementtrue);
292        }
293        tagElement.setSourceRange(start, this.tagSourceEnd-start+1);
294        this.scanner.resetTo(position, this.javadocEnd);
295        return tagElement;
296    }
297
298    @Override
299    protected void setSnippetIsValid(Object tagboolean value) {
300        if (tag instanceof TagElement) {
301            ((TagElementtag).setProperty(TagProperty.TAG_PROPERTY_SNIPPET_IS_VALIDvalue);
302        }
303    }
304
305    @Override
306    protected void setSnippetError(Object tagString value) {
307        if (tag instanceof TagElement) {
308            ((TagElementtag).setProperty(TagProperty.TAG_PROPERTY_SNIPPET_ERRORvalue);
309        }
310    }
311
312    @Override
313    protected void setSnippetID(Object tagString value) {
314        if (tag instanceof TagElement) {
315            ((TagElementtag).setProperty(TagProperty.TAG_PROPERTY_SNIPPET_IDvalue);
316        }
317    }
318
319    @Override
320    protected Object createSnippetRegion(String nameList<ObjecttagsObject snippetTagboolean isDummyRegionboolean considerPrevTag) {
321        if (!isDummyRegion) {
322            return createSnippetOriginalRegion(nametags);
323        }
324        List<TagElementtagsToBeProcessed = new ArrayList<>();
325        Object toBeReturned = null;
326        if (tags != null && tags.size() > 0) {
327            int start = -1;
328            int end = -1;
329            for (Object tag : tags) {
330                if (tag instanceof TagElement) {
331                    TagElement tagElem = (TagElementtag;
332                    tagsToBeProcessed.add(tagElem);
333                    int tagStart = tagElem.getStartPosition();
334                    int tagEnd = tagStart + tagElem.getLength();
335                    if (start == -1 || start > tagStart) {
336                        start = tagStart;
337                    }
338                    if (end ==-1 || end < tagEnd) {
339                        end = tagEnd;
340                    }
341                } else if (tag instanceof JavaDocRegion && snippetTag instanceof TagElement) {
342                    TagElement snippet = (TagElementsnippetTag;
343                    JavaDocRegion reg = (JavaDocRegiontag;
344                    if (!reg.isDummyRegion()) {
345                        snippet.fragments().add(reg);
346                    }
347                    toBeReturned = reg;
348                }
349            }
350            if (tagsToBeProcessed.size() > 0) {
351                boolean process = true;
352                if (considerPrevTag && snippetTag instanceof TagElement) {
353                    TagElement snippetTagElem = (TagElementsnippetTag;
354                    Object prevTag = snippetTagElem.fragments().get(snippetTagElem.fragments().size() - 1);
355                    if (prevTag instanceof TagElement) {
356                        tagsToBeProcessed.add(0, (TagElement)prevTag);
357                        snippetTagElem.fragments().remove(prevTag);
358                    } else if (prevTag instanceof JavaDocRegion) {
359                        JavaDocRegion region = (JavaDocRegionprevTag;
360                        region.tags().addAll(tagsToBeProcessed);
361                        toBeReturned = snippetTag;
362                        process = false;
363                    }
364                }
365                if (process) {
366                    if (tagsToBeProcessed.size() == 1) {
367                        return tagsToBeProcessed.get(0);
368                    }
369                    else {
370                        JavaDocRegion region = this.ast.newJavaDocRegion();
371                        region.tags().addAll(tagsToBeProcessed);
372                        region.setSourceRange(startend);
373                        toBeReturned = region;
374                    }
375                }
376            } else {
377                toBeReturned = snippetTag;
378            }
379        }
380        return toBeReturned;
381    }
382
383    private Object createSnippetOriginalRegion(String nameList<Objecttags) {
384        JavaDocRegion region = this.ast.newJavaDocRegion();
385        if (tags != null && tags.size() > 0) {
386            int start = -1;
387            int end = -1;
388            for (Object tag : tags) {
389                if (tag instanceof TagElement) {
390                    TagElement tagElem = (TagElementtag;
391                    region.tags().add(tagElem);
392                    int tagStart = tagElem.getStartPosition();
393                    int tagEnd = tagStart + tagElem.getLength();
394                    if (start == -1 || start > tagStart) {
395                        start = tagStart;
396                    }
397                    if (end ==-1 || end < tagEnd) {
398                        end = tagEnd;
399                    }
400                }
401            }
402            region.setSourceRange(startend-start);
403            region.setDummyRegion(false);
404        }
405        if (name != null) {
406            region.setTagName(name);
407        }
408        return region;
409    }
410
411    @Override
412    protected Object createSnippetInnerTag(String tagNameint startint end) {
413        if (tagName != null) {
414            TagElement tagElement = this.ast.newTagElement();
415            tagElement.setTagName(tagName.toString());
416            if (this.astPtr == -1) {
417                return null;
418            }
419            tagElement.setSourceRange(startend-start);
420            return tagElement;
421        }
422        return null;
423    }
424
425    @Override
426    protected void closeJavaDocRegion(String nameObject snippetTagint end) {
427        if (snippetTag instanceof TagElement) {
428            TagElement snippet = (TagElementsnippetTag;
429            List<JavaDocRegionregions = snippet.tagRegions();
430            JavaDocRegion regionToClose = null;
431            if (name != null) {
432                for (JavaDocRegion region : regions) {
433                    if (name.equals(region.getTagName())) {
434                        if (!this.isRegionToBeEnded(region)
435                                && !this.hasRegionEnded(region)) {
436                            regionToClose = region;
437                            break;
438                        }
439                    }
440                }
441            } else {
442                for (int iregions.size()-1i >-1i--) {
443                    JavaDocRegion region = regions.get(i);
444                    if (!this.isRegionToBeEnded(region)
445                            && !this.hasRegionEnded(region)) {
446                        regionToClose = region;
447                        break;
448                    }
449                }
450            }
451            if (regionToClose != null) {
452                setRegionToBeEnded(regionToClosetrue);
453                int start = regionToClose.getStartPosition();
454                int curEnd = start + regionToClose.getLength();
455                if (end > curEnd) {
456                    regionToClose.setSourceRange(startend-start);
457                }
458            }
459        }
460
461    }
462
463    @Override
464    protected void addTagProperties(Object tagMap<StringObjectmapint tagCount) {
465        if (tag instanceof TagElement) {
466            TagElement tagElement = (TagElementtag;
467            map.forEach((kv) -> {
468                TagProperty tagProperty = this.ast.newTagProperty();
469                tagProperty.setName(k);
470                if (v instanceof String) {
471                    tagProperty.setStringValue((String)v);
472                } else if (v instanceof ASTNode) {
473                    tagProperty.setNodeValue((ASTNode)v);
474                }
475                tagElement.tagProperties().add(tagProperty);
476            });
477            tagElement.setProperty(TagProperty.TAG_PROPERTY_SNIPPET_INLINE_TAG_COUNTtagCount);
478        }
479    }
480
481    @Override
482    protected void addSnippetInnerTag(Object objObject snippetTag) {
483        boolean isNotDummyRegion = false;
484        if (obj instanceof JavaDocRegion) {
485            JavaDocRegion region = (JavaDocRegionobj;
486            if (snippetTag instanceof TagElement) {
487                TagElement snippetTagElem = (TagElementsnippetTag;
488                if (!region.isDummyRegion()) {
489                    snippetTagElem.fragments().add(region);
490                    isNotDummyRegion = true;
491                } else {
492                    Iterator<Objectitr = region.tags().iterator();
493                    while (itr.hasNext()) {
494                        Object tag = itr.next();
495                        if (tag instanceof JavaDocRegion) {
496                            JavaDocRegion reg = (JavaDocRegiontag;
497                            if (!reg.isDummyRegion()) {
498                                region.tags().remove(reg);
499                                snippetTagElem.fragments().add(reg);
500                            }
501                        }
502                    }
503                }
504            }
505        }
506        if (obj instanceof AbstractTagElement && !isNotDummyRegion) {
507            AbstractTagElement tagElement = (AbstractTagElementobj;
508            AbstractTagElement previousTag = null;
509            if (this.astPtr == -1) {
510                return;
511            } else {
512                previousTag = (AbstractTagElement) this.astStack[this.astPtr];
513                List fragments = previousTag.fragments();
514                if (this.inlineTagStarted) {
515                    int size = fragments.size();
516                    if (size == 0) {
517                        //do nothing
518                    } else {
519                        // If last fragment is a tag, then use it as previous tag
520                        ASTNode lastFragment = (ASTNodefragments.get(size-1);
521                        if (lastFragment instanceof AbstractTagElement) {
522                            previousTag = (AbstractTagElementlastFragment;
523                        }
524                    }
525                }
526            }
527            previousTag.fragments().add(tagElement);
528        }
529    }
530
531
532    @Override
533    protected Object createTypeReference(int primitiveTokenboolean canBeModule) {
534        return createTypeReference(primitiveToken);
535    }
536
537    @Override
538    protected Object createTypeReference(int primitiveToken) {
539        int size = this.identifierLengthStack[this.identifierLengthPtr];
540        String[] identifiers = new String[size];
541        int pos = this.identifierPtr - size + 1;
542        for (int i = 0i < sizei++) {
543            identifiers[i] = new String(this.identifierStack[pos+i]);
544        }
545        ASTNode typeRef = null;
546        if (primitiveToken == -1) {
547            typeRef = this.ast.internalNewName(identifiers);
548        } else {
549            switch (primitiveToken) {
550                case TerminalTokens.TokenNamevoid :
551                    typeRef = this.ast.newPrimitiveType(PrimitiveType.VOID);
552                    break;
553                case TerminalTokens.TokenNameboolean :
554                    typeRef = this.ast.newPrimitiveType(PrimitiveType.BOOLEAN);
555                    break;
556                case TerminalTokens.TokenNamebyte :
557                    typeRef = this.ast.newPrimitiveType(PrimitiveType.BYTE);
558                    break;
559                case TerminalTokens.TokenNamechar :
560                    typeRef = this.ast.newPrimitiveType(PrimitiveType.CHAR);
561                    break;
562                case TerminalTokens.TokenNamedouble :
563                    typeRef = this.ast.newPrimitiveType(PrimitiveType.DOUBLE);
564                    break;
565                case TerminalTokens.TokenNamefloat :
566                    typeRef = this.ast.newPrimitiveType(PrimitiveType.FLOAT);
567                    break;
568                case TerminalTokens.TokenNameint :
569                    typeRef = this.ast.newPrimitiveType(PrimitiveType.INT);
570                    break;
571                case TerminalTokens.TokenNamelong :
572                    typeRef = this.ast.newPrimitiveType(PrimitiveType.LONG);
573                    break;
574                case TerminalTokens.TokenNameshort :
575                    typeRef = this.ast.newPrimitiveType(PrimitiveType.SHORT);
576                    break;
577                default:
578                    // should not happen
579                    return null;
580            }
581        }
582        // Update ref for whole name
583        int start = (int) (this.identifierPositionStack[pos] >>> 32);
584//        int end = (int) this.identifierPositionStack[this.identifierPtr];
585//        typeRef.setSourceRange(start, end-start+1);
586        // Update references of each simple name
587        if (size > 1) {
588            Name name = (Name)typeRef;
589            int nameIndex = size;
590            for (int i=this.identifierPtri>posi--, nameIndex--) {
591                int s = (int) (this.identifierPositionStack[i] >>> 32);
592                int e = (int) this.identifierPositionStack[i];
593                name.index = nameIndex;
594                SimpleName simpleName = ((QualifiedName)name).getName();
595                simpleName.index = nameIndex;
596                simpleName.setSourceRange(se-s+1);
597                name.setSourceRange(starte-start+1);
598                name =  ((QualifiedName)name).getQualifier();
599            }
600            int end = (int) this.identifierPositionStack[pos];
601            name.setSourceRange(startend-start+1);
602            name.index = nameIndex;
603        } else {
604            int end = (int) this.identifierPositionStack[pos];
605            typeRef.setSourceRange(startend-start+1);
606        }
607        return typeRef;
608    }
609
610    private ModuleQualifiedName createModuleReference(int moduleRefTokenCount) {
611        String[] identifiers = new String[moduleRefTokenCount];
612        for (int i = 0i < moduleRefTokenCounti++) {
613            identifiers[i] = new String(this.identifierStack[i]);
614        }
615        ModuleQualifiedName moduleRef = new ModuleQualifiedName(this.ast);
616
617        ASTNode typeRef = null;
618        typeRef = this.ast.internalNewName(identifiers);
619        int start = (int) (this.identifierPositionStack[0] >>> 32);
620        if (moduleRefTokenCount > 1) {
621            Name name = (Name)typeRef;
622            int nameIndex = moduleRefTokenCount;
623            for (int i=moduleRefTokenCount-1i>0i--, nameIndex--) {
624                int s = (int) (this.identifierPositionStack[i] >>> 32);
625                int e = (int) this.identifierPositionStack[i];
626                name.index = nameIndex;
627                SimpleName simpleName = ((QualifiedName)name).getName();
628                simpleName.index = nameIndex;
629                simpleName.setSourceRange(se-s+1);
630                name.setSourceRange(starte-start+1);
631                name =  ((QualifiedName)name).getQualifier();
632            }
633            int end = (int) this.identifierPositionStack[0];
634            name.setSourceRange(startend-start+1);
635            name.index = nameIndex;
636        } else {
637            int end = (int) this.identifierPositionStack[0];
638            typeRef.setSourceRange(startend-start+1);
639        }
640        moduleRef.setModuleQualifier((Name)typeRef);
641        moduleRef.setName(null);
642        moduleRef.setSourceRange(typeRef.getStartPosition(), typeRef.getLength()+1);
643        return moduleRef;
644    }
645
646    @Override
647    protected Object createModuleTypeReference(int primitiveTokenint  moduleRefTokenCount) {
648        int size = this.identifierLengthStack[this.identifierLengthPtr];
649        ModuleQualifiedName moduleRefnull;
650        Name typeRefnull;
651        if (size == moduleRefTokenCount) {
652            moduleRefcreateModuleReference(moduleRefTokenCount);
653            this.lastIdentifierEndPosition++;
654        } else {
655            String[] moduleIdentifiers = new String[moduleRefTokenCount];
656            String[] identifiers = new String[sizemoduleRefTokenCount];
657            int pos = this.identifierPtr - size + 1;
658            for (int i = 0i < sizei++) {
659                if (i < moduleRefTokenCount) {
660                    moduleIdentifiers[i] =  new String(this.identifierStack[pos+i]);
661                } else {
662                    identifiers[i-moduleRefTokenCount] = new String(this.identifierStack[pos+i]);
663                }
664            }
665            moduleRefcreateModuleReference(moduleRefTokenCount);
666            pos = this.identifierPtr+moduleRefTokenCount - size + 1;
667
668            if (primitiveToken == -1) {
669                typeRef = this.ast.internalNewName(identifiers);
670                // Update ref for whole name
671                int start = (int) (this.identifierPositionStack[pos] >>> 32);
672//                int end = (int) this.identifierPositionStack[this.identifierPtr];
673//                typeRef.setSourceRange(start, end-start+1);
674                // Update references of each simple name
675                if (size-moduleRefTokenCount > 1) {
676                    Name name = typeRef;
677                    int nameIndex = size-moduleRefTokenCount;
678                    for (int i=this.identifierPtri>posi--, nameIndex--) {
679                        int s = (int) (this.identifierPositionStack[i] >>> 32);
680                        int e = (int) this.identifierPositionStack[i];
681                        name.index = nameIndex;
682                        SimpleName simpleName = ((QualifiedName)name).getName();
683                        simpleName.index = nameIndex;
684                        simpleName.setSourceRange(se-s+1);
685                        name.setSourceRange(starte-start+1);
686                        name =  ((QualifiedName)name).getQualifier();
687                    }
688                    int end = (int) this.identifierPositionStack[pos];
689                    name.setSourceRange(startend-start+1);
690                    name.index = nameIndex;
691                } else {
692                    int end = (int) this.identifierPositionStack[pos];
693                    typeRef.setSourceRange(startend-start+1);
694                }
695                moduleRef.setName(typeRef);
696                moduleRef.setSourceRange(moduleRef.getStartPosition(), moduleRef.getLength() + typeRef.getLength());
697            }
698        }
699        return moduleRef;
700    }
701
702    @Override
703    protected boolean parseIdentifierTag(boolean report) {
704        if (super.parseIdentifierTag(report)) {
705            createTag();
706            this.index = this.tagSourceEnd+1;
707            this.scanner.resetTo(this.index, this.javadocEnd);
708            return true;
709        }
710        return false;
711    }
712
713    /*
714     * Parse @return tag declaration
715     */
716    protected boolean parseReturn() {
717        createTag();
718        return true;
719    }
720
721    @Override
722    protected boolean parseTag(int previousPosition) throws InvalidInputException {
723
724        // Read tag name
725        int currentPosition = this.index;
726        int token = readTokenAndConsume();
727        char[] tagName = CharOperation.NO_CHAR;
728        if (currentPosition == this.scanner.startPosition) {
729            this.tagSourceStart = this.scanner.getCurrentTokenStartPosition();
730            this.tagSourceEnd = this.scanner.getCurrentTokenEndPosition();
731            tagName = this.scanner.getCurrentIdentifierSource();
732        } else {
733            this.tagSourceEnd = currentPosition-1;
734        }
735
736        // Try to get tag name other than java identifier
737        // (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=51660)
738        if (this.scanner.currentCharacter != ' ' && !ScannerHelper.isWhitespace(this.scanner.currentCharacter)) {
739            tagNameToken: while (token != TerminalTokens.TokenNameEOF && this.index < this.scanner.eofPosition) {
740                int length = tagName.length;
741                // !, ", #, %, &, ', -, :, <, >, * chars and spaces are not allowed in tag names
742                switch (this.scanner.currentCharacter) {
743                    case '}':
744                    case '*'// break for '*' as this is perhaps the end of comment (bug 65288)
745                    case '!':
746                    case '#':
747                    case '%':
748                    case '&':
749                    case '\'':
750                    case '"':
751                    case ':':
752                    case '<':
753                    case '>':
754                        break tagNameToken;
755                    case '-'// allowed in tag names as this character is often used in doclets (bug 68087)
756                        System.arraycopy(tagName0tagName = new char[length+1], 0length);
757                        tagName[length] = this.scanner.currentCharacter;
758                        break;
759                    default:
760                        if (this.scanner.currentCharacter == ' ' || ScannerHelper.isWhitespace(this.scanner.currentCharacter)) {
761                            break tagNameToken;
762                        }
763                        token = readTokenAndConsume();
764                        char[] ident = this.scanner.getCurrentIdentifierSource();
765                        System.arraycopy(tagName0tagName = new char[length+ident.length], 0length);
766                        System.arraycopy(ident0tagNamelengthident.length);
767                        break;
768                }
769                this.tagSourceEnd = this.scanner.getCurrentTokenEndPosition();
770                this.scanner.getNextChar();
771                this.index = this.scanner.currentPosition;
772            }
773        }
774        int length = tagName.length;
775        this.index = this.tagSourceEnd+1;
776        this.scanner.currentPosition = this.tagSourceEnd+1;
777        this.tagSourceStart = previousPosition;
778
779        // tage name may be empty (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=125903)
780        if (tagName.length == 0) {
781            return false;
782        }
783
784        // Decide which parse to perform depending on tag name
785        this.tagValue = NO_TAG_VALUE;
786        boolean valid = true;
787        switch (token) {
788            case TerminalTokens.TokenNameIdentifier :
789                switch (tagName[0]) {
790                    case 'c':
791                        if (length == TAG_CATEGORY_LENGTH && CharOperation.equals(TAG_CATEGORYtagName)) {
792                            this.tagValue = TAG_CATEGORY_VALUE;
793                            valid = parseIdentifierTag(false); // TODO (frederic) reconsider parameter value when @category will be significant in spec
794                        } else if (length == TAG_CODE_LENGTH && CharOperation.equals(TAG_CODEtagName)) {
795                            this.tagValue = TAG_CODE_VALUE;
796                            createTag();
797                        } else {
798                            this.tagValue = TAG_OTHERS_VALUE;
799                            createTag();
800                        }
801                        break;
802                    case 'd':
803                        if (length == TAG_DEPRECATED_LENGTH && CharOperation.equals(TAG_DEPRECATEDtagName)) {
804                            this.deprecated = true;
805                            this.tagValue = TAG_DEPRECATED_VALUE;
806                        } else {
807                            this.tagValue = TAG_OTHERS_VALUE;
808                        }
809                        createTag();
810                    break;
811                    case 'i':
812                        if (length == TAG_INHERITDOC_LENGTH && CharOperation.equals(TAG_INHERITDOCtagName)) {
813                            if (this.reportProblems) {
814                                recordInheritedPosition((((long) this.tagSourceStart) << 32) + this.tagSourceEnd);
815                            }
816                            this.tagValue = TAG_INHERITDOC_VALUE;
817                        } else {
818                            this.tagValue = TAG_OTHERS_VALUE;
819                        }
820                        createTag();
821                    break;
822                    case 'p':
823                        if (length == TAG_PARAM_LENGTH && CharOperation.equals(TAG_PARAMtagName)) {
824                            this.tagValue = TAG_PARAM_VALUE;
825                            valid = parseParam();
826                        } else {
827                            this.tagValue = TAG_OTHERS_VALUE;
828                            createTag();
829                        }
830                    break;
831                    case 'e':
832                        if (length == TAG_EXCEPTION_LENGTH && CharOperation.equals(TAG_EXCEPTIONtagName)) {
833                            this.tagValue = TAG_EXCEPTION_VALUE;
834                            valid = parseThrows();
835                        } else {
836                            this.tagValue = TAG_OTHERS_VALUE;
837                            createTag();
838                        }
839                    break;
840                    case 's':
841                        if (length == TAG_SEE_LENGTH && CharOperation.equals(TAG_SEEtagName)) {
842                            this.tagValue = TAG_SEE_VALUE;
843                            if (this.inlineTagStarted) {
844                                // bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=53290
845                                // Cannot have @see inside inline comment
846                                valid = false;
847                            } else {
848                                valid = parseReference(true);
849                            }
850                        } else if (length == TAG_SNIPPET_LENGTH && CharOperation.equals(TAG_SNIPPETtagName)) {
851                            this.tagValue = TAG_SNIPPET_LENGTH;
852                            if (!this.inlineTagStarted) {
853                                // @snippet is an inline comment
854                                valid = false;
855                            } else {
856                                this.tagValue = TAG_SNIPPET_VALUE;
857                                valid = parseSnippet();
858                            }
859                        } else {
860                            this.tagValue = TAG_OTHERS_VALUE;
861                            createTag();
862                        }
863                    break;
864                    case 'l':
865                        if (length == TAG_LINK_LENGTH && CharOperation.equals(TAG_LINKtagName)) {
866                            this.tagValue = TAG_LINK_VALUE;
867                        } else if (length == TAG_LINKPLAIN_LENGTH && CharOperation.equals(TAG_LINKPLAINtagName)) {
868                            this.tagValue = TAG_LINKPLAIN_VALUE;
869                        } else if (length == TAG_LITERAL_LENGTH && CharOperation.equals(TAG_LITERALtagName)) {
870                            this.tagValue = TAG_LITERAL_VALUE;
871                        }
872
873                        if (this.tagValue != NO_TAG_VALUE && this.tagValue != TAG_LITERAL_VALUE)  {
874                            if (this.inlineTagStarted) {
875                                valid = parseReference(true);
876                            } else {
877                                // bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=53290
878                                // Cannot have @link outside inline comment
879                                valid = false;
880                            }
881                        } else {
882                            if (this.tagValue == NO_TAG_VALUE) this.tagValue = TAG_OTHERS_VALUE;
883                            createTag();
884                        }
885                    break;
886                    case 'v':
887                        if (this.sourceLevel >= ClassFileConstants.JDK1_5 && length == TAG_VALUE_LENGTH && CharOperation.equals(TAG_VALUEtagName)) {
888                            this.tagValue = TAG_VALUE_VALUE;
889                            if (this.inlineTagStarted) {
890                                valid = parseReference();
891                            } else {
892                                valid = false;
893                            }
894                        } else {
895                            this.tagValue = TAG_OTHERS_VALUE;
896                            createTag();
897                        }
898                    break;
899                    default:
900                        this.tagValue = TAG_OTHERS_VALUE;
901                        createTag();
902                }
903                break;
904            case TerminalTokens.TokenNamereturn :
905                this.tagValue = TAG_RETURN_VALUE;
906                valid = parseReturn();
907                break;
908            case TerminalTokens.TokenNamethrows :
909                this.tagValue = TAG_THROWS_VALUE;
910                valid = parseThrows();
911                break;
912            case TerminalTokens.TokenNameabstract:
913            case TerminalTokens.TokenNameassert:
914            case TerminalTokens.TokenNameboolean:
915            case TerminalTokens.TokenNamebreak:
916            case TerminalTokens.TokenNamebyte:
917            case TerminalTokens.TokenNamecase:
918            case TerminalTokens.TokenNamecatch:
919            case TerminalTokens.TokenNamechar:
920            case TerminalTokens.TokenNameclass:
921            case TerminalTokens.TokenNamecontinue:
922            case TerminalTokens.TokenNamedefault:
923            case TerminalTokens.TokenNamedo:
924            case TerminalTokens.TokenNamedouble:
925            case TerminalTokens.TokenNameelse:
926            case TerminalTokens.TokenNameextends:
927            case TerminalTokens.TokenNamefalse:
928            case TerminalTokens.TokenNamefinal:
929            case TerminalTokens.TokenNamefinally:
930            case TerminalTokens.TokenNamefloat:
931            case TerminalTokens.TokenNamefor:
932            case TerminalTokens.TokenNameif:
933            case TerminalTokens.TokenNameimplements:
934            case TerminalTokens.TokenNameimport:
935            case TerminalTokens.TokenNameinstanceof:
936            case TerminalTokens.TokenNameint:
937            case TerminalTokens.TokenNameinterface:
938            case TerminalTokens.TokenNamelong:
939            case TerminalTokens.TokenNamenative:
940            case TerminalTokens.TokenNamenew:
941            case TerminalTokens.TokenNamenull:
942            case TerminalTokens.TokenNamepackage:
943            case TerminalTokens.TokenNameprivate:
944            case TerminalTokens.TokenNameprotected:
945            case TerminalTokens.TokenNamepublic:
946            case TerminalTokens.TokenNameshort:
947            case TerminalTokens.TokenNamestatic:
948            case TerminalTokens.TokenNamestrictfp:
949            case TerminalTokens.TokenNamesuper:
950            case TerminalTokens.TokenNameswitch:
951            case TerminalTokens.TokenNamesynchronized:
952            case TerminalTokens.TokenNamethis:
953            case TerminalTokens.TokenNamethrow:
954            case TerminalTokens.TokenNametransient:
955            case TerminalTokens.TokenNametrue:
956            case TerminalTokens.TokenNametry:
957            case TerminalTokens.TokenNamevoid:
958            case TerminalTokens.TokenNamevolatile:
959            case TerminalTokens.TokenNamewhile:
960            case TerminalTokens.TokenNameenum :
961            case TerminalTokens.TokenNameconst :
962            case TerminalTokens.TokenNamegoto :
963                this.tagValue = TAG_OTHERS_VALUE;
964                createTag();
965                break;
966        }
967        this.textStart = this.index;
968        return valid;
969    }
970
971    @Override
972    protected boolean pushParamName(boolean isTypeParam) {
973        int idIndex = isTypeParam ? 1 : 0;
974        final SimpleName name = new SimpleName(this.ast);
975        name.internalSetIdentifier(new String(this.identifierStack[idIndex]));
976        int nameStart = (int) (this.identifierPositionStack[idIndex] >>> 32);
977        int nameEnd = (int) (this.identifierPositionStack[idIndex] & 0x00000000FFFFFFFFL);
978        name.setSourceRange(nameStartnameEnd-nameStart+1);
979        TagElement paramTag = this.ast.newTagElement();
980        paramTag.setTagName(TagElement.TAG_PARAM);
981        if (isTypeParam) { // specific storage for @param <E> (see bug 79809)
982            // '<' was stored in identifiers stack
983            TextElement text = this.ast.newTextElement();
984            text.setText(new String(this.identifierStack[0]));
985            int txtStart = (int) (this.identifierPositionStack[0] >>> 32);
986            int txtEnd = (int) (this.identifierPositionStack[0] & 0x00000000FFFFFFFFL);
987            text.setSourceRange(txtStarttxtEnd-txtStart+1);
988            paramTag.fragments().add(text);
989            // add simple name
990            paramTag.fragments().add(name);
991            // '>' was stored in identifiers stack
992            text = this.ast.newTextElement();
993            text.setText(new String(this.identifierStack[2]));
994            txtStart = (int) (this.identifierPositionStack[2] >>> 32);
995            txtEnd = (int) (this.identifierPositionStack[2] & 0x00000000FFFFFFFFL);
996            text.setSourceRange(txtStarttxtEnd-txtStart+1);
997            paramTag.fragments().add(text);
998            // set param tag source range
999            paramTag.setSourceRange(this.tagSourceStarttxtEnd-this.tagSourceStart+1);
1000        } else {
1001            paramTag.setSourceRange(this.tagSourceStartnameEnd-this.tagSourceStart+1);
1002            paramTag.fragments().add(name);
1003        }
1004        pushOnAstStack(paramTagtrue);
1005        return true;
1006    }
1007
1008    @Override
1009    protected boolean pushSeeRef(Object statement) {
1010        TagElement seeTag = this.ast.newTagElement();
1011        ASTNode node = (ASTNodestatement;
1012        seeTag.fragments().add(node);
1013        int end = node.getStartPosition()+node.getLength()-1;
1014        if (this.inlineTagStarted) {
1015            seeTag.setSourceRange(this.inlineTagStartend-this.inlineTagStart+1);
1016            switch (this.tagValue) {
1017                case TAG_LINK_VALUE:
1018                    seeTag.setTagName(TagElement.TAG_LINK);
1019                break;
1020                case TAG_LINKPLAIN_VALUE:
1021                    seeTag.setTagName(TagElement.TAG_LINKPLAIN);
1022                break;
1023                case TAG_VALUE_VALUE:
1024                    seeTag.setTagName(TagElement.TAG_VALUE);
1025                break;
1026            }
1027            TagElement previousTag = null;
1028            int previousStart = this.inlineTagStart;
1029            if (this.astPtr == -1) {
1030                previousTag = this.ast.newTagElement();
1031                pushOnAstStack(previousTagtrue);
1032            } else {
1033                previousTag = (TagElement) this.astStack[this.astPtr];
1034                previousStart = previousTag.getStartPosition();
1035            }
1036            previousTag.fragments().add(seeTag);
1037            previousTag.setSourceRange(previousStartend-previousStart+1);
1038        } else {
1039            seeTag.setTagName(TagElement.TAG_SEE);
1040            seeTag.setSourceRange(this.tagSourceStartend-this.tagSourceStart+1);
1041            pushOnAstStack(seeTagtrue);
1042        }
1043        return true;
1044    }
1045
1046    @Override
1047    protected void pushText(int startint end) {
1048
1049        // Create text element
1050        TextElement text = this.ast.newTextElement();
1051        text.setText(new String( this.sourcestartend-start));
1052        text.setSourceRange(startend-start);
1053
1054        // Search previous tag on which to add the text element
1055        TagElement previousTag = null;
1056        int previousStart = start;
1057        if (this.astPtr == -1) {
1058            previousTag = this.ast.newTagElement();
1059            previousTag.setSourceRange(startend-start);
1060            pushOnAstStack(previousTagtrue);
1061        } else {
1062            previousTag = (TagElement) this.astStack[this.astPtr];
1063            previousStart = previousTag.getStartPosition();
1064        }
1065
1066        // If we're in a inline tag, then retrieve previous tag in its fragments
1067        List fragments = previousTag.fragments();
1068        if (this.inlineTagStarted) {
1069            int size = fragments.size();
1070            if (size == 0) {
1071                // no existing fragment => just add the element
1072                TagElement inlineTag = this.ast.newTagElement();
1073                fragments.add(inlineTag);
1074                previousTag = inlineTag;
1075            } else {
1076                // If last fragment is a tag, then use it as previous tag
1077                ASTNode lastFragment = (ASTNodefragments.get(size-1);
1078                if (lastFragment.getNodeType() == ASTNode.TAG_ELEMENT) {
1079                    previousTag = (TagElementlastFragment;
1080                    previousStart = previousTag.getStartPosition();
1081                }
1082            }
1083        }
1084
1085        // Add the text
1086        previousTag.fragments().add(text);
1087        previousTag.setSourceRange(previousStartend-previousStart);
1088        this.textStart = -1;
1089    }
1090
1091    @Override
1092    protected void pushSnippetText(int startint endboolean addNewLineObject snippetTag) {
1093
1094        // Create text element
1095        TextElement text = this.ast.newTextElement();
1096        String textToBeAdded= new String( this.sourcestartend-start);
1097        int iindex = textToBeAdded.indexOf('*');
1098        if (iindex > -1 && textToBeAdded.substring(0iindex+1).trim().equals("*")) { //$NON-NLS-1$
1099            textToBeAdded = textToBeAdded.substring(iindex+1);
1100            if (addNewLine) {
1101                textToBeAdded += System.lineSeparator();
1102            }
1103        }
1104        text.setText(textToBeAdded);
1105        text.setSourceRange(startend-start);
1106
1107        // Search previous tag on which to add the text element
1108        AbstractTagElement previousTag = null;
1109        int previousStart = start;
1110        if (this.astPtr == -1) {
1111            previousTag = this.ast.newTagElement();
1112            previousTag.setSourceRange(startend-start);
1113            pushOnAstStack(previousTagtrue);
1114        } else {
1115            previousTag = (AbstractTagElement) this.astStack[this.astPtr];
1116            previousStart = previousTag.getStartPosition();
1117        }
1118
1119        AbstractTagElement prevTag = null;
1120        // If we're in a inline tag, then retrieve previous tag in its fragments
1121        List fragments = previousTag.fragments();
1122        if (this.inlineTagStarted) {
1123            int size = fragments.size();
1124            if (size == 0) {
1125                //do nothing
1126            } else {
1127                // If last fragment is a tag, then use it as previous tag
1128                ASTNode lastFragment = (ASTNodefragments.get(size-1);
1129                if (lastFragment instanceof AbstractTagElement) {
1130                    previousTag = (AbstractTagElementlastFragment;
1131                    previousStart = previousTag.getStartPosition();
1132                    if (this.snippetInlineTagStarted) {
1133                        fragments = previousTag.fragments();
1134                        size = fragments.size();
1135                        if (size == 0) {
1136                            //do nothing
1137                        } else {
1138                            lastFragment = (ASTNodefragments.get(size-1);
1139                            if (lastFragment instanceof AbstractTagElement) {
1140                                prevTag = (AbstractTagElementlastFragment;
1141                                this.snippetInlineTagStarted = false;
1142                            }
1143                        }
1144                        this.snippetInlineTagStarted = false;
1145                    }
1146                }
1147            }
1148        }
1149
1150        int finEnd = end;
1151        boolean isNotDummyJavaDocRegion = false;
1152        if (prevTag instanceof JavaDocRegion && !((JavaDocRegion)prevTag).isDummyRegion()) {
1153            isNotDummyJavaDocRegion = true;
1154        }
1155        // Add the text
1156        if (prevTag != null && !isNotDummyJavaDocRegion) {
1157
1158            prevTag.fragments().add(text);
1159            int curStart = prevTag.getStartPosition();
1160            int curEnd = curStart + prevTag.getLength();
1161            int finStart = start;
1162            if (curStart <  start) {
1163                finStart = curStart;
1164            }
1165            if (curEnd > end) {
1166                finEnd = curEnd;
1167            }
1168            prevTag.setSourceRange(finStartfinEnd - finStart);
1169        } else {
1170            previousTag.fragments().add(text);
1171        }
1172        previousTag.setSourceRange(previousStartfinEnd-previousStart);
1173        this.textStart = -1;
1174
1175        if (snippetTag instanceof TagElement) {
1176            fragments =  ((TagElementsnippetTag).fragments();
1177            for (Object frag : fragments) {
1178                if (frag instanceof JavaDocRegion) {
1179                    JavaDocRegion region = (JavaDocRegionfrag;
1180                    if (!region.isDummyRegion() && !hasRegionEnded(region)) {
1181                        int startPos = region.getStartPosition();
1182                        int endPos = startPos + region.getLength();
1183                        if (startPos > start) {
1184                            startPos = start;
1185                        }
1186                        if (endPos < end) {
1187                            endPos = end;
1188                        }
1189                        Object textVal = region.getProperty(TagProperty.TAG_PROPERTY_SNIPPET_REGION_TEXT);
1190                        if (!(textVal instanceof TextElement)) {
1191                            region.setProperty(TagProperty.TAG_PROPERTY_SNIPPET_REGION_TEXTtext);
1192                        }
1193                        region.setSourceRange(startPosendPos-startPos);
1194                        if (isRegionToBeEnded(region)) {
1195                            setRegionEnded(regiontrue);
1196                        }
1197                    }
1198                }
1199            }
1200        }
1201    }
1202
1203    private boolean hasRegionEnded(JavaDocRegion region) {
1204        boolean ended = false;
1205        if (region != null) {
1206            Object value = region.getProperty(JavaDocRegion.REGION_ENDED);
1207            if (value instanceof Boolean && ((Boolean)value).booleanValue()) {
1208                ended = true;
1209            }
1210        }
1211        return ended;
1212    }
1213
1214    private boolean isRegionToBeEnded(JavaDocRegion region) {
1215        boolean toBeEnded = false;
1216        if (region != null) {
1217            Object value = region.getProperty(JavaDocRegion.REGION_TO_BE_ENDED);
1218            if (value instanceof Boolean && ((Boolean)value).booleanValue()) {
1219                toBeEnded = true;
1220            }
1221        }
1222        return toBeEnded;
1223    }
1224
1225    private void setRegionToBeEnded(JavaDocRegion regionboolean value) {
1226        if (region != null) {
1227            region.setProperty(JavaDocRegion.REGION_TO_BE_ENDEDvalue);
1228        }
1229    }
1230
1231    private void setRegionEnded(JavaDocRegion regionboolean value) {
1232        if (region != null) {
1233            region.setProperty(JavaDocRegion.REGION_ENDEDvalue);
1234            setRegionToBeEnded(region, !value);
1235        }
1236    }
1237
1238    @Override
1239    protected void pushExternalSnippetText(String text,int startint end) {
1240        String snippetLangHeader = "<pre>"//$NON-NLS-1$ //the code snippets comes as preformatted so need to prefix them with <pre> tag
1241        String snipperLangFooter = "</pre>"//$NON-NLS-1$
1242        text = snippetLangHeader + text + snipperLangFooter;
1243        TextElement textElement = this.ast.newTextElement();
1244        textElement.setText(text);
1245        textElement.setSourceRange(startend-start);
1246
1247        // Search previous tag on which to add the text element
1248        TagElement previousTag = null;
1249        int previousStart = start;
1250        int previousEnd = end;
1251        if (this.astPtr == -1) {
1252            previousTag = this.ast.newTagElement();
1253            previousTag.setSourceRange(startend-start);
1254            pushOnAstStack(previousTagtrue);
1255        } else {
1256            previousTag = (TagElement) this.astStack[this.astPtr];
1257            previousStart = previousTag.getStartPosition();
1258            previousEnd = previousStart + previousTag.getLength();
1259        }
1260        previousTag.fragments().add(textElement);
1261        int curStart = previousStart;
1262        int curEnd = previousEnd;
1263        if (start < previousStart) {
1264            curStart = start;
1265        }
1266        if (end > previousEnd) {
1267            curEnd = end;
1268        }
1269        previousTag.setSourceRange(curStartcurEnd-curStart);
1270        this.textStart = -1;
1271    }
1272
1273
1274    @Override
1275    protected boolean pushThrowName(Object typeRef) {
1276        TagElement throwsTag = this.ast.newTagElement();
1277        switch (this.tagValue) {
1278            case TAG_THROWS_VALUE:
1279                throwsTag.setTagName(TagElement.TAG_THROWS);
1280            break;
1281            case TAG_EXCEPTION_VALUE:
1282                throwsTag.setTagName(TagElement.TAG_EXCEPTION);
1283            break;
1284        }
1285        throwsTag.setSourceRange(this.tagSourceStart, this.scanner.getCurrentTokenEndPosition()-this.tagSourceStart+1);
1286        throwsTag.fragments().add(typeRef);
1287        pushOnAstStack(throwsTagtrue);
1288        return true;
1289    }
1290
1291    @Override
1292    protected void refreshInlineTagPosition(int previousPosition) {
1293        if (this.astPtr != -1) {
1294            TagElement previousTag = (TagElement) this.astStack[this.astPtr];
1295            if (this.inlineTagStarted) {
1296                int previousStart = previousTag.getStartPosition();
1297                previousTag.setSourceRange(previousStartpreviousPosition-previousStart+1);
1298                if (previousTag.fragments().size() > 0) {
1299                    ASTNode inlineTag = (ASTNodepreviousTag.fragments().get(previousTag.fragments().size()-1);
1300                    if (inlineTag.getNodeType() == ASTNode.TAG_ELEMENT) {
1301                        int inlineStart = inlineTag.getStartPosition();
1302                        inlineTag.setSourceRange(inlineStartpreviousPosition-inlineStart+1);
1303                    }
1304                }
1305            }
1306        }
1307    }
1308
1309    /*
1310     * Add stored tag elements to associated comment.
1311     */
1312    @Override
1313    protected void updateDocComment() {
1314        for (int idx = 0idx <= this.astPtridx++) {
1315            this.docComment.tags().add(this.astStack[idx]);
1316        }
1317    }
1318
1319    @Override
1320    protected boolean areRegionsClosed() {
1321        // do nothing
1322        return true;
1323    }
1324
1325    @Override
1326    protected void setRegionPosition(int currentPosition) {
1327        // do nothing
1328    }
1329}
1330
MembersX
DocCommentParser:pushParamName
DocCommentParser:pushSnippetText:Block:Block:Block:Block:Block:textVal
DocCommentParser:createFieldReference:Block:Block:fieldRef
DocCommentParser:toString
DocCommentParser:createTypeReference
DocCommentParser:createSnippetRegion
DocCommentParser:parseReturn
DocCommentParser:pushSnippetText:Block:isNotDummyJavaDocRegion
DocCommentParser:pushThrowName:Block:throwsTag
DocCommentParser:createMethodReference:Block:Block:end
DocCommentParser:parseTag:Block:valid
DocCommentParser:createModuleTypeReference
DocCommentParser:createModuleTypeReference:Block:Block:Block:Block:Block:simpleName
DocCommentParser:pushExternalSnippetText:Block:snippetLangHeader
DocCommentParser:createModuleReference:Block:typeRef
DocCommentParser:parseIdentifierTag
DocCommentParser:createModuleReference:Block:identifiers
DocCommentParser:parseTag:Block:token
DocCommentParser:createSnippetTag:Block:Block:previousStart
DocCommentParser:setRegionPosition
DocCommentParser:addSnippetInnerTag:Block:Block:previousTag
DocCommentParser:addSnippetInnerTag:Block:Block:Block:snippetTagElem
DocCommentParser:createTag:Block:position
DocCommentParser:createSnippetTag:Block:start
DocCommentParser:createSnippetRegion:Block:Block:Block:process
DocCommentParser:createSnippetOriginalRegion
DocCommentParser:parse
DocCommentParser:addSnippetInnerTag
DocCommentParser:updateDocComment
DocCommentParser:createModuleTypeReference:Block:Block:Block:Block:Block:s
DocCommentParser:hasRegionEnded
DocCommentParser:createArgumentReference:Block:Block:Block:Block:argArrayType
DocCommentParser:pushText:Block:Block:Block:inlineTag
DocCommentParser:parseTag:Block:length
DocCommentParser:createModuleReference:Block:Block:Block:e
DocCommentParser:pushSeeRef
DocCommentParser:pushSnippetText:Block:Block:curStart
DocCommentParser:refreshInlineTagPosition:Block:Block:Block:Block:inlineTag
DocCommentParser:createArgumentReference:Block:Block:argument
DocCommentParser:createFieldReference:Block:Block:fieldName
DocCommentParser:createSnippetRegion:Block:Block:Block:Block:snippet
DocCommentParser:createModuleTypeReference:Block:moduleRef
DocCommentParser:createModuleTypeReference:Block:Block:Block:start
DocCommentParser:createModuleTypeReference:Block:Block:identifiers
DocCommentParser:pushSnippetText:Block:Block:Block:lastFragment
DocCommentParser:pushExternalSnippetText:Block:previousTag
DocCommentParser:createModuleReference:Block:Block:Block:s
DocCommentParser:createSnippetOriginalRegion:Block:Block:end
DocCommentParser:createArgumentReference:Block:Block:argEnd
DocCommentParser:createTag:Block:Block:previousStart
DocCommentParser:pushParamName:Block:name
DocCommentParser:pushSnippetText:Block:finEnd
DocCommentParser:createModuleTypeReference:Block:size
DocCommentParser:isRegionToBeEnded:Block:Block:value
DocCommentParser:createTypeReference:Block:Block:Block:simpleName
DocCommentParser:createTypeReference:Block:size
DocCommentParser:hasRegionEnded:Block:ended
DocCommentParser:createSnippetRegion:Block:Block:Block:Block:prevTag
DocCommentParser:addSnippetInnerTag:Block:Block:tagElement
DocCommentParser:addSnippetInnerTag:Block:Block:Block:Block:Block:Block:reg
DocCommentParser:createTypeReference:Block:typeRef
DocCommentParser:pushSeeRef:Block:Block:previousStart
DocCommentParser:addSnippetInnerTag:Block:Block:Block:fragments
DocCommentParser:parseTag:Block:Block:Block:ident
DocCommentParser:createModuleReference:Block:Block:Block:simpleName
DocCommentParser:createSnippetRegion:Block:Block:Block:Block:tagStart
DocCommentParser:createModuleTypeReference:Block:Block:Block:Block:Block:e
DocCommentParser:pushSnippetText:Block:iindex
DocCommentParser:closeJavaDocRegion
DocCommentParser:refreshInlineTagPosition:Block:Block:Block:Block:Block:inlineStart
DocCommentParser:createArgumentReference:Block:Block:Block:Block:Block:dimEnd
DocCommentParser:isRegionToBeEnded
DocCommentParser:addSnippetInnerTag:Block:Block:Block:Block:itr
DocCommentParser:createArgumentReference:Block:Block:Block:Block:Block:dimension
DocCommentParser:pushParamName:Block:idIndex
DocCommentParser:pushExternalSnippetText
DocCommentParser:createSnippetTag:Block:tagName
DocCommentParser:addSnippetInnerTag:Block:Block:Block:Block:Block:lastFragment
DocCommentParser:createSnippetRegion:Block:Block:Block:Block:reg
DocCommentParser:createTypeReference:Block:start
DocCommentParser:pushExternalSnippetText:Block:previousStart
DocCommentParser:createTag:Block:Block:previousTag
DocCommentParser:pushSnippetText:Block:Block:size
DocCommentParser:setSnippetIsValid
DocCommentParser:addSnippetInnerTag:Block:Block:Block:Block:Block:tag
DocCommentParser:createMethodReference
DocCommentParser:pushSnippetText:Block:textToBeAdded
DocCommentParser:createSnippetRegion:Block:Block:Block:Block:tagElem
DocCommentParser:createTag:Block:start
DocCommentParser:createSnippetOriginalRegion:Block:Block:start
DocCommentParser:pushParamName:Block:paramTag
DocCommentParser:refreshInlineTagPosition:Block:Block:Block:previousStart
DocCommentParser:createArgumentReference:Block:Block:Block:argTypeName
DocCommentParser:closeJavaDocRegion:Block:Block:Block:start
DocCommentParser:setRegionEnded
DocCommentParser:createTypeReference:Block:Block:Block:e
DocCommentParser:createModuleReference:Block:Block:name
DocCommentParser:pushSnippetText:Block:text
DocCommentParser:createTypeReference:Block:Block:Block:s
DocCommentParser:createTypeReference:Block:identifiers
DocCommentParser:closeJavaDocRegion:Block:Block:Block:curEnd
DocCommentParser:pushThrowName
DocCommentParser:createMethodReference:Block:Block:Block:parameters
DocCommentParser:addTagProperties
DocCommentParser:pushParamName:Block:Block:txtEnd
DocCommentParser:createSnippetOriginalRegion:Block:Block:Block:Block:tagStart
DocCommentParser:createTag:Block:tagName
DocCommentParser:pushSnippetText
DocCommentParser:createTag:Block:tagElement
DocCommentParser:addSnippetInnerTag:Block:Block:region
DocCommentParser:pushSeeRef:Block:end
DocCommentParser:createMethodReference:Block:Block:Block:Block:param
DocCommentParser:createTypeReference:Block:pos
DocCommentParser:pushExternalSnippetText:Block:curEnd
DocCommentParser:pushSnippetText:Block:previousStart
DocCommentParser:pushParamName:Block:Block:txtStart
DocCommentParser:ast
DocCommentParser:setRegionToBeEnded
DocCommentParser:pushSeeRef:Block:node
DocCommentParser:createTypeReference:Block:Block:nameIndex
DocCommentParser:parseTag:Block:Block:Block:length
DocCommentParser:closeJavaDocRegion:Block:Block:snippet
DocCommentParser:addSnippetInnerTag:Block:isNotDummyRegion
DocCommentParser:closeJavaDocRegion:Block:Block:Block:Block:region
DocCommentParser:createModuleReference:Block:start
DocCommentParser:pushExternalSnippetText:Block:previousEnd
DocCommentParser:isRegionToBeEnded:Block:toBeEnded
DocCommentParser:pushExternalSnippetText:Block:curStart
DocCommentParser:parseTag:Block:tagName
DocCommentParser:hasRegionEnded:Block:Block:value
DocCommentParser:parseTag
DocCommentParser:createSnippetTag:Block:position
DocCommentParser:createModuleTypeReference:Block:Block:Block:Block:end
DocCommentParser:pushText:Block:Block:size
DocCommentParser:pushSnippetText:Block:previousTag
DocCommentParser:pushSnippetText:Block:Block:Block:Block:Block:startPos
DocCommentParser:createSnippetOriginalRegion:Block:region
DocCommentParser:pushSnippetText:Block:prevTag
DocCommentParser:createSnippetRegion:Block:Block:Block:Block:tagEnd
DocCommentParser:createSnippetRegion:Block:Block:Block:Block:Block:region
DocCommentParser:refreshInlineTagPosition
DocCommentParser:createModuleTypeReference:Block:typeRef
DocCommentParser:areRegionsClosed
DocCommentParser:setComment
DocCommentParser:createFieldReference:Block:Block:Block:typeRef
DocCommentParser:createTag
DocCommentParser:createSnippetRegion:Block:Block:Block:Block:snippetTagElem
DocCommentParser:createArgumentReference
DocCommentParser:createSnippetRegion:Block:Block:end
DocCommentParser:docComment
DocCommentParser:createMethodReference:Block:Block:methodName
DocCommentParser:pushSnippetText:Block:Block:finStart
DocCommentParser:createSnippetInnerTag
DocCommentParser:addTagProperties:Block:Block:tagElement
DocCommentParser:createSnippetInnerTag:Block:Block:tagElement
DocCommentParser:pushSeeRef:Block:Block:previousTag
DocCommentParser:pushSnippetText:Block:fragments
DocCommentParser:createMethodReference:Block:Block:Block:typeRef
DocCommentParser:createSnippetTag
DocCommentParser:createSnippetRegion:Block:tagsToBeProcessed
DocCommentParser:createModuleTypeReference:Block:Block:Block:Block:name
DocCommentParser:createModuleTypeReference:Block:Block:Block:Block:nameIndex
DocCommentParser:closeJavaDocRegion:Block:Block:regionToClose
DocCommentParser:createModuleReference:Block:Block:end
DocCommentParser:createModuleReference
DocCommentParser:createArgumentReference:Block:Block:argStart
DocCommentParser:addSnippetInnerTag:Block:Block:Block:Block:size
DocCommentParser:createFieldReference:Block:Block:start
DocCommentParser:pushParamName:Block:Block:text
DocCommentParser:addTagProperties:Block:Block:Block:tagProperty
DocCommentParser:createModuleTypeReference:Block:Block:pos
DocCommentParser:createSnippetOriginalRegion:Block:Block:Block:Block:tagElem
DocCommentParser:createMethodReference:Block:Block:methodRef
DocCommentParser:createModuleReference:Block:Block:nameIndex
DocCommentParser:pushText:Block:fragments
DocCommentParser:pushText:Block:text
DocCommentParser:refreshInlineTagPosition:Block:Block:previousTag
DocCommentParser:closeJavaDocRegion:Block:Block:regions
DocCommentParser:createSnippetRegion:Block:toBeReturned
DocCommentParser:setSnippetError
DocCommentParser:createModuleReference:Block:moduleRef
DocCommentParser:pushExternalSnippetText:Block:snipperLangFooter
DocCommentParser:setSnippetID
DocCommentParser:createFieldReference:Block:Block:end
DocCommentParser:createMethodReference:Block:Block:start
DocCommentParser:pushSnippetText:Block:Block:Block:Block:region
DocCommentParser:pushSeeRef:Block:seeTag
DocCommentParser:pushText:Block:previousStart
DocCommentParser:pushSnippetText:Block:Block:Block:Block:Block:endPos
DocCommentParser:createSnippetOriginalRegion:Block:Block:Block:Block:tagEnd
DocCommentParser:pushText:Block:previousTag
DocCommentParser:pushExternalSnippetText:Block:textElement
DocCommentParser:createModuleTypeReference:Block:Block:moduleIdentifiers
DocCommentParser:pushParamName:Block:nameEnd
DocCommentParser:pushText
DocCommentParser:DocCommentParser
DocCommentParser:createSnippetTag:Block:tagElement
DocCommentParser:pushSnippetText:Block:Block:curEnd
DocCommentParser:createTypeReference:Block:Block:name
DocCommentParser:parseTag:Block:currentPosition
DocCommentParser:toString:Block:buffer
DocCommentParser:createArgumentReference:Block:Block:Block:argName
DocCommentParser:createMethodReference:Block:Block:length
DocCommentParser:createArgumentReference:Block:Block:argType
DocCommentParser:createTypeReference:Block:Block:end
DocCommentParser:createArgumentReference:Block:Block:Block:Block:Block:dimStart
DocCommentParser:createSnippetRegion:Block:Block:start
DocCommentParser:pushParamName:Block:nameStart
DocCommentParser:createArgumentReference:Block:Block:node
DocCommentParser:pushText:Block:Block:Block:lastFragment
DocCommentParser:createArgumentReference:Block:Block:Block:argNameStart
DocCommentParser:createFieldReference
DocCommentParser:createSnippetTag:Block:Block:previousTag
Members
X