Fixing @SuppressWarnings for marks-based hints.
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4 * Copyright 2008-2010 Sun Microsystems, Inc. All rights reserved.
6 * The contents of this file are subject to the terms of either the GNU
7 * General Public License Version 2 only ("GPL") or the Common
8 * Development and Distribution License("CDDL") (collectively, the
9 * "License"). You may not use this file except in compliance with the
10 * License. You can obtain a copy of the License at
11 * http://www.netbeans.org/cddl-gplv2.html
12 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13 * specific language governing permissions and limitations under the
14 * License. When distributing the software, include this License Header
15 * Notice in each file and include the License file at
16 * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
17 * particular file as subject to the "Classpath" exception as provided
18 * by Sun in the GPL Version 2 section of the License file that
19 * accompanied this code. If applicable, add the following below the
20 * License Header, with the fields enclosed by brackets [] replaced by
21 * your own identifying information:
22 * "Portions Copyrighted [year] [name of copyright owner]"
24 * If you wish your version of this file to be governed by only the CDDL
25 * or only the GPL Version 2, indicate your decision by adding
26 * "[Contributor] elects to include this software in this distribution
27 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28 * single choice of license, a recipient has the option to distribute
29 * your version of this file under either the CDDL, the GPL Version 2 or
30 * to extend the choice of license to its licensees as provided above.
31 * However, if you add GPL Version 2 code and therefore, elected the GPL
32 * Version 2 license, then the option applies only if the new code is
33 * made subject to such option by the copyright holder.
37 * Portions Copyrighted 2008-2010 Sun Microsystems, Inc.
40 package org.netbeans.modules.jackpot30.impl.hints;
42 import com.sun.source.tree.Tree;
43 import java.util.Stack;
44 import java.util.concurrent.atomic.AtomicBoolean;
45 import javax.lang.model.element.AnnotationMirror;
46 import javax.lang.model.element.AnnotationValue;
47 import javax.lang.model.element.Element;
48 import javax.lang.model.element.ExecutableElement;
49 import javax.lang.model.element.TypeElement;
50 import javax.swing.text.Document;
51 import org.netbeans.api.java.source.support.CancellableTreePathScanner;
52 import org.netbeans.editor.GuardedDocument;
53 import org.netbeans.editor.MarkBlock;
54 import org.netbeans.editor.MarkBlockChain;
55 import org.openide.filesystems.FileObject;
57 import com.sun.source.tree.Tree.Kind;
58 import com.sun.source.util.TreePath;
59 import com.sun.source.util.Trees;
60 import java.io.IOException;
61 import java.util.ArrayList;
62 import java.util.Collection;
63 import java.util.Collections;
64 import java.util.Comparator;
65 import java.util.HashMap;
66 import java.util.HashSet;
67 import java.util.Iterator;
68 import java.util.LinkedList;
69 import java.util.List;
71 import java.util.Map.Entry;
73 import javax.annotation.processing.ProcessingEnvironment;
74 import javax.lang.model.type.TypeMirror;
75 import org.netbeans.api.java.source.CompilationInfo;
76 import org.netbeans.modules.jackpot30.impl.MessageImpl;
77 import org.netbeans.modules.jackpot30.impl.RulesManager;
78 import org.netbeans.modules.jackpot30.impl.Utilities;
79 import org.netbeans.modules.jackpot30.impl.pm.BulkSearch;
80 import org.netbeans.modules.jackpot30.impl.pm.BulkSearch.BulkPattern;
81 import org.netbeans.modules.jackpot30.impl.pm.CopyFinder;
82 import org.netbeans.modules.jackpot30.impl.pm.CopyFinder.VariableAssignments;
83 import org.netbeans.modules.jackpot30.impl.pm.Pattern;
84 import org.netbeans.modules.jackpot30.spi.Hacks;
85 import org.netbeans.modules.jackpot30.spi.HintContext;
86 import org.netbeans.modules.jackpot30.spi.HintDescription;
87 import org.netbeans.modules.jackpot30.spi.HintDescription.Condition;
88 import org.netbeans.modules.jackpot30.spi.HintDescription.CustomCondition;
89 import org.netbeans.modules.jackpot30.spi.HintDescription.DeclarativeFixDescription;
90 import org.netbeans.modules.jackpot30.spi.HintDescription.ErrorDescriptionAcceptor;
91 import org.netbeans.modules.jackpot30.spi.HintDescription.FixAcceptor;
92 import org.netbeans.modules.jackpot30.spi.HintDescription.Literal;
93 import org.netbeans.modules.jackpot30.spi.HintDescription.MarkCondition;
94 import org.netbeans.modules.jackpot30.spi.HintDescription.MarksWorker;
95 import org.netbeans.modules.jackpot30.spi.HintDescription.Operator;
96 import org.netbeans.modules.jackpot30.spi.HintDescription.OtherwiseCondition;
97 import org.netbeans.modules.jackpot30.spi.HintDescription.PatternDescription;
98 import org.netbeans.modules.jackpot30.spi.HintDescription.Selector;
99 import org.netbeans.modules.jackpot30.spi.HintDescription.Value;
100 import org.netbeans.modules.jackpot30.spi.HintMetadata;
101 import org.netbeans.modules.jackpot30.spi.HintMetadata.HintSeverity;
102 import org.netbeans.modules.jackpot30.spi.support.FixFactory;
103 import org.netbeans.spi.editor.hints.ErrorDescription;
104 import org.netbeans.spi.editor.hints.ErrorDescriptionFactory;
105 import org.netbeans.spi.editor.hints.Fix;
106 import org.netbeans.spi.editor.hints.Severity;
107 import org.openide.util.Exceptions;
113 public class HintsInvoker {
115 private final Map<String, Long> timeLog = new HashMap<String, Long>();
117 private final CompilationInfo info;
118 private final int caret;
119 private final int from;
120 private final int to;
121 private final AtomicBoolean cancel;
123 public HintsInvoker(CompilationInfo info, AtomicBoolean cancel) {
124 this(info, -1, cancel);
127 public HintsInvoker(CompilationInfo info, int caret, AtomicBoolean cancel) {
128 this(info, caret, -1, -1, cancel);
131 public HintsInvoker(CompilationInfo info, int from, int to, AtomicBoolean cancel) {
132 this(info, -1, from, to, cancel);
135 private HintsInvoker(CompilationInfo info, int caret, int from, int to, AtomicBoolean cancel) {
140 this.cancel = cancel;
143 public List<ErrorDescription> computeHints(CompilationInfo info) {
144 return computeHints(info, new TreePath(info.getCompilationUnit()));
147 private List<ErrorDescription> computeHints(CompilationInfo info, TreePath startAt) {
148 List<HintDescription> descs = new LinkedList<HintDescription>();
149 for (Entry<HintMetadata, Collection<? extends HintDescription>> e : RulesManager.getInstance().allHints.entrySet()) {
150 HintMetadata m = e.getKey();
152 if (!RulesManager.getInstance().isHintEnabled(m)) {
157 if (m.kind == HintMetadata.Kind.SUGGESTION || m.kind == HintMetadata.Kind.SUGGESTION_NON_GUI) {
158 descs.addAll(e.getValue());
160 if (RulesManager.getInstance().getHintSeverity(m) == HintSeverity.CURRENT_LINE_WARNING) {
161 descs.addAll(e.getValue());
165 if (m.kind == HintMetadata.Kind.HINT || m.kind == HintMetadata.Kind.HINT_NON_GUI) {
166 if (RulesManager.getInstance().getHintSeverity(m) != HintSeverity.CURRENT_LINE_WARNING || from != (-1)) {
167 descs.addAll(e.getValue());
173 Map<Kind, List<HintDescription>> kindHints = new HashMap<Kind, List<HintDescription>>();
174 Map<PatternDescription, List<HintDescription>> patternHints = new HashMap<PatternDescription, List<HintDescription>>();
176 RulesManager.sortOut(descs, kindHints, patternHints);
178 long elementBasedStart = System.currentTimeMillis();
180 RulesManager.computeElementBasedHintsXXX(info, cancel, kindHints, patternHints);
182 long elementBasedEnd = System.currentTimeMillis();
184 timeLog.put("Computing Element Based Hints", elementBasedEnd - elementBasedStart);
186 List<ErrorDescription> errors = join(computeHints(info, startAt, kindHints, patternHints, new LinkedList<MessageImpl>()));
188 dumpTimeSpentInHints();
193 public List<ErrorDescription> computeHints(CompilationInfo info,
194 Map<Kind, List<HintDescription>> hints,
195 Map<PatternDescription, List<HintDescription>> patternHints) {
196 return computeHints(info, hints, patternHints, new LinkedList<MessageImpl>());
199 public List<ErrorDescription> computeHints(CompilationInfo info,
200 Map<Kind, List<HintDescription>> hints,
201 Map<PatternDescription, List<HintDescription>> patternHints,
202 Collection<? super MessageImpl> problems) {
203 return join(computeHints(info, new TreePath(info.getCompilationUnit()), hints, patternHints, problems));
206 public Map<HintDescription, List<ErrorDescription>> computeHints(CompilationInfo info,
208 Map<Kind, List<HintDescription>> hints,
209 Map<PatternDescription, List<HintDescription>> patternHints,
210 Collection<? super MessageImpl> problems) {
212 TreePath tp = info.getTreeUtilities().pathFor(caret);
213 return computeSuggestions(info, tp, hints, patternHints, problems);
215 if (from != (-1) && to != (-1)) {
216 return computeHintsInSpan(info, hints, patternHints, problems);
218 return computeHintsImpl(info, startAt, hints, patternHints, problems);
223 Map<HintDescription, List<ErrorDescription>> computeHintsImpl(CompilationInfo info,
225 Map<Kind, List<HintDescription>> hints,
226 Map<PatternDescription, List<HintDescription>> patternHints,
227 Collection<? super MessageImpl> problems) {
228 Map<HintDescription, List<ErrorDescription>> errors = new HashMap<HintDescription, List<ErrorDescription>>();
232 for (Entry<Kind, List<HintDescription>> e : hints.entrySet()) {
233 kindCount += e.getValue().size();
236 timeLog.put("[C] Kind Based Hints", kindCount);
238 if (!hints.isEmpty()) {
239 long kindStart = System.currentTimeMillis();
241 new ScannerImpl(info, cancel, hints).scan(startAt, errors);
243 long kindEnd = System.currentTimeMillis();
245 timeLog.put("Kind Based Hints", kindEnd - kindStart);
248 timeLog.put("[C] Pattern Based Hints", (long) patternHints.size());
250 long patternStart = System.currentTimeMillis();
252 Map<String, List<PatternDescription>> patternTests = computePatternTests(patternHints);
254 long bulkPatternStart = System.currentTimeMillis();
256 BulkPattern bulkPattern = BulkSearch.getDefault().create(info, patternTests.keySet());
258 long bulkPatternEnd = System.currentTimeMillis();
260 timeLog.put("Bulk Pattern preparation", bulkPatternEnd - bulkPatternStart);
262 long bulkStart = System.currentTimeMillis();
264 Map<String, Collection<TreePath>> occurringPatterns = BulkSearch.getDefault().match(info, startAt, bulkPattern, timeLog);
266 long bulkEnd = System.currentTimeMillis();
268 timeLog.put("Bulk Search", bulkEnd - bulkStart);
270 mergeAll(errors, doComputeHints(info, occurringPatterns, patternTests, patternHints, problems));
272 long patternEnd = System.currentTimeMillis();
274 timeLog.put("Pattern Based Hints", patternEnd - patternStart);
279 Map<HintDescription, List<ErrorDescription>> computeHintsInSpan(CompilationInfo info,
280 Map<Kind, List<HintDescription>> hints,
281 Map<PatternDescription, List<HintDescription>> patternHints,
282 Collection<? super MessageImpl> problems) {
284 TreePath path = info.getTreeUtilities().pathFor((from + to) / 2);
286 while (path.getLeaf().getKind() != Kind.COMPILATION_UNIT) {
287 int start = (int) info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), path.getLeaf());
288 int end = (int) info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), path.getLeaf());
290 if (start <= from && end >= to) {
294 path = path.getParentPath();
297 Map<HintDescription, List<ErrorDescription>> errors = new HashMap<HintDescription, List<ErrorDescription>>();
299 if (!hints.isEmpty()) {
300 long kindStart = System.currentTimeMillis();
302 new ScannerImpl(info, cancel, hints).scan(path, errors);
304 long kindEnd = System.currentTimeMillis();
306 timeLog.put("Kind Based Hints", kindEnd - kindStart);
309 if (!patternHints.isEmpty()) {
310 long patternStart = System.currentTimeMillis();
312 Map<String, List<PatternDescription>> patternTests = computePatternTests(patternHints);
314 long bulkStart = System.currentTimeMillis();
316 BulkPattern bulkPattern = BulkSearch.getDefault().create(info, patternTests.keySet());
317 Map<String, Collection<TreePath>> occurringPatterns = BulkSearch.getDefault().match(info, path, bulkPattern, timeLog);
319 long bulkEnd = System.currentTimeMillis();
321 timeLog.put("Bulk Search", bulkEnd - bulkStart);
323 mergeAll(errors, doComputeHints(info, occurringPatterns, patternTests, patternHints, problems));
325 long patternEnd = System.currentTimeMillis();
327 timeLog.put("Pattern Based Hints", patternEnd - patternStart);
333 Map<HintDescription, List<ErrorDescription>> computeSuggestions(CompilationInfo info,
335 Map<Kind, List<HintDescription>> hints,
336 Map<PatternDescription, List<HintDescription>> patternHints,
337 Collection<? super MessageImpl> problems) {
338 Map<HintDescription, List<ErrorDescription>> errors = new HashMap<HintDescription, List<ErrorDescription>>();
340 if (!hints.isEmpty()) {
341 long kindStart = System.currentTimeMillis();
343 TreePath proc = workOn;
345 while (proc != null) {
346 new ScannerImpl(info, cancel, hints).scanDoNotGoDeeper(proc, errors);
347 proc = proc.getParentPath();
350 long kindEnd = System.currentTimeMillis();
352 timeLog.put("Kind Based Suggestions", kindEnd - kindStart);
355 if (!patternHints.isEmpty()) {
356 long patternStart = System.currentTimeMillis();
358 Map<String, List<PatternDescription>> patternTests = computePatternTests(patternHints);
360 //pretend that all the patterns occur on all treepaths from the current path
361 //up (probably faster than using BulkSearch over whole file)
362 //TODO: what about machint trees under the current path?
363 Set<TreePath> paths = new HashSet<TreePath>();
365 TreePath tp = workOn;
369 tp = tp.getParentPath();
372 Map<String, Collection<TreePath>> occurringPatterns = new HashMap<String, Collection<TreePath>>();
374 for (String p : patternTests.keySet()) {
375 occurringPatterns.put(p, paths);
378 // long bulkStart = System.currentTimeMillis();
380 // BulkPattern bulkPattern = BulkSearch.getDefault().create(info, patternTests.keySet());
381 // Map<String, Collection<TreePath>> occurringPatterns = BulkSearch.getDefault().match(info, new TreePath(info.getCompilationUnit()), bulkPattern, timeLog);
383 // long bulkEnd = System.currentTimeMillis();
385 // Set<Tree> acceptedLeafs = new HashSet<Tree>();
387 // TreePath tp = workOn;
389 // while (tp != null) {
390 // acceptedLeafs.add(tp.getLeaf());
391 // tp = tp.getParentPath();
394 // for (Entry<String, Collection<TreePath>> e : occurringPatterns.entrySet()) {
395 // for (Iterator<TreePath> it = e.getValue().iterator(); it.hasNext(); ) {
396 // if (!acceptedLeafs.contains(it.next().getLeaf())) {
402 // timeLog.put("Bulk Search", bulkEnd - bulkStart);
404 mergeAll(errors, doComputeHints(info, occurringPatterns, patternTests, patternHints, problems));
406 long patternEnd = System.currentTimeMillis();
408 timeLog.put("Pattern Based Hints", patternEnd - patternStart);
414 public Map<HintDescription, List<ErrorDescription>> doComputeHints(CompilationInfo info, Map<String, Collection<TreePath>> occurringPatterns, Map<String, List<PatternDescription>> patterns, Map<PatternDescription, List<HintDescription>> patternHints) throws IllegalStateException {
415 return doComputeHints(info, occurringPatterns, patterns, patternHints, new LinkedList<MessageImpl>());
418 public static Map<String, List<PatternDescription>> computePatternTests(Map<PatternDescription, List<HintDescription>> patternHints) {
419 Map<String, List<PatternDescription>> patternTests = new HashMap<String, List<PatternDescription>>();
420 for (Entry<PatternDescription, List<HintDescription>> e : patternHints.entrySet()) {
421 String p = e.getKey().getPattern();
422 List<PatternDescription> descs = patternTests.get(p);
424 patternTests.put(p, descs = new LinkedList<PatternDescription>());
426 descs.add(e.getKey());
431 private Map<HintDescription, List<ErrorDescription>> doComputeHints(CompilationInfo info, Map<String, Collection<TreePath>> occurringPatterns, Map<String, List<PatternDescription>> patterns, Map<PatternDescription, List<HintDescription>> patternHints, Collection<? super MessageImpl> problems) throws IllegalStateException {
432 Map<HintDescription, List<ErrorDescription>> errors = new HashMap<HintDescription, List<ErrorDescription>>();
433 List<HintEvaluationData> evaluationData = new LinkedList<HintEvaluationData>();
435 for (Entry<String, Collection<TreePath>> occ : occurringPatterns.entrySet()) {
436 for (PatternDescription d : patterns.get(occ.getKey())) {
437 Map<String, TypeMirror> constraints = new HashMap<String, TypeMirror>();
439 for (Entry<String, String> e : d.getConstraints().entrySet()) {
440 constraints.put(e.getKey(), Hacks.parseFQNType(info, e.getValue()));
443 Pattern p = Pattern.compile(info, occ.getKey(), constraints, d.getImports());
444 TreePath toplevel = new TreePath(info.getCompilationUnit());
445 TreePath patt = new TreePath(toplevel, p.getPattern());
447 for (TreePath candidate : occ.getValue()) {
448 VariableAssignments verified = CopyFinder.computeVariables(info, patt, candidate, cancel, p.getConstraints());
450 if (verified == null) {
454 Set<String> suppressedWarnings = new HashSet<String>(Utilities.findSuppressedWarnings(info, candidate));
456 for (HintDescription hd : patternHints.get(d)) {
457 HintMetadata hm = hd.getMetadata();
458 HintContext c = new HintContext(info, hm, candidate, verified.variables, verified.multiVariables, verified.variables2Names, constraints, problems);
460 if (!Collections.disjoint(suppressedWarnings, hm.suppressWarnings))
463 if (hd.getWorker() instanceof MarksWorker) {
464 HintContext workerContext = new HintContext(c);
466 workerContext.enterScope();
468 MarksWorker mw = (MarksWorker) hd.getWorker();
469 List<FixEvaluationData> fixData = new LinkedList<FixEvaluationData>();
471 for (DeclarativeFixDescription fd : mw.fixes) {
472 HintContext fixContext = new HintContext(workerContext);
474 fixContext.enterScope();
475 fixData.add(new FixEvaluationData(fixContext, new LinkedList<Condition>(fd.marks), fd.acceptor));
478 HintEvaluationData data = new HintEvaluationData(workerContext, hd, new LinkedList<Condition>(mw.marks), mw.acceptor, fixData);
480 evaluationData.add(data);
484 Collection<? extends ErrorDescription> workerErrors = runHint(hd, c);
486 if (workerErrors != null) {
487 merge(errors, hd, workerErrors);
494 Map<Tree, Map<String, Object>> marks = new HashMap<Tree, Map<String, Object>>();
496 for (HintEvaluationData hed : evaluationData) {
497 enterSpeculativeAssignments(hed.ctx, hed.marks, marks);
499 for (FixEvaluationData fed : hed.fixDescriptions) {
500 //XXX: there is currently no test that would test this: (seee testSpeculativeAssignmentForFixes)
501 enterSpeculativeAssignments(hed.ctx, fed.marks, marks);
505 boolean wasChange = true;
507 while (wasChange /*!evaluationData.isEmpty()*/) {
508 boolean currentWasChange = false;
510 for (Iterator<HintEvaluationData> it = evaluationData.iterator(); it.hasNext(); ) {
511 HintEvaluationData hed = it.next();
512 int origMarksSize = hed.marks.size();
514 Boolean hres = processConditions(hed.ctx, marks, hed.marks, -1, -1);
516 currentWasChange |= origMarksSize != hed.marks.size();
523 if (hres != null && !hres) {
524 currentWasChange = true;
525 clearSpeculativeAssignments(hed.ctx, hed.marks, marks);
526 for (FixEvaluationData fed : hed.fixDescriptions) {
527 clearSpeculativeAssignments(hed.ctx, fed.marks, marks);
533 for (Iterator<FixEvaluationData> fixes = hed.fixDescriptions.iterator(); fixes.hasNext(); ) {
534 FixEvaluationData fed = fixes.next();
535 int o = fed.marks.size();
536 Boolean res = processConditions(fed.ctx, marks, fed.marks, hed.fixDescriptions.size(), hed.createdFixes.size());
538 currentWasChange |= o != fed.marks.size();
540 if (res == null) continue;
543 Fix fix = fed.acceptor.accept(fed.ctx);
546 hed.createdFixes.add(fix);
549 clearSpeculativeAssignments(fed.ctx, fed.marks, marks);
553 currentWasChange = true;
556 if (!wasChange && !currentWasChange) {
557 hed.fixDescriptions.clear();
560 if (hed.fixDescriptions.isEmpty()) {
561 //XXX: @SuppressWarnings!
562 ErrorDescription ed = hed.acceptor.accept(hed.ctx);
563 List<String> swKeys = new ArrayList<String>();
565 for (String key : hed.hd.getSuppressWarnings()) {
566 if (key == null) break;
570 List<Fix> fixes = new ArrayList<Fix>();
572 fixes.addAll(hed.createdFixes);
574 if (!swKeys.isEmpty()) {
575 fixes.addAll(FixFactory.createSuppressWarnings(info, hed.ctx.getPath(), swKeys.toArray(new String[0])));
578 ed = ErrorDescriptionFactory.createErrorDescription(ed.getSeverity(), ed.getDescription(), fixes, ed.getFile(), ed.getRange().getBegin().getOffset(), ed.getRange().getEnd().getOffset());
581 merge(errors, hed.hd, ed);
587 wasChange = currentWasChange;
593 // public static void computeHints(URI file, ProcessingEnvironment env, CompilationUnitTree cut, RulesManager m) {
594 // Map<Kind, HintDescription> hints = m.getKindBasedHints();
596 // if (hints.isEmpty()) {
600 // List<ErrorDescription> errors = new LinkedList<ErrorDescription>();
602 // File af = new File(file.getPath());
603 // FileObject f = FileUtil.toFileObject(af);
605 // new ScannerImpl(f, env, hints).scan(cut, errors);
607 // for (ErrorDescription ed : errors) {
608 // Diagnostic.Kind k;
610 // switch (ed.getSeverity()) {
612 // k = Diagnostic.Kind.ERROR;
615 // k = Diagnostic.Kind.WARNING;
619 // env.getMessager().printMessage(k, ed.getDescription());
623 public Map<String, Long> getTimeLog() {
627 private final class ScannerImpl extends CancellableTreePathScanner<Void, Map<HintDescription, List<ErrorDescription>>> {
629 private final Stack<Set<String>> suppresWarnings = new Stack<Set<String>>();
630 private final CompilationInfo info;
631 private final FileObject file;
632 private final ProcessingEnvironment env;
633 private final Map<Kind, List<HintDescription>> hints;
635 public ScannerImpl(CompilationInfo info, AtomicBoolean cancel, Map<Kind, List<HintDescription>> hints) {
643 public ScannerImpl(FileObject file, ProcessingEnvironment env, Map<Kind, List<HintDescription>> hints) {
644 super(new AtomicBoolean());
651 private void runAndAdd(TreePath path, List<HintDescription> rules, Map<HintDescription, List<ErrorDescription>> d) {
652 if (rules != null && !isInGuarded(info, path)) {
653 OUTER: for (HintDescription hd : rules) {
658 HintMetadata hm = hd.getMetadata();
660 for (String wname : hm.suppressWarnings) {
661 if( !suppresWarnings.empty() && suppresWarnings.peek().contains(wname)) {
666 HintContext c = new HintContext(info, hm, path, Collections.<String, TreePath>emptyMap(), Collections.<String, Collection<? extends TreePath>>emptyMap(), Collections.<String, String>emptyMap());
667 Collection<? extends ErrorDescription> errors = runHint(hd, c);
669 if (errors != null) {
670 merge(d, hd, errors);
677 public Void scan(Tree tree, Map<HintDescription, List<ErrorDescription>> p) {
681 TreePath tp = new TreePath(getCurrentPath(), tree);
682 Kind k = tree.getKind();
684 boolean b = pushSuppressWarrnings(tp);
686 runAndAdd(tp, hints.get(k), p);
692 return super.scan(tree, p);
695 suppresWarnings.pop();
701 public Void scan(TreePath path, Map<HintDescription, List<ErrorDescription>> p) {
702 Kind k = path.getLeaf().getKind();
703 boolean b = pushSuppressWarrnings(path);
705 runAndAdd(path, hints.get(k), p);
711 return super.scan(path, p);
714 suppresWarnings.pop();
719 public void scanDoNotGoDeeper(TreePath path, Map<HintDescription, List<ErrorDescription>> p) {
720 Kind k = path.getLeaf().getKind();
721 runAndAdd(path, hints.get(k), p);
724 private boolean pushSuppressWarrnings(TreePath path) {
725 switch(path.getLeaf().getKind()) {
729 Set<String> current = suppresWarnings.size() == 0 ? null : suppresWarnings.peek();
730 Set<String> nju = current == null ? new HashSet<String>() : new HashSet<String>(current);
732 Element e = getTrees().getElement(path);
735 for (AnnotationMirror am : e.getAnnotationMirrors()) {
736 String name = ((TypeElement)am.getAnnotationType().asElement()).getQualifiedName().toString();
737 if ( "java.lang.SuppressWarnings".equals(name) ) { // NOI18N
738 Map<? extends ExecutableElement, ? extends AnnotationValue> elementValues = am.getElementValues();
739 for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : elementValues.entrySet()) {
740 if( "value".equals(entry.getKey().getSimpleName().toString()) ) { // NOI18N
741 Object value = entry.getValue().getValue();
742 if ( value instanceof List) {
743 for (Object av : (List)value) {
744 if( av instanceof AnnotationValue ) {
745 Object wname = ((AnnotationValue)av).getValue();
746 if ( wname instanceof String ) {
747 nju.add((String)wname);
758 suppresWarnings.push(nju);
764 private Trees getTrees() {
765 return info != null ? info.getTrees() : Trees.instance(env);
769 static boolean isInGuarded(CompilationInfo info, TreePath tree) {
775 Document doc = info.getDocument();
777 if (doc instanceof GuardedDocument) {
778 int start = (int) info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), tree.getLeaf());
779 int end = (int) info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), tree.getLeaf());
780 GuardedDocument gdoc = (GuardedDocument) doc;
781 MarkBlockChain guardedBlockChain = gdoc.getGuardedBlockChain();
782 if (guardedBlockChain.compareBlock(start, end) == MarkBlock.INNER) {
786 } catch (IOException ex) {
787 Exceptions.printStackTrace(ex);
793 private Collection<? extends ErrorDescription> runHint(HintDescription hd, HintContext ctx) {
794 long start = System.nanoTime();
797 return hd.getWorker().createErrors(ctx);
799 long end = System.nanoTime();
800 reportSpentTime(hd.getMetadata().id, end - start);
804 public static <K, V> Map<K, List<V>> merge(Map<K, List<V>> to, K key, V value) {
805 List<V> toColl = to.get(key);
807 if (toColl == null) {
808 to.put(key, toColl = new LinkedList<V>());
816 public static <K, V> Map<K, List<V>> merge(Map<K, List<V>> to, K key, Collection<? extends V> value) {
817 List<V> toColl = to.get(key);
819 if (toColl == null) {
820 to.put(key, toColl = new LinkedList<V>());
823 toColl.addAll(value);
828 public static <K, V> Map<K, List<V>> mergeAll(Map<K, List<V>> to, Map<? extends K, ? extends Collection<? extends V>> what) {
829 for (Entry<? extends K, ? extends Collection<? extends V>> e : what.entrySet()) {
830 List<V> toColl = to.get(e.getKey());
832 if (toColl == null) {
833 to.put(e.getKey(), toColl = new LinkedList<V>());
836 toColl.addAll(e.getValue());
842 public static List<ErrorDescription> join(Map<?, ? extends List<? extends ErrorDescription>> errors) {
843 List<ErrorDescription> result = new LinkedList<ErrorDescription>();
845 for (Entry<?, ? extends Collection<? extends ErrorDescription>> e : errors.entrySet()) {
846 result.addAll(e.getValue());
852 private static final boolean logTimeSpentInHints = Boolean.getBoolean("java.HintsInvoker.time.in.hints");
853 private final Map<String, Long> hint2SpentTime = new HashMap<String, Long>();
855 private void reportSpentTime(String id, long nanoTime) {
856 if (!logTimeSpentInHints) return;
858 Long prev = hint2SpentTime.get(id);
864 hint2SpentTime.put(id, prev + nanoTime);
867 private void dumpTimeSpentInHints() {
868 if (!logTimeSpentInHints) return;
870 List<Entry<String, Long>> l = new ArrayList<Entry<String, Long>>(hint2SpentTime.entrySet());
872 Collections.sort(l, new Comparator<Entry<String, Long>>() {
874 public int compare(Entry<String, Long> o1, Entry<String, Long> o2) {
875 return (int) Math.signum(o1.getValue() - o2.getValue());
879 for (Entry<String, Long> e : l) {
880 System.err.println(e.getKey() + "=" + String.format("%3.2f", e.getValue() / 1000000.0));
885 private void enterSpeculativeAssignments(HintContext ctx, List<Condition> conditions, Map<Tree, Map<String, Object>> marks) {
886 for (Condition c : conditions) {
887 if (!(c instanceof MarkCondition)) continue;
889 MarkCondition mc = (MarkCondition) c;
891 if (mc.op != Operator.ASSIGN) {
895 assert mc.left instanceof Selector;
897 Selector s = (Selector) mc.left;
898 String treeName = s.selected.get(0);
899 String markName = s.selected.get(1);
900 TreePath tree = ctx.getVariables().get(treeName);
904 System.err.println("speculative assignment to: " + tree.getLeaf());
906 Map<String, Object> variables = marks.get(tree.getLeaf());
908 if (variables == null) {
909 marks.put(tree.getLeaf(), variables = new HashMap<String, Object>());
912 PossibleValue pv = (PossibleValue) variables.get(markName);
915 variables.put(markName, pv = new PossibleValue());
922 private void clearSpeculativeAssignments(HintContext ctx, List<Condition> conditions, Map<Tree, Map<String, Object>> marks) {
923 for (Condition c : conditions) {
924 if (!(c instanceof MarkCondition)) continue;
926 MarkCondition mc = (MarkCondition) c;
928 if (mc.op != Operator.ASSIGN) {
932 assert mc.left instanceof Selector;
934 Selector s = (Selector) mc.left;
935 String treeName = s.selected.get(0);
936 String markName = s.selected.get(1);
937 TreePath tree = ctx.getVariables().get(treeName);
941 System.err.println("clearing speculative assignment from: " + tree.getLeaf());
943 Map<String, Object> variables = marks.get(tree.getLeaf());
945 assert variables != null;
947 Object value = variables.get(markName);
949 if (!(value instanceof PossibleValue))
950 continue;//XXX: correct?
952 PossibleValue pv = (PossibleValue) value;
959 variables.remove(markName);
970 private static Boolean processConditions(HintContext ctx, Map<Tree, Map<String, Object>> marks, List<Condition> cond, int candidatesCount, int confirmedCount) {
971 if (cond.isEmpty()) {
972 return true; //implicitly accept
975 for (Iterator<Condition> it = cond.iterator(); it.hasNext(); ) {
976 Condition c = it.next();
978 if (c instanceof CustomCondition) {
979 if (!((CustomCondition) c).holds(ctx)) {
986 if (c instanceof OtherwiseCondition) {
987 if (candidatesCount > 1) return null;
988 if (confirmedCount > 0) return false;
993 MarkCondition mc = (MarkCondition) c;
997 assert mc.left instanceof Selector;
999 Object value = readValue(ctx, marks, mc.right);
1001 assert value != null;
1003 Selector s = (Selector) mc.left;
1004 String treeName = s.selected.get(0);
1005 String markName = s.selected.get(1);
1006 TreePath tree = ctx.getVariables().get(treeName);
1008 assert tree != null; //more gracefull handling, in some case may warn during parsing
1010 Map<String, Object> variables = marks.get(tree.getLeaf());
1012 if (variables == null) {
1013 marks.put(tree.getLeaf(), variables = new HashMap<String, Object>());
1016 variables.put(markName, value);
1019 Object left = readValue(ctx, marks, mc.left);
1020 Object right = readValue(ctx, marks, mc.right);
1022 System.err.println("left=" + left);
1023 System.err.println("right=" + right);
1025 if (left == null || right == null) {
1026 // System.err.println("marks=" + marks);
1027 // System.err.println("left=" + left);
1028 // System.err.println("right=" + right);
1029 //can never be true:
1033 if (left instanceof PossibleValue || right instanceof PossibleValue) {
1034 //nothing to set yet.
1038 if (!left.equals(right)) {
1045 Object left = readValue(ctx, marks, mc.left);
1046 Object right = readValue(ctx, marks, mc.right);
1048 if (left instanceof PossibleValue || right instanceof PossibleValue) {
1049 //nothing to set yet.
1053 if (left == right || (left != null && left.equals(right))) {
1060 throw new UnsupportedOperationException();
1066 assert cond.isEmpty();
1071 private static Object readValue(HintContext ctx, Map<Tree, Map<String, Object>> marks, Value v) {
1072 if (v instanceof Selector) {
1073 Selector s = (Selector) v;
1075 if (s.selected.size() == 1) {
1076 String name = s.selected.get(0);
1077 TreePath tree = ctx.getVariables().get(name);
1079 assert tree != null;
1081 return ctx.getInfo().getTrees().getElement(tree);
1084 if (s.selected.size() == 2) {
1085 String treeName = s.selected.get(0);
1086 String markName = s.selected.get(1);
1087 TreePath tree = ctx.getVariables().get(treeName);
1089 assert tree != null; //more gracefull handling, in some case may warn during parsing
1091 System.err.println("reading=" + tree.getLeaf() + "." + markName);
1093 Map<String, Object> variables = marks.get(tree.getLeaf());
1095 if (variables == null) return null;
1097 return variables.get(markName);
1104 if (v instanceof Literal) {
1105 return ((Literal) v).value;
1113 private static final class PossibleValue extends HashSet<MarkCondition> {}
1115 private static final class HintEvaluationData {
1116 public final HintContext ctx;
1117 public final HintDescription hd;
1118 public final List<Condition> marks;
1119 public final ErrorDescriptionAcceptor acceptor;
1120 public final List<FixEvaluationData> fixDescriptions;
1121 public final List<Fix> createdFixes = new LinkedList<Fix>();
1122 public HintEvaluationData(HintContext ctx, HintDescription hd, List<Condition> marks, ErrorDescriptionAcceptor acceptor, List<FixEvaluationData> fixDescriptions) {
1126 this.acceptor = acceptor;
1127 this.fixDescriptions = fixDescriptions;
1131 private static final class FixEvaluationData {
1132 public final HintContext ctx;
1133 public final List<Condition> marks;
1134 public final FixAcceptor acceptor;
1135 public FixEvaluationData(HintContext ctx, List<Condition> marks, FixAcceptor acceptor) {
1138 this.acceptor = acceptor;