1 19 20 package org.netbeans.modules.java.hints; 21 22 import com.sun.source.tree.CompilationUnitTree; 23 import com.sun.source.tree.MethodInvocationTree; 24 import com.sun.source.tree.Tree.Kind; 25 import com.sun.source.util.TreePath; 26 import java.io.IOException ; 27 import java.util.ArrayList ; 28 import java.util.Arrays ; 29 import java.util.Collections ; 30 import java.util.HashMap ; 31 import java.util.HashSet ; 32 import java.util.List ; 33 import java.util.Map ; 34 import java.util.Set ; 35 import java.util.logging.Level ; 36 import java.util.logging.Logger ; 37 import javax.lang.model.element.TypeElement; 38 import javax.swing.text.Document ; 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.SourceUtils; 44 import org.netbeans.api.java.source.WorkingCopy; 45 import org.netbeans.api.lexer.Token; 46 import org.netbeans.modules.java.editor.imports.ComputeImports; 47 import org.netbeans.modules.java.hints.ImportClassEnabler.ImportCandidatesHolder; 48 import org.netbeans.modules.java.hints.JavaHintsProvider; 49 import org.netbeans.modules.java.hints.LazyHintComputation; 50 import org.netbeans.modules.java.hints.spi.ErrorRule; 51 import org.netbeans.spi.editor.hints.ChangeInfo; 52 import org.netbeans.spi.editor.hints.Fix; 53 import org.openide.ErrorManager; 54 import org.openide.filesystems.FileObject; 55 import org.openide.util.NbBundle; 56 import org.openide.util.RequestProcessor; 57 58 59 63 public final class ImportClassEnabler implements ErrorRule<ImportCandidatesHolder> { 64 65 static RequestProcessor WORKER = new RequestProcessor("ImportClassEnabler", 1); 66 67 public ImportClassEnabler() { 68 } 69 70 public Set <String > getCodes() { 71 return new HashSet <String >(Arrays.asList( 72 "compiler.err.cant.resolve", 73 "compiler.err.cant.resolve.location", 74 "compiler.err.doesnt.exist", 75 "compiler.err.not.stmt")); 76 } 77 78 public List <Fix> run(final CompilationInfo info, String diagnosticKey, final int offset, TreePath treePath, Data<ImportCandidatesHolder> data) { 79 resume(); 80 81 int errorPosition = offset + 1; 83 if (errorPosition == (-1)) { 84 JavaHintsProvider.LOG.log(Level.FINE, "ImportClassEnabler.create errorPosition=-1"); 86 return Collections.<Fix>emptyList(); 87 } 88 89 TreePath path = info.getTreeUtilities().pathFor(errorPosition); 90 91 if (path.getParentPath() != null && path.getParentPath().getLeaf().getKind() == Kind.METHOD_INVOCATION) { 92 MethodInvocationTree mit = (MethodInvocationTree) path.getParentPath().getLeaf(); 95 96 if (!mit.getTypeArguments().contains(path.getLeaf())) { 97 return Collections.<Fix>emptyList(); 98 } 99 } 100 101 Token ident = JavaHintsProvider.findUnresolvedElementToken(info, offset); 102 103 JavaHintsProvider.LOG.log(Level.FINE, "ImportClassEnabler.create ident={0}", ident); 105 if (ident == null) { 106 return Collections.<Fix>emptyList(); 107 } 108 109 FileObject file = info.getFileObject(); 110 String simpleName = ident.text().toString(); 111 Pair<List <String >, List <String >> candidates = getCandidateFQNs(info, file, simpleName, data); 112 113 if (isCancelled()) { 114 JavaHintsProvider.LOG.log(Level.FINE, "ImportClassEnabler.cancelled."); 116 return Collections.<Fix>emptyList(); 117 } 118 119 List <String > filtered = candidates.getA(); 120 List <String > unfiltered = candidates.getB(); 121 List <Fix> fixes = new ArrayList <Fix>(); 122 123 if (unfiltered != null && filtered != null) { 124 for (String fqn : filtered) { 126 fixes.add(new FixImport(file, fqn, true)); 127 } 128 129 for (String fqn : unfiltered) { 130 if (!filtered.contains(fqn)) 131 fixes.add(new FixImport(file, fqn, false)); 132 } 133 } 134 135 JavaHintsProvider.LOG.log(Level.FINE, "ImportClassEnabler.create finished."); 137 return fixes; 138 } 139 140 public synchronized void cancel() { 141 JavaHintsProvider.LOG.log(Level.FINE, "ImportClassEnabler.cancel called."); 143 cancelled = true; 144 145 if (compImports != null) { 146 compImports.cancel(); 147 } 148 } 149 150 public String getId() { 151 return ImportClassEnabler.class.getName(); 152 } 153 154 public String getDisplayName() { 155 return "Add Import Fix"; 156 } 157 158 public String getDescription() { 159 return "Add Import Fix"; 160 } 161 162 private synchronized void resume() { 163 JavaHintsProvider.LOG.log(Level.FINE, "ImportClassEnabler.resume called."); 165 cancelled = false; 166 } 167 168 private synchronized boolean isCancelled() { 169 return cancelled; 170 } 171 172 private boolean cancelled; 173 private ComputeImports compImports; 174 175 private synchronized void setComputeImports(ComputeImports compImports) { 176 this.compImports = compImports; 177 } 178 179 public Pair<List <String >, List <String >> getCandidateFQNs(CompilationInfo info, FileObject file, String simpleName, Data<ImportCandidatesHolder> data) { 180 ImportCandidatesHolder holder = data.getData(); 181 182 if (holder == null) { 183 data.setData(holder = new ImportCandidatesHolder()); 184 } 185 186 Pair<Map <String , List <String >>, Map <String , List <String >>> result = holder.getCandidates(); 187 188 if (result == null || result.getA() == null || result.getB() == null) { 189 Map <String , List <String >> candidates = new HashMap <String , List <String >>(); 191 ComputeImports imp = new ComputeImports(); 192 193 setComputeImports(imp); 194 195 ComputeImports.Pair<Map <String , List <TypeElement>>, Map <String , List <TypeElement>>> rawCandidates = imp.computeCandidates(info); 196 197 setComputeImports(null); 198 199 if (isCancelled()) { 200 JavaHintsProvider.LOG.log(Level.FINE, "ImportClassEnabler.getCandidateFQNs cancelled, returning."); 202 return null; 203 } 204 205 for (String sn : rawCandidates.a.keySet()) { 206 List <String > c = new ArrayList <String >(); 207 208 for (TypeElement te : rawCandidates.a.get(sn)) { 209 c.add(te.getQualifiedName().toString()); 210 } 211 212 candidates.put(sn, c); 213 } 214 215 Map <String , List <String >> notFilteredCandidates = new HashMap <String , List <String >>(); 216 217 for (String sn : rawCandidates.b.keySet()) { 218 List <String > c = new ArrayList <String >(); 219 220 for (TypeElement te : rawCandidates.b.get(sn)) { 221 c.add(te.getQualifiedName().toString()); 222 } 223 224 notFilteredCandidates.put(sn, c); 225 } 226 227 result = new Pair(candidates, notFilteredCandidates); 228 229 holder.setCandidates(result); 230 } 231 232 List <String > candList = result.getA().get(simpleName); 233 List <String > notFilteredCandList = result.getB().get(simpleName); 234 235 return new Pair(candList, notFilteredCandList); 236 } 237 238 public static class ImportCandidatesHolder { 239 private Pair<Map <String , List <String >>, Map <String , List <String >>> candidates; 240 241 public Pair<Map <String , List <String >>, Map <String , List <String >>> getCandidates() { 242 return candidates; 243 } 244 245 public void setCandidates(Pair<Map <String , List <String >>, Map <String , List <String >>> candidates) { 246 this.candidates = candidates; 247 } 248 } 249 250 static final class FixImport implements Fix { 251 252 private FileObject file; 253 private String fqn; 254 private boolean isValid; 255 256 public FixImport(FileObject file, String fqn, boolean isValid) { 257 this.file = file; 258 this.fqn = fqn; 259 this.isValid = isValid; 260 } 261 262 public String getText() { 263 if (isValid) 264 return NbBundle.getMessage(ImportClassEnabler.class, "Add_import_for_X", new Object [] {fqn}); 265 else 266 return "<html><font color='#808080'><s>" + NbBundle.getMessage(ImportClassEnabler.class, "Add_import_for_X", new Object [] {fqn}); 267 } 268 269 public ChangeInfo implement() { 270 JavaSource js = JavaSource.forFileObject(file); 271 272 CancellableTask task = new CancellableTask<WorkingCopy>() { 273 274 public void run(WorkingCopy copy) throws Exception { 275 if (copy.toPhase(Phase.RESOLVED).compareTo(Phase.RESOLVED) < 0) 276 return; 277 278 TypeElement te = copy.getElements().getTypeElement(fqn); 279 280 if (te == null) { 281 Logger.getAnonymousLogger().warning(String.format("Attempt to fix import for FQN: %s, which does not have a TypeElement in currect context", fqn)); 282 return ; 283 } 284 285 CompilationUnitTree cut = SourceUtils.addImports( 286 copy.getCompilationUnit(), 287 Collections.singletonList(te.getQualifiedName().toString()), 288 copy.getTreeMaker() 289 ); 290 copy.rewrite(copy.getCompilationUnit(), cut); 291 } 292 293 public void cancel() { 294 } 295 }; 296 try { 297 js.runModificationTask(task).commit(); 298 return null; 299 } catch (IOException ex) { 300 ErrorManager.getDefault().notify(ex); 301 } 302 return null; 303 } 304 305 @Override 306 public int hashCode() { 307 return fqn.hashCode(); 308 } 309 310 @Override 311 public boolean equals(Object o) { 312 if (o instanceof FixImport) { 313 return fqn.equals(((FixImport) o).fqn); 314 } 315 316 return false; 317 } 318 } 319 } 320 | Popular Tags |