package is.L42.connected.withSafeOperators; import static auxiliaryGrammar.EncodingHelper.ensureExtractClassB; 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 java.util.function.Function; import coreVisitors.CloneVisitor; import coreVisitors.From; import platformSpecific.fakeInternet.ActionType; import ast.Ast; import ast.ErrorMessage; import ast.Ast.Doc; import ast.Ast.Path; import ast.Ast.Position; import ast.Ast.Stage; import ast.ExpCore.ClassB; import ast.ExpCore.ClassB.Member; import ast.ExpCore.ClassB.NestedClass; import programReduction.Program; import auxiliaryGrammar.Functions; import auxiliaryGrammar.UsedPaths; public class RemoveCode { public static ClassB removeUnreachableCode(ClassB originalCb){ System.out.println("removeUnreachableCode"); ClassB newCb=removeAllPrivates(originalCb); ClassB oldCb=newCb; Set<List<Ast.C>> justAdded = paths(newCb); do{ oldCb=newCb; //for all nested in newCb newCb=collectDepNested(justAdded,originalCb,newCb,newCb,Collections.emptyList()); //take all dependencies //add them from originalCb to newCb in newCb }while(!newCb.equals(oldCb)); return newCb; //colect all private/nonprivate names //for each name, collect used paths //do fix point: bring public any private used by public. //remove all names still private //be careful, some names may have to be removed, but //their nested may need to stay //for getting only the public: //create a copy where you delete all the privates //then, with fixpoint: //for all the classes that are in newL, if Cs is used, add Cs from oldL } private static Set<List<Ast.C>> paths(ClassB cb) { Set<List<Ast.C>> result=new HashSet<>(); collectPaths(result,Collections.emptyList(),cb); return result; } private static void collectPaths(Set<List<Ast.C>> accumulator,List<Ast.C> path,ClassB cb) { accumulator.add(path); for(Member m:cb.getMs()){ if(!(m instanceof NestedClass)){continue;} NestedClass nc=(NestedClass)m; List<Ast.C> pathi=new ArrayList<>(path); pathi.add(nc.getName()); collectPaths(accumulator,pathi,(ClassB)nc.getInner()); } } private static ClassB collectDepNested(Set<List<Ast.C>> justAdded,ClassB originalCb,ClassB accumulator,ClassB depSource,List<Ast.C> origin){ List<List<Ast.C>> dep=collectDep(depSource,origin); for(List<Ast.C> pi:dep){ if(justAdded.contains(pi)){continue;} justAdded.add(pi); accumulator=addDep(accumulator,pi,originalCb); } assert dep!=null:"to break"; for(Member m:depSource.getMs()){ if(!(m instanceof NestedClass)){continue;} NestedClass nc=(NestedClass)m; ClassB cbi=(ClassB)nc.getInner(); List<Ast.C> newOrigin=new ArrayList<>(origin); newOrigin.add(nc.getName()); accumulator=collectDepNested(justAdded,originalCb, accumulator,cbi,newOrigin); } return accumulator; } private static ClassB addDep(ClassB accumulator, List<Ast.C> path, ClassB originalCb) { if(path.isEmpty()){ return mergeNestedHolderWithDep(accumulator, originalCb); } Ast.C firstName=path.get(0); //either fistName does not exist in accumulator, and we call removeAllButPath //or we have to continue recursivelly. Optional<Member> optM = Functions.getIfInDom(accumulator.getMs(), firstName); NestedClass originalNc =(NestedClass) Functions.getIfInDom(originalCb.getMs(), firstName).get(); ClassB newInner; if(!optM.isPresent()){ newInner=removeAllButPath(path.subList(1, path.size()),(ClassB)originalNc.getInner()); } else{ NestedClass accumulatorNc =(NestedClass)optM.get(); newInner=addDep((ClassB)accumulatorNc.getInner(),path.subList(1, path.size()),(ClassB)originalNc.getInner()); } NestedClass nc=originalNc.withInner(newInner); List<Member> ms = new ArrayList<>(accumulator.getMs()); Functions.replaceIfInDom(ms,nc); return accumulator.withMs(ms); } private static ClassB mergeNestedHolderWithDep(ClassB accumulator, ClassB originalCb) { assert !accumulator.isInterface() :accumulator; assert accumulator.getSupertypes().isEmpty() :accumulator; assert accumulator.getDoc1().isEmpty() :accumulator; List<Member> ms = new ArrayList<>(); for(Member m:accumulator.getMs()){ assert m instanceof NestedClass: m; ms.add(m); } for(Member m:originalCb.getMs()){ if(m instanceof NestedClass){continue;} ms.add(m); } return originalCb.withMs(ms); } private static ClassB removeAllButPath(List<Ast.C> path, ClassB originalCb) { if(path.isEmpty()){ List<Member> ms = new ArrayList<>(); for(Member m:originalCb.getMs()){ if(m instanceof NestedClass){continue;} ms.add(m); } return originalCb.withMs(ms); } Ast.C firstName=path.get(0); List<Member> ms = new ArrayList<>(); for(Member m:originalCb.getMs()){ if(!(m instanceof NestedClass)){continue;} NestedClass nc=(NestedClass)m; if(!nc.getName().equals(firstName)){continue;} ClassB newInner=removeAllButPath(path.subList(1, path.size()),(ClassB)nc.getInner()); ms.add(nc.withInner(newInner)); } return ClassB.membersClass(ms,Position.noInfo,originalCb.getPhase()); } private static List<List<Ast.C>> collectDep(ClassB depSource, List<Ast.C> origin) { List<Path> dep = new UsedPaths().of(depSource); List<List<Ast.C>>result=new ArrayList<>(); for(Path pi:new HashSet<>(dep)){ if(pi.isPrimitive()){continue;} Path piF=From.fromP(pi, Path.outer(0, origin)); if(piF.outerNumber()==0){result.add(piF.getCBar());} } return result; } private static ClassB removeAllPrivates(ClassB cb) { return (ClassB)cb.accept(new CloneVisitor(){ public List<Member> liftMembers(List<Member> ms1) { List<Member>ms2=new ArrayList<>(); for(Member m:ms1){ if(!(m instanceof NestedClass)){ms2.add(m);continue;} NestedClass ns=(NestedClass)m; if(!ns.getName().isUnique()){ms2.add(m);continue;} //otherwise, not add } return super.liftMembers(ms2); } }); } }