cleanup (inspection "Java | Class structure | Utility class is not 'final'")
[idea/community.git] / jps / jps-builders / src / org / jetbrains / jps / builders / java / dependencyView / TypeRepr.java
1 // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package org.jetbrains.jps.builders.java.dependencyView;
3
4 import com.intellij.util.io.DataExternalizer;
5 import com.intellij.util.io.DataInputOutputUtil;
6 import org.jetbrains.annotations.NotNull;
7 import org.jetbrains.jps.builders.storage.BuildDataCorruptedException;
8 import org.jetbrains.org.objectweb.asm.Type;
9
10 import java.io.DataInput;
11 import java.io.DataOutput;
12 import java.io.IOException;
13 import java.util.Collection;
14 import java.util.Set;
15
16 /**
17  * @author: db
18  */
19 public final class TypeRepr {
20   private static final byte PRIMITIVE_TYPE = 0x0;
21   private static final byte CLASS_TYPE = 0x1;
22   private static final byte ARRAY_TYPE = 0x2;
23
24   private TypeRepr() {
25
26   }
27
28   interface AbstractType extends RW.Savable {
29     AbstractType[] EMPTY_TYPE_ARRAY = new AbstractType[0];
30
31     void updateClassUsages(DependencyContext context, int owner, Set<? super UsageRepr.Usage> s);
32     String getDescr(DependencyContext context);
33     @Override
34     void save(DataOutput out);
35   }
36
37   public static class PrimitiveType implements AbstractType {
38     public final int type;
39
40     @Override
41     public String getDescr(final DependencyContext context) {
42       return context.getValue(type);
43     }
44
45     @Override
46     public void updateClassUsages(final DependencyContext context, final int owner, final Set<? super UsageRepr.Usage> s) {
47
48     }
49
50     @Override
51     public void save(final DataOutput out) {
52       try {
53         out.writeByte(PRIMITIVE_TYPE);
54         DataInputOutputUtil.writeINT(out, type);
55       }
56       catch (IOException e) {
57         throw new BuildDataCorruptedException(e);
58       }
59     }
60
61     PrimitiveType(final int type) {
62       this.type = type;
63     }
64
65     PrimitiveType(final DataInput in) {
66       try {
67         type = DataInputOutputUtil.readINT(in);
68       }
69       catch (IOException e) {
70         throw new BuildDataCorruptedException(e);
71       }
72     }
73
74     @Override
75     public boolean equals(Object o) {
76       if (this == o) return true;
77       if (o == null || getClass() != o.getClass()) return false;
78
79       final PrimitiveType that = (PrimitiveType)o;
80
81       return type == that.type;
82     }
83
84     @Override
85     public int hashCode() {
86       return type;
87     }
88   }
89
90   public static class ArrayType implements AbstractType {
91     public final AbstractType elementType;
92
93     public AbstractType getDeepElementType() {
94       AbstractType current = this;
95
96       while (current instanceof ArrayType) {
97         current = ((ArrayType)current).elementType;
98       }
99
100       return current;
101     }
102
103     @Override
104     public String getDescr(final DependencyContext context) {
105       return "[" + elementType.getDescr(context);
106     }
107
108     @Override
109     public void updateClassUsages(final DependencyContext context, final int owner, final Set<? super UsageRepr.Usage> s) {
110       elementType.updateClassUsages(context, owner, s);
111     }
112
113     ArrayType(final AbstractType elementType) {
114       this.elementType = elementType;
115     }
116
117     @Override
118     public boolean equals(Object o) {
119       if (this == o) return true;
120       if (o == null || getClass() != o.getClass()) return false;
121
122       final ArrayType arrayType = (ArrayType)o;
123
124       return elementType.equals(arrayType.elementType);
125     }
126
127     @Override
128     public int hashCode() {
129       return elementType.hashCode();
130     }
131
132     @Override
133     public void save(final DataOutput out) {
134       try {
135         out.writeByte(ARRAY_TYPE);
136         elementType.save(out);
137       }
138       catch (IOException e) {
139         throw new BuildDataCorruptedException(e);
140       }
141     }
142   }
143
144   public static class ClassType implements AbstractType {
145     public static final ClassType[] EMPTY_ARRAY = new ClassType[0];
146     public final int className;
147
148     @Override
149     public String getDescr(final DependencyContext context) {
150       return "L" + context.getValue(className) + ";";
151     }
152
153     @Override
154     public void updateClassUsages(final DependencyContext context, final int owner, final Set<? super UsageRepr.Usage> s) {
155       s.add(UsageRepr.createClassUsage(context, className));
156     }
157
158     ClassType(final int className) {
159       this.className = className;
160     }
161
162     ClassType(final DataInput in) {
163       try {
164         className = DataInputOutputUtil.readINT(in);
165       }
166       catch (IOException e) {
167         throw new BuildDataCorruptedException(e);
168       }
169     }
170
171     @Override
172     public boolean equals(Object o) {
173       if (this == o) return true;
174       if (o == null || getClass() != o.getClass()) return false;
175
176       ClassType type = (ClassType)o;
177
178       if (className != type.className) return false;
179
180       return true;
181     }
182
183     @Override
184     public int hashCode() {
185       return className;
186     }
187
188     @Override
189     public void save(final DataOutput out) {
190       try {
191         out.writeByte(CLASS_TYPE);
192         DataInputOutputUtil.writeINT(out, className);
193       }
194       catch (IOException e) {
195         throw new BuildDataCorruptedException(e);
196       }
197     }
198   }
199
200   public static Collection<AbstractType> createClassType(final DependencyContext context,
201                                                          final String[] args,
202                                                          final Collection<AbstractType> acc) {
203     if (args != null) {
204       for (String a : args) {
205         acc.add(createClassType(context, context.get(a)));
206       }
207     }
208
209     return acc;
210   }
211
212   public static ClassType createClassType(final DependencyContext context, final int s) {
213     return (ClassType)context.getType(new ClassType(s));
214   }
215
216   public static AbstractType getType(final DependencyContext context, final int descr) {
217     return getType(InternedString.create(context, descr));
218   }
219   public static AbstractType getType(final DependencyContext context, final String descr) {
220     return getType(InternedString.create(context, descr));
221   }
222
223   public static AbstractType getType(InternedString descr) {
224     final DependencyContext context = descr.getContext();
225     final Type t = Type.getType(descr.asString());
226
227     switch (t.getSort()) {
228       case Type.OBJECT:
229         return context.getType(new ClassType(context.get(t.getClassName().replace('.', '/'))));
230
231       case Type.ARRAY:
232         return context.getType(new ArrayType(getType(context, t.getElementType())));
233
234       default:
235         return context.getType(new PrimitiveType(descr.asInt()));
236     }
237   }
238
239   public static AbstractType getType(final DependencyContext context, final Type t) {
240     return getType(context, t.getDescriptor());
241   }
242
243   public static AbstractType[] getType(final DependencyContext context, final Type[] t) {
244     if(t.length == 0) return AbstractType.EMPTY_TYPE_ARRAY;
245     final AbstractType[] r = new AbstractType[t.length];
246
247     for (int i = 0; i < r.length; i++) {
248       r[i] = getType(context, t[i]);
249     }
250
251     return r;
252   }
253
254   public static DataExternalizer<ClassType> classTypeExternalizer(final DependencyContext context) {
255     final DataExternalizer<AbstractType> delegate = externalizer(context);
256     return new DataExternalizer<ClassType>() {
257       @Override
258       public void save(@NotNull DataOutput out, ClassType value) throws IOException {
259         delegate.save(out, value);
260       }
261
262       @Override
263       public ClassType read(@NotNull DataInput in) throws IOException {
264         final AbstractType read = delegate.read(in);
265         if (read instanceof ClassType) {
266           return (ClassType)read;
267         }
268         throw new IOException("Expected: "+ ClassType.class.getName() + "; Actual: " + (read == null? "null" : read.getClass().getName()));
269       }
270     };
271   }
272
273   public static DataExternalizer<AbstractType> externalizer(final DependencyContext context) {
274     return new DataExternalizer<AbstractType>() {
275       @Override
276       public void save(@NotNull final DataOutput out, final AbstractType value) throws IOException {
277         value.save(out);
278       }
279
280       @Override
281       public AbstractType read(@NotNull final DataInput in) throws IOException {
282         AbstractType elementType;
283         int level = 0;
284
285         loop:
286         while (true) {
287           final byte tag = in.readByte();
288           switch (tag) {
289             case PRIMITIVE_TYPE:
290               elementType = context.getType(new PrimitiveType(in));
291               break loop;
292
293             case CLASS_TYPE:
294               elementType = context.getType(new ClassType(in));
295               break loop;
296
297             case ARRAY_TYPE:
298               level++;
299               break;
300
301             default :
302               System.out.println("Unknown type!");
303           }
304         }
305
306         for (int i = 0; i < level; i++) {
307           elementType = context.getType(new ArrayType(elementType));
308         }
309
310         return elementType;
311       }
312     };
313   }
314 }