package is.L42.connected.withSafeOperators; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; import platformSpecific.javaTranslation.Resources; import ast.Ast; import ast.ErrorMessage; import ast.ErrorMessage.PathMetaOrNonExistant; import ast.ExpCore.*; import ast.Ast.Doc; import ast.Ast.MethodSelector; import ast.Ast.Path; import ast.ExpCore.ClassB; import ast.ExpCore.ClassB.Member; import ast.ExpCore.ClassB.MethodImplemented; import ast.ExpCore.ClassB.MethodWithType; import ast.ExpCore.ClassB.NestedClass; import ast.Util.PathMwt; import ast.Util.PathMx; import auxiliaryGrammar.Functions; import programReduction.Program; import is.L42.connected.withSafeOperators.ExtractInfo.IsUsed; import is.L42.connected.withSafeOperators.Rename.UserForMethodResult; public class Abstract { public static ClassB toAbstract(ClassB cb, List<Ast.C> path){ Errors42.checkExistsPathMethod(cb, path, Optional.empty()); //check privacy coupled ClassB cbClear=cb.onClassNavigateToPathAndDo( path, cbi->clear(cbi)); Abstract.checkPrivacyCoupuled(cb,cbClear, path); return cbClear; } private static ClassB clear(ClassB cb) { //note: it would be wrong to remove implementation of private interfaces: //otherwise a use could rely on methods (the interface-implemented ones) that do not //exists any more. //we choose to not remove private trown exceptions just for coherence. //it is empty, cut it down! List<Member> newMs=new ArrayList<>(); for(Member m:cb.getMs()){ m.match( nc->{ if(nc.getName().isUnique()){return null;} newMs.add(nc.withInner(clear((ClassB)nc.getInner())));return null; }, mi->{return null;},//just implementation mt->{ if(mt.getMs().isUnique()){return null;} newMs.add(mt.with_inner(Optional.empty()));return null;} );} //create new class return cb.withMs(newMs); } public static ClassB toAbstract(Program p,ClassB cb, List<Ast.C> path,MethodSelector sel,MethodSelector newSel){ Errors42.checkExistsPathMethod(cb, path, Optional.of(sel)); if(path.isEmpty()){return auxToAbstract(p,cb,path,sel,newSel);} return cb.onClassNavigateToPathAndDo(path,cbi->auxToAbstract(p,cbi,path,sel,newSel)); } private static ClassB auxToAbstract(Program p,ClassB cb,List<Ast.C> pathForError,MethodSelector sel,MethodSelector newSel) { List<Member> newMs=new ArrayList<>(cb.getMs()); Member m=Functions.getIfInDom(newMs, sel).get(); //make m abstract if(m instanceof MethodWithType){ MethodWithType mwt=(MethodWithType)m; mwt=mwt.with_inner(Optional.empty()); Functions.replaceIfInDom(newMs,mwt); } else{//it is method implemented Functions.removeIfInDom(newMs, sel); } //create new class if(newSel==null){ return cb.withMs(newMs); } MethodWithType mwt1 = (MethodWithType) cb._getMember(sel); assert mwt1!=null; if(newSel!=null){Errors42.checkCompatibleMs(pathForError, mwt1, newSel);} Optional<MethodWithType> mwt2 = Optional.ofNullable((MethodWithType)cb._getMember(newSel)); mwt1=mwt1.withMs(newSel).withDoc(Doc.empty()).withMt(mwt1.getMt().withRefine(false));//never refine, see under if(mwt2.isPresent()){//Never there, so will never implement interfaces (on normalized classb) throw Errors42.errorMethodClash(pathForError, mwt1,mwt2.get(), false, Collections.emptyList(), false,false,false); } newMs.add(mwt1); return cb.withMs(newMs); } static void checkPrivacyCoupuled(ClassB cbFull,ClassB cbClear, List<Ast.C> path) { //start from a already cleared out of private states //check if all private nested classes are USED using IsUsed on cbClear //this also verify that no private nested classes are used as //type in public methods of public classes. //collect all PublicPath.privateMethod //use main->introspection.FindUsage List<Path>prPath=ExtractInfo.collectPrivatePathsAndSubpaths(cbFull,path); List<PathMx>prMeth=ExtractInfo.collectPrivateMethodsOfPublicPaths(cbFull,path); List<Path>coupuledPaths=new ArrayList<>(); for(Path pi:prPath){ Set<Path> used = ExtractInfo.IsUsed.of(cbClear,pi); if(used.isEmpty()){continue;} coupuledPaths.add(pi); } List<PathMx> ordered=new ArrayList<>(); try{ Set<PathMx> usedPrMeth =findUsage(prMeth,cbClear); //FindUsage.of(Program.empty(),prMeth, cbClear); if(coupuledPaths.isEmpty() && usedPrMeth.isEmpty()){return;} ordered.addAll(usedPrMeth); } catch(PathMetaOrNonExistant pne){ assert !coupuledPaths.isEmpty(); } Collections.sort(ordered,(px1,px2)->px1.toString().compareTo(px2.toString())); throw Errors42.errorPrivacyCoupuled(coupuledPaths, ordered); } private static class NotFound extends Error{ static NotFound nf=new NotFound();} private static Set<PathMx> findUsage(List<PathMx> prMeth, ClassB cbClear) { Set<PathMx> result=new HashSet<>(); for(PathMx pmx:prMeth){ assert pmx.getPath().outerNumber()==0; UserForMethodResult res= Rename.userForMethod(Resources.getP()/*wasEmpty*/, cbClear,pmx.getPath().getCBar(),pmx.getMs(),false); result.addAll(res.asClient); res.asThis.stream().map(e->new PathMx(Path.outer(0),e)).forEach(result::add); } return result; } }