33import java .util .HashMap ;
44import java .util .Map ;
55import java .util .Optional ;
6+
67import javax .annotation .processing .Messager ;
78import javax .tools .Diagnostic .Kind ;
89
1718import com .github .javaparser .resolution .types .ResolvedType ;
1819
1920import io .github .bldl .annotationProcessing .annotations .MyVariance ;
21+ import io .github .bldl .astParsing .AstManipulator ;
2022import io .github .bldl .astParsing .util .ClassData ;
2123import io .github .bldl .graph .ClassHierarchyGraph ;
2224
@@ -25,6 +27,7 @@ public class SubtypingCheckVisitor extends VoidVisitorAdapter<Void> {
2527 private final Messager messager ;
2628 private final ClassData classData ;
2729 private final ClassHierarchyGraph <String > classHierarchy ;
30+ private final String qualifiedClassName ;
2831
2932 public SubtypingCheckVisitor (Map <String , Map <Integer , Type >> methodParams ,
3033 Messager messager ,
@@ -34,6 +37,7 @@ public SubtypingCheckVisitor(Map<String, Map<Integer, Type>> methodParams,
3437 this .messager = messager ;
3538 this .classData = classData ;
3639 this .classHierarchy = classHierarchy ;
40+ qualifiedClassName = AstManipulator .appendPackageDeclaration (classData .packageName (), classData .className ());
3741 }
3842
3943 public void visit (MethodCallExpr methodCall , Void arg ) {
@@ -45,9 +49,11 @@ public void visit(MethodCallExpr methodCall, Void arg) {
4549 ResolvedType argumentType = methodCall .getArgument (i ).calculateResolvedType (),
4650 parameterType = methodParams .get (methodCall .getNameAsString ()).get (i ).resolve ();
4751 boolean valid = isValidSubtype (parameterType , argumentType );
48- if (!valid )
52+ if (!valid ) {
4953 messager .printMessage (Kind .ERROR ,
5054 String .format ("Invalid subtype for method call: %s" , methodCall .toString ()));
55+
56+ }
5157 }
5258 }
5359
@@ -56,11 +62,12 @@ public void visit(AssignExpr assignExpr, Void arg) {
5662 ResolvedType assignedType = assignExpr .getValue ().calculateResolvedType (),
5763 assigneeType = assignExpr .getTarget ().calculateResolvedType ();
5864 boolean valid = isValidSubtype (assigneeType , assignedType );
59- if (!valid )
65+ if (!valid ) {
6066 messager .printMessage (Kind .ERROR ,
6167 String .format ("Invalid subtype for assignment expression call: %s\n %s is not a subtype of %s" ,
6268 assignExpr .toString (),
6369 assignedType .toString (), assigneeType .toString ()));
70+ }
6471 }
6572
6673 public void visit (ForEachStmt n , Void arg ) {
@@ -76,18 +83,26 @@ public void visit(VariableDeclarator declaration, Void arg) {
7683 ResolvedType assignedType = initializer .get ().calculateResolvedType ();
7784 boolean valid = isValidSubtype (assigneeType ,
7885 assignedType );
79- if (!valid )
86+ if (!valid ) {
8087 messager .printMessage (Kind .ERROR ,
8188 String .format ("Invalid subtype for variable declaration: %s\n %s is not a subtype of %s" ,
8289 declaration .toString (),
8390 assignedType .toString (), assigneeType .toString ()));
91+
92+ }
8493 }
8594
8695 private boolean isValidSubtype (ResolvedType aType , ResolvedType assignType ) {
87- if (!aType .isReferenceType () || !assignType .isReferenceType ())
96+ var a = (Boolean .class );
97+ a .getName ();
98+ if (!aType .isReferenceType () || !assignType .isReferenceType ()) {
99+ messager .printMessage (Kind .NOTE ,
100+ aType .toString () + " or " + assignType .toString () + " is not a reference type." );
88101 return true ;
102+ }
89103
90104 ResolvedReferenceType assigneeType = aType .asReferenceType (), assignedType = assignType .asReferenceType ();
105+
91106 if (!classHierarchy .containsVertex (assigneeType .getQualifiedName ())) {
92107 messager .printMessage (Kind .WARNING ,
93108 String .format ("%s is not a user defined type, so no subtyping checks can be made" , assigneeType ));
@@ -98,38 +113,49 @@ private boolean isValidSubtype(ResolvedType aType, ResolvedType assignType) {
98113 String .format ("%s is not a user defined type, so no subtyping checks can be made" , assignedType ));
99114 return true ;
100115 }
101- if (!assigneeType .typeParametersValues ().isEmpty () || !assignedType .typeParametersValues ().isEmpty ())
116+ if (!assigneeType .typeParametersValues ().isEmpty () || !assignedType .typeParametersValues ().isEmpty ()) {
117+ messager .printMessage (Kind .NOTE ,
118+ "NO params for: " + assigneeType .toString () + " or " + assignedType .toString ());
119+ messager .printMessage (Kind .NOTE ,
120+ assigneeType .typeParametersValues ().toString ());
121+ messager .printMessage (Kind .NOTE ,
122+ assignedType .typeParametersValues ().toString ());
102123 return true ;
124+ }
103125
104126 var assigneeArgs = assigneeType .typeParametersValues ();
105127 var assignedArgs = assignedType .typeParametersValues ();
106- boolean isSubtype = true ;
107- // TODO update classData to use qualified name
108- if (assigneeType .getQualifiedName ().equals (classData .className ())) {
128+ boolean isSubtype = classHierarchy .isDescendant (assigneeType .getQualifiedName (),
129+ assignedType .getQualifiedName (), -1 );
130+ if (assigneeType .getQualifiedName ()
131+ .equals (qualifiedClassName )) {
132+ messager .printMessage (Kind .NOTE , "Found matching type for: " + assigneeType .getQualifiedName ());
109133 Map <Integer , MyVariance > paramVariance = new HashMap <>();
110134 for (var param : classData .params ().values ())
111135 paramVariance .put (param .index (), param .variance ());
112136 for (int i = 0 ; i < assigneeArgs .size (); ++i ) {
113- isSubtype = isSubtype && isValidSubtype (assigneeArgs .get (i ), assignedArgs .get (i ));
137+ isSubtype &= isValidSubtype (assigneeArgs .get (i ), assignedArgs .get (i ));
114138 ResolvedType assigneeArgType = assigneeArgs .get (i );
115139 ResolvedType assignedArgType = assignedArgs .get (i );
116140 if (!paramVariance .containsKey (i ) || !assigneeArgType .isReferenceType ()
117- || !assignedArgType .isReferenceType ())
141+ || !assignedArgType .isReferenceType ()) {
142+ isSubtype &= isValidSubtype (assigneeArgs .get (i ), assignedArgs .get (i ));
118143 continue ;
119-
144+ }
145+ isSubtype &= checkRequiredTypes (assignedArgType , paramVariance .get (i ));
120146 switch (paramVariance .get (i ).variance ()) {
121147 case COVARIANT :
122- isSubtype = isSubtype && classHierarchy .isDescendant (
148+ isSubtype &= classHierarchy .isDescendant (
123149 assigneeArgType .asReferenceType ().getQualifiedName (),
124150 assignedArgType .asReferenceType ().getQualifiedName (), paramVariance .get (i ).depth ());
125151 break ;
126152 case CONTRAVARIANT :
127- isSubtype = isSubtype && classHierarchy .isDescendant (
153+ isSubtype &= classHierarchy .isDescendant (
128154 assignedArgType .asReferenceType ().getQualifiedName (),
129155 assigneeArgType .asReferenceType ().getQualifiedName (), paramVariance .get (i ).depth ());
130156 break ;
131157 case BIVARIANT :
132- isSubtype = isSubtype && classHierarchy .isDescendant (
158+ isSubtype &= classHierarchy .isDescendant (
133159 assigneeArgType .asReferenceType ().getQualifiedName (),
134160 assignedArgType .asReferenceType ().getQualifiedName (), paramVariance .get (i ).depth ())
135161 || classHierarchy .isDescendant (
@@ -138,20 +164,39 @@ private boolean isValidSubtype(ResolvedType aType, ResolvedType assignType) {
138164 paramVariance .get (i ).depth ());
139165 break ;
140166 case SIDEVARIANT :
141- isSubtype = isSubtype && classHierarchy .sameLevel (
167+ isSubtype &= classHierarchy .sameLevel (
142168 assignedArgType .asReferenceType ().getQualifiedName (),
143169 assigneeArgType .asReferenceType ().getQualifiedName ());
144170 break ;
145171 default :
146- return true ;
172+ break ;
147173 }
148174 }
149175 return isSubtype ;
150176 }
151177
152178 for (int i = 0 ; i < assigneeArgs .size (); ++i )
153- isSubtype = isSubtype && isValidSubtype (assigneeArgs .get (i ), assignedArgs .get (i ));
154- return classHierarchy .isDescendant (assigneeType .getQualifiedName (),
155- assignedType .getQualifiedName (), -1 );
179+ isSubtype &= isValidSubtype (assigneeArgs .get (i ), assignedArgs .get (i ));
180+
181+ return isSubtype ;
182+ }
183+
184+ private boolean checkRequiredTypes (ResolvedType type , MyVariance variance ) {
185+ for (Class <?> cls : variance .requiredSubtypes ()) {
186+ if (!classHierarchy .isDescendant (type .asReferenceType ().getQualifiedName (), cls .getName (), -1 )) {
187+ messager .printMessage (Kind .ERROR ,
188+ type .asReferenceType ().getQualifiedName () + " does not have " + cls .getName () + " as subtype" );
189+ return false ;
190+ }
191+ }
192+ for (Class <?> cls : variance .requiredSupertypes ()) {
193+ if (!classHierarchy .isDescendant (cls .getName (), type .asReferenceType ().getQualifiedName (), -1 )) {
194+ messager .printMessage (Kind .ERROR , type .asReferenceType ().getQualifiedName () + " does not have "
195+ + cls .getName () + " as supertype" );
196+ return false ;
197+ }
198+
199+ }
200+ return true ;
156201 }
157202}
0 commit comments