1 /*******************************************************************************
2  * Copyright (c) 2004, 2017 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  *******************************************************************************/
14 package org.eclipse.jdt.internal.core;
15 
16 import org.eclipse.jdt.core.BindingKey;
17 import org.eclipse.jdt.core.ICompilationUnit;
18 import org.eclipse.jdt.core.IField;
19 import org.eclipse.jdt.core.IJavaElement;
20 import org.eclipse.jdt.core.IMember;
21 import org.eclipse.jdt.core.IMethod;
22 import org.eclipse.jdt.core.IModularClassFile;
23 import org.eclipse.jdt.core.IModuleDescription;
24 import org.eclipse.jdt.core.IPackageFragment;
25 import org.eclipse.jdt.core.IType;
26 import org.eclipse.jdt.core.ITypeParameter;
27 import org.eclipse.jdt.core.JavaModelException;
28 import org.eclipse.jdt.core.Signature;
29 import org.eclipse.jdt.core.WorkingCopyOwner;
30 import org.eclipse.jdt.core.compiler.CategorizedProblem;
31 import org.eclipse.jdt.core.compiler.CharOperation;
32 import org.eclipse.jdt.internal.codeassist.ISelectionRequestor;
33 import org.eclipse.jdt.internal.codeassist.SelectionEngine;
34 
35 public abstract class NamedMember extends Member {
36 
37 	/*
38 	 * This element's name, or an empty <code>String</code> if this
39 	 * element does not have a name.
40 	 */
41 	protected String name;
42 
NamedMember(JavaElement parent, String name)43 	public NamedMember(JavaElement parent, String name) {
44 		super(parent);
45 		this.name = name;
46 	}
47 
appendTypeParameters(StringBuffer buffer)48 	private void appendTypeParameters(StringBuffer buffer) throws JavaModelException {
49 		ITypeParameter[] typeParameters = getTypeParameters();
50 		int length = typeParameters.length;
51 		if (length == 0) return;
52 		buffer.append('<');
53 		for (int i = 0; i < length; i++) {
54 			ITypeParameter typeParameter = typeParameters[i];
55 			buffer.append(typeParameter.getElementName());
56 			String[] bounds = typeParameter.getBounds();
57 			int boundsLength = bounds.length;
58 			if (boundsLength > 0) {
59 				buffer.append(" extends "); //$NON-NLS-1$
60 				for (int j = 0; j < boundsLength; j++) {
61 					buffer.append(bounds[j]);
62 					if (j < boundsLength-1)
63 						buffer.append(" & "); //$NON-NLS-1$
64 				}
65 			}
66 			if (i < length-1)
67 				buffer.append(", "); //$NON-NLS-1$
68 		}
69 		buffer.append('>');
70 	}
71 
72 	@Override
getElementName()73 	public String getElementName() {
74 		return this.name;
75 	}
76 
getKey(IField field, boolean forceOpen)77 	protected String getKey(IField field, boolean forceOpen) throws JavaModelException {
78 		StringBuffer key = new StringBuffer();
79 
80 		// declaring class
81 		String declaringKey = getKey((IType) field.getParent(), forceOpen);
82 		key.append(declaringKey);
83 
84 		// field name
85 		key.append('.');
86 		key.append(field.getElementName());
87 
88 		return key.toString();
89 	}
90 
getKey(IMethod method, boolean forceOpen)91 	protected String getKey(IMethod method, boolean forceOpen) throws JavaModelException {
92 		StringBuffer key = new StringBuffer();
93 
94 		// declaring class
95 		String declaringKey = getKey((IType) method.getParent(), forceOpen);
96 		key.append(declaringKey);
97 
98 		// selector
99 		key.append('.');
100 		if (!method.isConstructor()) { // empty selector for ctors, cf. BindingKeyResolver.consumeMethod()
101 			String selector = method.getElementName();
102 			key.append(selector);
103 		}
104 
105 		// type parameters
106 		if (forceOpen) {
107 			ITypeParameter[] typeParameters = method.getTypeParameters();
108 			int length = typeParameters.length;
109 			if (length > 0) {
110 				key.append('<');
111 				for (int i = 0; i < length; i++) {
112 					ITypeParameter typeParameter = typeParameters[i];
113 					String[] bounds = typeParameter.getBounds();
114 					int boundsLength = bounds.length;
115 					char[][] boundSignatures = new char[boundsLength][];
116 					for (int j = 0; j < boundsLength; j++) {
117 						boundSignatures[j] = Signature.createCharArrayTypeSignature(bounds[j].toCharArray(), method.isBinary());
118 						CharOperation.replace(boundSignatures[j], '.', '/');
119 					}
120 					char[] sig = Signature.createTypeParameterSignature(typeParameter.getElementName().toCharArray(), boundSignatures);
121 					key.append(sig);
122 				}
123 				key.append('>');
124 			}
125 		}
126 
127 		// parameters
128 		key.append('(');
129 		String[] parameters = method.getParameterTypes();
130 		for (int i = 0, length = parameters.length; i < length; i++)
131 			key.append(parameters[i].replace('.', '/'));
132 		key.append(')');
133 
134 		// return type
135 		if (forceOpen)
136 			key.append(method.getReturnType().replace('.', '/'));
137 		else
138 			key.append('V');
139 
140 		return key.toString();
141 	}
142 
getKey(IType type, boolean forceOpen)143 	protected String getKey(IType type, boolean forceOpen) throws JavaModelException {
144 		StringBuffer key = new StringBuffer();
145 		key.append('L');
146 		String packageName = type.getPackageFragment().getElementName();
147 		key.append(packageName.replace('.', '/'));
148 		if (packageName.length() > 0)
149 			key.append('/');
150 		String typeQualifiedName = type.getTypeQualifiedName('$');
151 		ICompilationUnit cu = (ICompilationUnit) type.getAncestor(IJavaElement.COMPILATION_UNIT);
152 		if (cu != null) {
153 			String cuName = cu.getElementName();
154 			String mainTypeName = cuName.substring(0, cuName.lastIndexOf('.'));
155 			int end = typeQualifiedName.indexOf('$');
156 			if (end == -1)
157 				end = typeQualifiedName.length();
158 			String topLevelTypeName = typeQualifiedName.substring(0, end);
159 			if (!mainTypeName.equals(topLevelTypeName)) {
160 				key.append(mainTypeName);
161 				key.append('~');
162 			}
163 		}
164 		key.append(typeQualifiedName);
165 		key.append(';');
166 		return key.toString();
167 	}
getKey(IModuleDescription module, boolean forceOpen)168 	protected String getKey(IModuleDescription module, boolean forceOpen) throws JavaModelException {
169 		StringBuffer key = new StringBuffer();
170 		key.append('"');
171 		String modName = module.getElementName();
172 		key.append(modName);
173 		return key.toString();
174 	}
175 
getFullyQualifiedParameterizedName(String fullyQualifiedName, String uniqueKey)176 	protected String getFullyQualifiedParameterizedName(String fullyQualifiedName, String uniqueKey) throws JavaModelException {
177 		String[] typeArguments = new BindingKey(uniqueKey).getTypeArguments();
178 		int length = typeArguments.length;
179 		if (length == 0) return fullyQualifiedName;
180 		StringBuffer buffer = new StringBuffer();
181 		buffer.append(fullyQualifiedName);
182 		buffer.append('<');
183 		for (int i = 0; i < length; i++) {
184 			String typeArgument = typeArguments[i];
185 			buffer.append(Signature.toString(typeArgument));
186 			if (i < length-1)
187 				buffer.append(',');
188 		}
189 		buffer.append('>');
190 		return buffer.toString();
191 	}
192 
getPackageFragment()193 	protected IPackageFragment getPackageFragment() {
194 		return null;
195 	}
196 
getFullyQualifiedName(char enclosingTypeSeparator, boolean showParameters)197 	public String getFullyQualifiedName(char enclosingTypeSeparator, boolean showParameters) throws JavaModelException {
198 		String packageName = getPackageFragment().getElementName();
199 		if (packageName.equals(IPackageFragment.DEFAULT_PACKAGE_NAME)) {
200 			return getTypeQualifiedName(enclosingTypeSeparator, showParameters);
201 		}
202 		return packageName + '.' + getTypeQualifiedName(enclosingTypeSeparator, showParameters);
203 	}
204 
getTypeQualifiedName(char enclosingTypeSeparator, boolean showParameters)205 	public String getTypeQualifiedName(char enclosingTypeSeparator, boolean showParameters) throws JavaModelException {
206 		NamedMember declaringType;
207 		switch (this.parent.getElementType()) {
208 			case IJavaElement.COMPILATION_UNIT:
209 				if (showParameters) {
210 					StringBuffer buffer = new StringBuffer(this.name);
211 					appendTypeParameters(buffer);
212 					return buffer.toString();
213 				}
214 				return this.name;
215 			case IJavaElement.CLASS_FILE:
216 				if (this.parent instanceof IModularClassFile)
217 					return null;
218 				String classFileName = this.parent.getElementName();
219 				String typeName;
220 				if (classFileName.indexOf('$') == -1) {
221 					// top level class file: name of type is same as name of class file
222 					typeName = this.name;
223 				} else {
224 					// anonymous or local class file
225 					typeName = classFileName.substring(0, classFileName.lastIndexOf('.'))/*remove .class*/.replace('$', enclosingTypeSeparator);
226 				}
227 				if (showParameters) {
228 					StringBuffer buffer = new StringBuffer(typeName);
229 					appendTypeParameters(buffer);
230 					return buffer.toString();
231 				}
232 				return typeName;
233 			case IJavaElement.TYPE:
234 				declaringType = (NamedMember) this.parent;
235 				break;
236 			case IJavaElement.FIELD:
237 			case IJavaElement.INITIALIZER:
238 			case IJavaElement.METHOD:
239 				declaringType = (NamedMember) ((IMember) this.parent).getDeclaringType();
240 				break;
241 			default:
242 				return null;
243 		}
244 		StringBuffer buffer = new StringBuffer(declaringType.getTypeQualifiedName(enclosingTypeSeparator, showParameters));
245 		buffer.append(enclosingTypeSeparator);
246 		String simpleName = this.name.length() == 0 ? getOccurrenceCountSignature() : this.name;
247 		buffer.append(simpleName);
248 		if (showParameters) {
249 			appendTypeParameters(buffer);
250 		}
251 		return buffer.toString();
252 	}
253 	/*
254 	 * Returns the String representation of the occurrence count for this element.
255 	 * The occurrence count is a unique number representation to identify the particular element.
256 	 *
257 	 * @return the occurrence count for this element in the form of String
258 	 */
getOccurrenceCountSignature()259 	protected String getOccurrenceCountSignature() {
260 		return Integer.toString(this.occurrenceCount);
261 	}
getTypeParameters()262 	protected ITypeParameter[] getTypeParameters() throws JavaModelException {
263 		return null;
264 	}
265 
266 	/**
267 	 * @see IType#resolveType(String)
268 	 */
resolveType(String typeName)269 	public String[][] resolveType(String typeName) throws JavaModelException {
270 		return resolveType(typeName, DefaultWorkingCopyOwner.PRIMARY);
271 	}
272 
273 	/**
274 	 * @see IType#resolveType(String, WorkingCopyOwner)
275 	 */
resolveType(String typeName, WorkingCopyOwner owner)276 	public String[][] resolveType(String typeName, WorkingCopyOwner owner) throws JavaModelException {
277 		JavaProject project = (JavaProject) getJavaProject();
278 		SearchableEnvironment environment = project.newSearchableNameEnvironment(owner);
279 
280 		class TypeResolveRequestor implements ISelectionRequestor {
281 			String[][] answers = null;
282 			@Override
283 			public void acceptType(char[] packageName, char[] tName, int modifiers, boolean isDeclaration, char[] uniqueKey, int start, int end) {
284 				String[] answer = new String[]  {new String(packageName), new String(tName) };
285 				if (this.answers == null) {
286 					this.answers = new String[][]{ answer };
287 				} else {
288 					// grow
289 					int length = this.answers.length;
290 					System.arraycopy(this.answers, 0, this.answers = new String[length+1][], 0, length);
291 					this.answers[length] = answer;
292 				}
293 			}
294 			@Override
295 			public void acceptError(CategorizedProblem error) {
296 				// ignore
297 			}
298 			@Override
299 			public void acceptField(char[] declaringTypePackageName, char[] declaringTypeName, char[] fieldName, boolean isDeclaration, char[] uniqueKey, int start, int end) {
300 				// ignore
301 			}
302 			@Override
303 			public void acceptMethod(char[] declaringTypePackageName, char[] declaringTypeName, String enclosingDeclaringTypeSignature, char[] selector, char[][] parameterPackageNames, char[][] parameterTypeNames, String[] parameterSignatures, char[][] typeParameterNames, char[][][] typeParameterBoundNames, boolean isConstructor, boolean isDeclaration, char[] uniqueKey, int start, int end) {
304 				// ignore
305 			}
306 			@Override
307 			public void acceptPackage(char[] packageName){
308 				// ignore
309 			}
310 			@Override
311 			public void acceptTypeParameter(char[] declaringTypePackageName, char[] declaringTypeName, char[] typeParameterName, boolean isDeclaration, int start, int end) {
312 				// ignore
313 			}
314 			@Override
315 			public void acceptMethodTypeParameter(char[] declaringTypePackageName, char[] declaringTypeName, char[] selector, int selectorStart, int selcetorEnd, char[] typeParameterName, boolean isDeclaration, int start, int end) {
316 				// ignore
317 			}
318 			@Override
319 			public void acceptModule(char[] moduleName, char[] uniqueKey, int start, int end) {
320 				// ignore
321 			}
322 
323 		}
324 		TypeResolveRequestor requestor = new TypeResolveRequestor();
325 		SelectionEngine engine =
326 			new SelectionEngine(environment, requestor, project.getOptions(true), owner);
327 
328 		engine.selectType(typeName.toCharArray(), (IType) this);
329 		if (NameLookup.VERBOSE) {
330 			System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInSourcePackage: " + environment.nameLookup.timeSpentInSeekTypesInSourcePackage + "ms");  //$NON-NLS-1$ //$NON-NLS-2$
331 			System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInBinaryPackage: " + environment.nameLookup.timeSpentInSeekTypesInBinaryPackage + "ms");  //$NON-NLS-1$ //$NON-NLS-2$
332 		}
333 		return requestor.answers;
334 	}
335 }
336