View | Details | Raw Unified | Return to bug 237241 | Differences between
and this patch

Collapse All | Expand All

(-)model/org/eclipse/jdt/internal/core/JavadocConstants.java (+2 lines)
Lines 14-19 Link Here
14
14
15
	String ANCHOR_PREFIX_END = "\""; //$NON-NLS-1$
15
	String ANCHOR_PREFIX_END = "\""; //$NON-NLS-1$
16
	String ANCHOR_PREFIX_START = "<A NAME=\""; //$NON-NLS-1$
16
	String ANCHOR_PREFIX_START = "<A NAME=\""; //$NON-NLS-1$
17
	int ANCHOR_PREFIX_START_LENGHT = ANCHOR_PREFIX_START.length();
17
	String ANCHOR_SUFFIX = "</A>"; //$NON-NLS-1$
18
	String ANCHOR_SUFFIX = "</A>"; //$NON-NLS-1$
18
	int ANCHOR_SUFFIX_LENGTH = JavadocConstants.ANCHOR_SUFFIX.length();
19
	int ANCHOR_SUFFIX_LENGTH = JavadocConstants.ANCHOR_SUFFIX.length();
19
	String CONSTRUCTOR_DETAIL = "<!-- ========= CONSTRUCTOR DETAIL ======== -->"; //$NON-NLS-1$
20
	String CONSTRUCTOR_DETAIL = "<!-- ========= CONSTRUCTOR DETAIL ======== -->"; //$NON-NLS-1$
Lines 29-34 Link Here
29
	String METHOD_SUMMARY = "<!-- ========== METHOD SUMMARY =========== -->"; //$NON-NLS-1$
30
	String METHOD_SUMMARY = "<!-- ========== METHOD SUMMARY =========== -->"; //$NON-NLS-1$
30
	String NESTED_CLASS_SUMMARY = "<!-- ======== NESTED CLASS SUMMARY ======== -->"; //$NON-NLS-1$
31
	String NESTED_CLASS_SUMMARY = "<!-- ======== NESTED CLASS SUMMARY ======== -->"; //$NON-NLS-1$
31
	String PACKAGE_FILE_NAME = "package-summary.html"; //$NON-NLS-1$
32
	String PACKAGE_FILE_NAME = "package-summary.html"; //$NON-NLS-1$
33
	String SEPARATOR_START = "<!-- ="; //$NON-NLS-1$
32
	String START_OF_CLASS_DATA = "<!-- ======== START OF CLASS DATA ======== -->"; //$NON-NLS-1$
34
	String START_OF_CLASS_DATA = "<!-- ======== START OF CLASS DATA ======== -->"; //$NON-NLS-1$
33
	int START_OF_CLASS_DATA_LENGTH = JavadocConstants.START_OF_CLASS_DATA.length();
35
	int START_OF_CLASS_DATA_LENGTH = JavadocConstants.START_OF_CLASS_DATA.length();
34
}
36
}
(-)model/org/eclipse/jdt/internal/core/BinaryField.java (-19 / +3 lines)
Lines 14-20 Link Here
14
import org.eclipse.jdt.core.Flags;
14
import org.eclipse.jdt.core.Flags;
15
import org.eclipse.jdt.core.IAnnotation;
15
import org.eclipse.jdt.core.IAnnotation;
16
import org.eclipse.jdt.core.IField;
16
import org.eclipse.jdt.core.IField;
17
import org.eclipse.jdt.core.IJavaModelStatusConstants;
18
import org.eclipse.jdt.core.JavaModelException;
17
import org.eclipse.jdt.core.JavaModelException;
19
import org.eclipse.jdt.core.Signature;
18
import org.eclipse.jdt.core.Signature;
20
import org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation;
19
import org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation;
Lines 115-137 Link Here
115
	}
114
	}
116
}
115
}
117
public String getAttachedJavadoc(IProgressMonitor monitor) throws JavaModelException {
116
public String getAttachedJavadoc(IProgressMonitor monitor) throws JavaModelException {
118
	String contents = ((BinaryType) this.getDeclaringType()).getJavadocContents(monitor);
117
	JavadocContents javadocContents = ((BinaryType) this.getDeclaringType()).getJavadocContents(monitor);
119
	if (contents == null) return null;
118
	if (javadocContents == null) return null;
120
	int indexAnchor = contents.indexOf(
119
	return javadocContents.getChildDoc(this);
121
			JavadocConstants.ANCHOR_PREFIX_START + this.getElementName() + JavadocConstants.ANCHOR_PREFIX_END);
122
	if (indexAnchor == -1) throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.UNKNOWN_JAVADOC_FORMAT, this));
123
	int indexOfEndLink = contents.indexOf(JavadocConstants.ANCHOR_SUFFIX, indexAnchor);
124
	if (indexOfEndLink == -1) throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.UNKNOWN_JAVADOC_FORMAT, this));
125
	int indexOfNextField = contents.indexOf(JavadocConstants.ANCHOR_PREFIX_START, indexOfEndLink);
126
	int indexOfBottom = contents.indexOf(JavadocConstants.CONSTRUCTOR_DETAIL, indexOfEndLink);
127
	if (indexOfBottom == -1) {
128
		indexOfBottom = contents.indexOf(JavadocConstants.METHOD_DETAIL, indexOfEndLink);
129
		if (indexOfBottom == -1) {
130
			indexOfBottom = contents.indexOf(JavadocConstants.END_OF_CLASS_DATA, indexOfEndLink);
131
		}
132
	}
133
	indexOfNextField= Math.min(indexOfNextField, indexOfBottom);
134
	if (indexOfNextField == -1) throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.UNKNOWN_JAVADOC_FORMAT, this));
135
	return contents.substring(indexOfEndLink + JavadocConstants.ANCHOR_SUFFIX_LENGTH, indexOfNextField);
136
}
120
}
137
}
121
}
(-)model/org/eclipse/jdt/internal/core/BinaryMethod.java (-97 / +13 lines)
Lines 188-202 Link Here
188
		if ((modifiers & ClassFileConstants.AccSynthetic) != 0) {
188
		if ((modifiers & ClassFileConstants.AccSynthetic) != 0) {
189
			return this.parameterNames = getRawParameterNames(paramCount);
189
			return this.parameterNames = getRawParameterNames(paramCount);
190
		}
190
		}
191
		String javadocContents = null;
191
		JavadocContents javadocContents = null;
192
		IType declaringType = this.getDeclaringType();
192
		IType declaringType = this.getDeclaringType();
193
		PerProjectInfo projectInfo = JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(this.getJavaProject().getProject());
193
		PerProjectInfo projectInfo = JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(this.getJavaProject().getProject());
194
		synchronized (projectInfo.javadocCache) {
194
		synchronized (projectInfo.javadocCache) {
195
			javadocContents = (String) projectInfo.javadocCache.get(declaringType);
195
			javadocContents = (JavadocContents) projectInfo.javadocCache.get(declaringType);
196
			if (javadocContents == null) {
196
			if (javadocContents == null) {
197
				projectInfo.javadocCache.put(declaringType, BinaryType.EMPTY_JAVADOC);
197
				projectInfo.javadocCache.put(declaringType, BinaryType.EMPTY_JAVADOC);
198
			}
198
			}
199
		}
199
		}
200
		
201
		String methodDoc = null;
200
		if (javadocContents == null) {
202
		if (javadocContents == null) {
201
			long timeOut = 50; // default value
203
			long timeOut = 50; // default value
202
			try {
204
			try {
Lines 245-267 Link Here
245
					// ignore
247
					// ignore
246
				}
248
				}
247
			}
249
			}
248
			javadocContents = nameCollector.getJavadoc();
250
			methodDoc = nameCollector.getJavadoc();
249
		} else if (javadocContents != BinaryType.EMPTY_JAVADOC){
251
		} else if (javadocContents != BinaryType.EMPTY_JAVADOC){
250
			// need to extract the part relative to the binary method since javadoc contains the javadoc for the declaring type
252
			// need to extract the part relative to the binary method since javadoc contains the javadoc for the declaring type
251
			try {
253
			try {
252
				javadocContents = extractJavadoc(declaringType, javadocContents);
254
				methodDoc = javadocContents.getChildDoc(this);
253
			} catch(JavaModelException e) {
255
			} catch(JavaModelException e) {
254
				javadocContents = null;
256
				javadocContents = null;
255
			}
257
			}
256
		}
258
		}
257
		if (javadocContents != null && javadocContents != BinaryType.EMPTY_JAVADOC) {
259
		if (methodDoc != null) {
258
			final int indexOfOpenParen = javadocContents.indexOf('(');
260
			final int indexOfOpenParen = methodDoc.indexOf('(');
259
			if (indexOfOpenParen != -1) {
261
			if (indexOfOpenParen != -1) {
260
				final int indexOfClosingParen = javadocContents.indexOf(')', indexOfOpenParen);
262
				final int indexOfClosingParen = methodDoc.indexOf(')', indexOfOpenParen);
261
				if (indexOfClosingParen != -1) {
263
				if (indexOfClosingParen != -1) {
262
					final char[] paramsSource =
264
					final char[] paramsSource =
263
						CharOperation.replace(
265
						CharOperation.replace(
264
							javadocContents.substring(indexOfOpenParen + 1, indexOfClosingParen).toCharArray(),
266
							methodDoc.substring(indexOfOpenParen + 1, indexOfClosingParen).toCharArray(),
265
							"&nbsp;".toCharArray(), //$NON-NLS-1$
267
							"&nbsp;".toCharArray(), //$NON-NLS-1$
266
							new char[] {' '});
268
							new char[] {' '});
267
					final char[][] params = splitParameters(paramsSource, paramCount);
269
					final char[][] params = splitParameters(paramsSource, paramCount);
Lines 553-646 Link Here
553
	}
555
	}
554
}
556
}
555
public String getAttachedJavadoc(IProgressMonitor monitor) throws JavaModelException {
557
public String getAttachedJavadoc(IProgressMonitor monitor) throws JavaModelException {
556
	IType declaringType = this.getDeclaringType();
558
	JavadocContents javadocContents = ((BinaryType) this.getDeclaringType()).getJavadocContents(monitor);
557
559
	if (javadocContents == null) return null;
558
	String contents = ((BinaryType) declaringType).getJavadocContents(monitor);
560
	return javadocContents.getChildDoc(this);
559
	return extractJavadoc(declaringType, contents);
560
}
561
private String extractJavadoc(IType declaringType, String contents) throws JavaModelException {
562
	if (contents == null) return null;
563
564
	String typeQualifiedName = null;
565
	final boolean declaringTypeIsMember = declaringType.isMember();
566
	if (declaringTypeIsMember) {
567
		IType currentType = declaringType;
568
		StringBuffer buffer = new StringBuffer();
569
		while (currentType != null) {
570
			buffer.insert(0, currentType.getElementName());
571
			currentType = currentType.getDeclaringType();
572
			if (currentType != null) {
573
				buffer.insert(0, '.');
574
			}
575
		}
576
		typeQualifiedName = new String(buffer.toString());
577
	} else {
578
		typeQualifiedName = declaringType.getElementName();
579
	}
580
	String methodName = this.getElementName();
581
	if (this.isConstructor()) {
582
		methodName = typeQualifiedName;
583
	}
584
	IBinaryMethod info = (IBinaryMethod) getElementInfo();
585
	char[] genericSignature = info.getGenericSignature();
586
	String anchor = null;
587
	if (genericSignature != null) {
588
		genericSignature = CharOperation.replaceOnCopy(genericSignature, '/', '.');
589
		anchor = Util.toAnchor(genericSignature, methodName, Flags.isVarargs(this.getFlags()));
590
		if (anchor == null) throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.UNKNOWN_JAVADOC_FORMAT, this));
591
	} else {
592
		anchor = Signature.toString(this.getSignature().replace('/', '.'), methodName, null, true, false, Flags.isVarargs(this.getFlags()));
593
	}
594
	if (declaringTypeIsMember) {
595
		int depth = 0;
596
		final String packageFragmentName = declaringType.getPackageFragment().getElementName();
597
		// might need to remove a part of the signature corresponding to the synthetic argument
598
		final IJavaProject javaProject = declaringType.getJavaProject();
599
		char[][] typeNames = CharOperation.splitOn('.', typeQualifiedName.toCharArray());
600
		if (!Flags.isStatic(declaringType.getFlags())) depth++;
601
		StringBuffer typeName = new StringBuffer();
602
		for (int i = 0, max = typeNames.length; i < max; i++) {
603
			if (typeName.length() == 0) {
604
				typeName.append(typeNames[i]);
605
			} else {
606
				typeName.append('.').append(typeNames[i]);
607
			}
608
			IType resolvedType = javaProject.findType(packageFragmentName, String.valueOf(typeName));
609
			if (resolvedType != null && resolvedType.isMember() && !Flags.isStatic(resolvedType.getFlags())) depth++;
610
		}
611
		if (depth != 0) {
612
			int indexOfOpeningParen = anchor.indexOf('(');
613
			if (indexOfOpeningParen == -1) return null;
614
			int index = indexOfOpeningParen;
615
			indexOfOpeningParen++;
616
			for (int i = 0; i < depth; i++) {
617
				int indexOfComma = anchor.indexOf(',', index);
618
				if (indexOfComma != -1) {
619
					index = indexOfComma + 2;
620
				}
621
			}
622
			anchor = anchor.substring(0, indexOfOpeningParen) + anchor.substring(index);
623
		}
624
	}
625
	int indexAnchor = contents.indexOf(JavadocConstants.ANCHOR_PREFIX_START + anchor + JavadocConstants.ANCHOR_PREFIX_END);
626
	if (indexAnchor == -1) {
627
		return null; // method without javadoc
628
	}
629
	int indexOfEndLink = contents.indexOf(JavadocConstants.ANCHOR_SUFFIX, indexAnchor);
630
	if (indexOfEndLink == -1) throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.UNKNOWN_JAVADOC_FORMAT, this));
631
	int indexOfNextMethod = contents.indexOf(JavadocConstants.ANCHOR_PREFIX_START, indexOfEndLink);
632
	// find bottom
633
	int indexOfBottom = -1;
634
	if (this.isConstructor()) {
635
		indexOfBottom = contents.indexOf(JavadocConstants.METHOD_DETAIL, indexOfEndLink);
636
		if (indexOfBottom == -1) {
637
			indexOfBottom = contents.indexOf(JavadocConstants.END_OF_CLASS_DATA, indexOfEndLink);
638
		}
639
	} else {
640
		indexOfBottom = contents.indexOf(JavadocConstants.END_OF_CLASS_DATA, indexOfEndLink);
641
	}
642
	if (indexOfBottom == -1) throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.UNKNOWN_JAVADOC_FORMAT, this));
643
	indexOfNextMethod = indexOfNextMethod == -1 ? indexOfBottom : Math.min(indexOfNextMethod, indexOfBottom);
644
	return contents.substring(indexOfEndLink + JavadocConstants.ANCHOR_SUFFIX_LENGTH, indexOfNextMethod);
645
}
561
}
646
}
562
}
(-)model/org/eclipse/jdt/internal/core/BinaryType.java (-55 / +10 lines)
Lines 45-51 Link Here
45
	private static final IMethod[] NO_METHODS = new IMethod[0];
45
	private static final IMethod[] NO_METHODS = new IMethod[0];
46
	private static final IType[] NO_TYPES = new IType[0];
46
	private static final IType[] NO_TYPES = new IType[0];
47
	private static final IInitializer[] NO_INITIALIZERS = new IInitializer[0];
47
	private static final IInitializer[] NO_INITIALIZERS = new IInitializer[0];
48
	public static final String EMPTY_JAVADOC = org.eclipse.jdt.internal.compiler.util.Util.EMPTY_STRING;
48
	public static final JavadocContents EMPTY_JAVADOC = new JavadocContents(null, org.eclipse.jdt.internal.compiler.util.Util.EMPTY_STRING);
49
	
49
	
50
protected BinaryType(JavaElement parent, String name) {
50
protected BinaryType(JavaElement parent, String name) {
51
	super(parent, name);
51
	super(parent, name);
Lines 968-1028 Link Here
968
		buffer.append("<anonymous>"); //$NON-NLS-1$
968
		buffer.append("<anonymous>"); //$NON-NLS-1$
969
}
969
}
970
public String getAttachedJavadoc(IProgressMonitor monitor) throws JavaModelException {
970
public String getAttachedJavadoc(IProgressMonitor monitor) throws JavaModelException {
971
	final String contents = getJavadocContents(monitor);
971
	JavadocContents javadocContents = getJavadocContents(monitor);
972
	if (contents == null) return null;
972
	if (javadocContents == null) return null;
973
	final int indexOfStartOfClassData = contents.indexOf(JavadocConstants.START_OF_CLASS_DATA);
973
	return javadocContents.getTypeDoc();
974
	if (indexOfStartOfClassData == -1) throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.UNKNOWN_JAVADOC_FORMAT, this));
975
	int indexOfNextSummary = contents.indexOf(JavadocConstants.NESTED_CLASS_SUMMARY);
976
	if (this.isEnum() && indexOfNextSummary == -1) {
977
		// try to find enum constant summary start
978
		indexOfNextSummary = contents.indexOf(JavadocConstants.ENUM_CONSTANT_SUMMARY);
979
	}
980
	if (this.isAnnotation() && indexOfNextSummary == -1) {
981
		// try to find required enum constant summary start
982
		indexOfNextSummary = contents.indexOf(JavadocConstants.ANNOTATION_TYPE_REQUIRED_MEMBER_SUMMARY);
983
		if (indexOfNextSummary == -1) {
984
			// try to find optional enum constant summary start
985
			indexOfNextSummary = contents.indexOf(JavadocConstants.ANNOTATION_TYPE_OPTIONAL_MEMBER_SUMMARY);
986
		}
987
	}
988
	if (indexOfNextSummary == -1) {
989
		// try to find field summary start
990
		indexOfNextSummary = contents.indexOf(JavadocConstants.FIELD_SUMMARY);
991
	}
992
	if (indexOfNextSummary == -1) {
993
		// try to find constructor summary start
994
		indexOfNextSummary = contents.indexOf(JavadocConstants.CONSTRUCTOR_SUMMARY);
995
	}
996
	if (indexOfNextSummary == -1) {
997
		// try to find method summary start
998
		indexOfNextSummary = contents.indexOf(JavadocConstants.METHOD_SUMMARY);
999
	}
1000
	if (indexOfNextSummary == -1) {
1001
		// we take the end of class data
1002
		indexOfNextSummary = contents.indexOf(JavadocConstants.END_OF_CLASS_DATA);
1003
	}
1004
	if (indexOfNextSummary == -1) {
1005
		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.UNKNOWN_JAVADOC_FORMAT, this));
1006
	}
1007
	/*
1008
	 * Check out to cut off the hierarchy see 119844
1009
	 * We remove what the contents between the start of class data and the first <P>
1010
	 */
1011
	int start = indexOfStartOfClassData + JavadocConstants.START_OF_CLASS_DATA_LENGTH;
1012
	int indexOfFirstParagraph = contents.indexOf("<P>", start); //$NON-NLS-1$
1013
	if (indexOfFirstParagraph == -1) {
1014
		indexOfFirstParagraph = contents.indexOf("<p>", start); //$NON-NLS-1$
1015
	}
1016
	if (indexOfFirstParagraph != -1 && indexOfFirstParagraph < indexOfNextSummary) {
1017
		start = indexOfFirstParagraph;
1018
	}	
1019
	return contents.substring(start, indexOfNextSummary);
1020
}
974
}
1021
public String getJavadocContents(IProgressMonitor monitor) throws JavaModelException {
975
public JavadocContents getJavadocContents(IProgressMonitor monitor) throws JavaModelException {
1022
	PerProjectInfo projectInfo = JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(this.getJavaProject().getProject());
976
	PerProjectInfo projectInfo = JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(this.getJavaProject().getProject());
1023
	String cachedJavadoc = null;
977
	JavadocContents cachedJavadoc = null;
1024
	synchronized (projectInfo.javadocCache) {
978
	synchronized (projectInfo.javadocCache) {
1025
		cachedJavadoc = (String) projectInfo.javadocCache.get(this);
979
		cachedJavadoc = (JavadocContents) projectInfo.javadocCache.get(this);
1026
	}
980
	}
1027
	if (cachedJavadoc != null && cachedJavadoc != EMPTY_JAVADOC) {
981
	if (cachedJavadoc != null && cachedJavadoc != EMPTY_JAVADOC) {
1028
		return cachedJavadoc;
982
		return cachedJavadoc;
Lines 1057-1065 Link Here
1057
	
1011
	
1058
	if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
1012
	if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
1059
	final String contents = getURLContents(String.valueOf(pathBuffer));
1013
	final String contents = getURLContents(String.valueOf(pathBuffer));
1014
	JavadocContents javadocContents = new JavadocContents(this, contents);
1060
	synchronized (projectInfo.javadocCache) {
1015
	synchronized (projectInfo.javadocCache) {
1061
		projectInfo.javadocCache.put(this, contents);
1016
		projectInfo.javadocCache.put(this, javadocContents);
1062
	}
1017
	}
1063
	return contents;
1018
	return javadocContents;
1064
}
1019
}
1065
}
1020
}
(-)model/org/eclipse/jdt/internal/core/JavadocContents.java (+335 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 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.core;
12
13
import org.eclipse.jdt.core.Flags;
14
import org.eclipse.jdt.core.IJavaElement;
15
import org.eclipse.jdt.core.IJavaModelStatusConstants;
16
import org.eclipse.jdt.core.IJavaProject;
17
import org.eclipse.jdt.core.IType;
18
import org.eclipse.jdt.core.JavaModelException;
19
import org.eclipse.jdt.core.Signature;
20
import org.eclipse.jdt.core.compiler.CharOperation;
21
import org.eclipse.jdt.internal.compiler.env.IBinaryMethod;
22
import org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToIntArray;
23
import org.eclipse.jdt.internal.core.util.Util;
24
25
public class JavadocContents {
26
	private static final int[] UNKNOWN_FORMAT = new int[0]; 
27
	
28
	private BinaryType type;
29
	private String content;
30
	
31
	private int childrenStart;
32
	
33
	private int[] typeDocRange;
34
	private HashtableOfObjectToIntArray childrenDocRanges;
35
	
36
	public JavadocContents(BinaryType type, String content) {
37
		this.type = type;
38
		this.content = content;
39
	}
40
	
41
	/*
42
	 * Return the full content of the javadoc
43
	 */
44
	public String getContent() {
45
		return this.content;
46
	}
47
	
48
	/*
49
	 * Returns the part of the javadoc that describe the type
50
	 */
51
	public String getTypeDoc() throws JavaModelException {
52
		if (this.content == null) return null;
53
		
54
		synchronized (this) {
55
			if (this.typeDocRange == null) {
56
				this.computeTypeRange();
57
			}
58
		}
59
		
60
		if (typeDocRange != null) {
61
			if (typeDocRange == UNKNOWN_FORMAT) throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.UNKNOWN_JAVADOC_FORMAT, type));
62
			return this.content.substring(typeDocRange[0], typeDocRange[1]);
63
		}
64
		return null;
65
	}
66
	
67
	/*
68
	 * Returns the part of the javadoc that describe a child of the type (field, method)
69
	 */
70
	public String getChildDoc(IJavaElement child) throws JavaModelException {
71
		if (this.content == null) return null;
72
		
73
		synchronized (this) {
74
			if (this.childrenDocRanges == null) {
75
				this.computeChildrenRanges();
76
			}
77
		}
78
		
79
		int[] range = this.childrenDocRanges.get(child);
80
		if (range != null) {
81
			if (range == UNKNOWN_FORMAT) throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.UNKNOWN_JAVADOC_FORMAT, child));
82
			return this.content.substring(range[0], range[1]);
83
		}
84
		return null;
85
	}
86
87
	/*
88
	 * Compute the ranges of the parts of the javadoc that describe each child of the type (fields, methods)
89
	 */
90
	private void computeChildrenRanges() throws JavaModelException {
91
		this.childrenDocRanges = new HashtableOfObjectToIntArray();
92
		
93
		IJavaElement[] children = this.type.getChildren();
94
		
95
		int length = children.length;
96
		if (length > 0) {
97
			String typeQualifiedName = null;
98
			if (type.isMember()) {
99
				IType currentType = type;
100
				StringBuffer buffer = new StringBuffer();
101
				while (currentType != null) {
102
					buffer.insert(0, currentType.getElementName());
103
					currentType = currentType.getDeclaringType();
104
					if (currentType != null) {
105
						buffer.insert(0, '.');
106
					}
107
				}
108
				typeQualifiedName = new String(buffer.toString());
109
			} else {
110
				typeQualifiedName = type.getElementName();
111
			}
112
			
113
			// try to find the next separator part
114
			int lastIndex = content.indexOf(JavadocConstants.SEPARATOR_START, this.childrenStart);
115
			
116
			// try to find constructor detail start
117
			int indexOfConstructorDetails = content.indexOf(JavadocConstants.CONSTRUCTOR_DETAIL, lastIndex);
118
			lastIndex = indexOfConstructorDetails == -1 ? lastIndex : indexOfConstructorDetails;
119
			
120
			// try to find method detail start
121
			int indexOfMethodDetails = content.indexOf(JavadocConstants.METHOD_DETAIL, lastIndex);
122
			lastIndex = indexOfMethodDetails == -1 ? lastIndex : indexOfMethodDetails;
123
			
124
			// we take the end of class data
125
			int indexOfEndOfClassData = content.indexOf(JavadocConstants.END_OF_CLASS_DATA, lastIndex);
126
			
127
			// try to find the field detail end
128
			int indexOfFieldsBottom =
129
				indexOfConstructorDetails != -1 ? indexOfConstructorDetails :
130
					indexOfMethodDetails != -1 ? indexOfMethodDetails:
131
						indexOfEndOfClassData;
132
			
133
			// try to find the constructor detail end
134
			int indexOfConstructorsBottom =
135
				indexOfMethodDetails != -1 ? indexOfMethodDetails:
136
					indexOfEndOfClassData;
137
			
138
			// try to find the method detail end
139
			int indexOfMethodsBottom = indexOfEndOfClassData;
140
			
141
			String[] anchors = new String[length];
142
			int anchorCount = 0;
143
			
144
			// compute the end of the anchor prefix of each children
145
			for (int i = 0; i < length; i++) {
146
				IJavaElement child = children[i];
147
				switch (child.getElementType()) {
148
					case IJavaElement.METHOD:
149
						anchors[anchorCount] = computeMethodAnchorPrefixEnd((BinaryMethod)child, typeQualifiedName);
150
						children[anchorCount] = child;
151
						anchorCount++;
152
						break;
153
					case IJavaElement.FIELD:
154
						anchors[anchorCount] = child.getElementName() + JavadocConstants.ANCHOR_PREFIX_END;
155
						children[anchorCount] = child;
156
						anchorCount++;
157
						break;
158
				}
159
			}
160
			
161
			int fromIndex = 0;
162
			int index;
163
			
164
			// check each anchor in the javadoc
165
			while ((index = content.indexOf(JavadocConstants.ANCHOR_PREFIX_START, fromIndex)) != -1) {
166
				fromIndex = index + 1;
167
				
168
				int anchorEndStart = index + JavadocConstants.ANCHOR_PREFIX_START_LENGHT;
169
				
170
				// check if this anchor is an anchor of a known child
171
				done : for (int i = 0; i < anchorCount; i++) {
172
					String anchor = anchors[i];
173
					IJavaElement child = children[i];
174
					
175
					if (anchor != null && content.startsWith(anchor, anchorEndStart)) {
176
						
177
						// the child corresponding to the anchor is found.
178
						// the anchor is removed from the list of not found anchors
179
						anchors[i] = null;
180
						
181
						// try to find the bottom of the section
182
						int indexOfBottom = -1;
183
						switch (child.getElementType()) {
184
							case IJavaElement.METHOD:
185
								indexOfBottom = ((BinaryMethod)child).isConstructor() ? indexOfConstructorsBottom : indexOfMethodsBottom;
186
								break;
187
							case IJavaElement.FIELD:
188
								indexOfBottom = indexOfFieldsBottom;
189
								break;
190
						}
191
						
192
						if (indexOfBottom != -1) {
193
							// try to find the end of the anchor
194
							int indexOfEndLink = content.indexOf(JavadocConstants.ANCHOR_SUFFIX, anchorEndStart + anchor.length());
195
							if (indexOfEndLink != -1) {
196
								// try to find the next anchor
197
								int indexOfNextElement = content.indexOf(JavadocConstants.ANCHOR_PREFIX_START, indexOfEndLink);
198
								
199
								int javadocStart = indexOfEndLink + JavadocConstants.ANCHOR_SUFFIX_LENGTH;
200
								int javadocEnd = indexOfNextElement == -1 ? indexOfBottom : Math.min(indexOfNextElement, indexOfBottom);
201
								this.childrenDocRanges.put(child, new int[]{javadocStart, javadocEnd});
202
							} else {
203
								// the anchor has no suffix
204
								this.childrenDocRanges.put(child, UNKNOWN_FORMAT);
205
							}
206
						} else {
207
							// the detail section has no bottom
208
							this.childrenDocRanges.put(child, UNKNOWN_FORMAT);
209
						}
210
						break done;
211
					}
212
				}
213
			}
214
		}
215
	}
216
	
217
	private String computeMethodAnchorPrefixEnd(BinaryMethod method, String typeQualifiedName) throws JavaModelException {
218
		String methodName = method.getElementName();
219
		if (method.isConstructor()) {
220
			methodName = typeQualifiedName;
221
		}
222
		IBinaryMethod info = (IBinaryMethod) method.getElementInfo();
223
224
		char[] genericSignature = info.getGenericSignature();
225
		String anchor = null;
226
		if (genericSignature != null) {
227
			genericSignature = CharOperation.replaceOnCopy(genericSignature, '/', '.');
228
			anchor = Util.toAnchor(genericSignature, methodName, Flags.isVarargs(method.getFlags()));
229
			if (anchor == null) throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.UNKNOWN_JAVADOC_FORMAT, method));
230
		} else {
231
			anchor = Signature.toString(method.getSignature().replace('/', '.'), methodName, null, true, false, Flags.isVarargs(method.getFlags()));
232
		}
233
		IType declaringType = this.type;
234
		if (declaringType.isMember()) {
235
			int depth = 0;
236
			final String packageFragmentName = declaringType.getPackageFragment().getElementName();
237
			// might need to remove a part of the signature corresponding to the synthetic argument
238
			final IJavaProject javaProject = declaringType.getJavaProject();
239
			char[][] typeNames = CharOperation.splitOn('.', typeQualifiedName.toCharArray());
240
			if (!Flags.isStatic(declaringType.getFlags())) depth++;
241
			StringBuffer typeName = new StringBuffer();
242
			for (int i = 0, max = typeNames.length; i < max; i++) {
243
				if (typeName.length() == 0) {
244
					typeName.append(typeNames[i]);
245
				} else {
246
					typeName.append('.').append(typeNames[i]);
247
				}
248
				IType resolvedType = javaProject.findType(packageFragmentName, String.valueOf(typeName));
249
				if (resolvedType != null && resolvedType.isMember() && !Flags.isStatic(resolvedType.getFlags())) depth++;
250
			}
251
			if (depth != 0) {
252
				int indexOfOpeningParen = anchor.indexOf('(');
253
				if (indexOfOpeningParen == -1) return null;
254
				int index = indexOfOpeningParen;
255
				indexOfOpeningParen++;
256
				for (int i = 0; i < depth; i++) {
257
					int indexOfComma = anchor.indexOf(',', index);
258
					if (indexOfComma != -1) {
259
						index = indexOfComma + 2;
260
					}
261
				}
262
				anchor = anchor.substring(0, indexOfOpeningParen) + anchor.substring(index);
263
			}
264
		}
265
		return anchor + JavadocConstants.ANCHOR_PREFIX_END;
266
	}
267
	
268
	/*
269
	 * Compute the range of the part of the javadoc that describe the type
270
	 */
271
	private void computeTypeRange() throws JavaModelException {
272
		final int indexOfStartOfClassData = content.indexOf(JavadocConstants.START_OF_CLASS_DATA);
273
		if (indexOfStartOfClassData == -1) {
274
			this.typeDocRange = UNKNOWN_FORMAT;
275
			return;
276
		}
277
		int indexOfNextSeparator = content.indexOf(JavadocConstants.SEPARATOR_START, indexOfStartOfClassData);
278
		if (indexOfNextSeparator == -1) {
279
			this.typeDocRange = UNKNOWN_FORMAT;
280
			return;
281
		}
282
		int indexOfNextSummary = content.indexOf(JavadocConstants.NESTED_CLASS_SUMMARY, indexOfNextSeparator);
283
		if (indexOfNextSummary == -1 && type.isEnum()) {
284
			// try to find enum constant summary start
285
			indexOfNextSummary = content.indexOf(JavadocConstants.ENUM_CONSTANT_SUMMARY, indexOfNextSeparator);
286
		}
287
		if (indexOfNextSummary == -1 && type.isAnnotation()) {
288
			// try to find required enum constant summary start
289
			indexOfNextSummary = content.indexOf(JavadocConstants.ANNOTATION_TYPE_REQUIRED_MEMBER_SUMMARY, indexOfNextSeparator);
290
			if (indexOfNextSummary == -1) {
291
				// try to find optional enum constant summary start
292
				indexOfNextSummary = content.indexOf(JavadocConstants.ANNOTATION_TYPE_OPTIONAL_MEMBER_SUMMARY, indexOfNextSeparator);
293
			}
294
		}
295
		if (indexOfNextSummary == -1) {
296
			// try to find field summary start
297
			indexOfNextSummary = content.indexOf(JavadocConstants.FIELD_SUMMARY, indexOfNextSeparator);
298
		}
299
		if (indexOfNextSummary == -1) {
300
			// try to find constructor summary start
301
			indexOfNextSummary = content.indexOf(JavadocConstants.CONSTRUCTOR_SUMMARY, indexOfNextSeparator);
302
		}
303
		if (indexOfNextSummary == -1) {
304
			// try to find method summary start
305
			indexOfNextSummary = content.indexOf(JavadocConstants.METHOD_SUMMARY, indexOfNextSeparator);
306
		}
307
		
308
		if (indexOfNextSummary == -1) {
309
			// we take the end of class data
310
			indexOfNextSummary = content.indexOf(JavadocConstants.END_OF_CLASS_DATA, indexOfNextSeparator);
311
		} else {
312
			// improve performance of computation of children ranges
313
			this.childrenStart = indexOfNextSummary + 1;
314
		}
315
		
316
		if (indexOfNextSummary == -1) {
317
			this.typeDocRange = UNKNOWN_FORMAT;
318
			return;
319
		}
320
		/*
321
		 * Check out to cut off the hierarchy see 119844
322
		 * We remove what the contents between the start of class data and the first <P>
323
		 */
324
		int start = indexOfStartOfClassData + JavadocConstants.START_OF_CLASS_DATA_LENGTH;
325
		int indexOfFirstParagraph = content.indexOf("<P>", start); //$NON-NLS-1$
326
		if (indexOfFirstParagraph == -1) {
327
			indexOfFirstParagraph = content.indexOf("<p>", start); //$NON-NLS-1$
328
		}
329
		if (indexOfFirstParagraph != -1 && indexOfFirstParagraph < indexOfNextSummary) {
330
			start = indexOfFirstParagraph;
331
		}
332
		
333
		this.typeDocRange = new int[]{start, indexOfNextSummary};
334
	}
335
}

Return to bug 237241