KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > java > hints > JavaHintsProvider


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-2007 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.java.hints;
21
22 import java.io.IOException JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.Arrays JavaDoc;
25 import java.util.Collections JavaDoc;
26 import java.util.HashMap JavaDoc;
27 import java.util.List JavaDoc;
28 import java.util.Map JavaDoc;
29 import javax.lang.model.element.PackageElement;
30 import javax.lang.model.type.TypeKind;
31 import javax.swing.text.Document JavaDoc;
32 import javax.swing.text.StyledDocument JavaDoc;
33 import javax.tools.Diagnostic;
34 import org.netbeans.api.java.source.CancellableTask;
35 import org.netbeans.api.timers.TimesCollector;
36 import org.netbeans.spi.editor.hints.Fix;
37 import org.netbeans.spi.editor.hints.LazyFixList;
38 import org.netbeans.spi.editor.hints.Severity;
39 import org.openide.ErrorManager;
40 import org.openide.filesystems.FileObject;
41 import org.openide.filesystems.FileUtil;
42 import org.openide.loaders.DataObject;
43 import org.openide.text.Line;
44 import com.sun.source.util.TreePath;
45 import java.util.EnumMap JavaDoc;
46 import java.util.HashSet JavaDoc;
47 import java.util.Set JavaDoc;
48 import java.util.logging.Level JavaDoc;
49 import java.util.logging.Logger JavaDoc;
50 import javax.lang.model.element.Element;
51 import javax.swing.text.BadLocationException JavaDoc;
52 import javax.swing.text.Position JavaDoc;
53 import javax.swing.text.Position.Bias;
54 import org.netbeans.api.java.lexer.JavaTokenId;
55 import org.netbeans.api.java.source.CompilationInfo;
56 import org.netbeans.api.java.source.JavaSource;
57 import org.netbeans.api.lexer.Token;
58 import org.netbeans.api.lexer.TokenHierarchy;
59 import org.netbeans.api.lexer.TokenSequence;
60 import org.netbeans.modules.java.hints.CreatorBasedLazyFixList;
61 import org.netbeans.modules.java.hints.ImportClassEnabler.ImportCandidatesHolder;
62 import org.netbeans.modules.java.hints.LazyHintComputationFactory;
63 import org.netbeans.modules.java.hints.infrastructure.RulesManager;
64 import org.netbeans.modules.java.hints.spi.ErrorRule;
65 import org.netbeans.modules.java.hints.spi.ErrorRule.Data;
66 import org.netbeans.spi.editor.hints.ErrorDescription;
67 import org.netbeans.spi.editor.hints.ErrorDescriptionFactory;
68 import org.netbeans.spi.editor.hints.HintsController;
69 import org.openide.cookies.EditorCookie;
70 import org.openide.cookies.LineCookie;
71 import org.openide.text.NbDocument;
72
73
74
75 /**
76  * @author Jan Lahoda
77  * @author leon chiver
78  */

79 public final class JavaHintsProvider implements CancellableTask<CompilationInfo> {
80     
81     public static ErrorManager ERR = ErrorManager.getDefault().getInstance("org.netbeans.modules.java.hints"); // NOI18N
82
public static Logger JavaDoc LOG = Logger.getLogger("org.netbeans.modules.java.hints"); // NOI18N
83

84     private FileObject file;
85     
86     /** Creates a new instance of JavaHintsProvider */
87     JavaHintsProvider(FileObject file) {
88         this.file = file;
89     }
90     
91     private static final Map JavaDoc<Diagnostic.Kind, Severity> errorKind2Severity;
92     
93     static {
94         errorKind2Severity = new EnumMap JavaDoc<Diagnostic.Kind, Severity>(Diagnostic.Kind.class);
95         errorKind2Severity.put(Diagnostic.Kind.ERROR, Severity.ERROR);
96         errorKind2Severity.put(Diagnostic.Kind.MANDATORY_WARNING, Severity.WARNING);
97         errorKind2Severity.put(Diagnostic.Kind.WARNING, Severity.WARNING);
98         errorKind2Severity.put(Diagnostic.Kind.NOTE, Severity.WARNING);
99         errorKind2Severity.put(Diagnostic.Kind.OTHER, Severity.WARNING);
100     }
101     
102     List JavaDoc<ErrorDescription> computeErrors(CompilationInfo info, Document JavaDoc doc) {
103         JavaSource js = JavaSource.forFileObject(file);
104         List JavaDoc<Diagnostic> errors = info.getDiagnostics();
105         List JavaDoc<ErrorDescription> descs = new ArrayList JavaDoc<ErrorDescription>();
106         
107         if (ERR.isLoggable(ErrorManager.INFORMATIONAL))
108             ERR.log(ErrorManager.INFORMATIONAL, "errors = " + errors );
109         
110         Map JavaDoc<Class JavaDoc, Data> data = new HashMap JavaDoc<Class JavaDoc, Data>();
111         
112         for (Diagnostic d : errors) {
113             if (isCanceled())
114                 return null;
115             
116             if (ERR.isLoggable(ErrorManager.INFORMATIONAL))
117                 ERR.log(ErrorManager.INFORMATIONAL, "d = " + d );
118             
119             Map JavaDoc<String JavaDoc, List JavaDoc<ErrorRule>> code2Rules = RulesManager.getInstance().getErrors();
120             
121             List JavaDoc<ErrorRule> rules = code2Rules.get(d.getCode());
122             
123             if (ERR.isLoggable(ErrorManager.INFORMATIONAL)) {
124                 ERR.log(ErrorManager.INFORMATIONAL, "code= " + d.getCode());
125                 ERR.log(ErrorManager.INFORMATIONAL, "rules = " + rules);
126             }
127             
128             LazyFixList ehm;
129             
130             if (rules != null) {
131                 ehm = new CreatorBasedLazyFixList(info.getFileObject(), d.getCode(), (int)getPrefferedPosition(info, d), rules, data);
132             } else {
133                 ehm = ErrorDescriptionFactory.lazyListForFixes(Collections.<Fix>emptyList());
134             }
135             
136             if (ERR.isLoggable(ErrorManager.INFORMATIONAL))
137                 ERR.log(ErrorManager.INFORMATIONAL, "ehm=" + ehm);
138             
139             final String JavaDoc desc = d.getMessage(null);
140             final Position JavaDoc[] range = getLine(info, d, doc, (int)d.getStartPosition(), (int)d.getEndPosition());
141             
142             if (isCanceled())
143                 return null;
144             
145             if (range[0] == null || range[1] == null)
146                 continue;
147             
148             descs.add(ErrorDescriptionFactory.createErrorDescription(errorKind2Severity.get(d.getKind()), desc, ehm, doc, range[0], range[1]));
149         }
150         
151         if (isCanceled())
152             return null;
153         
154         LazyHintComputationFactory.getAndClearToCompute(file);
155         
156         return descs;
157     }
158     
159     public Document JavaDoc getDocument() {
160         try {
161             DataObject d = DataObject.find(file);
162             EditorCookie ec = (EditorCookie) d.getCookie(EditorCookie.class);
163             
164             if (ec == null)
165                 return null;
166             
167             return ec.getDocument();
168         } catch (IOException JavaDoc e) {
169             Logger.getLogger(JavaHintsProvider.class.getName()).log(Level.INFO, "SemanticHighlighter: Cannot find DataObject for file: " + FileUtil.getFileDisplayName(file), e);
170             return null;
171         }
172     }
173     
174     public static Token findUnresolvedElementToken(CompilationInfo info, int offset) {
175         TokenSequence<JavaTokenId> ts = info.getTokenHierarchy().tokenSequence();
176         
177         ts.move(offset);
178         if (ts.moveNext()) {
179             Token t = ts.token();
180
181             if (t.id() == JavaTokenId.DOT) {
182                 ts.moveNext();
183                 t = ts.token();
184             } else {
185                 if (t.id() == JavaTokenId.LT) {
186                     ts.moveNext();
187                     t = ts.token();
188                 }
189             }
190
191             if (t.id() == JavaTokenId.IDENTIFIER) {
192                 return ts.offsetToken();
193             }
194         }
195         return null;
196     }
197     
198     private static int[] findUnresolvedElementSpan(CompilationInfo info, int offset) {
199         TokenHierarchy th = info.getTokenHierarchy();
200         
201         Token t = findUnresolvedElementToken(info, offset);
202         
203         if (t != null) {
204             return new int[] {
205                 t.offset(th),
206                 t.offset(th) + t.length()
207             };
208         }
209         
210         return null;
211     }
212     
213     static TreePath findUnresolvedElement(CompilationInfo info, int offset) {
214         int[] span = findUnresolvedElementSpan(info, offset);
215         
216         if (span != null) {
217             return info.getTreeUtilities().pathFor(span[0] + 1);
218         } else {
219             return null;
220         }
221     }
222     
223     private static final Set JavaDoc<String JavaDoc> CANNOT_RESOLVE = new HashSet JavaDoc<String JavaDoc>(Arrays.asList(
224             "compiler.err.cant.resolve",
225             "compiler.err.cant.resolve.location",
226             "compiler.err.doesnt.exist"
227     ));
228     
229     private static final Set JavaDoc<String JavaDoc> UNDERLINE_IDENTIFIER = new HashSet JavaDoc<String JavaDoc>(Arrays.asList(
230             "compiler.err.local.var.accessed.from.icls.needs.final",
231             "compiler.err.var.might.not.have.been.initialized"
232     ));
233     
234     private Position JavaDoc[] getLine(CompilationInfo info, Diagnostic d, final Document JavaDoc doc, int startOffset, int endOffset) {
235         StyledDocument JavaDoc sdoc = (StyledDocument JavaDoc) doc;
236         DataObject dObj = (DataObject)doc.getProperty(doc.StreamDescriptionProperty );
237         LineCookie lc = (LineCookie) dObj.getCookie(LineCookie.class);
238         int lineNumber = NbDocument.findLineNumber(sdoc, startOffset);
239         int lineOffset = NbDocument.findLineOffset(sdoc, lineNumber);
240         Line line = lc.getLineSet().getCurrent(lineNumber);
241         
242         boolean rangePrepared = false;
243         
244         if (CANNOT_RESOLVE.contains(d.getCode())) {
245             int[] span = findUnresolvedElementSpan(info, (int) getPrefferedPosition(info, d));
246             
247             if (span != null && span[0] != (-1) && span[1] != (-1)) {
248                 startOffset = span[0];
249                 endOffset = span[1];
250                 rangePrepared = true;
251             }
252         }
253         
254         if (UNDERLINE_IDENTIFIER.contains(d.getCode())) {
255             TokenSequence<JavaTokenId> ts = info.getTokenHierarchy().tokenSequence(JavaTokenId.language());
256             
257             int diff = ts.move((int) getPrefferedPosition(info, d));
258             
259             if (ts.moveNext() && diff >= 0 && diff < ts.token().length()) {
260                 Token<JavaTokenId> t = ts.token();
261                 
262                 if (t.id() == JavaTokenId.IDENTIFIER) {
263                     startOffset = ts.offset();
264                     endOffset = startOffset + t.length();
265                     rangePrepared = true;
266                 }
267             }
268         }
269         
270         if (!rangePrepared) {
271             String JavaDoc text = line.getText();
272             
273             int column = 0;
274             int length = text.length();
275             
276             while (column < text.length() && Character.isWhitespace(text.charAt(column)))
277                 column++;
278             
279             while (length > 0 && Character.isWhitespace(text.charAt(length - 1)))
280                 length--;
281             
282             startOffset = lineOffset + column;
283             endOffset = lineOffset + length;
284         }
285         
286         if (ERR.isLoggable(ErrorManager.INFORMATIONAL)) {
287             ERR.log(ErrorManager.INFORMATIONAL, "startOffset = " + startOffset );
288             ERR.log(ErrorManager.INFORMATIONAL, "endOffset = " + endOffset );
289         }
290         
291         final int startOffsetFinal = startOffset;
292         final int endOffsetFinal = endOffset;
293         final Position JavaDoc[] result = new Position JavaDoc[2];
294         
295         doc.render(new Runnable JavaDoc() {
296             public void run() {
297                 if (isCanceled())
298                     return;
299                 
300                 int len = doc.getLength();
301                 
302                 if (startOffsetFinal >= len || endOffsetFinal >= len) {
303                     if (!isCanceled() && ERR.isLoggable(ErrorManager.WARNING)) {
304                         ERR.log(ErrorManager.WARNING, "document changed, but not canceled?" );
305                         ERR.log(ErrorManager.WARNING, "len = " + len );
306                         ERR.log(ErrorManager.WARNING, "startOffset = " + startOffsetFinal );
307                         ERR.log(ErrorManager.WARNING, "endOffset = " + endOffsetFinal );
308                     }
309                     cancel();
310                     
311                     return;
312                 }
313                 
314                 try {
315                     result[0] = NbDocument.createPosition(doc, startOffsetFinal, Bias.Forward);
316                     result[1] = NbDocument.createPosition(doc, endOffsetFinal, Bias.Backward);
317                 } catch (BadLocationException JavaDoc e) {
318                     ERR.notify(ErrorManager.ERROR, e);
319                 }
320             }
321         });
322         
323         return result;
324     }
325     
326     private boolean cancel;
327     
328     synchronized boolean isCanceled() {
329         return cancel;
330     }
331     
332     public synchronized void cancel() {
333         cancel = true;
334     }
335     
336     synchronized void resume() {
337         cancel = false;
338     }
339     
340     public void run(CompilationInfo info) {
341         resume();
342         
343         Document JavaDoc doc = getDocument();
344         
345         if (doc == null) {
346             Logger.getLogger(JavaHintsProvider.class.getName()).log(Level.INFO, "SemanticHighlighter: Cannot get document!");
347             return ;
348         }
349         
350         long start = System.currentTimeMillis();
351         
352         List JavaDoc<ErrorDescription> errors = computeErrors(info, doc);
353         
354         if (errors == null) //meaning: cancelled
355
return ;
356         
357         HintsController.setErrors(doc, "java-hints", errors);
358         
359         long end = System.currentTimeMillis();
360         
361         TimesCollector.getDefault().reportTime(info.getFileObject(), "java-hints", "Java Hints", end - start);
362     }
363     
364     private long getPrefferedPosition(CompilationInfo info, Diagnostic d) {
365         if ("compiler.err.doesnt.exist".equals(d.getCode())) {
366             return d.getStartPosition();
367         }
368         if ("compiler.err.not.stmt".equals(d.getCode())) {
369             //check for "Collections.":
370
TreePath path = findUnresolvedElement(info, (int) d.getStartPosition() - 1);
371             Element el = path != null ? info.getTrees().getElement(path) : null;
372             
373             if (el == null || el.asType().getKind() == TypeKind.ERROR) {
374                 return d.getStartPosition() - 1;
375             }
376             
377             if (el.asType().getKind() == TypeKind.PACKAGE) {
378                 //check if the package does actually exist:
379
String JavaDoc s = ((PackageElement) el).getQualifiedName().toString();
380                 if (info.getElements().getPackageElement(s) == null) {
381                     //it does not:
382
return d.getStartPosition() - 1;
383                 }
384             }
385             
386             return d.getStartPosition();
387         }
388         
389         return d.getPosition();
390     }
391     
392 }
393
394
Popular Tags