1 /* 2 * Copyright 2014, Google Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 package org.jf.smalidea.psi.impl; 33 34 import com.intellij.lang.ASTNode; 35 import com.intellij.openapi.command.WriteCommandAction; 36 import com.intellij.psi.PsiElement; 37 import com.intellij.psi.PsiModifier.ModifierConstant; 38 import com.intellij.psi.PsiModifierList; 39 import com.intellij.psi.PsiModifierListOwner; 40 import com.intellij.psi.StubBasedPsiElement; 41 import com.intellij.psi.impl.source.tree.Factory; 42 import com.intellij.psi.impl.source.tree.TreeElement; 43 import com.intellij.util.IncorrectOperationException; 44 import org.jetbrains.annotations.NonNls; 45 import org.jetbrains.annotations.NotNull; 46 import org.jetbrains.annotations.Nullable; 47 import org.jf.dexlib2.AccessFlags; 48 import org.jf.smalidea.SmaliTokens; 49 import org.jf.smalidea.psi.iface.SmaliModifierListOwner; 50 import org.jf.smalidea.psi.stub.SmaliModifierListStub; 51 import org.jf.smalidea.psi.stub.element.SmaliModifierListElementType; 52 53 import javax.annotation.Nonnull; 54 55 public class SmaliModifierList extends SmaliStubBasedPsiElement<SmaliModifierListStub> 56 implements StubBasedPsiElement<SmaliModifierListStub>, PsiModifierList { SmaliModifierList(@otNull ASTNode node)57 public SmaliModifierList(@NotNull ASTNode node) { 58 super(node); 59 } 60 SmaliModifierList(@otNull SmaliModifierListStub stub)61 public SmaliModifierList(@NotNull SmaliModifierListStub stub) { 62 super(stub, SmaliModifierListElementType.INSTANCE); 63 } 64 getAccessFlags()65 public int getAccessFlags() { 66 SmaliModifierListStub stub = getStub(); 67 if (stub != null) { 68 return stub.getAccessFlags(); 69 } 70 71 int flags = 0; 72 73 for (PsiElement accessSpec: findChildrenByType(SmaliTokens.ACCESS_SPEC)) { 74 AccessFlags flag = AccessFlags.getAccessFlag(accessSpec.getText()); 75 if (flag != null) { 76 flags |= flag.getValue(); 77 } 78 } 79 80 return flags; 81 } 82 hasModifierProperty(@odifierConstant @otNull @onNls String name)83 @Override public boolean hasModifierProperty(@ModifierConstant @NotNull @NonNls String name) { 84 return hasExplicitModifier(name); 85 } 86 hasExplicitModifier(@odifierConstant @otNull @onNls String name)87 @Override public boolean hasExplicitModifier(@ModifierConstant @NotNull @NonNls String name) { 88 SmaliModifierListStub stub = getStub(); 89 if (stub != null) { 90 AccessFlags flag = AccessFlags.getAccessFlag(name); 91 if (flag == null) { 92 return false; 93 } 94 return (stub.getAccessFlags() & flag.getValue()) != 0; 95 } 96 97 for (PsiElement accessSpec: findChildrenByType(SmaliTokens.ACCESS_SPEC)) { 98 if (accessSpec.getText().equals(name)) { 99 return true; 100 } 101 } 102 103 return false; 104 } 105 106 @Override setModifierProperty(@odifierConstant @otNull @onNls String name, boolean addModifier)107 public void setModifierProperty(@ModifierConstant @NotNull @NonNls String name, boolean addModifier) 108 throws IncorrectOperationException { 109 if (addModifier) { 110 111 final TreeElement leaf = Factory.createSingleLeafElement(SmaliTokens.ACCESS_SPEC, name, null, getManager()); 112 113 new WriteCommandAction.Simple(getProject(), getContainingFile()) { 114 @Override protected void run() throws Throwable { 115 addInternal(leaf, leaf, null, null); 116 } 117 }.execute(); 118 } else { 119 final PsiElement accessSpec = getAccessFlagElement(name); 120 if (accessSpec != null) { 121 new WriteCommandAction.Simple(getProject(), getContainingFile()) { 122 @Override protected void run() throws Throwable { 123 accessSpec.delete(); 124 } 125 }.execute(); 126 } 127 } 128 } 129 130 @Override checkSetModifierProperty(@odifierConstant @otNull @onNls String name, boolean addModifier)131 public void checkSetModifierProperty(@ModifierConstant @NotNull @NonNls String name, boolean addModifier) 132 throws IncorrectOperationException { 133 } 134 135 @Nonnull getParentForAnnotations()136 private SmaliModifierListOwner getParentForAnnotations() { 137 SmaliModifierListOwner parent = (SmaliModifierListOwner)getStubOrPsiParentOfType(PsiModifierListOwner.class); 138 assert parent != null; 139 return parent; 140 } 141 getAnnotations()142 @NotNull @Override public SmaliAnnotation[] getAnnotations() { 143 return getParentForAnnotations().getAnnotations(); 144 } 145 getApplicableAnnotations()146 @NotNull @Override public SmaliAnnotation[] getApplicableAnnotations() { 147 return getParentForAnnotations().getApplicableAnnotations(); 148 } 149 findAnnotation(@otNull @onNls String qualifiedName)150 @Nullable @Override public SmaliAnnotation findAnnotation(@NotNull @NonNls String qualifiedName) { 151 return getParentForAnnotations().findAnnotation(qualifiedName); 152 } 153 addAnnotation(@otNull @onNls String qualifiedName)154 @NotNull @Override public SmaliAnnotation addAnnotation(@NotNull @NonNls String qualifiedName) { 155 return getParentForAnnotations().addAnnotation(qualifiedName); 156 } 157 getAccessFlagElement(@otNull String accessFlag)158 @Nullable public PsiElement getAccessFlagElement(@NotNull String accessFlag) { 159 for (PsiElement accessSpec: findChildrenByType(SmaliTokens.ACCESS_SPEC)) { 160 if (accessSpec.getText().equals(accessFlag)) { 161 return accessSpec; 162 } 163 } 164 return null; 165 } 166 } 167