KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > tasklist > javaparser > ErrorSuggester


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.tasklist.javaparser;
21
22 import javax.swing.text.*;
23 import javax.swing.event.*;
24 import java.awt.*;
25 import java.awt.event.*;
26 import javax.swing.*;
27 import java.util.List JavaDoc;
28 import java.util.ArrayList JavaDoc;
29 import java.util.Arrays JavaDoc;
30 import java.util.Collections JavaDoc;
31 import java.util.Comparator JavaDoc;
32 import java.util.Iterator JavaDoc;
33 import org.openide.ErrorManager;
34 import org.openide.cookies.SourceCookie;
35 import org.openide.explorer.view.*;
36 import org.openide.nodes.*;
37 import org.netbeans.modules.java.*;
38 import org.openide.filesystems.*;
39
40 import org.openide.src.*;
41
42 import org.openide.loaders.DataObject;
43 import org.openide.src.Identifier;
44 import org.openide.src.Import;
45 import org.openide.src.SourceElement;
46 import org.openide.src.SourceException;
47 import org.openide.util.NbBundle;
48 import org.openide.util.Utilities;
49
50 import org.openide.cookies.LineCookie;
51 import org.openide.loaders.DataObject;
52 import org.openide.text.Line;
53 import org.openide.ErrorManager;
54
55 import java.util.TreeSet JavaDoc;
56 import java.lang.reflect.Modifier JavaDoc;
57 import java.io.IOException JavaDoc;
58
59 import org.netbeans.editor.ext.java.*;
60 import org.netbeans.modules.editor.java.*;
61 import org.netbeans.modules.java.Parsing;
62 import org.netbeans.modules.java.ParserMessage;
63 import org.netbeans.modules.java.parser.*;
64
65 import org.netbeans.modules.tasklist.core.ConfPanel;
66 import org.netbeans.modules.tasklist.core.TLUtils;
67 import org.netbeans.modules.tasklist.client.*;
68 import org.netbeans.modules.tasklist.providers.DocumentSuggestionProvider;
69 import org.netbeans.modules.tasklist.providers.SuggestionContext;
70
71
72 /**
73  * This class lists the javac errors for the current document/class
74  * <p>
75  * It suggests following:
76  * <ul>
77  * <li>add import if unresolved class exists in CCDB
78  * <li>correct case if unresolved class in CCDB
79  * <li>convert unresolved variable into method call if empty parameter list method exists in CCDB
80  * <li>create method for unresolver methods in current source code class
81  * <li>convert length() to size() and vice versa if in CCDB
82  * <li>cast to required type as reported by parser (no compatabilty checked)
83  * </ul>
84  *
85  * @author Tor Norbye
86  */

87
88
89 public class ErrorSuggester extends DocumentSuggestionProvider
90     implements Parsing.Listener {
91
92     final private static String JavaDoc TYPE = "nb-java-errors"; // NOI18N
93
// XXX as a hack, SuggestionList knows about the above type name
94
// (to make the node expanded by default, whereas other types are collapsed)
95
// so if you change the above, be sure to change it in SuggestionList
96
// as well!
97

98     public String JavaDoc getType() {
99         return TYPE;
100     }
101     
102     private SuggestionContext env;
103     private Object JavaDoc request = null;
104
105     // javadoc in super()
106
// public void rescan(SuggestionContext env, Object request) {
107
// this.request = request;
108
// this.env = env;
109
// Parsing.addParsingListener(this);
110
// try {
111
// DataObject dataObject = DataObject.find(env.getFileObject());
112
// // Cause a reparse, and then the resulting parse
113
// // event will force a scan()
114
// if (dataObject instanceof JavaDataObject) {
115
// //Parsing.requestParse((JavaDataObject)dobj, false);
116
// requestParse((JavaDataObject)dataObject, false);
117
// }
118
// } catch (IOException ex) {
119
// ex.printStackTrace();
120
// }
121
// }
122

123
124     /** Request that a particular JavaDataObject is parsed.
125      */

126     private static void requestParse(JavaDataObject jdo, boolean now) {
127         // Note: the below (getCookie) creates an environment which
128
// records the original data object associated with this parser,
129
// that's why you don't see the file to be parsed anywhere else
130
// here...
131
JavaParser parser = (JavaParser)jdo.getCookie(JavaParser.class);
132         if (parser == null) {
133             System.out.println("Parser not found!");
134             return;
135         }
136         final ParseSourceRequest req;
137         req = new ParseSourceRequest((Object JavaDoc)JavaParser.DEEP_PARSER);
138         boolean ignoreClean = true;
139         int priority = now ?
140             JavaParser.PRIORITY_DEMAND :
141             JavaParser.PRIORITY_NORMAL;
142         org.openide.util.Task t = parser.parse(priority, ignoreClean, false, req);
143     }
144
145     public void notifyStop() {
146         Parsing.removeParsingListener(this);
147     }
148
149     // The errors associated with the given data object has
150
// changed
151
private void errorsChanged(SuggestionContext env) {
152         List JavaDoc newTasks = scan(env);
153         SuggestionManager manager = SuggestionManager.getDefault();
154         if ((newTasks == null) && (showingTasks == null)) {
155             return;
156         }
157
158         manager.register(TYPE, newTasks, showingTasks);
159         showingTasks = newTasks;
160     }
161     
162     /** Scan the given document for suggestions. Typically called
163      * when a document is shown or when a document is edited, but
164      * could also be called for example as part of a directory
165      * scan for suggestions.
166      * <p>
167      * @param document The document being hidden
168      * @param dataobject The Data Object for the file being opened
169      *
170      */

171     public List JavaDoc scan(SuggestionContext env) {
172         ArrayList JavaDoc tasks = null;
173         SuggestionManager manager = SuggestionManager.getDefault();
174
175         // >experimental JMI
176
// List jmierrors = JMImpl.findErrors(env.getFileObject());
177
// Iterator ite = jmierrors.iterator();
178
// while (ite.hasNext()) {
179
// Object next = (Object) ite.next();
180
// System.err.println("JMI-ERROR " + next);
181
// }
182
// <experimental JMI
183

184         DataObject dataObject = null;
185         try {
186             dataObject = DataObject.find(env.getFileObject());
187         } catch (IOException JavaDoc ex) {
188             return null;
189         }
190         if (manager.isEnabled(TYPE)) {
191             // I can later check if this.dobj == dobj and this.editor != null, if
192
// so just use this.editor
193
ParserMessage[] errors = getMessages(env);
194             if ((errors != null) && (errors.length > 0)) {
195                 Arrays.sort(errors, new Comparator JavaDoc() {
196                     public int compare(Object JavaDoc o1, Object JavaDoc o2) {
197                         ParserMessage a = (ParserMessage)o1;
198                         ParserMessage b = (ParserMessage)o2;
199                         return a.getLineNumber() - b.getLineNumber();
200                     }
201                 });
202                 int n = errors.length;
203                 if (n > 30) {
204                     n = 30;
205                 }
206                 for (int i = 0; i < n; i++) {
207                     ParserMessage err = errors[i];
208                     String JavaDoc summary = err.getDescription();
209
210                     SuggestionAgent s = manager.createSuggestion(TYPE,
211                                     summary,
212                                     null,
213                                                 this);
214                     
215                     // Lazily compute Line from the ParserMessage. It
216
// was removed from the interface because in the
217
// implementation, pushError was getting called
218
// with a null argument, so the ParserMessageImpl
219
// object itself couldn't compute the data object
220
// to find the line.
221
Line line = TLUtils.getLineByNumber(dataObject, err.getLineNumber());
222                     s.setLine(line);
223                     if (summary.indexOf("warning: ") != -1) {
224                         // Speecial image for icons
225
s.setIcon(Utilities.loadImage("org/netbeans/modules/tasklist/javaparser/warning.gif")); // NOI18N
226
}
227                     s.setPriority(SuggestionPriority.HIGH);
228                     if (tasks == null) {
229                         tasks = new ArrayList JavaDoc(errors.length);
230                     }
231                     tasks.add(s.getSuggestion());
232                     
233                     // Create Error-fix Suggestions
234

235                     handleError(manager, tasks, env.getDocument(), dataObject,
236                                 summary, line, err.getLineNumber(),
237                                 err.getColumn());
238                     // TODO: additional checks here...
239
}
240             }
241         }
242         return tasks;
243     }
244
245     /** Check the given error message to see if we can help resolve
246      * it, and register "solutions" into the given tasks list.
247      * @param manager The suggestion manager to use
248      * @param tasks List of Suggestions. May be empty. This method will
249      * add to it any suggestions that it thinks will help fix the error.
250      * For example, if the error is "No such class: List", it may add
251      * two suggestions: "import java.awt.List" and "import java.util.List"
252      * @param doc The document for the file containing the error. Used by the
253      * SuggestionPerformers to modify the document when the user wants
254      * to apply a fix suggestion.
255      * TODO: get rid of this parameter (such that it's computed/located/
256      * opened automatically by the SuggestionPerformers when you perform
257      * the fix.
258      * @param dobj The data object for the file containing the error
259      * @param summary The compiler error message as provided by javac
260      * @param lineNumber The line number of the error message
261      * @param column The column provided for the error, if any
262      */

263     public void handleError(SuggestionManager manager, List JavaDoc tasks,
264                             final Document doc, final DataObject dobj,
265                             String JavaDoc summary,
266                             Line line,
267                             int lineNumber,
268                             int column) {
269         if (/* manager.isEnabled(IMPORTTYPE) && */
270             // Yup, the below is a big i18n fiasco. However,
271
// I don't have a choice - I don't have access to
272
// the error type in symbolic form, so I have to resort
273
// to messages. I suppose I could use a message catalog
274
// to solve the case where the compiler error and the
275
// IDE are running in the same locale?
276
// Luckily, this can be fixed with JSR-199 when it's
277
// provided
278
summary.startsWith("cannot resolve symbol")) {
279             // Btw, this is defined as "compiler.err.cant.resolve"
280
// in "compiler.properties" in javac.jar's
281
// org/netbeans/lib/javac/v8/resources package...
282
// I don't see other locales there, so perhaps I don't
283
// have a problem!!!
284

285             int lix2 = summary.indexOf("location: package"); // NOI18N
286
if (lix2 != -1) {
287                 // This is a missing class in an import statement.
288
// That pretty much means you haven't mounted
289
// a directory you should (somehow the code completion
290
// knows about it). Can't really help with that.
291
return;
292             }
293
294
295             int ix = summary.indexOf("symbol : class ");
296             if (ix != -1) {
297                 // Might have found a symbol that isn't included yet
298
ix += "symbol : class ".length();
299                 int eix = summary.indexOf(' ', ix);
300                 if (eix != -1) {
301                     String JavaDoc symbol = summary.substring(ix,eix);
302                     
303                     // TODO: create suggestion for creating a new class
304
// named "symbol"
305

306                     //JCFinder finder = JavaCompletion.getFinder();
307
// XXX Make sure JCStorage does some kind of caching!
308
//JCFinder finder = JCStorage.getStorage().
309
// caseSensitive, naturalSort, showDeprecated
310
// getFinder(true, true, true);
311
JCFinder finder = getSensitiveFinder();
312                     List JavaDoc list = finder.findClasses(null, symbol, true);
313                     if ((list != null) && (list.size() > 0)) {
314                         // Score! Let's propose suggestions for importing these
315
// classes
316
Iterator JavaDoc itr = list.iterator();
317                         while (itr.hasNext()) {
318                             final JCClass classname = (JCClass)itr.next();
319                             SuggestionPerformer action =
320                                 new ImportPerformer(lineNumber,
321                                                     dobj, doc,
322                                                     classname);
323                             String JavaDoc fname = dobj.getPrimaryFile().getNameExt();
324                             String JavaDoc sum = NbBundle.getMessage(ErrorSuggester.class,
325                             "ImportClassSg", classname, fname); // NOI18N
326
SuggestionAgent s =
327                                 manager.createSuggestion(TYPE,
328                                                          sum,
329                                                          action,
330                                                          this);
331
332                             s.setLine(line);
333                             Image taskIcon =
334                                 Utilities.loadImage("org/netbeans/modules/tasklist/javaparser/import-sg.gif"); // NOI18N
335

336                             s.setIcon(taskIcon);
337                             s.setPriority(SuggestionPriority.HIGH);
338                             tasks.add(s.getSuggestion());
339                         }
340                     }
341
342                     // Also check to see if we have spelling errors
343
// XXX Make sure JCStorage does some kind of caching!
344
//finder = JCStorage.getStorage().
345
// caseSensitive, naturalSort, showDeprecated
346
// getFinder(false, true, true);
347
finder = getInsensitiveFinder();
348                     //list = findClasses(finder, null, symbol, true);
349
list = finder.findClasses(null, symbol, true);
350                     if ((list != null) && (list.size() > 0)) {
351                         // Score! Let's propose suggestions for importing these
352
// classes
353
Iterator JavaDoc itr = list.iterator();
354                         while (itr.hasNext()) {
355                             final JCClass clz = (JCClass)itr.next();
356                             final String JavaDoc newClass = clz.getName();
357                             if (!newClass.equals(symbol)) {
358                                 // Yay - it's a casing-error
359
final String JavaDoc oldClass = symbol;
360                                 String JavaDoc beforeDesc =
361                                     NbBundle.getMessage(ErrorSuggester.class,
362                                          "ReplaceClassConfirmation"); // NOI18N
363
String JavaDoc afterDesc =
364                                     NbBundle.getMessage(ErrorSuggester.class,
365                                          "ReplaceClassAfter"); // NOI18N
366

367                                 SuggestionPerformer action =
368                                     new ReplaceSymbolPerformer(
369                                                    lineNumber,
370                                                    column,
371                                                    line,
372                                                    dobj,
373                                                    doc,
374                                                    oldClass,
375                                                    newClass,
376                                                    beforeDesc,
377                                                    afterDesc,
378                                                    clz,
379                                                    false);
380                                 String JavaDoc sum =
381                                     NbBundle.getMessage(ErrorSuggester.class,
382                                                         "ReplaceClassSg",// NOI18N
383
oldClass,
384                                                         newClass); // NOI18N
385
SuggestionAgent s =
386                                     manager.createSuggestion(TYPE,
387                                                              sum,
388                                                              action,
389                                                              this);
390                                 s.setLine(line);
391                                 Image taskIcon = Utilities.loadImage("org/netbeans/modules/tasklist/javaparser/import-sg.gif"); // NOI18N
392

393                                 s.setIcon(taskIcon);
394                                 s.setPriority(SuggestionPriority.HIGH);
395                                 tasks.add(s.getSuggestion());
396                             }
397                         }
398                     }
399                 } else {
400                     //System.out.println("Didn't find end index of the symbol!");
401
}
402                 return;
403             }
404
405             // See if it's a missing variable - if so, you may have forgotten
406
// to make it a method (add "()" at the end, e.g.
407
// System.out.println(mystring.length); -> mystring.length())
408
final String JavaDoc symVar = "symbol : variable "; // NOI18N
409
ix = summary.indexOf(symVar);
410             
411             final String JavaDoc locClass = "location: class "; // NOI18N
412
final String JavaDoc locInterface = "location: interface "; // NOI18N
413
int lix = summary.indexOf(locClass);
414             if (lix != -1) {
415                 lix += locClass.length();
416             } else {
417                 lix = summary.indexOf(locInterface);
418                 if (lix != -1) {
419                     lix += locInterface.length();
420                 }
421             }
422
423             if ((ix != -1) && (lix != -1)) {
424                 // Might have found a symbol that isn't included yet
425
ix += symVar.length();
426                 int eix = summary.indexOf(' ', ix);
427                 if (eix != -1) {
428                     String JavaDoc symbol = summary.substring(ix,eix);
429                     String JavaDoc location = summary.substring(lix);
430                     
431                     // TODO - if I had an AST Tree (will JSR-199 give me one?)
432
// I could find out the type expected of the variable,
433
// and add a suggestion offering to add a field to the
434
// class of that type (should be easily customizable
435
// by the user since s/he may want a more specific type,
436
// e.g. ArrayList instead of List)
437

438                     //JCFinder finder = JavaCompletion.getFinder();
439
// XXX Make sure JCStorage does some kind of caching!
440
//JCFinder finder = JCStorage.getStorage().
441
// caseSensitive, naturalSort, showDeprecated
442
// getFinder(true, true, true);
443
JCFinder finder = getSensitiveFinder();
444                     if (Character.isUpperCase(symbol.charAt(0))) {
445                         // Probably a static context class reference, e.g.
446
// Arrays.sort() -> "Arrays" is undefined variable
447
List JavaDoc list = finder.findClasses(null, symbol, true);
448                         if ((list != null) && (list.size() > 0)) {
449                             // Score! Let's propose suggestions for importing these
450
// classes
451
Iterator JavaDoc itr = list.iterator();
452                             while (itr.hasNext()) {
453                                 final JCClass classname = (JCClass)itr.next();
454                                 // TODO Factor this stuff so that it's shared with the Import Class code above
455
SuggestionPerformer action =
456                                     new ImportPerformer(lineNumber,
457                                                         dobj, doc,
458                                                         classname);
459                                 String JavaDoc fname = dobj.getPrimaryFile().getNameExt();
460                                 String JavaDoc sum = NbBundle.getMessage(ErrorSuggester.class,
461                                 "ImportClassSg", classname, fname); // NOI18N
462
SuggestionAgent s =
463                                 manager.createSuggestion(TYPE,
464                                                          sum,
465                                                          action,
466                                                          this);
467                                 s.setLine(line);
468                                 Image taskIcon =
469                                 Utilities.loadImage("org/netbeans/modules/tasklist/javaparser/import-sg.gif"); // NOI18N
470

471                                 s.setIcon(taskIcon);
472                                 s.setPriority(SuggestionPriority.HIGH);
473                                 tasks.add(s.getSuggestion());
474                             }
475                         }
476                     } else {
477                         JCClass clz = finder.getExactClass(location);
478                         if (clz == null) {
479                             // Most likely because the symbol is in the current
480
// class - which is not compilable (we have an error
481
// after all) so there is no JCClass for it.
482
return;
483                         }
484                         boolean staticOnly = false; // ? Hack it by looking at ctx?
485
boolean inspectOuterClasses = true;
486                         List JavaDoc list = finder.findMethods(clz, symbol, true,
487                         staticOnly, inspectOuterClasses);
488                         if ((list != null) && (list.size() > 0)) {
489                             // Score! Let's propose suggestions for converting
490
// this symbol to a method
491
Iterator JavaDoc itr = list.iterator();
492                             while (itr.hasNext()) {
493                                 
494                                 // TODO - ensure that the method found has no
495
// arguments!!!
496

497                                 final Object JavaDoc mtd = itr.next();
498                                 final String JavaDoc var = symbol;
499                                 final String JavaDoc varAfter = var + "()";
500                                 String JavaDoc beforeDesc =
501                                     NbBundle.getMessage(ErrorSuggester.class,
502                                          "ChangeMethodConfirmation"); // NOI18N
503
String JavaDoc afterDesc =
504                                     NbBundle.getMessage(ErrorSuggester.class,
505                                          "ChangeMethodAfter"); // NOI18N
506
SuggestionPerformer action =
507                                     new ReplaceSymbolPerformer(
508                                               lineNumber,
509                                               column,
510                                               line,
511                                               dobj,
512                                               doc,
513                                               var,
514                                               varAfter,
515                                               beforeDesc,
516                                               afterDesc,
517                                               null,
518                                               true);
519                                 String JavaDoc sum =
520                                     NbBundle.getMessage(ErrorSuggester.class,
521                                      "MakeMethodSg", var, varAfter); // NOI18N
522
SuggestionAgent s =
523                                     manager.createSuggestion(TYPE,
524                                                              sum,
525                                                              action,
526                                                              this);
527                                 s.setLine(line);
528                                 Image taskIcon = Utilities.loadImage("org/netbeans/modules/tasklist/javaparser/import-sg.gif"); // NOI18N
529

530                                 s.setIcon(taskIcon);
531                                 s.setPriority(SuggestionPriority.HIGH);
532                                 
533                                 tasks.add(s.getSuggestion());
534                             }
535                         }
536                     }
537                 } else {
538                     //System.out.println("Didn't find end index of the symbol!");
539
}
540             }
541
542
543
544             // See if it's a missing method - if so, you may have used the
545
// wrong case / have used a typo. Look for likely candidates.
546
final String JavaDoc symMet = "symbol : method "; // NOI18N
547
ix = summary.indexOf(symMet);
548
549             /* lix should still contain the right value after the previous check
550             lix = summary.indexOf(locClass);
551             if (lix != -1) {
552                 lix += locClass.length();
553             } else {
554                 lix = summary.indexOf(locInterface);
555                 if (lix != -1) {
556                     lix += locInterface.length();
557                 }
558             }
559             */

560
561             if ((ix != -1) && (lix != -1)) {
562                 ix += symMet.length();
563                 int eix = summary.indexOf(' ', ix);
564                 if (eix != -1) {
565                     String JavaDoc symbol = summary.substring(ix,eix);
566                     String JavaDoc location = summary.substring(lix);
567
568                     //JCFinder finder = JavaCompletion.getFinder();
569
// XXX Make sure JCStorage does some kind of caching!
570
//JCFinder finder = JCStorage.getStorage().
571
// caseSensitive, naturalSort, showDeprecated
572
// getFinder(false, true, true);
573
JCFinder finder = getInsensitiveFinder();
574                     JCClass clz = finder.getExactClass(location);
575                     if (clz == null) {
576                         // Most likely because the symbol is in the current
577
// class - which is not compilable (we have an error
578
// after all) so there is no JCClass for it.
579
suggestCreateMethod(symbol, summary, eix, location, tasks, lineNumber, column, dobj, manager);
580                         return;
581                     }
582                     boolean staticOnly = false; // ? Hack it by looking at ctx?
583
boolean inspectOuterClasses = true;
584
585
586                     // Special case: it's easy to confused about
587
// "size" vs "length" so check for this special case
588
if (symbol.equals("length")) {
589                         JCFinder sfinder = getSensitiveFinder();
590                         List JavaDoc list = sfinder.findMethods(clz, "size", false,
591                               staticOnly, inspectOuterClasses);
592                         if ((list != null) && (list.size() > 0)) {
593                             final String JavaDoc method = symbol;
594                             final JCMethod mtd = (JCMethod)list.get(0);
595                             final String JavaDoc newMethod = mtd.getName();
596
597                             createMethodReplaceSuggestion(
598                                          manager, tasks, doc, dobj,
599                                          line, lineNumber,
600                                          column, method, newMethod);
601                         }
602                     } else if (symbol.equals("size")) {
603                         JCFinder sfinder = getSensitiveFinder();
604                         List JavaDoc list = sfinder.findMethods(clz, "length", false,
605                               staticOnly, inspectOuterClasses);
606                         if ((list != null) && (list.size() > 0)) {
607                             final String JavaDoc method = symbol;
608                             final JCMethod mtd = (JCMethod)list.get(0);
609                             final String JavaDoc newMethod = mtd.getName();
610                             createMethodReplaceSuggestion(
611                                          manager, tasks, doc, dobj, line,
612                                          lineNumber,
613                                          column, method, newMethod);
614                         }
615                     }
616
617                     // NOTE -- local finder!
618
//List list = findMethods(finder, clz, symbol, false,
619
List JavaDoc list = finder.findMethods(clz, symbol, false,
620                         staticOnly, inspectOuterClasses);
621                     if ((list != null) && (list.size() > 0)) {
622                         // Score! Let's propose suggestions for replacing
623
// this symbol with the "correct" method
624
List JavaDoc used = new ArrayList JavaDoc(list.size());
625                         Iterator JavaDoc itr = list.iterator();
626                         while (itr.hasNext()) {
627                             final JCMethod mtd = (JCMethod)itr.next();
628                             final String JavaDoc newMethod = mtd.getName();
629                             // Skip identical
630
if (newMethod.equals(symbol)) {
631                                 continue;
632                             }
633                             boolean alreadyUsed = false;
634                             for (int k = 0; k < used.size(); k++) {
635                                 // Some methods appear multiple times (because
636
// it's overloaded - but we want only a single
637
// replacement suggestion)
638
if (used.get(k).equals(newMethod)) {
639                                     alreadyUsed = true;
640                                     break;
641                                 }
642                             }
643                             if (alreadyUsed) {
644                                 continue;
645                             }
646                             used.add(newMethod);
647                                     
648                             final String JavaDoc method = symbol;
649
650                             createMethodReplaceSuggestion(
651                                          manager, tasks, doc, dobj, line,
652                                          lineNumber,
653                                          column, method, newMethod);
654                         }
655                     } else {
656                         suggestCreateMethod(symbol, summary, eix, location, tasks, lineNumber, column, dobj, manager);
657                     }
658                 }
659             }
660         } else if (summary.startsWith("incompatible types") && // NOI18N
661
(column > 0)) {
662             // See if we need to add a cast
663
//
664
// I first though I could recognize = so that I
665
// could change x = y; to x = (Bar)y;
666
// but the mismatch can be elsewhere, e.g.
667
// Integer.parseInt(object); which should be changed
668
// to Integer.parseInt((String)object);
669
// So we really have to rely on the column parameter
670
// here.
671
// Note that this code is a bit ugly because I get some
672
// unexpected column positions; compare the output of javac
673
// on Object x = null; Integer i = x;
674
// and Iterator it; Float f = it.next();
675
// With future revisions of the parser compiler I should
676
// ensure that this code still works. Luckily we're using
677
// a netbeans-shipped version of the compiler, not an arbitrary
678
// one picked up in the user's environment (some other jdk,
679
// or jikes, etc.)
680

681             // TODO We probably should see if casting is possible,
682
// (e.g. if I the target cast is a subclass of what
683
// was found) but that's probably expensive.
684

685
686             final String JavaDoc foundStr = "found : "; // NOI18N
687
int fix = summary.indexOf(foundStr);
688             final String JavaDoc reqStr = "required: "; // NOI18N
689
int rix = summary.indexOf(reqStr);
690             if ((fix != -1) && (rix != -1)) {
691                 fix += foundStr.length();
692                 rix += reqStr.length();
693                 int efix = summary.indexOf('\n', fix);
694                 if (efix != -1) {
695                     // Offer to insert
696
String JavaDoc found = summary.substring(fix, efix);
697                     String JavaDoc req = summary.substring(rix);
698                     // Make sure there is only a single = on the line
699
// (and a ;, so we don't get confused about multi
700
// line statements.)
701

702                     // TODO Use org.openide.src to check if the current class
703
// can be cast to the new class.
704

705                     column--; // The position should be zero based!
706

707                     String JavaDoc text = line.getText();
708                     if (column < text.length() && text.charAt(column) == '(') {
709                         // Compute position backwards.
710
boolean fd = false; // found valid exit point
711
int i = column;
712                         for (; i >= 0; i--) {
713                             if (Character.isSpace(text.charAt(i))) {
714                                 fd = true;
715                                 break;
716                             } else if (text.charAt(i) == '=') {
717                                 fd = true;
718                                 break;
719                             } else if (text.charAt(i) == ')') {
720                                 break;
721                             }
722                         }
723                         if (fd) {
724                             // Make sure
725
if (i+1 < (column-1)) {
726                                 column = i+1;
727                             } else {
728                                 // TODO Looks like this was an existing cast.
729
// (e.g.
730
// Object x;
731
// ArrayList list = (List)x;
732
// Here we get an incompatible types error,
733
// but we can't -insert- a cast, we have to
734
// change the existing one.
735
//
736
// Perhaps do a symbol replacement here? We
737
// already have a performer for that.
738
int end = text.indexOf(')', column);
739                                 if (end != -1) {
740                                     // Don't call this "method"something,
741
// it's a generic replacer
742
createMethodReplaceSuggestion(
743                                          manager, tasks, doc, dobj,
744                                          line, lineNumber,
745                                          column, text.substring(column+1, end),
746                                          getClassName(req));
747                                 }
748                                 return;
749                             }
750                         } else {
751                             // Rename here as well?
752
return; // TODO handle with rename instead of bail!
753
}
754                     }
755
756                     createCastSuggestion(manager, tasks, doc, dobj, line,
757                                          column, req);
758                 }
759             }
760         }
761     }
762
763     // Given a fully qualified package name to a class, return just
764
// the class name. Uses case to distinguish packages from inner
765
// classes.
766
private static String JavaDoc getClassName(String JavaDoc full) {
767         int n = full.length()-1; // -1: last char can't be "."
768
// Find first dot whose next character is uppercase
769
for (int i = 0; i < n; i++) {
770             if ((full.charAt(i) == '.') &&
771                 (Character.isUpperCase(full.charAt(i+1)))) {
772                 return full.substring(i+1);
773             }
774         }
775         return full;
776     }
777
778     /** Suggest to the user to create a method with the given arguments
779       * in the given class */

780     private void suggestCreateMethod(String JavaDoc symbol, String JavaDoc summary, int eix,
781                                      String JavaDoc location, List JavaDoc tasks,
782                                      int lineNumber,
783                                      int column,
784                                      DataObject dobj,
785                                      SuggestionManager manager) {
786         // See if we can find the target location
787
if (location.startsWith("java.") ||
788             location.startsWith("javax.")) {
789             // If you're referring to a nonexistent method in java.*
790
// or javax.* you probably don't want to add a method there...
791
return;
792         }
793
794         // PENDING Do findAll?
795
FileObject f = null;
796         int div = location.lastIndexOf('.');
797         if (div != -1) {
798             // Have a package
799
String JavaDoc pkg = location.substring(0, div);
800             String JavaDoc file = location.substring(div+1);
801             // PENDING Do findAll?
802
f = Repository.getDefault().find(pkg, file, "java");
803         } else {
804             // PENDING Do findAll?
805
f = Repository.getDefault().find(".", location, "java");
806         }
807         if (f == null) {
808             return;
809         }
810         DataObject obj = null;
811         try {
812             obj = DataObject.find(f);
813         } catch (Exception JavaDoc e) {
814             return;
815         }
816
817         // Look for method arguments, starting at position eix in summary
818
int ix = summary.indexOf('(', eix);
819         String JavaDoc args = "";
820         if (ix != -1) {
821             eix = summary.indexOf(')', ix);
822             args = summary.substring(ix+1, eix);
823         }
824         if (args.length() == 0) {
825             args = NbBundle.getMessage(ErrorSuggester.class, "NoArgs");//NOI18N
826
}
827
828         SourceCookie sc = null;
829         sc = (SourceCookie)obj.getCookie(SourceCookie.Editor.class);
830         if (sc == null) {
831             return;
832         }
833
834         boolean makePublic = (obj.getFolder() != dobj.getFolder()); // same dir?
835
SuggestionPerformer action = new CreateMethodPerformer(obj,
836                                             symbol, location, args, makePublic);
837         String JavaDoc sum = NbBundle.getMessage(ErrorSuggester.class,
838                                          "CreateMethod", // NOI18N
839
symbol, location, args);
840         SuggestionAgent s = manager.createSuggestion(TYPE, sum, action, this);
841         s.setLine(TLUtils.getLineByNumber(dobj, lineNumber));
842         Image taskIcon = Utilities.loadImage("org/netbeans/modules/tasklist/javaparser/import-sg.gif"); // NOI18N
843
s.setIcon(taskIcon);
844         s.setPriority(SuggestionPriority.HIGH);
845         tasks.add(s.getSuggestion());
846     }
847
848     private void createCastSuggestion(
849                              SuggestionManager manager, List JavaDoc tasks,
850                              final Document doc,
851                              final DataObject dobj,
852                                  Line line,
853                              int column,
854                              String JavaDoc reqType) {
855         String JavaDoc beforeDesc =
856             NbBundle.getMessage(ErrorSuggester.class,
857                                 "CastConfirmation", reqType); // NOI18N
858
String JavaDoc reqClass = getClassName(reqType);
859         SuggestionPerformer action =
860             new CastPerformer(column,
861                               line,
862                               dobj,
863                               doc,
864                               reqType,
865                               reqClass,
866                               beforeDesc);
867         
868         String JavaDoc sum = NbBundle.getMessage(ErrorSuggester.class,
869                                          "AddCast", reqClass); // NOI18N
870
SuggestionAgent s =
871             manager.createSuggestion(TYPE,
872                                      sum,
873                                      action,
874                                      this);
875         s.setLine(line);
876         Image taskIcon = Utilities.loadImage("org/netbeans/modules/tasklist/javaparser/import-sg.gif"); // NOI18N
877

878         s.setIcon(taskIcon);
879         s.setPriority(SuggestionPriority.HIGH);
880         
881         tasks.add(s.getSuggestion());
882     }
883
884     private void createMethodReplaceSuggestion(
885                              SuggestionManager manager, List JavaDoc tasks,
886                              final Document doc,
887                              final DataObject dobj,
888                              Line line,
889                              int lineNumber,
890                              int column,
891                              String JavaDoc method,
892                              String JavaDoc newMethod) {
893         String JavaDoc beforeDesc =
894             NbBundle.getMessage(ErrorSuggester.class,
895                                 "ReplaceMethodConfirmation"); // NOI18N
896
String JavaDoc afterDesc =
897             NbBundle.getMessage(ErrorSuggester.class,
898                                 "ReplaceMethodAfter"); // NOI18N
899
SuggestionPerformer action =
900             new ReplaceSymbolPerformer(lineNumber,
901                                        column,
902                                        line,
903                                        dobj,
904                                        doc,
905                                        method,
906                                        newMethod,
907                                        beforeDesc,
908                                        afterDesc,
909                                        null,
910                                        false);
911         
912         String JavaDoc sum = NbBundle.getMessage(ErrorSuggester.class,
913                                          "ReplaceMethodSg", method, newMethod); // NOI18N
914
SuggestionAgent s =
915             manager.createSuggestion(TYPE,
916                                      sum,
917                                      action,
918                                      this);
919         s.setLine(line);
920         Image taskIcon = Utilities.loadImage("org/netbeans/modules/tasklist/javaparser/import-sg.gif"); // NOI18N
921

922         s.setIcon(taskIcon);
923         s.setPriority(SuggestionPriority.HIGH);
924         
925         tasks.add(s.getSuggestion());
926     }
927
928
929     JCFinder getInsensitiveFinder() {
930         if (finderNoCase == null) {
931             finderNoCase = JCStorage.getStorage().
932                 // XXX What do I do for naturalSort? Sorting is not
933
// important so do the most performante one!
934

935                 // caseSensitive, naturalSort, showDeprecated
936
getFinder(false, true, true);
937         }
938         return finderNoCase;
939     }
940
941     static JCFinder getSensitiveFinder() {
942         // XXX Perhaps I can just do
943
return JavaCompletion.getFinder();
944         /* However - does that show deprecated methods? Is that even
945            important? (Probably yes! We're trying to fix a compile error
946            and the user may have referred to that deprecated method
947            Ah yes, it seems to show deprecated!
948
949         if (finderCase == null) {
950             finderCase = JCStorage.getStorage().
951                 // caseSensitive, naturalSort, showDeprecated
952                 getFinder(true, true, true);
953         }
954         return finderCase;
955         */

956     }
957
958     JCFinder finderNoCase = null;
959     JCFinder finderCase = null;
960
961     private ParserMessage[] getMessages(SuggestionContext env) {
962         // XXX todo: store messages for all data objects here
963
if (env == this.env) {
964             return messages;
965         } else {
966             return null;
967         }
968     }
969
970     private ParserMessage[] messages = null;
971
972
973     public void objectParsed(Parsing.Event evt) {
974         // fix for #37768 & #40638
975
if (env == null || (env.getFileObject().isValid() == false))
976             return;
977         
978         DataObject dataObject = null;
979         try {
980             dataObject = DataObject.find(env.getFileObject());
981         } catch (IOException JavaDoc ex) {
982             ErrorManager.getDefault().notify(ex);
983         }
984         
985         if (evt.getJavaDataObject() == dataObject) {
986             messages = evt.getMessages();
987             errorsChanged(env);
988         } else {
989             //System.out.println("Received parsing info for " + evt.getJavaDataObject() + " ... discarding.");
990

991             // I could stash away the errors here... but that ain't
992
// good.
993
// This has two disadvantages:
994
// (1) I don't know when parsing begins - so I'll have to
995
// add myself as a listener immediately
996
// (2) I don't know when documents are closed - so I don't
997
// know when to flush out errors from the cache.
998
// Solution: Could register interest in layer such that
999
// Parsing knows whether or not it should collect info.
1000
}
1001    }
1002
1003    /** The list of tasks we're currently showing in the tasklist */
1004    private List JavaDoc showingTasks = null;
1005}
1006
1007
1008
Popular Tags