1 19 package org.netbeans.modules.java.hints; 20 21 import com.sun.source.tree.ClassTree; 22 import com.sun.source.tree.ModifiersTree; 23 import com.sun.source.tree.NewClassTree; 24 import com.sun.source.tree.Tree; 25 import com.sun.source.tree.Tree.Kind; 26 import com.sun.source.util.TreePath; 27 import com.sun.source.util.TreePathScanner; 28 import java.io.IOException ; 29 import java.util.ArrayList ; 30 import java.util.Arrays ; 31 import java.util.HashSet ; 32 import java.util.List ; 33 import java.util.Set ; 34 import javax.lang.model.element.Element; 35 import javax.lang.model.element.ExecutableElement; 36 import javax.lang.model.element.Modifier; 37 import javax.lang.model.util.ElementFilter; 38 import javax.swing.text.BadLocationException ; 39 import org.netbeans.api.java.source.CancellableTask; 40 import org.netbeans.api.java.source.CompilationInfo; 41 import org.netbeans.api.java.source.JavaSource; 42 import org.netbeans.api.java.source.JavaSource.Phase; 43 import org.netbeans.api.java.source.WorkingCopy; 44 import org.netbeans.modules.java.editor.codegen.GeneratorUtils; 45 import org.netbeans.modules.java.hints.spi.ErrorRule; 46 import org.netbeans.spi.editor.hints.ChangeInfo; 47 import org.netbeans.spi.editor.hints.Fix; 48 import org.openide.util.Exceptions; 49 50 54 public final class ImplementAllAbstractMethodsCreator implements ErrorRule<Void > { 55 56 57 public ImplementAllAbstractMethodsCreator() { 58 } 59 60 public Set <String > getCodes() { 61 return new HashSet <String >(Arrays.asList( 62 "compiler.err.abstract.cant.be.instantiated", 63 "compiler.err.does.not.override.abstract", 64 "compiler.err.abstract.cant.be.instantiated")); 65 } 66 67 public List <Fix> run(final CompilationInfo info, String diagnosticKey, final int offset, TreePath treePath, Data<Void > data) { 68 final List <Fix> result = new ArrayList <Fix>(); 69 70 analyze(info.getJavaSource(), offset, info, new Performer() { 71 public void fixAllAbstractMethods(TreePath pathToModify, Tree toModify) { 72 result.add(new FixImpl(info.getJavaSource(), offset, null)); 73 } 74 public void makeClassAbstract(Tree toModify, String className) { 75 result.add(new FixImpl(info.getJavaSource(), offset, className)); 76 } 77 }); 78 79 return result; 80 } 81 82 public void cancel() { 83 } 85 86 public String getId() { 87 return ImplementAllAbstractMethodsCreator.class.getName(); 88 } 89 90 public String getDisplayName() { 91 return "Implement All Abstract Methods Fix"; 92 } 93 94 public String getDescription() { 95 return "Implement All Abstract Methods Fix"; 96 } 97 98 private static interface Performer { 99 100 public void fixAllAbstractMethods(TreePath pathToModify, Tree toModify); 101 public void makeClassAbstract(Tree toModify, String className); 102 103 } 104 105 private static void analyze(JavaSource js, int offset, CompilationInfo info, Performer performer) { 106 final TreePath path = info.getTreeUtilities().pathFor(offset + 1); 107 Element e = info.getTrees().getElement(path); 108 boolean isUsableElement = e != null && (e.getKind().isClass() || e.getKind().isInterface()); 109 110 if (isUsableElement) { 111 for (ExecutableElement ee : ElementFilter.methodsIn(e.getEnclosedElements())) { 113 if (ee.getModifiers().contains(Modifier.ABSTRACT)) { 114 performer.makeClassAbstract(path.getLeaf(), e.getSimpleName().toString()); 115 return; 116 } 117 } 118 119 performer.fixAllAbstractMethods(path, path.getLeaf()); 120 } else { 121 if (path.getLeaf().getKind() == Kind.NEW_CLASS) { 122 final boolean[] parentError = new boolean[] {false}; 127 new TreePathScanner() { 128 @Override 129 public Object visitNewClass(NewClassTree nct, Object o) { 130 if (path.getLeaf() == nct) { 131 parentError[0] = getCurrentPath().getParentPath().getLeaf().getKind() == Kind.ERRONEOUS; 132 } 133 return super.visitNewClass(nct, o); 134 } 135 }.scan(path.getParentPath(), null); 136 if (!parentError[0]) { 137 performer.fixAllAbstractMethods(path, path.getLeaf()); 138 } 139 } 140 } 141 } 142 143 private static final class FixImpl implements Fix { 144 145 private JavaSource js; 146 private int offset; 147 private String makeClassAbstractName; 148 149 public FixImpl(JavaSource js, int offset, String makeClassAbstractName) { 150 this.js = js; 151 this.offset = offset; 152 this.makeClassAbstractName = makeClassAbstractName; 153 } 154 155 public String getText() { 156 return makeClassAbstractName == null ? "Implement all abstract methods" : "Make class " + makeClassAbstractName + " abstract"; 157 } 158 159 public ChangeInfo implement() { 160 try { 161 final boolean[] repeat = new boolean[] {true}; 162 163 while (repeat[0]) { 164 repeat[0] = false; 165 js.runModificationTask(new CancellableTask<WorkingCopy>() { 166 public void cancel() { 167 } 168 public void run(final WorkingCopy copy) throws IOException { 169 copy.toPhase(Phase.RESOLVED); 170 analyze(js, offset, copy, new Performer() { 171 public void fixAllAbstractMethods(TreePath pathToModify, Tree toModify) { 172 if (toModify.getKind() == Kind.NEW_CLASS) { 173 int insertOffset = (int) copy.getTrees().getSourcePositions().getEndPosition(copy.getCompilationUnit(), toModify); 174 if (insertOffset != (-1)) { 175 try { 176 copy.getDocument().insertString(insertOffset, " {}", null); 177 offset = insertOffset + 1; 178 repeat[0] = true; 179 } catch (BadLocationException e) { 180 Exceptions.printStackTrace(e); 181 } catch (IOException e) { 182 Exceptions.printStackTrace(e); 183 } 184 } 185 } else { 186 GeneratorUtils.generateAllAbstractMethodImplementations(copy, pathToModify); 187 } 188 } 189 public void makeClassAbstract(Tree toModify, String className) { 190 if (toModify.getKind() == Kind.CLASS) { 192 ClassTree clazz = (ClassTree) toModify; 193 ModifiersTree modifiers = clazz.getModifiers(); 194 Set <Modifier> newModifiersSet = new HashSet <Modifier>(modifiers.getFlags()); 195 196 newModifiersSet.add(Modifier.ABSTRACT); 197 198 copy.rewrite(modifiers, copy.getTreeMaker().Modifiers(newModifiersSet, modifiers.getAnnotations())); 199 } 200 } 201 }); 202 } 203 }).commit(); 204 } 205 } catch (IOException e) { 206 Exceptions.printStackTrace(e); 207 } 208 return null; 209 } 210 211 } 212 } 213 | Popular Tags |