1
3 package jminusminus;
4
5 import java.lang.reflect.Array;
6 import java.lang.reflect.Modifier;
7 import java.util.Arrays;
8 import java.util.ArrayList;
9 import java.util.Hashtable;
10
11
24
25 class Type {
26
27
28 private Class<?> classRep;
29
30
31 private static Hashtable<String, Type> types = new Hashtable<String, Type>();
32
33
34 public final static Type INT = typeFor(int.class);
35
36
37 public final static Type CHAR = typeFor(char.class);
38
39
40 public final static Type BOOLEAN = typeFor(boolean.class);
41
42
43 public final static Type BOXED_INT = typeFor(java.lang.Integer.class);
44
45
46 public final static Type BOXED_CHAR = typeFor(java.lang.Character.class);
47
48
49 public final static Type BOXED_BOOLEAN = typeFor(java.lang.Boolean.class);
50
51
52 public static Type STRING = typeFor(java.lang.String.class);
53
54
55 public static Type OBJECT = typeFor(java.lang.Object.class);
56
57
58 public final static Type VOID = typeFor(void.class);
59
60
61 public final static Type NULLTYPE = new Type(java.lang.Object.class);
62
63
66 public final static Type CONSTRUCTOR = new Type(null);
67
68
69 public final static Type ANY = new Type(null);
70
71
79
80 private Type(Class<?> classRep) {
81 this.classRep = classRep;
82 }
83
84
85
86 protected Type() {
87 super();
88 }
89
90
97
98 public static Type typeFor(Class<?> classRep) {
99 if (types.get(descriptorFor(classRep)) == null) {
100 types.put(descriptorFor(classRep), new Type(classRep));
101 }
102 return types.get(descriptorFor(classRep));
103 }
104
105
111
112 public Class<?> classRep() {
113 return classRep;
114 }
115
116
123
124 public void setClassRep(Class<?> classRep) {
125 this.classRep = classRep;
126 }
127
128
135
136 public boolean equals(Type that) {
137 return this.toDescriptor().equals(that.toDescriptor());
138 }
139
140
145
146 public boolean isArray() {
147 return classRep.isArray();
148 }
149
150
155
156 public Type componentType() {
157 return typeFor(classRep.getComponentType());
158 }
159
160
166
167 public Type superClass() {
168 return classRep == null || classRep.getSuperclass() == null ? null
169 : typeFor(classRep.getSuperclass());
170 }
171
172
177
178 public boolean isPrimitive() {
179 return classRep.isPrimitive();
180 }
181
182
187
188 public boolean isInterface() {
189 return classRep.isInterface();
190 }
191
192
197
198 public boolean isReference() {
199 return !isPrimitive();
200 }
201
202
207
208 public boolean isFinal() {
209 return Modifier.isFinal(classRep.getModifiers());
210 }
211
212
217
218 public boolean isAbstract() {
219 return Modifier.isAbstract(classRep.getModifiers());
220 }
221
222
229
230 public boolean isJavaAssignableFrom(Type that) {
231 return this.classRep.isAssignableFrom(that.classRep);
232 }
233
234
241
242 public ArrayList<Method> abstractMethods() {
243 ArrayList<Method> inheritedAbstractMethods = superClass() == null ? new ArrayList<Method>()
244 : superClass().abstractMethods();
245 ArrayList<Method> abstractMethods = new ArrayList<Method>();
246 ArrayList<Method> declaredConcreteMethods = declaredConcreteMethods();
247 ArrayList<Method> declaredAbstractMethods = declaredAbstractMethods();
248 abstractMethods.addAll(declaredAbstractMethods);
249 for (Method method : inheritedAbstractMethods) {
250 if (!declaredConcreteMethods.contains(method)
251 && !declaredAbstractMethods.contains(method)) {
252 abstractMethods.add(method);
253 }
254 }
255 return abstractMethods;
256 }
257
258
263
264 private ArrayList<Method> declaredAbstractMethods() {
265 ArrayList<Method> declaredAbstractMethods = new ArrayList<Method>();
266 for (java.lang.reflect.Method method : classRep.getDeclaredMethods()) {
267 if (Modifier.isAbstract(method.getModifiers())) {
268 declaredAbstractMethods.add(new Method(method));
269 }
270 }
271 return declaredAbstractMethods;
272 }
273
274
279
280 private ArrayList<Method> declaredConcreteMethods() {
281 ArrayList<Method> declaredConcreteMethods = new ArrayList<Method>();
282 for (java.lang.reflect.Method method : classRep.getDeclaredMethods()) {
283 if (!Modifier.isAbstract(method.getModifiers())) {
284 declaredConcreteMethods.add(new Method(method));
285 }
286 }
287 return declaredConcreteMethods;
288 }
289
290
299
300 public void mustMatchOneOf(int line, Type... expectedTypes) {
301 if (this == Type.ANY)
302 return;
303 for (int i = 0; i < expectedTypes.length; i++) {
304 if (matchesExpected(expectedTypes[i])) {
305 return;
306 }
307 }
308 JAST.compilationUnit.reportSemanticError(line,
309 "Type %s doesn't match any of the expected types %s", this,
310 Arrays.toString(expectedTypes));
311 }
312
313
322
323 public void mustMatchExpected(int line, Type expectedType) {
324 if (!matchesExpected(expectedType)) {
325 JAST.compilationUnit.reportSemanticError(line,
326 "Type %s doesn't match type %s", this, expectedType);
327 }
328 }
329
330
338
339 public boolean matchesExpected(Type expected) {
340 return this == Type.ANY || expected == Type.ANY
341 || (this == Type.NULLTYPE && expected.isReference())
342 || this.equals(expected);
343 }
344
345
356
357 public static boolean argTypesMatch(Class<?>[] argTypes1,
358 Class<?>[] argTypes2) {
359 if (argTypes1.length != argTypes2.length) {
360 return false;
361 }
362 for (int i = 0; i < argTypes1.length; i++) {
363 if (!Type.descriptorFor(argTypes1[i]).equals(
364 Type.descriptorFor(argTypes2[i]))) {
365 return false;
366 }
367 }
368 return true;
369 }
370
371
377
378 public String simpleName() {
379 return classRep.getSimpleName();
380 }
381
382
388
389 public String toString() {
390 return toJava(this.classRep);
391 }
392
393
399
400 public String toDescriptor() {
401 return descriptorFor(classRep);
402 }
403
404
412
413 private static String descriptorFor(Class<?> cls) {
414 return cls == null ? "V" : cls == void.class ? "V"
415 : cls.isArray() ? "[" + descriptorFor(cls.getComponentType())
416 : cls.isPrimitive() ? (cls == int.class ? "I"
417 : cls == char.class ? "C"
418 : cls == boolean.class ? "Z" : "?")
419 : "L" + cls.getName().replace('.', '/') + ";";
420 }
421
422
428
429 public String jvmName() {
430 return this.isArray() || this.isPrimitive() ? this.toDescriptor()
431 : classRep.getName().replace('.', '/');
432 }
433
434
443
444 private static String toJava(Class classRep) {
445 return classRep.isArray() ? toJava(classRep.getComponentType()) + "[]"
446 : classRep.getName();
447 }
448
449
454
455 public String packageName() {
456 String name = toString();
457 return name.lastIndexOf('.') == -1 ? "" : name.substring(0, name
458 .lastIndexOf('.') - 1);
459 }
460
461
467
468 public String argumentTypeForAppend() {
469 return this == Type.STRING || this.isPrimitive() ? toDescriptor()
470 : "Ljava/lang/Object;";
471 }
472
473
485
486 public Method methodFor(String name, Type[] argTypes) {
487 Class[] classes = new Class[argTypes.length];
488 for (int i = 0; i < argTypes.length; i++) {
489 classes[i] = argTypes[i].classRep;
490 }
491 Class cls = classRep;
492
493 while (cls != null) {
495 java.lang.reflect.Method[] methods = cls.getDeclaredMethods();
496 for (java.lang.reflect.Method method : methods) {
497 if (method.getName().equals(name)
498 && Type.argTypesMatch(classes, method
499 .getParameterTypes())) {
500 return new Method(method);
501 }
502 }
503 cls = cls.getSuperclass();
504 }
505 return null;
506 }
507
508
518
519 public Constructor constructorFor(Type[] argTypes) {
520 Class[] classes = new Class[argTypes.length];
521 for (int i = 0; i < argTypes.length; i++) {
522 classes[i] = argTypes[i].classRep;
523 }
524
525 java.lang.reflect.Constructor[] constructors = classRep
527 .getDeclaredConstructors();
528 for (java.lang.reflect.Constructor constructor : constructors) {
529 if (argTypesMatch(classes, constructor.getParameterTypes())) {
530 return new Constructor(constructor);
531 }
532 }
533 return null;
534 }
535
536
543
544 public Field fieldFor(String name) {
545 Class<?> cls = classRep;
546 while (cls != null) {
547 java.lang.reflect.Field[] fields = cls.getDeclaredFields();
548 for (java.lang.reflect.Field field : fields) {
549 if (field.getName().equals(name)) {
550 return new Field(field);
551 }
552 }
553 cls = cls.getSuperclass();
554 }
555 return null;
556 }
557
558
566
567 public static String argTypesAsString(Type[] argTypes) {
568 if (argTypes.length == 0) {
569 return "()";
570 } else {
571 String str = "(" + argTypes[0].toString();
572 for (int i = 1; i < argTypes.length; i++) {
573 str += "," + argTypes[i];
574 }
575 str += ")";
576 return str;
577 }
578 }
579
580
590
591 public boolean checkAccess(int line, Member member) {
592 if (!checkAccess(line, classRep, member.declaringType().classRep)) {
593 return false;
594 }
595
596 if (member.isPublic()) {
598 return true;
599 }
600 java.lang.Package p1 = classRep.getPackage();
601 java.lang.Package p2 = member.declaringType().classRep.getPackage();
602 if ((p1 == null ? "" : p1.getName()).equals((p2 == null ? "" : p2
603 .getName()))) {
604 return true;
605 }
606 if (member.isProtected()) {
607 if (classRep.getPackage().getName().equals(
608 member.declaringType().classRep.getPackage().getName())
609 || typeFor(member.getClass().getDeclaringClass())
610 .isJavaAssignableFrom(this)) {
611 return true;
612 } else {
613 JAST.compilationUnit.reportSemanticError(line,
614 "The protected member, " + member.name()
615 + ", is not accessible.");
616 return false;
617 }
618 }
619 if (member.isPrivate()) {
620 if (descriptorFor(classRep).equals(
621 descriptorFor(member.member().getDeclaringClass()))) {
622 return true;
623 } else {
624 JAST.compilationUnit.reportSemanticError(line,
625 "The private member, " + member.name()
626 + ", is not accessible.");
627 return false;
628 }
629 }
630
631 if (packageName().equals(member.declaringType().packageName())) {
633 return true;
634 } else {
635 JAST.compilationUnit.reportSemanticError(line, "The member, "
636 + member.name()
637 + ", is not accessible because it's in a different "
638 + "package.");
639 return false;
640 }
641 }
642
643
652
653 public boolean checkAccess(int line, Type targetType) {
654 if (targetType.isPrimitive()) {
655 return true;
656 }
657 if (targetType.isArray()) {
658 return this.checkAccess(line, targetType.componentType());
659 }
660 return checkAccess(line, classRep, targetType.classRep);
661 }
662
663
674
675 public static boolean checkAccess(int line, Class referencingType,
676 Class type) {
677 java.lang.Package p1 = referencingType.getPackage();
678 java.lang.Package p2 = type.getPackage();
679 if (Modifier.isPublic(type.getModifiers())
680 || (p1 == null ? "" : p1.getName()).equals((p2 == null ? ""
681 : p2.getName()))) {
682 return true;
683 } else {
684 JAST.compilationUnit.reportSemanticError(line, "The type, "
685 + type.getCanonicalName() + ", is not accessible from "
686 + referencingType.getCanonicalName());
687 return false;
688 }
689 }
690
691
700
701 public Type resolve(Context context) {
702 return this;
703 }
704
705
715
716 public static String signatureFor(String name, Type[] argTypes) {
717 String signature = name + "(";
718 if (argTypes.length > 0) {
719 signature += argTypes[0].toString();
720 for (int i = 1; i < argTypes.length; i++) {
721 signature += "," + argTypes[i].toString();
722 }
723 }
724 signature += ")";
725 return signature;
726 }
727
728 }
729
730
734
735 class TypeName extends Type {
736
737
740 private int line;
741
742
743 private String name;
744
745
754
755 public TypeName(int line, String name) {
756 this.line = line;
757 this.name = name;
758 }
759
760
765
766 public int line() {
767 return line;
768 }
769
770
775
776 public String jvmName() {
777 return name.replace('.', '/');
778 }
779
780
785
786 public String toDescriptor() {
787 return "L" + jvmName() + ";";
788 }
789
790
795
796 public String toString() {
797 return name;
798 }
799
800
805
806 public String simpleName() {
807 return name.substring(name.lastIndexOf('.') + 1);
808 }
809
810
819
820 public Type resolve(Context context) {
821 Type resolvedType = context.lookupType(name);
822 if (resolvedType == null) {
823 try {
825 resolvedType = typeFor(Class.forName(name));
826 context.addType(line, resolvedType);
827 } catch (Exception e) {
831 JAST.compilationUnit.reportSemanticError(line,
832 "Unable to locate a type named %s", name);
833 resolvedType = Type.ANY;
834 }
835 }
836 if (resolvedType != Type.ANY) {
837 Type referencingType = ((JTypeDecl) (context.classContext
838 .definition())).thisType();
839 Type.checkAccess(line, referencingType.classRep(), resolvedType
840 .classRep());
841 }
842 return resolvedType;
843 }
844 }
845
846
851
852 class ArrayTypeName extends Type {
853
854
855 private Type componentType;
856
857
863
864 public ArrayTypeName(Type componentType) {
865 this.componentType = componentType;
866 }
867
868
873
874 public Type componentType() {
875 return componentType;
876 }
877
878
883
884 public String toDescriptor() {
885 return "[" + componentType.toDescriptor();
886 }
887
888
893
894 public String toString() {
895 return componentType.toString() + "[]";
896 }
897
898
905
906 public Type resolve(Context context) {
907 componentType = componentType.resolve(context);
908
909 Class classRep = Array.newInstance(componentType().classRep(), 0)
912 .getClass();
913 return Type.typeFor(classRep);
914 }
915
916 }
917