/* * Glue code for integrating accessibility adjustment with name unlocking to make it more powerful. * * The basic idea is to collect accessibility constraints before unlocking names and solving them if necessary. * * At the moment, we use a pipelined approach in which we first adjust accessibility, and then unlock names. * This is not always sufficient, however, since name unlocking can introduce new locked names, for which * another round of accessibility adjusting may be necessary. * * Implementing this efficiently is not trivial, and it needs some changes to the way name unlocking is performed * currently. */ aspect AccessibilityGlue { public void Program.eliminateLockedNamesInSubtree() { // check naming constraints first; if that fails we don't have to solve constraints checkNamingConstraints(); adjustAccessibility(); eliminateLockedNames(); while(!affectedByUnlock.isEmpty()) { adjustAccessibility(collectAccessibilityConstraints(affectedByUnlock)); affectedByUnlock.clear(); eliminateLockedNames(); } flushCaches(); } private Collection Program.collectAccessibilityConstraints(Collection accs) { Collection seed = new LinkedList(); for(Access acc : accs) acc.collectAccessibilityConstraints(seed); return seed; } private void Program.adjustAccessibility() { adjustAccessibility(accessibilityConstraints()); } private void Program.adjustAccessibility(Collection seed) { Collection accessibilityConstraints = relevantAccessibilityConstraints(seed); if(accessibilityConstraints.isEmpty()) return; Map acc_map = solve(accessibilityConstraints); if(acc_map == null) throw new RefactoringException("cannot adjust accessibilities"); adjustAccessibilities(acc_map); flushCaches(); } protected void Program.adjustAccessibilities(Map acc_map) { for(Map.Entry e : acc_map.entrySet()) { Visible vis = e.getKey(); if(!vis.fromSource()) throw new RefactoringException("cannot adjust accessibility of library element"); // TODO: hide this behind an interface (see ChangeAccessibility.jrag) if(vis instanceof FieldDeclaration) { FieldDeclaration fd = (FieldDeclaration)vis; programRoot().lockNames(fd.name()); } else if(vis instanceof MethodDecl) { MethodDecl md = (MethodDecl)vis; programRoot().lockMethodNames(md.name()); } else if(vis instanceof TypeDecl) { TypeDecl td = (TypeDecl)vis; programRoot().lockNames(td.name()); } vis.setVisibility(e.getValue()); } } // undo support for caching accessibility constraints that reference a certain Visible refine AccessibilityConstraints public void Visible.referencedBy(final AccessibilityConstraint c) { refined(c); if (Program.isRecordingASTChanges()) { Program.addUndoAction(new ASTModificationReplaceEdit(this.isInTree(), this, IDstart, IDend, getID(), getID()) { @Override public void undo() { referencingAccessibilityConstraints.remove(c); } @Override public void redo() { if (Program.isRecordingASTChanges()) Program.addUndoAction(this); refined(c); } @Override public String toString() { return "Visible.referencedBy"; } }); } } }