/******************************************************************************* * Copyright (c) 2015, 2016 Google, Inc and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Stefan Xenos (Google) - Initial implementation *******************************************************************************/ package org.eclipse.jdt.internal.core.nd.java; import java.util.Collections; import java.util.List; import org.eclipse.jdt.internal.core.nd.Nd; import org.eclipse.jdt.internal.core.nd.db.IString; import org.eclipse.jdt.internal.core.nd.field.FieldInt; import org.eclipse.jdt.internal.core.nd.field.FieldList; import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne; import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany; import org.eclipse.jdt.internal.core.nd.field.FieldOneToOne; import org.eclipse.jdt.internal.core.nd.field.FieldShort; import org.eclipse.jdt.internal.core.nd.field.FieldString; import org.eclipse.jdt.internal.core.nd.field.StructDef; import org.eclipse.jdt.internal.core.nd.util.CharArrayUtils; import org.eclipse.jdt.internal.core.util.CharArrayBuffer; public class NdMethod extends NdBinding { public static final FieldString METHOD_NAME; public static final FieldShort METHOD_FLAGS; public static final FieldOneToMany<NdVariable> DECLARED_VARIABLES; public static final FieldList<NdMethodParameter> PARAMETERS; public static final FieldOneToOne<NdConstant> DEFAULT_VALUE; public static final FieldList<NdMethodException> EXCEPTIONS; public static final FieldManyToOne<NdTypeSignature> RETURN_TYPE; public static final FieldOneToOne<NdMethodAnnotationData> ANNOTATION_DATA; public static final FieldInt DECLARATION_POSITION; @SuppressWarnings("hiding") public static final StructDef<NdMethod> type; static { type = StructDef.create(NdMethod.class, NdBinding.type); METHOD_NAME = type.addString(); METHOD_FLAGS = type.addShort(); PARAMETERS = FieldList.create(type, NdMethodParameter.type); DECLARED_VARIABLES = FieldOneToMany.create(type, NdVariable.DECLARING_METHOD); DEFAULT_VALUE = FieldOneToOne.create(type, NdConstant.type, NdConstant.PARENT_METHOD); EXCEPTIONS = FieldList.create(type, NdMethodException.type); RETURN_TYPE = FieldManyToOne.create(type, NdTypeSignature.USED_AS_RETURN_TYPE); ANNOTATION_DATA = FieldOneToOne.create(type, NdMethodAnnotationData.type, NdMethodAnnotationData.METHOD); DECLARATION_POSITION = type.addInt(); type.done(); } public static final byte FLG_GENERIC_SIGNATURE_PRESENT = 0x0001; public static final byte FLG_THROWS_SIGNATURE_PRESENT = 0x0002; public NdMethod(Nd nd, long address) { super(nd, address); } public NdMethodParameter createNewParameter() { return PARAMETERS.append(getNd(), getAddress()); } public void allocateParameters(int numParameters) { PARAMETERS.allocate(this.nd, this.address, numParameters); } public IString getMethodName() { return METHOD_NAME.get(getNd(), this.address); } public void setMethodName(char[] selectorAndDescriptor) { METHOD_NAME.put(getNd(), getAddress(), selectorAndDescriptor); } /** * Returns method parameter names that were not defined by the compiler. */ public char[][] getParameterNames() { List<NdMethodParameter> params = getMethodParameters(); // Use index to count the "real" parameters. int index = 0; char[][] result = new char[params.size()][]; for (int idx = 0; idx < result.length; idx++) { NdMethodParameter param = params.get(idx); if (!param.isCompilerDefined()) { result[index] = param.getName().getChars(); index++; } } return CharArrayUtils.subarray(result, 0, index); } public List<NdMethodParameter> getMethodParameters() { return PARAMETERS.asList(getNd(), this.address); } public List<NdAnnotation> getAnnotations() { NdMethodAnnotationData annotationData = getAnnotationData(); if (annotationData != null) { return annotationData.getAnnotations(); } return Collections.emptyList(); } public void setDefaultValue(NdConstant value) { DEFAULT_VALUE.put(getNd(), this.address, value); } public NdConstant getDefaultValue() { return DEFAULT_VALUE.get(getNd(), this.address); } public void setReturnType(NdTypeSignature createTypeSignature) { RETURN_TYPE.put(getNd(), this.address, createTypeSignature); } public List<NdTypeAnnotation> getTypeAnnotations() { NdMethodAnnotationData annotationData = getAnnotationData(); if (annotationData != null) { return annotationData.getTypeAnnotations(); } return Collections.emptyList(); } public List<NdMethodException> getExceptions() { return EXCEPTIONS.asList(getNd(), this.address); } /** * Returns the return type for this method or null if the method returns void */ public NdTypeSignature getReturnType() { return RETURN_TYPE.get(getNd(), this.address); } public int getFlags() { return METHOD_FLAGS.get(getNd(), this.address); } public boolean hasAllFlags(int flags) { int ourFlags = getFlags(); return (ourFlags & flags) == flags; } public void setFlags(int flags) { METHOD_FLAGS.put(getNd(), this.address, (short) (getFlags() | flags)); } public void setTagBits(long bits) { if (bits != 0) { createAnnotationData().setTagBits(bits); } else { NdMethodAnnotationData annotationData = getAnnotationData(); if (annotationData != null) { annotationData.setTagBits(bits); } } } public long getTagBits() { NdMethodAnnotationData annotations = getAnnotationData(); if (annotations == null) { return 0; } return annotations.getTagBits(); } public String toString() { try { CharArrayBuffer arrayBuffer = new CharArrayBuffer(); arrayBuffer.append(getSelector()); getGenericSignature(arrayBuffer, true); return arrayBuffer.toString(); } catch (RuntimeException e) { // This is called most often from the debugger, so we want to return something meaningful even // if the code is buggy, the database is corrupt, or we don't have a read lock. return super.toString(); } } public char[] getSelector() { IString methodName = METHOD_NAME.get(getNd(), getAddress()); char[] methodNameString = methodName.getChars(); int bracketIndex = CharArrayUtils.indexOf('(', methodNameString); if (bracketIndex == -1) { bracketIndex = methodNameString.length; } return CharArrayUtils.subarray(methodNameString, 0, bracketIndex); } public boolean isConstructor() { return org.eclipse.jdt.internal.compiler.classfmt.JavaBinaryNames.isConstructor(getSelector()); } public boolean isClInit() { return org.eclipse.jdt.internal.compiler.classfmt.JavaBinaryNames.isClinit(getSelector()); } public void getGenericSignature(CharArrayBuffer result, boolean includeExceptions) { NdTypeParameter.getSignature(result, getTypeParameters()); result.append('('); for (NdMethodParameter next : getMethodParameters()) { // Compiler-defined arguments don't show up in the generic signature if (!next.isCompilerDefined()) { next.getType().getSignature(result); } } result.append(')'); NdTypeSignature returnType = getReturnType(); if (returnType == null) { result.append('V'); } else { returnType.getSignature(result); } if (includeExceptions) { List<NdMethodException> exceptions = getExceptions(); for (NdMethodException next : exceptions) { result.append('^'); next.getExceptionType().getSignature(result); } } } /** * Creates the {@link NdMethodAnnotationData} struct for this method if it does not already exist. Returns * the existing or newly-created struct. */ public NdMethodAnnotationData createAnnotationData() { NdMethodAnnotationData result = getAnnotationData(); if (result == null) { result = new NdMethodAnnotationData(this); } return result; } private NdMethodAnnotationData getAnnotationData() { return ANNOTATION_DATA.get(getNd(), getAddress()); } public NdMethodException createException(NdTypeSignature createTypeSignature) { NdMethodException result = EXCEPTIONS.append(getNd(), getAddress()); result.setExceptionType(createTypeSignature); return result; } public void allocateExceptions(int length) { EXCEPTIONS.allocate(this.nd, this.address, length); } public NdAnnotation createAnnotation() { return createAnnotationData().createAnnotation(); } public NdTypeAnnotation createTypeAnnotation() { return createAnnotationData().createTypeAnnotation(); } public void allocateAnnotations(int length) { if (length > 0) { createAnnotationData().allocateAnnotations(length); } } public void allocateTypeAnnotations(int length) { if (length > 0) { createAnnotationData().allocateTypeAnnotations(length); } } public void setDeclarationPosition(int position) { DECLARATION_POSITION.put(getNd(), getAddress(), position); } /** * Returns the unique 0-based position of the method within the class it was * declared in. */ public int getDeclarationPosition() { return DECLARATION_POSITION.get(getNd(), getAddress()); } public char[] getMethodDescriptor() { char[] name = getMethodName().getChars(); int descriptorStart = CharArrayUtils.indexOf('(', name, 0, name.length); return CharArrayUtils.subarray(name, descriptorStart, name.length); } }