1
3 package jminusminus;
4
5 import java.lang.reflect.Array;
6 import java.lang.reflect.Modifier;
7
8 import java.util.Arrays;
9 import java.util.ArrayList;
10 import java.util.Hashtable;
11
12
24 class Type {
25 private Class<?> classRep;
27
28 private static Hashtable<String, Type> types = new Hashtable<String, Type>();
30
31
34 public final static Type INT = typeFor(int.class);
35
36
39 public final static Type CHAR = typeFor(char.class);
40
41
44 public final static Type BOOLEAN = typeFor(boolean.class);
45
46
49 public final static Type LONG = typeFor(long.class);
50
51
54 public final static Type DOUBLE = typeFor(double.class);
55
56
59 public final static Type BOXED_INT = typeFor(java.lang.Integer.class);
60
61
64 public final static Type BOXED_CHAR = typeFor(java.lang.Character.class);
65
66
69 public final static Type BOXED_BOOLEAN = typeFor(java.lang.Boolean.class);
70
71
74 public final static Type BOXED_LONG = typeFor(java.lang.Long.class);
75
76
79 public final static Type BOXED_DOUBLE = typeFor(java.lang.Double.class);
80
81
84 public final static Type STRING = typeFor(java.lang.String.class);
85
86
89 public final static Type OBJECT = typeFor(java.lang.Object.class);
90
91
94 public final static Type VOID = typeFor(void.class);
95
96
99 public final static Type NULLTYPE = new Type(java.lang.Object.class);
100
101
104 public final static Type ANY = new Type(null);
105
106
109 public final static Type CONSTRUCTOR = new Type(null);
110
111
114 protected Type() {
115 super();
116 }
117
118
125 public static Type typeFor(Class<?> classRep) {
126 if (types.get(descriptorFor(classRep)) == null) {
127 types.put(descriptorFor(classRep), new Type(classRep));
128 }
129 return types.get(descriptorFor(classRep));
130 }
131
132
137 public Class<?> classRep() {
138 return classRep;
139 }
140
141
146 public void setClassRep(Class<?> classRep) {
147 this.classRep = classRep;
148 }
149
150
156 public boolean equals(Type other) {
157 return this.toDescriptor().equals(other.toDescriptor());
158 }
159
160
165 public boolean isArray() {
166 return classRep.isArray();
167 }
168
169
174 public Type componentType() {
175 return typeFor(classRep.getComponentType());
176 }
177
178
183 public Type superClass() {
184 return classRep == null || classRep.getSuperclass() == null ? null :
185 typeFor(classRep.getSuperclass());
186 }
187
188
193 public boolean isPrimitive() {
194 return classRep.isPrimitive();
195 }
196
197
202 public boolean isInterface() {
203 return classRep.isInterface();
204 }
205
206
211 public boolean isReference() {
212 return !isPrimitive();
213 }
214
215
220 public boolean isFinal() {
221 return Modifier.isFinal(classRep.getModifiers());
222 }
223
224
229 public boolean isAbstract() {
230 return Modifier.isAbstract(classRep.getModifiers());
231 }
232
233
239 public boolean isJavaAssignableFrom(Type that) {
240 return this.classRep.isAssignableFrom(that.classRep);
241 }
242
243
254 public ArrayList<Method> abstractMethods() {
255 ArrayList<Method> inheritedAbstractMethods = superClass() == null ? new ArrayList<Method>()
256 : superClass().abstractMethods();
257 ArrayList<Method> abstractMethods = new ArrayList<Method>();
258 ArrayList<Method> declaredConcreteMethods = declaredConcreteMethods();
259 ArrayList<Method> declaredAbstractMethods = declaredAbstractMethods();
260 abstractMethods.addAll(declaredAbstractMethods);
261 for (Method method : inheritedAbstractMethods) {
262 if (!declaredConcreteMethods.contains(method) &&
263 !declaredAbstractMethods.contains(method)) {
264 abstractMethods.add(method);
265 }
266 }
267 return abstractMethods;
268 }
269
270
275 private ArrayList<Method> declaredAbstractMethods() {
276 ArrayList<Method> declaredAbstractMethods = new ArrayList<Method>();
277 for (java.lang.reflect.Method method : classRep.getDeclaredMethods()) {
278 if (Modifier.isAbstract(method.getModifiers())) {
279 declaredAbstractMethods.add(new Method(method));
280 }
281 }
282 return declaredAbstractMethods;
283 }
284
285
290 private ArrayList<Method> declaredConcreteMethods() {
291 ArrayList<Method> declaredConcreteMethods = new ArrayList<Method>();
292 for (java.lang.reflect.Method method : classRep.getDeclaredMethods()) {
293 if (!Modifier.isAbstract(method.getModifiers())) {
294 declaredConcreteMethods.add(new Method(method));
295 }
296 }
297 return declaredConcreteMethods;
298 }
299
300
307 public void mustMatchOneOf(int line, Type... expectedTypes) {
308 if (this == Type.ANY) {
309 return;
310 }
311 for (Type type : expectedTypes) {
312 if (matchesExpected(type)) {
313 return;
314 }
315 }
316 JAST.compilationUnit.reportSemanticError(line,
317 "Type %s doesn't match any of the expected types %s", this,
318 Arrays.toString(expectedTypes));
319 }
320
321
328 public void mustMatchExpected(int line, Type expectedType) {
329 if (!matchesExpected(expectedType)) {
330 JAST.compilationUnit.reportSemanticError(line, "Type %s doesn't match type %s", this,
331 expectedType);
332 }
333 }
334
335
341 public boolean matchesExpected(Type expected) {
342 return this == Type.ANY || expected == Type.ANY ||
343 (this == Type.NULLTYPE && expected.isReference()) || this.equals(expected);
344 }
345
346
353 public static boolean argTypesMatch(Class<?>[] argTypes1, Class<?>[] argTypes2) {
354 if (argTypes1.length != argTypes2.length) {
355 return false;
356 }
357 for (int i = 0; i < argTypes1.length; i++) {
358 if (!Type.descriptorFor(argTypes1[i]).equals(Type.descriptorFor(argTypes2[i]))) {
359 return false;
360 }
361 }
362 return true;
363 }
364
365
370 public String simpleName() {
371 return classRep.getSimpleName();
372 }
373
374
379 public String toString() {
380 return toJava(this.classRep);
381 }
382
383
388 public String toDescriptor() {
389 return descriptorFor(classRep);
390 }
391
392
397 public String jvmName() {
398 return this.isArray() || this.isPrimitive() ?
399 this.toDescriptor() : classRep.getName().replace('.', '/');
400 }
401
402
407 public String packageName() {
408 String name = toString();
409 return name.lastIndexOf('.') == -1 ? "" : name.substring(0, name.lastIndexOf('.') - 1);
410 }
411
412
418 public String argumentTypeForAppend() {
419 return this == Type.STRING || this.isPrimitive() ? toDescriptor() : "Ljava/lang/Object;";
420 }
421
422
429 public Method methodFor(String name, Type[] argTypes) {
430 Class[] classes = new Class[argTypes.length];
431 for (int i = 0; i < argTypes.length; i++) {
432 classes[i] = argTypes[i].classRep;
433 }
434 Class cls = classRep;
435
436 while (cls != null) {
438 java.lang.reflect.Method[] methods = cls.getDeclaredMethods();
439 for (java.lang.reflect.Method method : methods) {
440 if (method.getName().equals(name) && Type.argTypesMatch(classes,
441 method.getParameterTypes())) {
442 return new Method(method);
443 }
444 }
445 cls = cls.getSuperclass();
446 }
447
448 return null;
449 }
450
451
457 public Constructor constructorFor(Type[] argTypes) {
458 Class[] classes = new Class[argTypes.length];
459 for (int i = 0; i < argTypes.length; i++) {
460 classes[i] = argTypes[i].classRep;
461 }
462
463 java.lang.reflect.Constructor[] constructors = classRep.getDeclaredConstructors();
465 for (java.lang.reflect.Constructor constructor : constructors) {
466 if (argTypesMatch(classes, constructor.getParameterTypes())) {
467 return new Constructor(constructor);
468 }
469 }
470
471 return null;
472 }
473
474
480 public Field fieldFor(String name) {
481 Class<?> cls = classRep;
482 while (cls != null) {
483 java.lang.reflect.Field[] fields = cls.getDeclaredFields();
484 for (java.lang.reflect.Field field : fields) {
485 if (field.getName().equals(name)) {
486 return new Field(field);
487 }
488 }
489 cls = cls.getSuperclass();
490 }
491 return null;
492 }
493
494
500 public static String argTypesAsString(Type[] argTypes) {
501 if (argTypes.length == 0) {
502 return "()";
503 } else {
504 String str = "(" + argTypes[0].toString();
505 for (int i = 1; i < argTypes.length; i++) {
506 str += "," + argTypes[i];
507 }
508 str += ")";
509 return str;
510 }
511 }
512
513
520 public boolean checkAccess(int line, Member member) {
521 if (!checkAccess(line, classRep, member.declaringType().classRep)) {
522 return false;
523 }
524 if (member.isPublic()) {
526 return true;
527 }
528 java.lang.Package p1 = classRep.getPackage();
529 java.lang.Package p2 = member.declaringType().classRep.getPackage();
530 if ((p1 == null ? "" : p1.getName()).equals((p2 == null ? "" : p2.getName()))) {
531 return true;
532 }
533 if (member.isProtected()) {
534 if (classRep.getPackage().getName().equals(
535 member.declaringType().classRep.getPackage().getName())
536 || typeFor(member.getClass().getDeclaringClass())
537 .isJavaAssignableFrom(this)) {
538 return true;
539 } else {
540 JAST.compilationUnit.reportSemanticError(line,
541 "The protected member, " + member.name() + ", is not accessible.");
542 return false;
543 }
544 }
545 if (member.isPrivate()) {
546 if (descriptorFor(classRep).equals(
547 descriptorFor(member.member().getDeclaringClass()))) {
548 return true;
549 } else {
550 JAST.compilationUnit.reportSemanticError(line,
551 "The private member, " + member.name() + ", is not accessible.");
552 return false;
553 }
554 }
555
556 if (packageName().equals(member.declaringType().packageName())) {
558 return true;
559 } else {
560 JAST.compilationUnit.reportSemanticError(line, "The member, " + member.name() +
561 ", is not accessible because it's in a different package.");
562 return false;
563 }
564 }
565
566
573 public boolean checkAccess(int line, Type targetType) {
574 if (targetType.isPrimitive()) {
575 return true;
576 }
577 if (targetType.isArray()) {
578 return this.checkAccess(line, targetType.componentType());
579 }
580 return checkAccess(line, classRep, targetType.classRep);
581 }
582
583
593 public static boolean checkAccess(int line, Class referencingType, Class type) {
594 java.lang.Package p1 = referencingType.getPackage();
595 java.lang.Package p2 = type.getPackage();
596 if (Modifier.isPublic(type.getModifiers()) ||
597 (p1 == null ? "" : p1.getName()).equals((p2 == null ? "" : p2.getName()))) {
598 return true;
599 } else {
600 JAST.compilationUnit.reportSemanticError(line, "The type, " + type.getCanonicalName() +
601 ", is not accessible from " + referencingType.getCanonicalName());
602 return false;
603 }
604 }
605
606
612 public Type resolve(Context context) {
613 return this;
614 }
615
616
623 public static String signatureFor(String name, Type[] argTypes) {
624 String signature = name + "(";
625 if (argTypes.length > 0) {
626 signature += argTypes[0].toString();
627 for (int i = 1; i < argTypes.length; i++) {
628 signature += "," + argTypes[i].toString();
629 }
630 }
631 signature += ")";
632 return signature;
633 }
634
635 private Type(Class<?> classRep) {
638 this.classRep = classRep;
639 }
640
641 private static String descriptorFor(Class<?> classRep) {
643 return classRep == null ? "V" : classRep == void.class ? "V"
644 : classRep.isArray() ? "[" + descriptorFor(classRep.getComponentType())
645 : classRep.isPrimitive() ? (classRep == int.class ? "I"
646 : classRep == char.class ? "C"
647 : classRep == boolean.class ? "Z"
648 : classRep == double.class ? "D"
649 : classRep == long.class ? "J" : "?")
650 : "L" + classRep.getName().replace('.', '/') + ";";
651 }
652
653 private static String toJava(Class classRep) {
655 return classRep.isArray() ? toJava(classRep.getComponentType()) + "[]" : classRep.getName();
656 }
657 }
658
659
662 class TypeName extends Type {
663 private int line;
665
666 private String name;
668
669
675 public TypeName(int line, String name) {
676 this.line = line;
677 this.name = name;
678 }
679
680
685 public int line() {
686 return line;
687 }
688
689
692 public String jvmName() {
693 return name.replace('.', '/');
694 }
695
696
699 public String toDescriptor() {
700 return "L" + jvmName() + ";";
701 }
702
703
706 public String toString() {
707 return name;
708 }
709
710
713 public String simpleName() {
714 return name.substring(name.lastIndexOf('.') + 1);
715 }
716
717
720 public Type resolve(Context context) {
721 Type resolvedType = context.lookupType(name);
722 if (resolvedType == null) {
723 try {
725 resolvedType = typeFor(Class.forName(name));
726 context.addType(line, resolvedType);
727 } catch (Exception e) {
728 JAST.compilationUnit.reportSemanticError(line, "Unable to locate %s", name);
729 resolvedType = Type.ANY;
730 }
731 }
732 return resolvedType;
733 }
734 }
735
736
741 class ArrayTypeName extends Type {
742 private Type componentType;
744
745
750 public ArrayTypeName(Type componentType) {
751 this.componentType = componentType;
752 }
753
754
757 public Type componentType() {
758 return componentType;
759 }
760
761
764 public String toDescriptor() {
765 return "[" + componentType.toDescriptor();
766 }
767
768
771 public String toString() {
772 return componentType.toString() + "[]";
773 }
774
775
778 public Type resolve(Context context) {
779 componentType = componentType.resolve(context);
780 Class classRep = Array.newInstance(componentType().classRep(), 0).getClass();
781 return Type.typeFor(classRep);
782 }
783 }
784