| /* |
| * Copyright 2014, Google Inc. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following disclaimer |
| * in the documentation and/or other materials provided with the |
| * distribution. |
| * * Neither the name of Google Inc. nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| package org.jf.smalidea.psi.impl; |
| |
| import com.intellij.lang.ASTNode; |
| import com.intellij.psi.*; |
| import com.intellij.psi.PsiModifier.ModifierConstant; |
| import com.intellij.util.IncorrectOperationException; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| import org.jf.smalidea.psi.SmaliElementTypes; |
| import org.jf.smalidea.psi.iface.SmaliModifierListOwner; |
| import org.jf.smalidea.psi.stub.SmaliMethodParameterStub; |
| import org.jf.smalidea.util.NameUtils; |
| |
| public class SmaliMethodParameter extends SmaliStubBasedPsiElement<SmaliMethodParameterStub> |
| implements PsiParameter, SmaliModifierListOwner { |
| public SmaliMethodParameter(@NotNull SmaliMethodParameterStub stub) { |
| super(stub, SmaliElementTypes.METHOD_PARAMETER); |
| } |
| |
| public SmaliMethodParameter(@NotNull ASTNode node) { |
| super(node); |
| } |
| |
| @NotNull @Override public SmaliModifierList getModifierList() { |
| return getRequiredStubOrPsiChild(SmaliElementTypes.MODIFIER_LIST); |
| } |
| |
| @NotNull @Override public PsiElement getDeclarationScope() { |
| return getParentMethod(); |
| } |
| |
| @Override public boolean isVarArgs() { |
| if (getType().getArrayDimensions() == 0 || !getParentMethod().isVarArgs()) { |
| return false; |
| } |
| |
| SmaliMethodParamList paramList = getStubOrPsiParentOfType(SmaliMethodParamList.class); |
| if (paramList == null) { |
| return false; |
| } |
| SmaliMethodParameter[] parameters = paramList.getParameters(); |
| // is this the last parameter? |
| return parameters[parameters.length-1] == this; |
| } |
| |
| @NotNull @Override public SmaliTypeElement getTypeElement() { |
| SmaliTypeElement typeElement = findChildByClass(SmaliTypeElement.class); |
| assert typeElement != null; |
| return typeElement; |
| } |
| |
| @NotNull @Override public PsiType getType() { |
| SmaliMethodParameterStub stub = getStub(); |
| if (stub != null) { |
| return NameUtils.resolveSmaliToPsiType(this, stub.getSmaliTypeName()); |
| } |
| return getTypeElement().getType(); |
| } |
| |
| @Nullable @Override public PsiExpression getInitializer() { |
| // not applicable |
| return null; |
| } |
| |
| @Override public boolean hasInitializer() { |
| return false; |
| } |
| |
| @Override public void normalizeDeclaration() throws IncorrectOperationException { |
| // not applicable |
| } |
| |
| @Nullable @Override public Object computeConstantValue() { |
| // not applicable |
| return null; |
| } |
| |
| @Nullable @Override public String getName() { |
| SmaliMethodParameterStub stub = getStub(); |
| if (stub != null) { |
| return stub.getName(); |
| } |
| SmaliLocalName name = getNameIdentifier(); |
| if (name == null) { |
| return null; |
| } |
| // TODO: get the actual string value |
| return getNameIdentifier().getText(); |
| } |
| |
| @Nullable @Override public SmaliLocalName getNameIdentifier() { |
| SmaliParameterStatement parameterStatement = findParameterStatement(); |
| if (parameterStatement == null) { |
| return null; |
| } |
| |
| return parameterStatement.getNameIdentifier(); |
| } |
| |
| @Override public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException { |
| // TODO: implement this |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override public boolean hasModifierProperty(@ModifierConstant @NonNls @NotNull String name) { |
| // not applicable |
| return false; |
| } |
| |
| /** |
| * Returns the number of registers required for this parameter. 1 for most types, but 2 for double/long. |
| */ |
| public int getRegisterCount() { |
| PsiType type = getType(); |
| if (type == PsiType.DOUBLE || type == PsiType.LONG) { |
| return 2; |
| } |
| return 1; |
| } |
| |
| @NotNull public SmaliMethod getParentMethod() { |
| SmaliMethod smaliMethod = findStubOrPsiAncestorOfType(SmaliMethod.class); |
| assert smaliMethod != null; |
| return smaliMethod; |
| } |
| |
| /** |
| * Gets the parameter register number of this parameters. This is the number of a pNN style register reference. |
| */ |
| public int getParameterRegisterNumber() { |
| // TODO: it might be a good idea to cache this, or at least do it non-recursively |
| PsiElement prevSibling = getPrevSibling(); |
| if (prevSibling == null) { |
| return getParentMethod().isStatic() ? 0 : 1; |
| } |
| assert prevSibling instanceof SmaliMethodParameter; |
| SmaliMethodParameter prevParam = (SmaliMethodParameter)prevSibling; |
| return prevParam.getParameterRegisterNumber() + prevParam.getRegisterCount(); |
| } |
| |
| /** |
| * Gets the register number of this parameters. This is the number of a rNN style register reference. |
| */ |
| public int getRegisterNumber() { |
| SmaliMethod parentMethod = getParentMethod(); |
| return getParameterRegisterNumber() + parentMethod.getRegisterCount() - |
| parentMethod.getParameterRegisterCount(); |
| } |
| |
| @Nullable |
| private SmaliParameterStatement findParameterStatement() { |
| SmaliMethod parentMethod = getParentMethod(); |
| |
| for (SmaliParameterStatement parameterStatement: parentMethod.getParameterStatements()) { |
| SmaliRegisterReference registerReference = parameterStatement.getParameterRegister(); |
| if (registerReference != null && registerReference.getRegisterNumber() == getRegisterNumber()) { |
| return parameterStatement; |
| } |
| } |
| return null; |
| } |
| |
| @NotNull @Override public SmaliAnnotation[] getAnnotations() { |
| SmaliParameterStatement parameterStatement = findParameterStatement(); |
| if (parameterStatement == null) { |
| return new SmaliAnnotation[0]; |
| } |
| return parameterStatement.getAnnotations(); |
| } |
| |
| @NotNull @Override public SmaliAnnotation[] getApplicableAnnotations() { |
| return getAnnotations(); |
| } |
| |
| @Nullable @Override public SmaliAnnotation findAnnotation(@NotNull @NonNls String qualifiedName) { |
| SmaliParameterStatement parameterStatement = findParameterStatement(); |
| if (parameterStatement == null) { |
| return null; |
| } |
| return parameterStatement.findAnnotation(qualifiedName); |
| } |
| |
| @NotNull @Override public SmaliAnnotation addAnnotation(@NotNull @NonNls String qualifiedName) { |
| SmaliParameterStatement parameterStatement = findParameterStatement(); |
| if (parameterStatement == null) { |
| // TODO: add a parameter statement for this parameter if not found |
| throw new UnsupportedOperationException(); |
| } |
| return parameterStatement.addAnnotation(qualifiedName); |
| } |
| } |