api/src/org/netbeans/modules/jackpot30/impl/hints/HintsInvoker.java
author Jan Lahoda <jlahoda@netbeans.org>
Sun, 06 Mar 2011 19:23:09 +0100
branchmarks
changeset 555 b9a0402dbea3
parent 554 59cba1c67c40
permissions -rw-r--r--
Fixing @SuppressWarnings for marks-based hints.
jlahoda@0
     1
/*
jlahoda@0
     2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
jlahoda@0
     3
 *
jlahoda@297
     4
 * Copyright 2008-2010 Sun Microsystems, Inc. All rights reserved.
jlahoda@0
     5
 *
jlahoda@0
     6
 * The contents of this file are subject to the terms of either the GNU
jlahoda@0
     7
 * General Public License Version 2 only ("GPL") or the Common
jlahoda@0
     8
 * Development and Distribution License("CDDL") (collectively, the
jlahoda@0
     9
 * "License"). You may not use this file except in compliance with the
jlahoda@0
    10
 * License. You can obtain a copy of the License at
jlahoda@0
    11
 * http://www.netbeans.org/cddl-gplv2.html
jlahoda@0
    12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
jlahoda@0
    13
 * specific language governing permissions and limitations under the
jlahoda@0
    14
 * License.  When distributing the software, include this License Header
jlahoda@0
    15
 * Notice in each file and include the License file at
jlahoda@0
    16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
jlahoda@0
    17
 * particular file as subject to the "Classpath" exception as provided
jlahoda@0
    18
 * by Sun in the GPL Version 2 section of the License file that
jlahoda@0
    19
 * accompanied this code. If applicable, add the following below the
jlahoda@0
    20
 * License Header, with the fields enclosed by brackets [] replaced by
jlahoda@0
    21
 * your own identifying information:
jlahoda@0
    22
 * "Portions Copyrighted [year] [name of copyright owner]"
jlahoda@0
    23
 *
jlahoda@0
    24
 * If you wish your version of this file to be governed by only the CDDL
jlahoda@0
    25
 * or only the GPL Version 2, indicate your decision by adding
jlahoda@0
    26
 * "[Contributor] elects to include this software in this distribution
jlahoda@0
    27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
jlahoda@0
    28
 * single choice of license, a recipient has the option to distribute
jlahoda@0
    29
 * your version of this file under either the CDDL, the GPL Version 2 or
jlahoda@0
    30
 * to extend the choice of license to its licensees as provided above.
jlahoda@0
    31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
jlahoda@0
    32
 * Version 2 license, then the option applies only if the new code is
jlahoda@0
    33
 * made subject to such option by the copyright holder.
jlahoda@0
    34
 *
jlahoda@0
    35
 * Contributor(s):
jlahoda@0
    36
 *
jlahoda@297
    37
 * Portions Copyrighted 2008-2010 Sun Microsystems, Inc.
jlahoda@0
    38
 */
jlahoda@0
    39
jlahoda@23
    40
package org.netbeans.modules.jackpot30.impl.hints;
jlahoda@0
    41
jlahoda@0
    42
import com.sun.source.tree.Tree;
jlahoda@0
    43
import java.util.Stack;
jlahoda@0
    44
import java.util.concurrent.atomic.AtomicBoolean;
jlahoda@0
    45
import javax.lang.model.element.AnnotationMirror;
jlahoda@0
    46
import javax.lang.model.element.AnnotationValue;
jlahoda@0
    47
import javax.lang.model.element.Element;
jlahoda@0
    48
import javax.lang.model.element.ExecutableElement;
jlahoda@0
    49
import javax.lang.model.element.TypeElement;
jlahoda@0
    50
import javax.swing.text.Document;
jlahoda@0
    51
import org.netbeans.api.java.source.support.CancellableTreePathScanner;
jlahoda@0
    52
import org.netbeans.editor.GuardedDocument;
jlahoda@0
    53
import org.netbeans.editor.MarkBlock;
jlahoda@0
    54
import org.netbeans.editor.MarkBlockChain;
jlahoda@0
    55
import org.openide.filesystems.FileObject;
jlahoda@0
    56
jlahoda@0
    57
import com.sun.source.tree.Tree.Kind;
jlahoda@0
    58
import com.sun.source.util.TreePath;
jlahoda@0
    59
import com.sun.source.util.Trees;
jlahoda@0
    60
import java.io.IOException;
jlahoda@297
    61
import java.util.ArrayList;
jlahoda@23
    62
import java.util.Collection;
jlahoda@23
    63
import java.util.Collections;
jlahoda@297
    64
import java.util.Comparator;
jlahoda@0
    65
import java.util.HashMap;
jlahoda@0
    66
import java.util.HashSet;
jlahoda@522
    67
import java.util.Iterator;
jlahoda@0
    68
import java.util.LinkedList;
jlahoda@0
    69
import java.util.List;
jlahoda@0
    70
import java.util.Map;
jlahoda@0
    71
import java.util.Map.Entry;
jlahoda@0
    72
import java.util.Set;
jlahoda@0
    73
import javax.annotation.processing.ProcessingEnvironment;
jlahoda@10
    74
import javax.lang.model.type.TypeMirror;
jlahoda@0
    75
import org.netbeans.api.java.source.CompilationInfo;
jlahoda@213
    76
import org.netbeans.modules.jackpot30.impl.MessageImpl;
jlahoda@23
    77
import org.netbeans.modules.jackpot30.impl.RulesManager;
jlahoda@214
    78
import org.netbeans.modules.jackpot30.impl.Utilities;
jlahoda@23
    79
import org.netbeans.modules.jackpot30.impl.pm.BulkSearch;
jlahoda@23
    80
import org.netbeans.modules.jackpot30.impl.pm.BulkSearch.BulkPattern;
jlahoda@23
    81
import org.netbeans.modules.jackpot30.impl.pm.CopyFinder;
jlahoda@81
    82
import org.netbeans.modules.jackpot30.impl.pm.CopyFinder.VariableAssignments;
jlahoda@23
    83
import org.netbeans.modules.jackpot30.impl.pm.Pattern;
jlahoda@269
    84
import org.netbeans.modules.jackpot30.spi.Hacks;
jlahoda@23
    85
import org.netbeans.modules.jackpot30.spi.HintContext;
jlahoda@23
    86
import org.netbeans.modules.jackpot30.spi.HintDescription;
jlahoda@553
    87
import org.netbeans.modules.jackpot30.spi.HintDescription.Condition;
jlahoda@553
    88
import org.netbeans.modules.jackpot30.spi.HintDescription.CustomCondition;
jlahoda@522
    89
import org.netbeans.modules.jackpot30.spi.HintDescription.DeclarativeFixDescription;
jlahoda@554
    90
import org.netbeans.modules.jackpot30.spi.HintDescription.ErrorDescriptionAcceptor;
jlahoda@554
    91
import org.netbeans.modules.jackpot30.spi.HintDescription.FixAcceptor;
jlahoda@522
    92
import org.netbeans.modules.jackpot30.spi.HintDescription.Literal;
jlahoda@522
    93
import org.netbeans.modules.jackpot30.spi.HintDescription.MarkCondition;
jlahoda@522
    94
import org.netbeans.modules.jackpot30.spi.HintDescription.MarksWorker;
jlahoda@522
    95
import org.netbeans.modules.jackpot30.spi.HintDescription.Operator;
jlahoda@553
    96
import org.netbeans.modules.jackpot30.spi.HintDescription.OtherwiseCondition;
jlahoda@23
    97
import org.netbeans.modules.jackpot30.spi.HintDescription.PatternDescription;
jlahoda@522
    98
import org.netbeans.modules.jackpot30.spi.HintDescription.Selector;
jlahoda@522
    99
import org.netbeans.modules.jackpot30.spi.HintDescription.Value;
jlahoda@297
   100
import org.netbeans.modules.jackpot30.spi.HintMetadata;
jlahoda@297
   101
import org.netbeans.modules.jackpot30.spi.HintMetadata.HintSeverity;
jlahoda@555
   102
import org.netbeans.modules.jackpot30.spi.support.FixFactory;
jlahoda@0
   103
import org.netbeans.spi.editor.hints.ErrorDescription;
jlahoda@554
   104
import org.netbeans.spi.editor.hints.ErrorDescriptionFactory;
jlahoda@522
   105
import org.netbeans.spi.editor.hints.Fix;
jlahoda@554
   106
import org.netbeans.spi.editor.hints.Severity;
jlahoda@0
   107
import org.openide.util.Exceptions;
jlahoda@0
   108
jlahoda@0
   109
/**
jlahoda@0
   110
 *
jlahoda@0
   111
 * @author lahvac
jlahoda@0
   112
 */
jlahoda@297
   113
public class HintsInvoker {
jlahoda@0
   114
jlahoda@107
   115
    private final Map<String, Long> timeLog = new HashMap<String, Long>();
jlahoda@0
   116
jlahoda@297
   117
    private final CompilationInfo info;
jlahoda@297
   118
    private final int caret;
jlahoda@297
   119
    private final int from;
jlahoda@297
   120
    private final int to;
jlahoda@297
   121
    private final AtomicBoolean cancel;
jlahoda@0
   122
jlahoda@297
   123
    public HintsInvoker(CompilationInfo info, AtomicBoolean cancel) {
jlahoda@297
   124
        this(info, -1, cancel);
jlahoda@0
   125
    }
jlahoda@0
   126
jlahoda@297
   127
    public HintsInvoker(CompilationInfo info, int caret, AtomicBoolean cancel) {
jlahoda@297
   128
        this(info, caret, -1, -1, cancel);
jlahoda@297
   129
    }
jlahoda@297
   130
jlahoda@297
   131
    public HintsInvoker(CompilationInfo info, int from, int to, AtomicBoolean cancel) {
jlahoda@297
   132
        this(info, -1, from, to, cancel);
jlahoda@297
   133
    }
jlahoda@297
   134
jlahoda@297
   135
    private HintsInvoker(CompilationInfo info, int caret, int from, int to, AtomicBoolean cancel) {
jlahoda@297
   136
        this.info = info;
jlahoda@297
   137
        this.caret = caret;
jlahoda@297
   138
        this.from = from;
jlahoda@297
   139
        this.to = to;
jlahoda@297
   140
        this.cancel = cancel;
jlahoda@0
   141
    }
jlahoda@0
   142
jlahoda@0
   143
    public List<ErrorDescription> computeHints(CompilationInfo info) {
jlahoda@0
   144
        return computeHints(info, new TreePath(info.getCompilationUnit()));
jlahoda@0
   145
    }
jlahoda@0
   146
jlahoda@0
   147
    private List<ErrorDescription> computeHints(CompilationInfo info, TreePath startAt) {
jlahoda@297
   148
        List<HintDescription> descs = new LinkedList<HintDescription>();
jlahoda@297
   149
        for (Entry<HintMetadata, Collection<? extends HintDescription>> e : RulesManager.getInstance().allHints.entrySet()) {
jlahoda@297
   150
            HintMetadata m = e.getKey();
jlahoda@297
   151
jlahoda@297
   152
            if (!RulesManager.getInstance().isHintEnabled(m)) {
jlahoda@297
   153
                continue;
jlahoda@297
   154
            }
jlahoda@297
   155
jlahoda@297
   156
            if (caret != -1) {
jlahoda@297
   157
                if (m.kind == HintMetadata.Kind.SUGGESTION || m.kind == HintMetadata.Kind.SUGGESTION_NON_GUI) {
jlahoda@297
   158
                    descs.addAll(e.getValue());
jlahoda@297
   159
                } else {
jlahoda@297
   160
                    if (RulesManager.getInstance().getHintSeverity(m) == HintSeverity.CURRENT_LINE_WARNING) {
jlahoda@297
   161
                        descs.addAll(e.getValue());
jlahoda@297
   162
                    }
jlahoda@297
   163
                }
jlahoda@297
   164
            } else {
jlahoda@297
   165
                if (m.kind == HintMetadata.Kind.HINT || m.kind == HintMetadata.Kind.HINT_NON_GUI) {
jlahoda@297
   166
                    if (RulesManager.getInstance().getHintSeverity(m) != HintSeverity.CURRENT_LINE_WARNING || from != (-1)) {
jlahoda@297
   167
                        descs.addAll(e.getValue());
jlahoda@297
   168
                    }
jlahoda@297
   169
                }
jlahoda@297
   170
            }
jlahoda@297
   171
        }
jlahoda@297
   172
jlahoda@45
   173
        Map<Kind, List<HintDescription>> kindHints = new HashMap<Kind, List<HintDescription>>();
jlahoda@45
   174
        Map<PatternDescription, List<HintDescription>> patternHints = new HashMap<PatternDescription, List<HintDescription>>();
jlahoda@45
   175
jlahoda@297
   176
        RulesManager.sortOut(descs, kindHints, patternHints);
jlahoda@32
   177
jlahoda@107
   178
        long elementBasedStart = System.currentTimeMillis();
jlahoda@107
   179
jlahoda@32
   180
        RulesManager.computeElementBasedHintsXXX(info, cancel, kindHints, patternHints);
jlahoda@297
   181
jlahoda@107
   182
        long elementBasedEnd = System.currentTimeMillis();
jlahoda@107
   183
jlahoda@297
   184
        timeLog.put("Computing Element Based Hints", elementBasedEnd - elementBasedStart);
jlahoda@107
   185
jlahoda@330
   186
        List<ErrorDescription> errors = join(computeHints(info, startAt, kindHints, patternHints, new LinkedList<MessageImpl>()));
jlahoda@297
   187
jlahoda@297
   188
        dumpTimeSpentInHints();
jlahoda@297
   189
        
jlahoda@297
   190
        return errors;
jlahoda@10
   191
    }
jlahoda@0
   192
jlahoda@32
   193
    public List<ErrorDescription> computeHints(CompilationInfo info,
jlahoda@32
   194
                                        Map<Kind, List<HintDescription>> hints,
jlahoda@32
   195
                                        Map<PatternDescription, List<HintDescription>> patternHints) {
jlahoda@213
   196
        return computeHints(info, hints, patternHints, new LinkedList<MessageImpl>());
jlahoda@213
   197
    }
jlahoda@213
   198
jlahoda@213
   199
    public List<ErrorDescription> computeHints(CompilationInfo info,
jlahoda@213
   200
                                        Map<Kind, List<HintDescription>> hints,
jlahoda@213
   201
                                        Map<PatternDescription, List<HintDescription>> patternHints,
jlahoda@213
   202
                                        Collection<? super MessageImpl> problems) {
jlahoda@330
   203
        return join(computeHints(info, new TreePath(info.getCompilationUnit()), hints, patternHints, problems));
jlahoda@297
   204
    }
jlahoda@297
   205
jlahoda@330
   206
    public Map<HintDescription, List<ErrorDescription>> computeHints(CompilationInfo info,
jlahoda@297
   207
                                        TreePath startAt,
jlahoda@297
   208
                                        Map<Kind, List<HintDescription>> hints,
jlahoda@297
   209
                                        Map<PatternDescription, List<HintDescription>> patternHints,
jlahoda@297
   210
                                        Collection<? super MessageImpl> problems) {
jlahoda@297
   211
        if (caret != -1) {
jlahoda@297
   212
            TreePath tp = info.getTreeUtilities().pathFor(caret);
jlahoda@297
   213
            return computeSuggestions(info, tp, hints, patternHints, problems);
jlahoda@297
   214
        } else {
jlahoda@297
   215
            if (from != (-1) && to != (-1)) {
jlahoda@297
   216
                return computeHintsInSpan(info, hints, patternHints, problems);
jlahoda@297
   217
            } else {
jlahoda@330
   218
                return computeHintsImpl(info, startAt, hints, patternHints, problems);
jlahoda@297
   219
            }
jlahoda@297
   220
        }
jlahoda@32
   221
    }
jlahoda@32
   222
jlahoda@330
   223
    Map<HintDescription, List<ErrorDescription>> computeHintsImpl(CompilationInfo info,
jlahoda@10
   224
                                        TreePath startAt,
jlahoda@23
   225
                                        Map<Kind, List<HintDescription>> hints,
jlahoda@213
   226
                                        Map<PatternDescription, List<HintDescription>> patternHints,
jlahoda@213
   227
                                        Collection<? super MessageImpl> problems) {
jlahoda@330
   228
        Map<HintDescription, List<ErrorDescription>> errors = new HashMap<HintDescription, List<ErrorDescription>>();
jlahoda@0
   229
jlahoda@297
   230
        long kindCount = 0;
jlahoda@297
   231
jlahoda@297
   232
        for (Entry<Kind, List<HintDescription>> e : hints.entrySet()) {
jlahoda@297
   233
            kindCount += e.getValue().size();
jlahoda@297
   234
        }
jlahoda@297
   235
jlahoda@297
   236
        timeLog.put("[C] Kind Based Hints", kindCount);
jlahoda@297
   237
jlahoda@10
   238
        if (!hints.isEmpty()) {
jlahoda@107
   239
            long kindStart = System.currentTimeMillis();
jlahoda@107
   240
jlahoda@10
   241
            new ScannerImpl(info, cancel, hints).scan(startAt, errors);
jlahoda@107
   242
jlahoda@107
   243
            long kindEnd = System.currentTimeMillis();
jlahoda@107
   244
jlahoda@297
   245
            timeLog.put("Kind Based Hints", kindEnd - kindStart);
jlahoda@10
   246
        }
jlahoda@107
   247
jlahoda@297
   248
        timeLog.put("[C] Pattern Based Hints", (long) patternHints.size());
jlahoda@297
   249
jlahoda@107
   250
        long patternStart = System.currentTimeMillis();
jlahoda@297
   251
jlahoda@47
   252
        Map<String, List<PatternDescription>> patternTests = computePatternTests(patternHints);
jlahoda@47
   253
jlahoda@297
   254
        long bulkPatternStart = System.currentTimeMillis();
jlahoda@297
   255
jlahoda@297
   256
        BulkPattern bulkPattern = BulkSearch.getDefault().create(info, patternTests.keySet());
jlahoda@297
   257
jlahoda@297
   258
        long bulkPatternEnd = System.currentTimeMillis();
jlahoda@297
   259
jlahoda@297
   260
        timeLog.put("Bulk Pattern preparation", bulkPatternEnd - bulkPatternStart);
jlahoda@297
   261
jlahoda@107
   262
        long bulkStart = System.currentTimeMillis();
jlahoda@297
   263
jlahoda@297
   264
        Map<String, Collection<TreePath>> occurringPatterns = BulkSearch.getDefault().match(info, startAt, bulkPattern, timeLog);
jlahoda@297
   265
jlahoda@107
   266
        long bulkEnd = System.currentTimeMillis();
jlahoda@107
   267
jlahoda@297
   268
        timeLog.put("Bulk Search", bulkEnd - bulkStart);
jlahoda@297
   269
jlahoda@330
   270
        mergeAll(errors, doComputeHints(info, occurringPatterns, patternTests, patternHints, problems));
jlahoda@47
   271
jlahoda@107
   272
        long patternEnd = System.currentTimeMillis();
jlahoda@107
   273
jlahoda@297
   274
        timeLog.put("Pattern Based Hints", patternEnd - patternStart);
jlahoda@297
   275
jlahoda@297
   276
        return errors;
jlahoda@297
   277
    }
jlahoda@297
   278
jlahoda@330
   279
    Map<HintDescription, List<ErrorDescription>> computeHintsInSpan(CompilationInfo info,
jlahoda@297
   280
                                        Map<Kind, List<HintDescription>> hints,
jlahoda@297
   281
                                        Map<PatternDescription, List<HintDescription>> patternHints,
jlahoda@297
   282
                                        Collection<? super MessageImpl> problems) {
jlahoda@297
   283
jlahoda@297
   284
        TreePath path = info.getTreeUtilities().pathFor((from + to) / 2);
jlahoda@297
   285
jlahoda@297
   286
        while (path.getLeaf().getKind() != Kind.COMPILATION_UNIT) {
jlahoda@297
   287
            int start = (int) info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), path.getLeaf());
jlahoda@297
   288
            int end = (int) info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), path.getLeaf());
jlahoda@297
   289
jlahoda@297
   290
            if (start <= from && end >= to) {
jlahoda@297
   291
                break;
jlahoda@297
   292
            }
jlahoda@297
   293
jlahoda@297
   294
            path = path.getParentPath();
jlahoda@297
   295
        }
jlahoda@297
   296
jlahoda@330
   297
        Map<HintDescription, List<ErrorDescription>> errors = new HashMap<HintDescription, List<ErrorDescription>>();
jlahoda@297
   298
jlahoda@297
   299
        if (!hints.isEmpty()) {
jlahoda@297
   300
            long kindStart = System.currentTimeMillis();
jlahoda@297
   301
jlahoda@297
   302
            new ScannerImpl(info, cancel, hints).scan(path, errors);
jlahoda@297
   303
jlahoda@297
   304
            long kindEnd = System.currentTimeMillis();
jlahoda@297
   305
jlahoda@297
   306
            timeLog.put("Kind Based Hints", kindEnd - kindStart);
jlahoda@297
   307
        }
jlahoda@297
   308
jlahoda@297
   309
        if (!patternHints.isEmpty()) {
jlahoda@297
   310
            long patternStart = System.currentTimeMillis();
jlahoda@297
   311
jlahoda@297
   312
            Map<String, List<PatternDescription>> patternTests = computePatternTests(patternHints);
jlahoda@297
   313
jlahoda@297
   314
            long bulkStart = System.currentTimeMillis();
jlahoda@297
   315
jlahoda@297
   316
            BulkPattern bulkPattern = BulkSearch.getDefault().create(info, patternTests.keySet());
jlahoda@297
   317
            Map<String, Collection<TreePath>> occurringPatterns = BulkSearch.getDefault().match(info, path, bulkPattern, timeLog);
jlahoda@297
   318
jlahoda@297
   319
            long bulkEnd = System.currentTimeMillis();
jlahoda@297
   320
jlahoda@297
   321
            timeLog.put("Bulk Search", bulkEnd - bulkStart);
jlahoda@297
   322
jlahoda@330
   323
            mergeAll(errors, doComputeHints(info, occurringPatterns, patternTests, patternHints, problems));
jlahoda@297
   324
jlahoda@297
   325
            long patternEnd = System.currentTimeMillis();
jlahoda@297
   326
jlahoda@297
   327
            timeLog.put("Pattern Based Hints", patternEnd - patternStart);
jlahoda@297
   328
        }
jlahoda@297
   329
jlahoda@297
   330
        return errors;
jlahoda@297
   331
    }
jlahoda@297
   332
jlahoda@330
   333
    Map<HintDescription, List<ErrorDescription>> computeSuggestions(CompilationInfo info,
jlahoda@297
   334
                                        TreePath workOn,
jlahoda@297
   335
                                        Map<Kind, List<HintDescription>> hints,
jlahoda@297
   336
                                        Map<PatternDescription, List<HintDescription>> patternHints,
jlahoda@297
   337
                                        Collection<? super MessageImpl> problems) {
jlahoda@330
   338
        Map<HintDescription, List<ErrorDescription>> errors = new HashMap<HintDescription, List<ErrorDescription>>();
jlahoda@297
   339
jlahoda@297
   340
        if (!hints.isEmpty()) {
jlahoda@297
   341
            long kindStart = System.currentTimeMillis();
jlahoda@297
   342
jlahoda@297
   343
            TreePath proc = workOn;
jlahoda@297
   344
jlahoda@297
   345
            while (proc != null) {
jlahoda@297
   346
                new ScannerImpl(info, cancel, hints).scanDoNotGoDeeper(proc, errors);
jlahoda@297
   347
                proc = proc.getParentPath();
jlahoda@297
   348
            }
jlahoda@297
   349
jlahoda@297
   350
            long kindEnd = System.currentTimeMillis();
jlahoda@297
   351
jlahoda@297
   352
            timeLog.put("Kind Based Suggestions", kindEnd - kindStart);
jlahoda@297
   353
        }
jlahoda@297
   354
jlahoda@297
   355
        if (!patternHints.isEmpty()) {
jlahoda@323
   356
            long patternStart = System.currentTimeMillis();
jlahoda@323
   357
jlahoda@323
   358
            Map<String, List<PatternDescription>> patternTests = computePatternTests(patternHints);
jlahoda@323
   359
jlahoda@323
   360
            //pretend that all the patterns occur on all treepaths from the current path
jlahoda@323
   361
            //up (probably faster than using BulkSearch over whole file)
jlahoda@323
   362
            //TODO: what about machint trees under the current path?
jlahoda@323
   363
            Set<TreePath> paths = new HashSet<TreePath>();
jlahoda@323
   364
jlahoda@323
   365
            TreePath tp = workOn;
jlahoda@323
   366
jlahoda@323
   367
            while (tp != null) {
jlahoda@323
   368
                paths.add(tp);
jlahoda@323
   369
                tp = tp.getParentPath();
jlahoda@323
   370
            }
jlahoda@323
   371
jlahoda@323
   372
            Map<String, Collection<TreePath>> occurringPatterns = new HashMap<String, Collection<TreePath>>();
jlahoda@323
   373
jlahoda@323
   374
            for (String p : patternTests.keySet()) {
jlahoda@323
   375
                occurringPatterns.put(p, paths);
jlahoda@323
   376
            }
jlahoda@323
   377
jlahoda@297
   378
//            long bulkStart = System.currentTimeMillis();
jlahoda@297
   379
//
jlahoda@297
   380
//            BulkPattern bulkPattern = BulkSearch.getDefault().create(info, patternTests.keySet());
jlahoda@323
   381
//            Map<String, Collection<TreePath>> occurringPatterns = BulkSearch.getDefault().match(info, new TreePath(info.getCompilationUnit()), bulkPattern, timeLog);
jlahoda@297
   382
//
jlahoda@297
   383
//            long bulkEnd = System.currentTimeMillis();
jlahoda@297
   384
//
jlahoda@323
   385
//            Set<Tree> acceptedLeafs = new HashSet<Tree>();
jlahoda@323
   386
//
jlahoda@323
   387
//            TreePath tp = workOn;
jlahoda@323
   388
//
jlahoda@323
   389
//            while (tp != null) {
jlahoda@323
   390
//                acceptedLeafs.add(tp.getLeaf());
jlahoda@323
   391
//                tp = tp.getParentPath();
jlahoda@323
   392
//            }
jlahoda@323
   393
//
jlahoda@323
   394
//            for (Entry<String, Collection<TreePath>> e : occurringPatterns.entrySet()) {
jlahoda@323
   395
//                for (Iterator<TreePath> it = e.getValue().iterator(); it.hasNext(); ) {
jlahoda@323
   396
//                    if (!acceptedLeafs.contains(it.next().getLeaf())) {
jlahoda@323
   397
//                        it.remove();
jlahoda@323
   398
//                    }
jlahoda@323
   399
//                }
jlahoda@323
   400
//            }
jlahoda@323
   401
//
jlahoda@297
   402
//            timeLog.put("Bulk Search", bulkEnd - bulkStart);
jlahoda@323
   403
jlahoda@330
   404
            mergeAll(errors, doComputeHints(info, occurringPatterns, patternTests, patternHints, problems));
jlahoda@323
   405
jlahoda@323
   406
            long patternEnd = System.currentTimeMillis();
jlahoda@323
   407
jlahoda@323
   408
            timeLog.put("Pattern Based Hints", patternEnd - patternStart);
jlahoda@297
   409
        }
jlahoda@107
   410
jlahoda@47
   411
        return errors;
jlahoda@47
   412
    }
jlahoda@47
   413
jlahoda@330
   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 {
jlahoda@323
   415
        return doComputeHints(info, occurringPatterns, patterns, patternHints, new LinkedList<MessageImpl>());
jlahoda@47
   416
    }
jlahoda@47
   417
jlahoda@47
   418
    public static Map<String, List<PatternDescription>> computePatternTests(Map<PatternDescription, List<HintDescription>> patternHints) {
jlahoda@10
   419
        Map<String, List<PatternDescription>> patternTests = new HashMap<String, List<PatternDescription>>();
jlahoda@23
   420
        for (Entry<PatternDescription, List<HintDescription>> e : patternHints.entrySet()) {
jlahoda@10
   421
            String p = e.getKey().getPattern();
jlahoda@10
   422
            List<PatternDescription> descs = patternTests.get(p);
jlahoda@10
   423
            if (descs == null) {
jlahoda@10
   424
                patternTests.put(p, descs = new LinkedList<PatternDescription>());
jlahoda@10
   425
            }
jlahoda@10
   426
            descs.add(e.getKey());
jlahoda@10
   427
        }
jlahoda@47
   428
        return patternTests;
jlahoda@47
   429
    }
jlahoda@297
   430
jlahoda@330
   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 {
jlahoda@330
   432
        Map<HintDescription, List<ErrorDescription>> errors = new HashMap<HintDescription, List<ErrorDescription>>();
jlahoda@522
   433
        List<HintEvaluationData> evaluationData = new LinkedList<HintEvaluationData>();
jlahoda@297
   434
jlahoda@67
   435
        for (Entry<String, Collection<TreePath>> occ : occurringPatterns.entrySet()) {
jlahoda@67
   436
            for (PatternDescription d : patterns.get(occ.getKey())) {
jlahoda@10
   437
                Map<String, TypeMirror> constraints = new HashMap<String, TypeMirror>();
jlahoda@10
   438
jlahoda@10
   439
                for (Entry<String, String> e : d.getConstraints().entrySet()) {
jlahoda@269
   440
                    constraints.put(e.getKey(), Hacks.parseFQNType(info, e.getValue()));
jlahoda@10
   441
                }
jlahoda@10
   442
jlahoda@220
   443
                Pattern p = Pattern.compile(info, occ.getKey(), constraints, d.getImports());
jlahoda@10
   444
                TreePath toplevel = new TreePath(info.getCompilationUnit());
jlahoda@10
   445
                TreePath patt = new TreePath(toplevel, p.getPattern());
jlahoda@10
   446
jlahoda@67
   447
                for (TreePath candidate : occ.getValue()) {
jlahoda@81
   448
                    VariableAssignments verified = CopyFinder.computeVariables(info, patt, candidate, cancel, p.getConstraints());
jlahoda@67
   449
jlahoda@67
   450
                    if (verified == null) {
jlahoda@67
   451
                        continue;
jlahoda@67
   452
                    }
jlahoda@297
   453
jlahoda@214
   454
                    Set<String> suppressedWarnings = new HashSet<String>(Utilities.findSuppressedWarnings(info, candidate));
jlahoda@47
   455
jlahoda@23
   456
                    for (HintDescription hd : patternHints.get(d)) {
jlahoda@297
   457
                        HintMetadata hm = hd.getMetadata();
jlahoda@455
   458
                        HintContext c = new HintContext(info, hm, candidate, verified.variables, verified.multiVariables, verified.variables2Names, constraints, problems);
jlahoda@297
   459
jlahoda@297
   460
                        if (!Collections.disjoint(suppressedWarnings, hm.suppressWarnings))
jlahoda@214
   461
                            continue;
jlahoda@297
   462
jlahoda@522
   463
                        if (hd.getWorker() instanceof MarksWorker) {
jlahoda@527
   464
                            HintContext workerContext = new HintContext(c);
jlahoda@527
   465
jlahoda@527
   466
                            workerContext.enterScope();
jlahoda@527
   467
                            
jlahoda@522
   468
                            MarksWorker mw = (MarksWorker) hd.getWorker();
jlahoda@522
   469
                            List<FixEvaluationData> fixData = new LinkedList<FixEvaluationData>();
jlahoda@522
   470
jlahoda@522
   471
                            for (DeclarativeFixDescription fd : mw.fixes) {
jlahoda@527
   472
                                HintContext fixContext = new HintContext(workerContext);
jlahoda@527
   473
jlahoda@527
   474
                                fixContext.enterScope();
jlahoda@554
   475
                                fixData.add(new FixEvaluationData(fixContext, new LinkedList<Condition>(fd.marks), fd.acceptor));
jlahoda@522
   476
                            }
jlahoda@522
   477
jlahoda@553
   478
                            HintEvaluationData data = new HintEvaluationData(workerContext, hd, new LinkedList<Condition>(mw.marks), mw.acceptor, fixData);
jlahoda@522
   479
jlahoda@522
   480
                            evaluationData.add(data);
jlahoda@522
   481
                            continue;
jlahoda@522
   482
                        }
jlahoda@522
   483
jlahoda@297
   484
                        Collection<? extends ErrorDescription> workerErrors = runHint(hd, c);
jlahoda@23
   485
jlahoda@23
   486
                        if (workerErrors != null) {
jlahoda@330
   487
                            merge(errors, hd, workerErrors);
jlahoda@23
   488
                        }
jlahoda@10
   489
                    }
jlahoda@10
   490
                }
jlahoda@10
   491
            }
jlahoda@10
   492
        }
jlahoda@0
   493
jlahoda@522
   494
        Map<Tree, Map<String, Object>> marks = new HashMap<Tree, Map<String, Object>>();
jlahoda@522
   495
jlahoda@522
   496
        for (HintEvaluationData hed : evaluationData) {
jlahoda@522
   497
            enterSpeculativeAssignments(hed.ctx, hed.marks, marks);
jlahoda@522
   498
jlahoda@522
   499
            for (FixEvaluationData fed : hed.fixDescriptions) {
jlahoda@522
   500
                //XXX: there is currently no test that would test this: (seee testSpeculativeAssignmentForFixes)
jlahoda@522
   501
                enterSpeculativeAssignments(hed.ctx, fed.marks, marks);
jlahoda@522
   502
            }
jlahoda@522
   503
        }
jlahoda@522
   504
jlahoda@522
   505
        boolean wasChange = true;
jlahoda@522
   506
jlahoda@522
   507
        while (wasChange /*!evaluationData.isEmpty()*/) {
jlahoda@522
   508
            boolean currentWasChange = false;
jlahoda@522
   509
jlahoda@522
   510
            for (Iterator<HintEvaluationData> it = evaluationData.iterator(); it.hasNext(); ) {
jlahoda@522
   511
                HintEvaluationData hed = it.next();
jlahoda@522
   512
                int origMarksSize = hed.marks.size();
jlahoda@522
   513
jlahoda@553
   514
                Boolean hres = processConditions(hed.ctx, marks, hed.marks, -1, -1);
jlahoda@522
   515
jlahoda@522
   516
                currentWasChange |= origMarksSize != hed.marks.size();
jlahoda@522
   517
jlahoda@522
   518
                if (hres == null) {
jlahoda@522
   519
                    //XXX???
jlahoda@522
   520
                    continue;
jlahoda@522
   521
                }
jlahoda@522
   522
jlahoda@522
   523
                if (hres != null && !hres) {
jlahoda@522
   524
                    currentWasChange = true;
jlahoda@527
   525
                    clearSpeculativeAssignments(hed.ctx, hed.marks, marks);
jlahoda@522
   526
                    for (FixEvaluationData fed : hed.fixDescriptions) {
jlahoda@527
   527
                        clearSpeculativeAssignments(hed.ctx, fed.marks, marks);
jlahoda@522
   528
                    }
jlahoda@522
   529
                    it.remove();
jlahoda@522
   530
                    continue;
jlahoda@522
   531
                }
jlahoda@522
   532
jlahoda@522
   533
                for (Iterator<FixEvaluationData> fixes = hed.fixDescriptions.iterator(); fixes.hasNext(); ) {
jlahoda@522
   534
                    FixEvaluationData fed = fixes.next();
jlahoda@522
   535
                    int o = fed.marks.size();
jlahoda@553
   536
                    Boolean res = processConditions(fed.ctx, marks, fed.marks, hed.fixDescriptions.size(), hed.createdFixes.size());
jlahoda@522
   537
jlahoda@522
   538
                    currentWasChange |= o != fed.marks.size();
jlahoda@522
   539
jlahoda@522
   540
                    if (res == null) continue;
jlahoda@522
   541
jlahoda@522
   542
                    if (res) {
jlahoda@554
   543
                        Fix fix = fed.acceptor.accept(fed.ctx);
jlahoda@522
   544
jlahoda@554
   545
                        if (fix != null) {
jlahoda@522
   546
                            hed.createdFixes.add(fix);
jlahoda@522
   547
                        }
jlahoda@522
   548
                    } else {
jlahoda@527
   549
                        clearSpeculativeAssignments(fed.ctx, fed.marks, marks);
jlahoda@522
   550
                    }
jlahoda@522
   551
jlahoda@522
   552
                    fixes.remove();
jlahoda@522
   553
                    currentWasChange = true;
jlahoda@522
   554
                }
jlahoda@522
   555
jlahoda@522
   556
                if (!wasChange && !currentWasChange) {
jlahoda@522
   557
                    hed.fixDescriptions.clear();
jlahoda@522
   558
                }
jlahoda@522
   559
jlahoda@522
   560
                if (hed.fixDescriptions.isEmpty()) {
jlahoda@554
   561
                    //XXX: @SuppressWarnings!
jlahoda@554
   562
                    ErrorDescription ed = hed.acceptor.accept(hed.ctx);
jlahoda@555
   563
                    List<String> swKeys = new ArrayList<String>();
jlahoda@522
   564
jlahoda@555
   565
                    for (String key : hed.hd.getSuppressWarnings()) {
jlahoda@555
   566
                        if (key == null) break;
jlahoda@555
   567
                        swKeys.add(key);
jlahoda@555
   568
                    }
jlahoda@555
   569
jlahoda@555
   570
                    List<Fix> fixes = new ArrayList<Fix>();
jlahoda@555
   571
jlahoda@555
   572
                    fixes.addAll(hed.createdFixes);
jlahoda@555
   573
jlahoda@555
   574
                    if (!swKeys.isEmpty()) {
jlahoda@555
   575
                        fixes.addAll(FixFactory.createSuppressWarnings(info, hed.ctx.getPath(), swKeys.toArray(new String[0])));
jlahoda@555
   576
                    }
jlahoda@555
   577
jlahoda@555
   578
                    ed = ErrorDescriptionFactory.createErrorDescription(ed.getSeverity(), ed.getDescription(), fixes, ed.getFile(), ed.getRange().getBegin().getOffset(), ed.getRange().getEnd().getOffset());
jlahoda@554
   579
jlahoda@554
   580
                    if (ed != null) {
jlahoda@522
   581
                        merge(errors, hed.hd, ed);
jlahoda@522
   582
                    }
jlahoda@522
   583
                    it.remove();
jlahoda@522
   584
                }
jlahoda@522
   585
            }
jlahoda@522
   586
jlahoda@522
   587
            wasChange = currentWasChange;
jlahoda@522
   588
        }
jlahoda@522
   589
jlahoda@0
   590
        return errors;
jlahoda@0
   591
    }
jlahoda@297
   592
jlahoda@23
   593
//    public static void computeHints(URI file, ProcessingEnvironment env, CompilationUnitTree cut, RulesManager m) {
jlahoda@23
   594
//        Map<Kind, HintDescription> hints = m.getKindBasedHints();
jlahoda@23
   595
//
jlahoda@23
   596
//        if (hints.isEmpty()) {
jlahoda@23
   597
//            return ;
jlahoda@23
   598
//        }
jlahoda@23
   599
//
jlahoda@23
   600
//        List<ErrorDescription> errors = new  LinkedList<ErrorDescription>();
jlahoda@23
   601
//
jlahoda@23
   602
//        File af = new File(file.getPath());
jlahoda@23
   603
//        FileObject f = FileUtil.toFileObject(af);
jlahoda@23
   604
//
jlahoda@23
   605
//        new ScannerImpl(f, env, hints).scan(cut, errors);
jlahoda@23
   606
//
jlahoda@23
   607
//        for (ErrorDescription ed : errors) {
jlahoda@23
   608
//            Diagnostic.Kind k;
jlahoda@23
   609
//
jlahoda@23
   610
//            switch (ed.getSeverity()) {
jlahoda@23
   611
//                case ERROR:
jlahoda@23
   612
//                    k = Diagnostic.Kind.ERROR;
jlahoda@23
   613
//                    break;
jlahoda@23
   614
//                default:
jlahoda@23
   615
//                    k = Diagnostic.Kind.WARNING;
jlahoda@23
   616
//                    break;
jlahoda@23
   617
//            }
jlahoda@23
   618
//
jlahoda@23
   619
//            env.getMessager().printMessage(k, ed.getDescription());
jlahoda@23
   620
//        }
jlahoda@23
   621
//    }
jlahoda@297
   622
jlahoda@297
   623
    public Map<String, Long> getTimeLog() {
jlahoda@297
   624
        return timeLog;
jlahoda@297
   625
    }
jlahoda@297
   626
jlahoda@330
   627
    private final class ScannerImpl extends CancellableTreePathScanner<Void, Map<HintDescription, List<ErrorDescription>>> {
jlahoda@0
   628
jlahoda@0
   629
        private final Stack<Set<String>> suppresWarnings = new Stack<Set<String>>();
jlahoda@0
   630
        private final CompilationInfo info;
jlahoda@0
   631
        private final FileObject file;
jlahoda@0
   632
        private final ProcessingEnvironment env;
jlahoda@23
   633
        private final Map<Kind, List<HintDescription>> hints;
jlahoda@0
   634
jlahoda@23
   635
        public ScannerImpl(CompilationInfo info, AtomicBoolean cancel, Map<Kind, List<HintDescription>> hints) {
jlahoda@0
   636
            super(cancel);
jlahoda@0
   637
            this.info = info;
jlahoda@0
   638
            this.file = null;
jlahoda@0
   639
            this.env  = null;
jlahoda@0
   640
            this.hints = hints;
jlahoda@0
   641
        }
jlahoda@0
   642
jlahoda@23
   643
        public ScannerImpl(FileObject file, ProcessingEnvironment env, Map<Kind, List<HintDescription>> hints) {
jlahoda@0
   644
            super(new AtomicBoolean());
jlahoda@0
   645
            this.info = null;
jlahoda@0
   646
            this.file = file;
jlahoda@0
   647
            this.env = env;
jlahoda@0
   648
            this.hints = hints;
jlahoda@0
   649
        }
jlahoda@0
   650
jlahoda@330
   651
        private void runAndAdd(TreePath path, List<HintDescription> rules, Map<HintDescription, List<ErrorDescription>> d) {
jlahoda@0
   652
            if (rules != null && !isInGuarded(info, path)) {
jlahoda@297
   653
                OUTER: for (HintDescription hd : rules) {
jlahoda@0
   654
                    if (isCanceled()) {
jlahoda@0
   655
                        return ;
jlahoda@0
   656
                    }
jlahoda@0
   657
jlahoda@297
   658
                    HintMetadata hm = hd.getMetadata();
jlahoda@0
   659
jlahoda@297
   660
                    for (String wname : hm.suppressWarnings) {
jlahoda@297
   661
                        if( !suppresWarnings.empty() && suppresWarnings.peek().contains(wname)) {
jlahoda@297
   662
                            continue OUTER;
jlahoda@0
   663
                        }
jlahoda@0
   664
                    }
jlahoda@0
   665
jlahoda@297
   666
                    HintContext c = new HintContext(info, hm, path, Collections.<String, TreePath>emptyMap(), Collections.<String, Collection<? extends TreePath>>emptyMap(), Collections.<String, String>emptyMap());
jlahoda@297
   667
                    Collection<? extends ErrorDescription> errors = runHint(hd, c);
jlahoda@0
   668
jlahoda@297
   669
                    if (errors != null) {
jlahoda@330
   670
                        merge(d, hd, errors);
jlahoda@0
   671
                    }
jlahoda@0
   672
                }
jlahoda@0
   673
            }
jlahoda@0
   674
        }
jlahoda@0
   675
jlahoda@0
   676
        @Override
jlahoda@330
   677
        public Void scan(Tree tree, Map<HintDescription, List<ErrorDescription>> p) {
jlahoda@0
   678
            if (tree == null)
jlahoda@0
   679
                return null;
jlahoda@0
   680
jlahoda@0
   681
            TreePath tp = new TreePath(getCurrentPath(), tree);
jlahoda@0
   682
            Kind k = tree.getKind();
jlahoda@0
   683
jlahoda@297
   684
            boolean b = pushSuppressWarrnings(tp);
jlahoda@297
   685
            try {
jlahoda@297
   686
                runAndAdd(tp, hints.get(k), p);
jlahoda@0
   687
jlahoda@297
   688
                if (isCanceled()) {
jlahoda@297
   689
                    return null;
jlahoda@297
   690
                }
jlahoda@297
   691
jlahoda@297
   692
                return super.scan(tree, p);
jlahoda@297
   693
            } finally {
jlahoda@297
   694
                if (b) {
jlahoda@297
   695
                    suppresWarnings.pop();
jlahoda@297
   696
                }
jlahoda@0
   697
            }
jlahoda@0
   698
        }
jlahoda@0
   699
jlahoda@0
   700
        @Override
jlahoda@330
   701
        public Void scan(TreePath path, Map<HintDescription, List<ErrorDescription>> p) {
jlahoda@0
   702
            Kind k = path.getLeaf().getKind();
jlahoda@297
   703
            boolean b = pushSuppressWarrnings(path);
jlahoda@297
   704
            try {
jlahoda@297
   705
                runAndAdd(path, hints.get(k), p);
jlahoda@0
   706
jlahoda@297
   707
                if (isCanceled()) {
jlahoda@297
   708
                    return null;
jlahoda@297
   709
                }
jlahoda@297
   710
jlahoda@297
   711
                return super.scan(path, p);
jlahoda@297
   712
            } finally {
jlahoda@297
   713
                if (b) {
jlahoda@297
   714
                    suppresWarnings.pop();
jlahoda@297
   715
                }
jlahoda@0
   716
            }
jlahoda@0
   717
        }
jlahoda@0
   718
jlahoda@330
   719
        public void scanDoNotGoDeeper(TreePath path, Map<HintDescription, List<ErrorDescription>> p) {
jlahoda@297
   720
            Kind k = path.getLeaf().getKind();
jlahoda@297
   721
            runAndAdd(path, hints.get(k), p);
jlahoda@0
   722
        }
jlahoda@0
   723
jlahoda@297
   724
        private boolean pushSuppressWarrnings(TreePath path) {
jlahoda@297
   725
            switch(path.getLeaf().getKind()) {
jlahoda@297
   726
                case CLASS:
jlahoda@297
   727
                case METHOD:
jlahoda@297
   728
                case VARIABLE:
jlahoda@297
   729
                    Set<String> current = suppresWarnings.size() == 0 ? null : suppresWarnings.peek();
jlahoda@297
   730
                    Set<String> nju = current == null ? new HashSet<String>() : new HashSet<String>(current);
jlahoda@0
   731
jlahoda@297
   732
                    Element e = getTrees().getElement(path);
jlahoda@0
   733
jlahoda@297
   734
                    if ( e != null) {
jlahoda@297
   735
                        for (AnnotationMirror am : e.getAnnotationMirrors()) {
jlahoda@297
   736
                            String name = ((TypeElement)am.getAnnotationType().asElement()).getQualifiedName().toString();
jlahoda@297
   737
                            if ( "java.lang.SuppressWarnings".equals(name) ) { // NOI18N
jlahoda@297
   738
                                Map<? extends ExecutableElement, ? extends AnnotationValue> elementValues = am.getElementValues();
jlahoda@297
   739
                                for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : elementValues.entrySet()) {
jlahoda@297
   740
                                    if( "value".equals(entry.getKey().getSimpleName().toString()) ) { // NOI18N
jlahoda@297
   741
                                        Object value = entry.getValue().getValue();
jlahoda@297
   742
                                        if ( value instanceof List) {
jlahoda@297
   743
                                            for (Object av : (List)value) {
jlahoda@297
   744
                                                if( av instanceof AnnotationValue ) {
jlahoda@297
   745
                                                    Object wname = ((AnnotationValue)av).getValue();
jlahoda@297
   746
                                                    if ( wname instanceof String ) {
jlahoda@297
   747
                                                        nju.add((String)wname);
jlahoda@297
   748
                                                    }
jlahoda@297
   749
                                                }
jlahoda@0
   750
                                            }
jlahoda@0
   751
                                        }
jlahoda@0
   752
                                    }
jlahoda@0
   753
                                }
jlahoda@0
   754
                            }
jlahoda@0
   755
                        }
jlahoda@297
   756
                    }
jlahoda@0
   757
jlahoda@297
   758
                    suppresWarnings.push(nju);
jlahoda@297
   759
                    return true;
jlahoda@0
   760
            }
jlahoda@297
   761
            return false;
jlahoda@0
   762
        }
jlahoda@0
   763
jlahoda@0
   764
        private Trees getTrees() {
jlahoda@0
   765
            return info != null ? info.getTrees() : Trees.instance(env);
jlahoda@0
   766
        }
jlahoda@0
   767
    }
jlahoda@0
   768
jlahoda@0
   769
    static boolean isInGuarded(CompilationInfo info, TreePath tree) {
jlahoda@0
   770
        if (info == null) {
jlahoda@0
   771
            return false;
jlahoda@0
   772
        }
jlahoda@297
   773
jlahoda@0
   774
        try {
jlahoda@0
   775
            Document doc = info.getDocument();
jlahoda@0
   776
jlahoda@0
   777
            if (doc instanceof GuardedDocument) {
jlahoda@0
   778
                int start = (int) info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), tree.getLeaf());
jlahoda@0
   779
                int end = (int) info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), tree.getLeaf());
jlahoda@0
   780
                GuardedDocument gdoc = (GuardedDocument) doc;
jlahoda@0
   781
                MarkBlockChain guardedBlockChain = gdoc.getGuardedBlockChain();
jlahoda@0
   782
                if (guardedBlockChain.compareBlock(start, end) == MarkBlock.INNER) {
jlahoda@0
   783
                    return true;
jlahoda@0
   784
                }
jlahoda@0
   785
            }
jlahoda@0
   786
        } catch (IOException ex) {
jlahoda@0
   787
            Exceptions.printStackTrace(ex);
jlahoda@0
   788
        }
jlahoda@0
   789
jlahoda@0
   790
        return false;
jlahoda@0
   791
    }
jlahoda@0
   792
jlahoda@297
   793
    private Collection<? extends ErrorDescription> runHint(HintDescription hd, HintContext ctx) {
jlahoda@297
   794
        long start = System.nanoTime();
jlahoda@0
   795
jlahoda@297
   796
        try {
jlahoda@297
   797
            return hd.getWorker().createErrors(ctx);
jlahoda@297
   798
        } finally {
jlahoda@297
   799
            long end = System.nanoTime();
jlahoda@297
   800
            reportSpentTime(hd.getMetadata().id, end - start);
jlahoda@297
   801
        }
jlahoda@297
   802
    }
jlahoda@297
   803
jlahoda@330
   804
    public static <K, V> Map<K, List<V>> merge(Map<K, List<V>> to, K key, V value) {
jlahoda@330
   805
        List<V> toColl = to.get(key);
jlahoda@330
   806
jlahoda@330
   807
        if (toColl == null) {
jlahoda@330
   808
            to.put(key, toColl = new LinkedList<V>());
jlahoda@330
   809
        }
jlahoda@330
   810
jlahoda@330
   811
        toColl.add(value);
jlahoda@330
   812
jlahoda@330
   813
        return to;
jlahoda@330
   814
    }
jlahoda@330
   815
jlahoda@330
   816
    public static <K, V> Map<K, List<V>> merge(Map<K, List<V>> to, K key, Collection<? extends V> value) {
jlahoda@330
   817
        List<V> toColl = to.get(key);
jlahoda@330
   818
jlahoda@330
   819
        if (toColl == null) {
jlahoda@330
   820
            to.put(key, toColl = new LinkedList<V>());
jlahoda@330
   821
        }
jlahoda@330
   822
jlahoda@330
   823
        toColl.addAll(value);
jlahoda@330
   824
jlahoda@330
   825
        return to;
jlahoda@330
   826
    }
jlahoda@330
   827
jlahoda@330
   828
    public static <K, V> Map<K, List<V>> mergeAll(Map<K, List<V>> to, Map<? extends K, ? extends Collection<? extends V>> what) {
jlahoda@330
   829
        for (Entry<? extends K, ? extends Collection<? extends V>> e : what.entrySet()) {
jlahoda@330
   830
            List<V> toColl = to.get(e.getKey());
jlahoda@330
   831
jlahoda@330
   832
            if (toColl == null) {
jlahoda@330
   833
                to.put(e.getKey(), toColl = new LinkedList<V>());
jlahoda@330
   834
            }
jlahoda@330
   835
jlahoda@330
   836
            toColl.addAll(e.getValue());
jlahoda@330
   837
        }
jlahoda@330
   838
jlahoda@330
   839
        return to;
jlahoda@330
   840
    }
jlahoda@330
   841
jlahoda@330
   842
    public static List<ErrorDescription> join(Map<?, ? extends List<? extends ErrorDescription>> errors) {
jlahoda@330
   843
        List<ErrorDescription> result = new LinkedList<ErrorDescription>();
jlahoda@330
   844
jlahoda@330
   845
        for (Entry<?, ? extends Collection<? extends ErrorDescription>> e : errors.entrySet()) {
jlahoda@330
   846
            result.addAll(e.getValue());
jlahoda@330
   847
        }
jlahoda@330
   848
jlahoda@330
   849
        return result;
jlahoda@330
   850
    }
jlahoda@330
   851
jlahoda@297
   852
    private static final boolean logTimeSpentInHints = Boolean.getBoolean("java.HintsInvoker.time.in.hints");
jlahoda@297
   853
    private final Map<String, Long> hint2SpentTime = new HashMap<String, Long>();
jlahoda@297
   854
jlahoda@297
   855
    private void reportSpentTime(String id, long nanoTime) {
jlahoda@297
   856
        if (!logTimeSpentInHints) return;
jlahoda@297
   857
        
jlahoda@297
   858
        Long prev = hint2SpentTime.get(id);
jlahoda@297
   859
jlahoda@297
   860
        if (prev == null) {
jlahoda@297
   861
            prev = (long) 0;
jlahoda@0
   862
        }
jlahoda@0
   863
jlahoda@297
   864
        hint2SpentTime.put(id, prev + nanoTime);
jlahoda@297
   865
    }
jlahoda@297
   866
jlahoda@297
   867
    private void dumpTimeSpentInHints() {
jlahoda@297
   868
        if (!logTimeSpentInHints) return;
jlahoda@297
   869
jlahoda@297
   870
        List<Entry<String, Long>> l = new ArrayList<Entry<String, Long>>(hint2SpentTime.entrySet());
jlahoda@297
   871
jlahoda@297
   872
        Collections.sort(l, new Comparator<Entry<String, Long>>() {
jlahoda@297
   873
            @Override
jlahoda@297
   874
            public int compare(Entry<String, Long> o1, Entry<String, Long> o2) {
jlahoda@297
   875
                return (int) Math.signum(o1.getValue() - o2.getValue());
jlahoda@297
   876
            }
jlahoda@297
   877
        });
jlahoda@297
   878
jlahoda@297
   879
        for (Entry<String, Long> e : l) {
jlahoda@297
   880
            System.err.println(e.getKey() + "=" + String.format("%3.2f", e.getValue() / 1000000.0));
jlahoda@0
   881
        }
jlahoda@0
   882
    }
jlahoda@522
   883
jlahoda@522
   884
jlahoda@553
   885
    private void enterSpeculativeAssignments(HintContext ctx, List<Condition> conditions, Map<Tree, Map<String, Object>> marks) {
jlahoda@553
   886
        for (Condition c : conditions) {
jlahoda@553
   887
            if (!(c instanceof MarkCondition)) continue;
jlahoda@553
   888
jlahoda@553
   889
            MarkCondition mc = (MarkCondition) c;
jlahoda@553
   890
jlahoda@522
   891
            if (mc.op != Operator.ASSIGN) {
jlahoda@522
   892
                continue;
jlahoda@522
   893
            }
jlahoda@522
   894
jlahoda@522
   895
            assert mc.left instanceof Selector;
jlahoda@522
   896
jlahoda@522
   897
            Selector s = (Selector) mc.left;
jlahoda@522
   898
            String treeName = s.selected.get(0);
jlahoda@522
   899
            String markName = s.selected.get(1);
jlahoda@522
   900
            TreePath tree = ctx.getVariables().get(treeName);
jlahoda@522
   901
jlahoda@522
   902
            assert tree != null;
jlahoda@522
   903
jlahoda@522
   904
            System.err.println("speculative assignment to: " + tree.getLeaf());
jlahoda@522
   905
jlahoda@522
   906
            Map<String, Object> variables = marks.get(tree.getLeaf());
jlahoda@522
   907
jlahoda@522
   908
            if (variables == null) {
jlahoda@522
   909
                marks.put(tree.getLeaf(), variables = new HashMap<String, Object>());
jlahoda@522
   910
            }
jlahoda@522
   911
jlahoda@522
   912
            PossibleValue pv = (PossibleValue) variables.get(markName);
jlahoda@522
   913
jlahoda@522
   914
            if (pv == null) {
jlahoda@522
   915
                variables.put(markName, pv = new PossibleValue());
jlahoda@522
   916
            }
jlahoda@522
   917
jlahoda@522
   918
            pv.add(mc);
jlahoda@522
   919
        }
jlahoda@522
   920
    }
jlahoda@522
   921
jlahoda@553
   922
    private void clearSpeculativeAssignments(HintContext ctx, List<Condition> conditions, Map<Tree, Map<String, Object>> marks) {
jlahoda@553
   923
        for (Condition c : conditions) {
jlahoda@553
   924
            if (!(c instanceof MarkCondition)) continue;
jlahoda@553
   925
jlahoda@553
   926
            MarkCondition mc = (MarkCondition) c;
jlahoda@553
   927
jlahoda@522
   928
            if (mc.op != Operator.ASSIGN) {
jlahoda@522
   929
                continue;
jlahoda@522
   930
            }
jlahoda@522
   931
jlahoda@522
   932
            assert mc.left instanceof Selector;
jlahoda@522
   933
jlahoda@522
   934
            Selector s = (Selector) mc.left;
jlahoda@522
   935
            String treeName = s.selected.get(0);
jlahoda@522
   936
            String markName = s.selected.get(1);
jlahoda@522
   937
            TreePath tree = ctx.getVariables().get(treeName);
jlahoda@522
   938
jlahoda@522
   939
            assert tree != null;
jlahoda@522
   940
jlahoda@522
   941
            System.err.println("clearing speculative assignment from: " + tree.getLeaf());
jlahoda@522
   942
jlahoda@522
   943
            Map<String, Object> variables = marks.get(tree.getLeaf());
jlahoda@522
   944
jlahoda@522
   945
            assert variables != null;
jlahoda@522
   946
jlahoda@522
   947
            Object value = variables.get(markName);
jlahoda@522
   948
jlahoda@522
   949
            if (!(value instanceof PossibleValue))
jlahoda@522
   950
                continue;//XXX: correct?
jlahoda@522
   951
jlahoda@522
   952
            PossibleValue pv = (PossibleValue) value;
jlahoda@522
   953
jlahoda@522
   954
            assert pv != null;
jlahoda@522
   955
jlahoda@522
   956
            pv.remove(mc);
jlahoda@522
   957
jlahoda@522
   958
            if (pv.isEmpty()) {
jlahoda@522
   959
                variables.remove(markName);
jlahoda@522
   960
            }
jlahoda@522
   961
        }
jlahoda@522
   962
    }
jlahoda@522
   963
jlahoda@522
   964
    /**true==accepted
jlahoda@522
   965
     * false==rejected
jlahoda@522
   966
     * null==nothing
jlahoda@522
   967
     *
jlahoda@522
   968
     * @return
jlahoda@522
   969
     */
jlahoda@553
   970
    private static Boolean processConditions(HintContext ctx, Map<Tree, Map<String, Object>> marks, List<Condition> cond, int candidatesCount, int confirmedCount) {
jlahoda@522
   971
        if (cond.isEmpty()) {
jlahoda@522
   972
            return true; //implicitly accept
jlahoda@522
   973
        }
jlahoda@522
   974
jlahoda@553
   975
        for (Iterator<Condition> it = cond.iterator(); it.hasNext(); ) {
jlahoda@553
   976
            Condition c = it.next();
jlahoda@522
   977
jlahoda@553
   978
            if (c instanceof CustomCondition) {
jlahoda@553
   979
                if (!((CustomCondition) c).holds(ctx)) {
jlahoda@553
   980
                    return false;
jlahoda@553
   981
                }
jlahoda@553
   982
                it.remove();
jlahoda@553
   983
                continue;
jlahoda@553
   984
            }
jlahoda@553
   985
jlahoda@553
   986
            if (c instanceof OtherwiseCondition) {
jlahoda@553
   987
                if (candidatesCount > 1) return null;
jlahoda@553
   988
                if (confirmedCount > 0) return false;
jlahoda@553
   989
                it.remove();
jlahoda@553
   990
                continue;
jlahoda@553
   991
            }
jlahoda@553
   992
jlahoda@553
   993
            MarkCondition mc = (MarkCondition) c;
jlahoda@553
   994
jlahoda@553
   995
            switch (mc.op) {
jlahoda@522
   996
                case ASSIGN:
jlahoda@553
   997
                    assert mc.left instanceof Selector;
jlahoda@522
   998
jlahoda@553
   999
                    Object value = readValue(ctx, marks, mc.right);
jlahoda@522
  1000
jlahoda@522
  1001
                    assert value != null;
jlahoda@522
  1002
jlahoda@553
  1003
                    Selector s = (Selector) mc.left;
jlahoda@522
  1004
                    String treeName = s.selected.get(0);
jlahoda@522
  1005
                    String markName = s.selected.get(1);
jlahoda@522
  1006
                    TreePath tree = ctx.getVariables().get(treeName);
jlahoda@522
  1007
jlahoda@522
  1008
                    assert tree != null; //more gracefull handling, in some case may warn during parsing
jlahoda@522
  1009
jlahoda@522
  1010
                    Map<String, Object> variables = marks.get(tree.getLeaf());
jlahoda@522
  1011
jlahoda@522
  1012
                    if (variables == null) {
jlahoda@522
  1013
                        marks.put(tree.getLeaf(), variables = new HashMap<String, Object>());
jlahoda@522
  1014
                    }
jlahoda@522
  1015
jlahoda@522
  1016
                    variables.put(markName, value);
jlahoda@522
  1017
                    break;
jlahoda@522
  1018
                case EQUALS: {
jlahoda@553
  1019
                    Object left = readValue(ctx, marks, mc.left);
jlahoda@553
  1020
                    Object right = readValue(ctx, marks, mc.right);
jlahoda@522
  1021
jlahoda@522
  1022
                    System.err.println("left=" + left);
jlahoda@522
  1023
                    System.err.println("right=" + right);
jlahoda@522
  1024
jlahoda@522
  1025
                    if (left == null || right == null) {
jlahoda@522
  1026
//                        System.err.println("marks=" + marks);
jlahoda@522
  1027
//                        System.err.println("left=" + left);
jlahoda@522
  1028
//                        System.err.println("right=" + right);
jlahoda@522
  1029
                        //can never be true:
jlahoda@522
  1030
                        return false;
jlahoda@522
  1031
                    }
jlahoda@522
  1032
jlahoda@522
  1033
                    if (left instanceof PossibleValue || right instanceof PossibleValue) {
jlahoda@522
  1034
                        //nothing to set yet.
jlahoda@522
  1035
                        return null;
jlahoda@522
  1036
                    }
jlahoda@522
  1037
jlahoda@522
  1038
                    if (!left.equals(right)) {
jlahoda@522
  1039
                        return false;
jlahoda@522
  1040
                    }
jlahoda@522
  1041
jlahoda@522
  1042
                    break;
jlahoda@522
  1043
                }
jlahoda@522
  1044
                case NOT_EQUALS: {
jlahoda@553
  1045
                    Object left = readValue(ctx, marks, mc.left);
jlahoda@553
  1046
                    Object right = readValue(ctx, marks, mc.right);
jlahoda@522
  1047
jlahoda@522
  1048
                    if (left instanceof PossibleValue || right instanceof PossibleValue) {
jlahoda@522
  1049
                        //nothing to set yet.
jlahoda@522
  1050
                        return null;
jlahoda@522
  1051
                    }
jlahoda@522
  1052
jlahoda@522
  1053
                    if (left == right || (left != null && left.equals(right))) {
jlahoda@522
  1054
                        return false;
jlahoda@522
  1055
                    }
jlahoda@522
  1056
jlahoda@522
  1057
                    break;
jlahoda@522
  1058
                }
jlahoda@522
  1059
                default:
jlahoda@522
  1060
                    throw new UnsupportedOperationException();
jlahoda@522
  1061
            }
jlahoda@522
  1062
jlahoda@522
  1063
            it.remove();
jlahoda@522
  1064
        }
jlahoda@522
  1065
jlahoda@522
  1066
        assert cond.isEmpty();
jlahoda@522
  1067
jlahoda@522
  1068
        return true;
jlahoda@522
  1069
    }
jlahoda@522
  1070
jlahoda@522
  1071
    private static Object readValue(HintContext ctx, Map<Tree, Map<String, Object>> marks, Value v) {
jlahoda@522
  1072
        if (v instanceof Selector) {
jlahoda@522
  1073
            Selector s = (Selector) v;
jlahoda@522
  1074
jlahoda@522
  1075
            if (s.selected.size() == 1) {
jlahoda@522
  1076
                String name = s.selected.get(0);
jlahoda@522
  1077
                TreePath tree = ctx.getVariables().get(name);
jlahoda@522
  1078
jlahoda@522
  1079
                assert tree != null;
jlahoda@522
  1080
jlahoda@522
  1081
                return ctx.getInfo().getTrees().getElement(tree);
jlahoda@522
  1082
            }
jlahoda@522
  1083
jlahoda@522
  1084
            if (s.selected.size() == 2) {
jlahoda@522
  1085
                String treeName = s.selected.get(0);
jlahoda@522
  1086
                String markName = s.selected.get(1);
jlahoda@522
  1087
                TreePath tree = ctx.getVariables().get(treeName);
jlahoda@522
  1088
jlahoda@522
  1089
                assert tree != null; //more gracefull handling, in some case may warn during parsing
jlahoda@522
  1090
jlahoda@522
  1091
                System.err.println("reading=" + tree.getLeaf() + "." + markName);
jlahoda@522
  1092
jlahoda@522
  1093
                Map<String, Object> variables = marks.get(tree.getLeaf());
jlahoda@522
  1094
jlahoda@522
  1095
                if (variables == null) return null;
jlahoda@522
  1096
jlahoda@522
  1097
                return variables.get(markName);
jlahoda@522
  1098
            }
jlahoda@522
  1099
jlahoda@522
  1100
            assert false;
jlahoda@522
  1101
        }
jlahoda@522
  1102
jlahoda@522
  1103
        //XXX: not tested!
jlahoda@522
  1104
        if (v instanceof Literal) {
jlahoda@522
  1105
            return ((Literal) v).value;
jlahoda@522
  1106
        }
jlahoda@522
  1107
jlahoda@522
  1108
        assert false;
jlahoda@522
  1109
jlahoda@522
  1110
        return null;
jlahoda@522
  1111
    }
jlahoda@522
  1112
jlahoda@522
  1113
    private static final class PossibleValue extends HashSet<MarkCondition> {}
jlahoda@522
  1114
jlahoda@522
  1115
    private static final class HintEvaluationData {
jlahoda@522
  1116
        public final HintContext ctx;
jlahoda@522
  1117
        public final HintDescription hd;
jlahoda@553
  1118
        public final List<Condition> marks;
jlahoda@554
  1119
        public final ErrorDescriptionAcceptor acceptor;
jlahoda@522
  1120
        public final List<FixEvaluationData> fixDescriptions;
jlahoda@522
  1121
        public final List<Fix> createdFixes = new LinkedList<Fix>();
jlahoda@554
  1122
        public HintEvaluationData(HintContext ctx, HintDescription hd, List<Condition> marks, ErrorDescriptionAcceptor acceptor, List<FixEvaluationData> fixDescriptions) {
jlahoda@522
  1123
            this.ctx = ctx;
jlahoda@522
  1124
            this.hd = hd;
jlahoda@522
  1125
            this.marks = marks;
jlahoda@522
  1126
            this.acceptor = acceptor;
jlahoda@522
  1127
            this.fixDescriptions = fixDescriptions;
jlahoda@522
  1128
        }
jlahoda@522
  1129
    }
jlahoda@522
  1130
jlahoda@522
  1131
    private static final class FixEvaluationData {
jlahoda@527
  1132
        public final HintContext ctx;
jlahoda@553
  1133
        public final List<Condition> marks;
jlahoda@554
  1134
        public final FixAcceptor acceptor;
jlahoda@554
  1135
        public FixEvaluationData(HintContext ctx, List<Condition> marks, FixAcceptor acceptor) {
jlahoda@527
  1136
            this.ctx = ctx;
jlahoda@522
  1137
            this.marks = marks;
jlahoda@522
  1138
            this.acceptor = acceptor;
jlahoda@522
  1139
        }
jlahoda@522
  1140
    }
jlahoda@522
  1141
jlahoda@0
  1142
}