1 19 package org.netbeans.modules.java.hints; 20 21 import com.sun.source.tree.BlockTree; 22 import com.sun.source.tree.CatchTree; 23 import com.sun.source.tree.ExpressionTree; 24 import com.sun.source.tree.MethodTree; 25 import com.sun.source.tree.StatementTree; 26 import com.sun.source.tree.ThrowTree; 27 import com.sun.source.tree.Tree; 28 import com.sun.source.tree.Tree.Kind; 29 import com.sun.source.tree.TryTree; 30 import com.sun.source.util.TreePath; 31 import java.io.IOException ; 32 import java.util.ArrayList ; 33 import java.util.Collections ; 34 import java.util.EnumSet ; 35 import java.util.HashSet ; 36 import java.util.List ; 37 import java.util.Map ; 38 import java.util.Set ; 39 import javax.lang.model.element.Element; 40 import javax.lang.model.element.ElementKind; 41 import javax.lang.model.element.ExecutableElement; 42 import javax.lang.model.element.Modifier; 43 import javax.lang.model.element.VariableElement; 44 import javax.lang.model.type.TypeMirror; 45 import javax.lang.model.type.TypeKind; 46 import javax.swing.text.Document ; 47 import javax.tools.Diagnostic; 48 import org.netbeans.api.java.source.CancellableTask; 49 import org.netbeans.api.java.source.CompilationInfo; 50 import org.netbeans.api.java.source.ElementHandle; 51 import org.netbeans.api.java.source.JavaSource; 52 import org.netbeans.api.java.source.JavaSource.Phase; 53 import org.netbeans.api.java.source.TreeMaker; 54 import org.netbeans.api.java.source.TypeMirrorHandle; 55 import org.netbeans.api.java.source.WorkingCopy; 56 import org.netbeans.modules.editor.java.Utilities; 57 import org.netbeans.modules.java.hints.ImportClassEnabler.ImportCandidatesHolder; 58 import org.netbeans.modules.java.hints.spi.ErrorRule; 59 import org.netbeans.spi.editor.hints.ChangeInfo; 60 import org.netbeans.spi.editor.hints.ErrorDescriptionFactory; 61 import org.netbeans.spi.editor.hints.Fix; 62 import org.netbeans.spi.editor.hints.LazyFixList; 63 import org.openide.ErrorManager; 64 65 69 public final class UncaughtExceptionCreator implements ErrorRule<Void > { 70 71 74 public UncaughtExceptionCreator() { 75 } 76 77 private List <? extends TypeMirror> findUncauchedExceptions(CompilationInfo info, TreePath path, List <? extends TypeMirror> exceptions) { 78 List <TypeMirror> result = new ArrayList <TypeMirror>(); 79 80 result.addAll(exceptions); 81 82 while (path != null) { 83 Element currentElement = info.getTrees().getElement(path); 84 85 if (currentElement != null && EXECUTABLE_ELEMENTS.contains(currentElement.getKind())) { 86 ExecutableElement ee = (ExecutableElement) currentElement; 87 88 result.removeAll(ee.getThrownTypes()); 89 break; 90 } 91 92 Tree currentTree = path.getLeaf(); 93 94 if (currentTree.getKind() == Kind.TRY) { 95 TryTree tt = (TryTree) currentTree; 96 97 for (CatchTree c : tt.getCatches()) { 98 TreePath catchPath = new TreePath(new TreePath(path, c), c.getParameter()); 99 VariableElement variable = (VariableElement) info.getTrees().getElement(catchPath); 100 101 result.remove(variable.asType()); 102 } 103 } 104 105 path = path.getParentPath(); 106 } 107 108 return result; 109 } 110 111 public Set <String > getCodes() { 112 return Collections.singleton("compiler.err.unreported.exception.need.to.catch.or.throw"); 113 } 114 115 public List <Fix> run(CompilationInfo info, String diagnosticKey, int offset, TreePath treePath, Data<Void > data) { 116 List <Fix> result = new ArrayList <Fix>(); 117 TreePath path = info.getTreeUtilities().pathFor(offset + 1); 118 List <? extends TypeMirror> uncauched = null; 119 Element el; 120 121 OUTTER: while (path != null) { 122 Tree leaf = path.getLeaf(); 123 124 switch (leaf.getKind()) { 125 case NEW_CLASS: 126 case METHOD_INVOCATION: 127 el = info.getTrees().getElement(path); 128 if (el != null && EXECUTABLE_ELEMENTS.contains(el.getKind())) { 129 uncauched = ((ExecutableElement) el).getThrownTypes(); 130 } 131 path = path.getParentPath(); 132 break OUTTER; 133 case THROW: 134 TypeMirror uncaughtException = info.getTrees().getTypeMirror(new TreePath(path, ((ThrowTree) leaf).getExpression())); 135 uncauched = Collections.singletonList(uncaughtException); 136 break OUTTER; 137 } 138 139 path = path.getParentPath(); 140 } 141 142 if (uncauched != null) { 143 uncauched = findUncauchedExceptions(info, path, uncauched); 144 145 TreePath pathRec = path; 146 147 while (pathRec != null && pathRec.getLeaf().getKind() != Kind.METHOD) { 148 pathRec = pathRec.getParentPath(); 149 } 150 151 ExecutableElement method = pathRec != null ? (ExecutableElement) info.getTrees().getElement(pathRec) : null; 152 153 if (method != null) { 154 for (TypeMirror tm : uncauched) { 155 if (tm.getKind() != TypeKind.ERROR) 156 result.add(new AddThrowsClauseHintImpl(info.getJavaSource(), Utilities.getTypeName(tm, true).toString(), TypeMirrorHandle.create(tm), ElementHandle.create(method))); 157 } 158 } 159 160 if (!uncauched.isEmpty()) { 161 List <TypeMirrorHandle> thandles = new ArrayList <TypeMirrorHandle>(); 162 163 for (TypeMirror tm : uncauched) { 164 if (tm.getKind() != TypeKind.ERROR) 165 thandles.add(TypeMirrorHandle.create(tm)); 166 } 167 result.add(new MagicSurroundWithTryCatch(info.getJavaSource(), thandles, offset)); 168 } 169 } 170 171 return result; 172 } 173 174 public void cancel() { 175 } 177 178 public String getId() { 179 return UncaughtExceptionCreator.class.getName(); 180 } 181 182 public String getDisplayName() { 183 return "Add Throws Clause and Surround With try-catch Fixes"; 184 } 185 186 public String getDescription() { 187 return "Add Throws Clause and Surround With try-catch Fixes"; 188 } 189 190 private static final Set <ElementKind> EXECUTABLE_ELEMENTS = EnumSet.of(ElementKind.CONSTRUCTOR, ElementKind. METHOD); 191 192 private static final class AddThrowsClauseHintImpl implements Fix { 193 194 private JavaSource js; 195 private String fqn; 196 private TypeMirrorHandle thandle; 197 private ElementHandle<ExecutableElement> method; 198 199 public AddThrowsClauseHintImpl(JavaSource js, String fqn, TypeMirrorHandle thandle, ElementHandle<ExecutableElement> method) { 200 this.js = js; 201 this.fqn = fqn; 202 this.thandle = thandle; 203 this.method = method; 204 } 205 206 public String getText() { 207 return "Add throws clause for " + fqn; 208 } 209 210 public ChangeInfo implement() { 211 try { 212 js.runModificationTask(new CancellableTask<WorkingCopy>() { 213 public void cancel() { 214 } 215 public void run(WorkingCopy wc) throws Exception { 216 wc.toPhase(Phase.RESOLVED); 217 Tree tree = wc.getTrees().getTree(method.resolve(wc)); 218 219 assert tree != null; 220 assert tree.getKind() == Kind.METHOD; 221 222 MethodTree nue = wc.getTreeMaker().addMethodThrows((MethodTree) tree, (ExpressionTree) wc.getTreeMaker().Type(thandle.resolve(wc))); 223 224 wc.rewrite(tree, nue); 225 } 226 }).commit(); 227 } catch (IOException e) { 228 ErrorManager.getDefault().notify(e); 229 } 230 return null; 231 } 232 233 } 234 235 private static final class SurroundWithTryCatch implements Fix { 236 237 private JavaSource js; 238 private List <TypeMirrorHandle> thandles; 239 private int offset; 240 241 public SurroundWithTryCatch(JavaSource js, List <TypeMirrorHandle> thandles, int offset) { 242 this.js = js; 243 this.thandles = thandles; 244 this.offset = offset; 245 } 246 247 public String getText() { 248 return "Surround with try-catch"; 249 } 250 251 public ChangeInfo implement() { 252 try { 253 js.runModificationTask(new CancellableTask<WorkingCopy>() { 254 public void cancel() { 255 } 256 public void run(WorkingCopy wc) throws Exception { 257 wc.toPhase(Phase.RESOLVED); 258 TreePath currentPath = wc.getTreeUtilities().pathFor(offset + 1); 259 260 while (currentPath != null && !STATEMENT_KINDS.contains(currentPath.getLeaf().getKind())) 262 currentPath = currentPath.getParentPath(); 263 264 TreeMaker make = wc.getTreeMaker(); 265 Tree t = currentPath.getLeaf(); 266 BlockTree bt = make.Block(Collections.singletonList((StatementTree) t), false); 267 List <CatchTree> catches = new ArrayList <CatchTree>(); 268 269 for (TypeMirrorHandle th : thandles) { 270 catches.add(make.Catch(make.Variable(make.Modifiers(EnumSet.noneOf(Modifier.class)), "ex", make.Type(th.resolve(wc)), null), make.Block(Collections.<StatementTree>emptyList(), false))); 271 } 272 wc.rewrite(t, make.Try(bt, catches, null)); 273 } 274 }).commit(); 275 } catch (IOException e) { 276 ErrorManager.getDefault().notify(e); 277 } 278 return null; 279 } 280 281 } 282 283 static final Set <Kind> STATEMENT_KINDS; 284 285 static { 286 Set <Kind> kinds = new HashSet <Kind>(); 287 288 for (Kind k : Kind.values()) { 289 Class c = k.asInterface(); 290 291 if (c != null && StatementTree.class.isAssignableFrom(c)) { 292 kinds.add(k); 293 } 294 } 295 296 STATEMENT_KINDS = Collections.unmodifiableSet(EnumSet.copyOf(kinds)); 297 } 298 299 } 300 | Popular Tags |