11package io .github .bldl .astParsing ;
22
33import com .github .javaparser .ast .CompilationUnit ;
4+ import com .github .javaparser .ast .Node ;
45import com .github .javaparser .ast .NodeList ;
56import com .github .javaparser .ast .PackageDeclaration ;
67import com .github .javaparser .ast .body .ClassOrInterfaceDeclaration ;
1011import com .github .javaparser .ast .expr .MethodCallExpr ;
1112import com .github .javaparser .ast .expr .Name ;
1213import com .github .javaparser .ast .expr .NameExpr ;
14+ import com .github .javaparser .ast .nodeTypes .NodeWithAnnotations ;
1315import com .github .javaparser .ast .type .ClassOrInterfaceType ;
1416import com .github .javaparser .ast .type .Type ;
1517import com .github .javaparser .ast .type .TypeParameter ;
18+ import com .github .javaparser .ast .visitor .ModifierVisitor ;
19+ import com .github .javaparser .ast .visitor .Visitable ;
1620import com .github .javaparser .utils .CodeGenerationUtils ;
1721import com .github .javaparser .utils .SourceRoot ;
22+ import io .github .bldl .annotationProcessing .annotations .MyVariance ;
1823import io .github .bldl .astParsing .util .ClassData ;
1924import io .github .bldl .astParsing .util .MethodData ;
25+ import io .github .bldl .astParsing .util .ParamData ;
2026import io .github .bldl .astParsing .visitors .CastInsertionVisitor ;
2127import io .github .bldl .astParsing .visitors .MethodCollector ;
2228import io .github .bldl .astParsing .visitors .TypeEraserVisitor ;
2733
2834import java .io .File ;
2935import java .nio .file .Paths ;
30- import java .util .Arrays ;
3136import java .util .HashMap ;
3237import java .util .HashSet ;
3338import java .util .Map ;
@@ -51,9 +56,9 @@ public AstManipulator(Messager messager, String sourceFolder) {
5156
5257 public void applyChanges () {
5358 this .sourceRoot .getCompilationUnits ().forEach (cu -> {
54- // messager.printMessage(Kind.NOTE, "Saving cu: " + cu.toString());
5559 changePackageDeclaration (cu );
5660 });
61+ messager .printMessage (Kind .NOTE , "Saving modified AST's to output directory" );
5762 this .sourceRoot .saveAll (
5863 CodeGenerationUtils .mavenModuleRoot (AstManipulator .class ).resolve (Paths .get (sourceFolder + "/output" )));
5964 }
@@ -62,45 +67,62 @@ public SourceRoot getSourceRoot() {
6267 return sourceRoot ;
6368 }
6469
65- public void eraseTypesAndInsertCasts (String cls , String packageName , String typeOfInterest ) {
70+ public void eraseTypesAndInsertCasts (String cls , String packageName , Map < String , MyVariance > mp ) {
6671 messager .printMessage (Kind .NOTE ,
67- String .format ("Now parsing AST's for class %s and type param %s " , cls , typeOfInterest ));
72+ String .format ("Now parsing AST's for class %s" , cls ));
6873 File dir = Paths .get (sourceFolder ).toFile ();
6974 assert dir .exists ();
7075 assert dir .isDirectory ();
71-
72- ClassData classData = computeClassData (cls , packageName , typeOfInterest );
76+ eraseAnnotations ( cls , packageName );
77+ ClassData classData = computeClassData (cls , packageName , mp );
7378 messager .printMessage (Kind .NOTE , "Collected class data:\n " + classData );
7479 Map <String , MethodData > methodMap = new HashMap <>();
75-
76- sourceRoot .parse (packageName , cls ).accept (new MethodCollector (Arrays .asList (typeOfInterest )),
80+ sourceRoot .parse (packageName , cls ).accept (new MethodCollector (mp .keySet ()),
7781 methodMap );
7882
7983 messager .printMessage (Kind .NOTE , "Collected methods:\n " + methodMap .toString ());
8084 changeAST (dir , classData , methodMap , "" );
8185 }
8286
87+ public void eraseAnnotations (String cls , String packageName ) {
88+ Set <String > annotations = Set .of ("MyVariance" , "Covariant" , "Contravariant" );
89+ CompilationUnit cu = sourceRoot .parse (packageName , cls );
90+ cu .accept (new ModifierVisitor <Void >() {
91+ @ Override
92+ public Visitable visit (Parameter n , Void arg ) {
93+ n .getAnnotations ().removeIf (annotation -> annotations .contains (annotation .getNameAsString ()));
94+ return super .visit (n , arg );
95+ }
96+
97+ public Visitable visit (TypeParameter n , Void arg ) {
98+ n .getAnnotations ().removeIf (annotation -> annotations .contains (annotation .getNameAsString ()));
99+ return super .visit (n , arg );
100+ }
101+ }, null );
102+ }
103+
83104 public ClassHierarchyGraph <String > computeClassHierarchy () {
84105 ClassHierarchyGraph <String > g = new ClassHierarchyGraph <>();
85106 g .addVertex ("Object" );
86107 computeClassHierarchyRec (g , Paths .get (sourceFolder ).toFile (), "" );
87108 return g ;
88109 }
89110
90- private ClassData computeClassData (String cls , String packageName , String typeOfInterest ) {
111+ private ClassData computeClassData (String cls , String packageName , Map < String , MyVariance > mp ) {
91112 CompilationUnit cu = sourceRoot .parse (packageName , cls );
113+ Map <String , ParamData > indexAndBound = new HashMap <>();
92114 var a = cu .findAll (ClassOrInterfaceDeclaration .class ).get (0 ).getTypeParameters ();
93115 for (int i = 0 ; i < a .size (); ++i ) {
94116 TypeParameter type = a .get (i );
95117 NodeList <ClassOrInterfaceType > boundList = type .getTypeBound ();
96118 String leftMostBound = boundList == null || boundList .size () == 0 ? "Object" : boundList .get (0 ).asString ();
97- if (type . getNameAsString ().equals ( typeOfInterest )) {
98- a . get ( i );
99- return new ClassData ( cls . replaceFirst ( " \\ .java$" , "" ), leftMostBound , i );
119+ if (mp . keySet ().contains ( type . getNameAsString () )) {
120+ indexAndBound . put ( type . getNameAsString (),
121+ new ParamData ( i , leftMostBound , mp . get ( type . getNameAsString ())) );
100122 }
101123
102124 }
103- return null ;
125+ return new ClassData ( cls . replaceFirst ( " \\ .java$" , "" ), indexAndBound ) ;
104126 }
105127
106128 private void changeAST (File dir , ClassData classData , Map <String , MethodData > methodMap ,
@@ -117,12 +139,11 @@ private void changeAST(File dir, ClassData classData, Map<String, MethodData> me
117139
118140 CompilationUnit cu = sourceRoot .parse (packageName , fileName );
119141
120- Set <Pair <String , String >> varsToWatch = new HashSet <>();
142+ Set <Pair <String , ClassOrInterfaceType >> varsToWatch = new HashSet <>();
121143 cu .accept (new VariableCollector (classData ), varsToWatch );
122- messager .printMessage (Kind .NOTE , "Collected variables to watch:\n " + varsToWatch );
123- performSubtypingChecks (cu , classData , methodMap , varsToWatch );
144+ // performSubtypingChecks(cu, classData, methodMap, varsToWatch);
124145 cu .accept (new TypeEraserVisitor (classData ), null );
125- for (Pair <String , String > var : varsToWatch ) {
146+ for (Pair <String , ClassOrInterfaceType > var : varsToWatch ) {
126147 CastInsertionVisitor castInsertionVisitor = new CastInsertionVisitor (var , methodMap );
127148 cu .accept (castInsertionVisitor , null );
128149 }
@@ -177,6 +198,10 @@ private void performSubtypingChecks(CompilationUnit cu, ClassData classData,
177198 Map <String , MethodData > methodMap ,
178199 Set <Pair <String , String >> varsToWatch ) {
179200 Map <String , Map <Integer , Type >> methodParams = collectMethodParams (cu , classData );
201+ Map <String , String > varsToWatchMap = new HashMap <>();
202+ varsToWatch .forEach (p -> {
203+ varsToWatchMap .put (p .first , p .second );
204+ });
180205 cu .findAll (MethodCallExpr .class ).forEach (methodCall -> {
181206 if (!methodParams .containsKey (methodCall .getNameAsString ()))
182207 return ;
@@ -189,20 +214,28 @@ private void performSubtypingChecks(CompilationUnit cu, ClassData classData,
189214 String name = ((NameExpr ) e ).getNameAsString ();
190215 varsToWatch .forEach (p -> {
191216 if (p .first .equals (name )) {
192- // check subtyping
217+ // boolean valid = isValidSubtype(name, name, annotation);
218+ // if (!valid)
219+ messager .printMessage (Kind .ERROR ,
220+ String .format ("Invalid subtype for method call: " , methodCall .toString ()));
193221 }
194222 });
195223 }
196224
197225 });
198- cu .findAll (AssignExpr .class ).forEach (assignExpr -> {
226+ // cu.findAll(AssignExpr.class).forEach(assignExpr -> {
227+ // if (!(assignExpr.getTarget() instanceof NameExpr))
228+ // return;
229+ // NameExpr name = (NameExpr) assignExpr.getTarget();
230+ // if (!varsToWatchMap.containsKey(name.toString()))
231+ // return;
199232
200- messager .printMessage (Kind .NOTE , assignExpr .toString ());
201- messager .printMessage (Kind .NOTE , assignExpr .getTarget ().getClass ().toString ());
202- messager .printMessage (Kind .NOTE , assignExpr .getValue ().getClass ().toString ());
203- });
233+ // });
204234 // cu.findAll(ForEachStmt.class).forEach(stmt -> {
205235
236+ // });
237+ // cu.findAll(VariableDeclarationExpr.class).forEach(stmt -> {
238+
206239 // });
207240 }
208241
@@ -218,15 +251,33 @@ private Map<String, Map<Integer, Type>> collectMethodParams(CompilationUnit cu,
218251 String methodName = dec .getNameAsString ();
219252 if (type .getNameAsString ().equals (classData .className ())) {
220253 mp .putIfAbsent (methodName , new HashMap <>());
221- mp .get (methodName ).put (i , type .getTypeArguments ().get ().get (classData .indexOfParam ()));
254+ // mp.get(methodName).put(i,
255+ // type.getTypeArguments().get().get(classData.indexOfParam()));
222256 }
223257 }
224258 });
225259 return mp ;
226260 }
227261
228- private String resolveType () {
229- return null ;
262+ private boolean isValidSubtype (String assigneeType , String assignedType , MyVariance annotation ) {
263+ if (!classHierarchy .containsVertex (assigneeType )) {
264+ messager .printMessage (Kind .WARNING ,
265+ String .format ("%s is not a user defined type, so no subtyping checks can be made" , assigneeType ));
266+ return true ;
267+ }
268+ if (!classHierarchy .containsVertex (assignedType )) {
269+ messager .printMessage (Kind .WARNING ,
270+ String .format ("%s is not a user defined type, so no subtyping checks can be made" , assignedType ));
271+ return true ;
272+ }
273+ switch (annotation .variance ()) {
274+ case COVARIANT :
275+ return classHierarchy .isDescendant (assignedType , assigneeType );
276+ case CONTRAVARIANT :
277+ return classHierarchy .isDescendant (assigneeType , assignedType );
278+ default :
279+ return false ;
280+ }
230281 }
231282
232283}
0 commit comments