001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.core;
011:
012: import java.util.ArrayList;
013: import java.util.HashMap;
014:
015: import org.eclipse.jdt.core.*;
016: import org.eclipse.jdt.core.compiler.CharOperation;
017: import org.eclipse.jdt.core.compiler.IScanner;
018: import org.eclipse.jdt.core.compiler.ITerminalSymbols;
019: import org.eclipse.jdt.core.compiler.InvalidInputException;
020: import org.eclipse.jdt.internal.compiler.impl.Constant;
021: import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
022: import org.eclipse.jdt.internal.core.util.MementoTokenizer;
023:
024: /**
025: * @see IMember
026: */
027:
028: public abstract class Member extends SourceRefElement implements
029: IMember {
030:
031: protected Member(JavaElement parent) {
032: super (parent);
033: }
034:
035: protected static boolean areSimilarMethods(String name1,
036: String[] params1, String name2, String[] params2,
037: String[] simpleNames1) {
038:
039: if (name1.equals(name2)) {
040: int params1Length = params1.length;
041: if (params1Length == params2.length) {
042: for (int i = 0; i < params1Length; i++) {
043: String simpleName1 = simpleNames1 == null ? Signature
044: .getSimpleName(Signature.toString(Signature
045: .getTypeErasure(params1[i])))
046: : simpleNames1[i];
047: String simpleName2 = Signature
048: .getSimpleName(Signature.toString(Signature
049: .getTypeErasure(params2[i])));
050: if (!simpleName1.equals(simpleName2)) {
051: return false;
052: }
053: }
054: return true;
055: }
056: }
057: return false;
058: }
059:
060: /**
061: * Converts a field constant from the compiler's representation
062: * to the Java Model constant representation (Number or String).
063: */
064: protected static Object convertConstant(Constant constant) {
065: if (constant == null)
066: return null;
067: if (constant == Constant.NotAConstant) {
068: return null;
069: }
070: switch (constant.typeID()) {
071: case TypeIds.T_boolean:
072: return constant.booleanValue() ? Boolean.TRUE
073: : Boolean.FALSE;
074: case TypeIds.T_byte:
075: return new Byte(constant.byteValue());
076: case TypeIds.T_char:
077: return new Character(constant.charValue());
078: case TypeIds.T_double:
079: return new Double(constant.doubleValue());
080: case TypeIds.T_float:
081: return new Float(constant.floatValue());
082: case TypeIds.T_int:
083: return new Integer(constant.intValue());
084: case TypeIds.T_long:
085: return new Long(constant.longValue());
086: case TypeIds.T_short:
087: return new Short(constant.shortValue());
088: case TypeIds.T_JavaLangString:
089: return constant.stringValue();
090: default:
091: return null;
092: }
093: }
094:
095: /*
096: * Helper method for SourceType.findMethods and BinaryType.findMethods
097: */
098: public static IMethod[] findMethods(IMethod method,
099: IMethod[] methods) {
100: String elementName = method.getElementName();
101: String[] parameters = method.getParameterTypes();
102: int paramLength = parameters.length;
103: String[] simpleNames = new String[paramLength];
104: for (int i = 0; i < paramLength; i++) {
105: String erasure = Signature.getTypeErasure(parameters[i]);
106: simpleNames[i] = Signature.getSimpleName(Signature
107: .toString(erasure));
108: }
109: ArrayList list = new ArrayList();
110: for (int i = 0, length = methods.length; i < length; i++) {
111: IMethod existingMethod = methods[i];
112: if (areSimilarMethods(elementName, parameters,
113: existingMethod.getElementName(), existingMethod
114: .getParameterTypes(), simpleNames)) {
115: list.add(existingMethod);
116: }
117: }
118: int size = list.size();
119: if (size == 0) {
120: return null;
121: } else {
122: IMethod[] result = new IMethod[size];
123: list.toArray(result);
124: return result;
125: }
126: }
127:
128: public String[] getCategories() throws JavaModelException {
129: IType type = (IType) getAncestor(IJavaElement.TYPE);
130: if (type == null)
131: return CharOperation.NO_STRINGS;
132: if (type.isBinary()) {
133: return CharOperation.NO_STRINGS;
134: } else {
135: SourceTypeElementInfo info = (SourceTypeElementInfo) ((SourceType) type)
136: .getElementInfo();
137: HashMap map = info.getCategories();
138: if (map == null)
139: return CharOperation.NO_STRINGS;
140: String[] categories = (String[]) map.get(this );
141: if (categories == null)
142: return CharOperation.NO_STRINGS;
143: return categories;
144: }
145: }
146:
147: /**
148: * @see IMember
149: */
150: public IClassFile getClassFile() {
151: IJavaElement element = getParent();
152: while (element instanceof IMember) {
153: element = element.getParent();
154: }
155: if (element instanceof IClassFile) {
156: return (IClassFile) element;
157: }
158: return null;
159: }
160:
161: /**
162: * @see IMember
163: */
164: public IType getDeclaringType() {
165: JavaElement parentElement = (JavaElement) getParent();
166: if (parentElement.getElementType() == TYPE) {
167: return (IType) parentElement;
168: }
169: return null;
170: }
171:
172: /**
173: * @see IMember
174: */
175: public int getFlags() throws JavaModelException {
176: MemberElementInfo info = (MemberElementInfo) getElementInfo();
177: return info.getModifiers();
178: }
179:
180: /*
181: * @see JavaElement
182: */
183: public IJavaElement getHandleFromMemento(String token,
184: MementoTokenizer memento, WorkingCopyOwner workingCopyOwner) {
185: switch (token.charAt(0)) {
186: case JEM_COUNT:
187: return getHandleUpdatingCountFromMemento(memento,
188: workingCopyOwner);
189: case JEM_TYPE:
190: String typeName;
191: if (memento.hasMoreTokens()) {
192: typeName = memento.nextToken();
193: char firstChar = typeName.charAt(0);
194: if (firstChar == JEM_FIELD
195: || firstChar == JEM_INITIALIZER
196: || firstChar == JEM_METHOD
197: || firstChar == JEM_TYPE
198: || firstChar == JEM_COUNT) {
199: token = typeName;
200: typeName = ""; //$NON-NLS-1$
201: } else {
202: token = null;
203: }
204: } else {
205: typeName = ""; //$NON-NLS-1$
206: token = null;
207: }
208: JavaElement type = (JavaElement) getType(typeName, 1);
209: if (token == null) {
210: return type.getHandleFromMemento(memento,
211: workingCopyOwner);
212: } else {
213: return type.getHandleFromMemento(token, memento,
214: workingCopyOwner);
215: }
216: case JEM_LOCALVARIABLE:
217: if (!memento.hasMoreTokens())
218: return this ;
219: String varName = memento.nextToken();
220: if (!memento.hasMoreTokens())
221: return this ;
222: memento.nextToken(); // JEM_COUNT
223: if (!memento.hasMoreTokens())
224: return this ;
225: int declarationStart = Integer
226: .parseInt(memento.nextToken());
227: if (!memento.hasMoreTokens())
228: return this ;
229: memento.nextToken(); // JEM_COUNT
230: if (!memento.hasMoreTokens())
231: return this ;
232: int declarationEnd = Integer.parseInt(memento.nextToken());
233: if (!memento.hasMoreTokens())
234: return this ;
235: memento.nextToken(); // JEM_COUNT
236: if (!memento.hasMoreTokens())
237: return this ;
238: int nameStart = Integer.parseInt(memento.nextToken());
239: if (!memento.hasMoreTokens())
240: return this ;
241: memento.nextToken(); // JEM_COUNT
242: if (!memento.hasMoreTokens())
243: return this ;
244: int nameEnd = Integer.parseInt(memento.nextToken());
245: if (!memento.hasMoreTokens())
246: return this ;
247: memento.nextToken(); // JEM_COUNT
248: if (!memento.hasMoreTokens())
249: return this ;
250: String typeSignature = memento.nextToken();
251: return new LocalVariable(this , varName, declarationStart,
252: declarationEnd, nameStart, nameEnd, typeSignature);
253: case JEM_TYPE_PARAMETER:
254: if (!memento.hasMoreTokens())
255: return this ;
256: String typeParameterName = memento.nextToken();
257: JavaElement typeParameter = new TypeParameter(this ,
258: typeParameterName);
259: return typeParameter.getHandleFromMemento(memento,
260: workingCopyOwner);
261: }
262: return null;
263: }
264:
265: /**
266: * @see JavaElement#getHandleMemento()
267: */
268: protected char getHandleMementoDelimiter() {
269: return JavaElement.JEM_TYPE;
270: }
271:
272: /*
273: * Returns the outermost context defining a local element. Per construction, it can only be a
274: * method/field/initializarer member; thus, returns null if this member is already a top-level type or member type.
275: * e.g for X.java/X/Y/foo()/Z/bar()/T, it will return X.java/X/Y/foo()
276: */
277: public Member getOuterMostLocalContext() {
278: IJavaElement current = this ;
279: Member lastLocalContext = null;
280: parentLoop: while (true) {
281: switch (current.getElementType()) {
282: case CLASS_FILE:
283: case COMPILATION_UNIT:
284: break parentLoop; // done recursing
285: case TYPE:
286: // cannot be a local context
287: break;
288: case INITIALIZER:
289: case FIELD:
290: case METHOD:
291: // these elements can define local members
292: lastLocalContext = (Member) current;
293: break;
294: }
295: current = current.getParent();
296: }
297: return lastLocalContext;
298: }
299:
300: public ISourceRange getJavadocRange() throws JavaModelException {
301: ISourceRange range = this .getSourceRange();
302: if (range == null)
303: return null;
304: IBuffer buf = null;
305: if (this .isBinary()) {
306: buf = this .getClassFile().getBuffer();
307: } else {
308: ICompilationUnit compilationUnit = this
309: .getCompilationUnit();
310: if (!compilationUnit.isConsistent()) {
311: return null;
312: }
313: buf = compilationUnit.getBuffer();
314: }
315: final int start = range.getOffset();
316: final int length = range.getLength();
317: if (length > 0 && buf.getChar(start) == '/') {
318: IScanner scanner = ToolFactory.createScanner(true, false,
319: false, false);
320: scanner.setSource(buf.getText(start, length).toCharArray());
321: try {
322: int docOffset = -1;
323: int docEnd = -1;
324:
325: int terminal = scanner.getNextToken();
326: loop: while (true) {
327: switch (terminal) {
328: case ITerminalSymbols.TokenNameCOMMENT_JAVADOC:
329: docOffset = scanner
330: .getCurrentTokenStartPosition();
331: docEnd = scanner.getCurrentTokenEndPosition() + 1;
332: terminal = scanner.getNextToken();
333: break;
334: case ITerminalSymbols.TokenNameCOMMENT_LINE:
335: case ITerminalSymbols.TokenNameCOMMENT_BLOCK:
336: terminal = scanner.getNextToken();
337: continue loop;
338: default:
339: break loop;
340: }
341: }
342: if (docOffset != -1) {
343: return new SourceRange(docOffset + start, docEnd
344: - docOffset + 1);
345: }
346: } catch (InvalidInputException ex) {
347: // try if there is inherited Javadoc
348: }
349: }
350: return null;
351: }
352:
353: /**
354: * @see IMember
355: */
356: public ISourceRange getNameRange() throws JavaModelException {
357: MemberElementInfo info = (MemberElementInfo) getElementInfo();
358: return new SourceRange(info.getNameSourceStart(), info
359: .getNameSourceEnd()
360: - info.getNameSourceStart() + 1);
361: }
362:
363: /**
364: * @see IMember
365: */
366: public IType getType(String typeName, int count) {
367: if (isBinary()) {
368: throw new IllegalArgumentException(
369: "Not a source member " + toStringWithAncestors()); //$NON-NLS-1$
370: } else {
371: SourceType type = new SourceType(this , typeName);
372: type.occurrenceCount = count;
373: return type;
374: }
375: }
376:
377: /**
378: * @see IMember#getTypeRoot()
379: */
380: public ITypeRoot getTypeRoot() {
381: IJavaElement element = getParent();
382: while (element instanceof IMember) {
383: element = element.getParent();
384: }
385: return (ITypeRoot) element;
386: }
387:
388: /**
389: * @see IMember
390: */
391: public boolean isBinary() {
392: return false;
393: }
394:
395: protected boolean isMainMethod(IMethod method)
396: throws JavaModelException {
397: if ("main".equals(method.getElementName()) && Signature.SIG_VOID.equals(method.getReturnType())) { //$NON-NLS-1$
398: int flags = method.getFlags();
399: if (Flags.isStatic(flags) && Flags.isPublic(flags)) {
400: String[] paramTypes = method.getParameterTypes();
401: if (paramTypes.length == 1) {
402: String typeSignature = Signature
403: .toString(paramTypes[0]);
404: return "String[]".equals(Signature.getSimpleName(typeSignature)); //$NON-NLS-1$
405: }
406: }
407: }
408: return false;
409: }
410:
411: /**
412: * @see IJavaElement
413: */
414: public boolean isReadOnly() {
415: return getClassFile() != null;
416: }
417:
418: /**
419: */
420: public String readableName() {
421:
422: IJavaElement declaringType = getDeclaringType();
423: if (declaringType != null) {
424: String declaringName = ((JavaElement) getDeclaringType())
425: .readableName();
426: StringBuffer buffer = new StringBuffer(declaringName);
427: buffer.append('.');
428: buffer.append(this .getElementName());
429: return buffer.toString();
430: } else {
431: return super .readableName();
432: }
433: }
434:
435: /**
436: * Updates the name range for this element.
437: */
438: protected void updateNameRange(int nameStart, int nameEnd) {
439: try {
440: MemberElementInfo info = (MemberElementInfo) getElementInfo();
441: info.setNameSourceStart(nameStart);
442: info.setNameSourceEnd(nameEnd);
443: } catch (JavaModelException npe) {
444: return;
445: }
446: }
447: }
|