1/*
2 * Copyright 2016, 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
32package org.jf.smalidea.dexlib;
33
34import com.google.common.base.Function;
35import com.google.common.base.Predicate;
36import com.google.common.collect.ImmutableSet;
37import com.google.common.collect.Iterables;
38import com.google.common.collect.Lists;
39import com.intellij.psi.PsiClass;
40import com.intellij.psi.PsiField;
41import com.intellij.psi.PsiMethod;
42import com.intellij.psi.PsiModifierList;
43import org.jf.dexlib2.AccessFlags;
44import org.jf.dexlib2.base.reference.BaseTypeReference;
45import org.jf.dexlib2.iface.Annotation;
46import org.jf.dexlib2.iface.ClassDef;
47import org.jf.dexlib2.iface.Field;
48import org.jf.dexlib2.iface.Method;
49import org.jf.smalidea.util.NameUtils;
50
51import javax.annotation.Nonnull;
52import javax.annotation.Nullable;
53import java.util.Arrays;
54import java.util.List;
55import java.util.Set;
56
57public class SmalideaClassDef extends BaseTypeReference implements ClassDef {
58    private final PsiClass psiClass;
59
60    public SmalideaClassDef(PsiClass psiClass) {
61        this.psiClass = psiClass;
62    }
63
64    @Override public int getAccessFlags() {
65        PsiModifierList modifierList = psiClass.getModifierList();
66        int flags = 0;
67
68        if (modifierList == null) {
69            return flags;
70        }
71
72        if (modifierList.hasModifierProperty("public")) {
73            flags |= AccessFlags.PUBLIC.getValue();
74        }
75
76        if (modifierList.hasModifierProperty("final")) {
77            flags |= AccessFlags.FINAL.getValue();
78        }
79
80        if (modifierList.hasModifierProperty("abstract")) {
81            flags |= AccessFlags.ABSTRACT.getValue();
82        }
83
84        if (psiClass.isInterface()) {
85            flags |= AccessFlags.INTERFACE.getValue();
86        }
87
88        if (psiClass.isEnum()) {
89            flags |= AccessFlags.ENUM.getValue();
90        }
91
92        if (psiClass.isAnnotationType()) {
93            flags |= AccessFlags.ANNOTATION.getValue();
94        }
95
96        return flags;
97    }
98
99    @Nonnull @Override public String getType() {
100        return NameUtils.javaToSmaliType(psiClass);
101    }
102
103    @Nullable @Override public String getSuperclass() {
104        PsiClass superClass = psiClass.getSuperClass();
105        if (superClass == null) {
106            return null;
107        }
108        return NameUtils.javaToSmaliType(superClass);
109    }
110
111    @Nonnull @Override public List<String> getInterfaces() {
112        List<String> interfaceList = Lists.newArrayList();
113        PsiClass[] interfaces = psiClass.getInterfaces();
114        if (interfaces == null) {
115            return interfaceList;
116        }
117
118        for (PsiClass psiClass: interfaces) {
119            interfaceList.add(NameUtils.javaToSmaliType(psiClass));
120        }
121
122        return interfaceList;
123    }
124
125    @Nullable @Override public String getSourceFile() {
126        return null;
127    }
128
129    @Nonnull @Override public Set<? extends Annotation> getAnnotations() {
130        return ImmutableSet.of();
131    }
132
133    @Nonnull @Override public Iterable<? extends Field> getStaticFields() {
134        return Iterables.transform(
135                Iterables.filter(Arrays.asList(psiClass.getFields()), new Predicate<PsiField>() {
136                    @Override public boolean apply(PsiField psiField) {
137                        PsiModifierList modifierList = psiField.getModifierList();
138                        if (modifierList == null) {
139                            return false;
140                        }
141                        return modifierList.hasModifierProperty("static");
142                    }
143                }),
144                new Function<PsiField, Field>() {
145                    @Nullable @Override public Field apply(@Nullable PsiField psiField) {
146                        return new SmalideaField(psiField);
147                    }
148                });
149    }
150
151    @Nonnull @Override public Iterable<? extends Field> getInstanceFields() {
152        return Iterables.transform(
153                Iterables.filter(Arrays.asList(psiClass.getFields()), new Predicate<PsiField>() {
154                    @Override public boolean apply(PsiField psiField) {
155                        PsiModifierList modifierList = psiField.getModifierList();
156                        if (modifierList == null) {
157                            return true;
158                        }
159                        return !modifierList.hasModifierProperty("static");
160                    }
161                }),
162                new Function<PsiField, Field>() {
163                    @Nullable @Override public Field apply(@Nullable PsiField psiField) {
164                        return new SmalideaField(psiField);
165                    }
166                });
167    }
168
169    @Nonnull @Override public Iterable<? extends Field> getFields() {
170        return Iterables.concat(getStaticFields(), getInstanceFields());
171    }
172
173    @Nonnull @Override public Iterable<? extends Method> getDirectMethods() {
174        return Iterables.transform(
175                Iterables.filter(
176                        Iterables.concat(
177                            Arrays.asList(psiClass.getConstructors()),
178                            Arrays.asList(psiClass.getMethods())),
179                        new Predicate<PsiMethod>() {
180                    @Override public boolean apply(PsiMethod psiMethod) {
181                        PsiModifierList modifierList = psiMethod.getModifierList();
182                        return modifierList.hasModifierProperty("static") ||
183                                modifierList.hasModifierProperty("private") ||
184                                modifierList.hasModifierProperty("constructor");
185                    }
186                }),
187                new Function<PsiMethod, Method>() {
188                    @Nullable @Override public Method apply(PsiMethod psiMethod) {
189                        return new SmalideaMethod(psiMethod);
190                    }
191                });
192    }
193
194    @Nonnull @Override public Iterable<? extends Method> getVirtualMethods() {
195        return Iterables.transform(
196                Iterables.filter(Arrays.asList(psiClass.getMethods()), new Predicate<PsiMethod>() {
197                    @Override public boolean apply(PsiMethod psiMethod) {
198                        PsiModifierList modifierList = psiMethod.getModifierList();
199                        return !modifierList.hasModifierProperty("static") &&
200                                !modifierList.hasModifierProperty("private") &&
201                                !modifierList.hasModifierProperty("constructor");
202                    }
203                }),
204                new Function<PsiMethod, Method>() {
205                    @Nullable @Override public Method apply(PsiMethod psiMethod) {
206                        return new SmalideaMethod(psiMethod);
207                    }
208                });
209    }
210
211    @Nonnull @Override public Iterable<? extends Method> getMethods() {
212        return Iterables.concat(getDirectMethods(), getVirtualMethods());
213    }
214}
215