Committing first sketch of decision-based multi-file hints API
authorJan Lahoda <jlahoda@netbeans.org>
Thu, 09 May 2013 23:11:06 +0200
changeset 957f0892c603898
parent 956 8ecdbdbce732
child 958 e2f6bb85a163
Committing first sketch of decision-based multi-file hints API
java.hints/hintsimpl/build.xml
java.hints/hintsimpl/manifest.mf
java.hints/hintsimpl/nbproject/build-impl.xml
java.hints/hintsimpl/nbproject/genfiles.properties
java.hints/hintsimpl/nbproject/project.properties
java.hints/hintsimpl/nbproject/project.xml
java.hints/hintsimpl/nbproject/suite.properties
java.hints/hintsimpl/src/org/netbeans/modules/jackpot30/hintsimpl/Bundle.properties
java.hints/hintsimpl/src/org/netbeans/modules/jackpot30/hintsimpl/GlobalyUnused.java
java.hints/hintsimpl/test/unit/src/org/netbeans/modules/jackpot30/hintsimpl/GlobalyUnusedNGTest.java
java.hints/java.hints.test/nbproject/genfiles.properties
java.hints/java.hints.test/nbproject/project.properties
java.hints/java.hints.test/nbproject/project.xml
java.hints/java.hints.test/src/org/netbeans/modules/java/hints/test/api/HintTest.java
java.hints/java.hints.test/test/unit/src/org/netbeans/modules/java/hints/test/api/HintTestTest.java
java.hints/nbproject/project.properties
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/providers/code/CodeHintProviderImpl.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/providers/spi/Trigger.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/SPIAccessor.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/batch/BatchSearch.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/hints/GlobalProcessingContext.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/hints/HintsInvoker.java
java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/Decision.java
java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/HintContext.java
java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/TriggerDecision.java
java.hints/spi.java.hints/test/unit/src/org/netbeans/spi/java/hints/MatcherUtilitiesTest.java
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/java.hints/hintsimpl/build.xml	Thu May 09 23:11:06 2013 +0200
     1.3 @@ -0,0 +1,8 @@
     1.4 +<?xml version="1.0" encoding="UTF-8"?>
     1.5 +<!-- You may freely edit this file. See harness/README in the NetBeans platform -->
     1.6 +<!-- for some information on what you could do (e.g. targets to override). -->
     1.7 +<!-- If you delete this file and reopen the project it will be recreated. -->
     1.8 +<project name="org.netbeans.modules.jackpot30.hintsimpl" default="netbeans" basedir=".">
     1.9 +    <description>Builds, tests, and runs the project org.netbeans.modules.jackpot30.hintsimpl.</description>
    1.10 +    <import file="nbproject/build-impl.xml"/>
    1.11 +</project>
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/java.hints/hintsimpl/manifest.mf	Thu May 09 23:11:06 2013 +0200
     2.3 @@ -0,0 +1,5 @@
     2.4 +Manifest-Version: 1.0
     2.5 +OpenIDE-Module: org.netbeans.modules.jackpot30.hintsimpl
     2.6 +OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/jackpot30/hintsimpl/Bundle.properties
     2.7 +OpenIDE-Module-Specification-Version: 1.0
     2.8 +
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/java.hints/hintsimpl/nbproject/build-impl.xml	Thu May 09 23:11:06 2013 +0200
     3.3 @@ -0,0 +1,45 @@
     3.4 +<?xml version="1.0" encoding="UTF-8"?>
     3.5 +<!--
     3.6 +*** GENERATED FROM project.xml - DO NOT EDIT  ***
     3.7 +***         EDIT ../build.xml INSTEAD         ***
     3.8 +-->
     3.9 +<project name="org.netbeans.modules.jackpot30.hintsimpl-impl" basedir="..">
    3.10 +    <fail message="Please build using Ant 1.7.1 or higher.">
    3.11 +        <condition>
    3.12 +            <not>
    3.13 +                <antversion atleast="1.7.1"/>
    3.14 +            </not>
    3.15 +        </condition>
    3.16 +    </fail>
    3.17 +    <property file="nbproject/private/suite-private.properties"/>
    3.18 +    <property file="nbproject/suite.properties"/>
    3.19 +    <fail unless="suite.dir">You must set 'suite.dir' to point to your containing module suite</fail>
    3.20 +    <property file="${suite.dir}/nbproject/private/platform-private.properties"/>
    3.21 +    <property file="${suite.dir}/nbproject/platform.properties"/>
    3.22 +    <macrodef name="property" uri="http://www.netbeans.org/ns/nb-module-project/2">
    3.23 +        <attribute name="name"/>
    3.24 +        <attribute name="value"/>
    3.25 +        <sequential>
    3.26 +            <property name="@{name}" value="${@{value}}"/>
    3.27 +        </sequential>
    3.28 +    </macrodef>
    3.29 +    <macrodef name="evalprops" uri="http://www.netbeans.org/ns/nb-module-project/2">
    3.30 +        <attribute name="property"/>
    3.31 +        <attribute name="value"/>
    3.32 +        <sequential>
    3.33 +            <property name="@{property}" value="@{value}"/>
    3.34 +        </sequential>
    3.35 +    </macrodef>
    3.36 +    <property file="${user.properties.file}"/>
    3.37 +    <nbmproject2:property name="harness.dir" value="nbplatform.${nbplatform.active}.harness.dir" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
    3.38 +    <nbmproject2:property name="nbplatform.active.dir" value="nbplatform.${nbplatform.active}.netbeans.dest.dir" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
    3.39 +    <nbmproject2:evalprops property="cluster.path.evaluated" value="${cluster.path}" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
    3.40 +    <fail message="Path to 'platform' cluster missing in $${cluster.path} property or using corrupt Netbeans Platform (missing harness).">
    3.41 +        <condition>
    3.42 +            <not>
    3.43 +                <contains string="${cluster.path.evaluated}" substring="platform"/>
    3.44 +            </not>
    3.45 +        </condition>
    3.46 +    </fail>
    3.47 +    <import file="${harness.dir}/build.xml"/>
    3.48 +</project>
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/java.hints/hintsimpl/nbproject/genfiles.properties	Thu May 09 23:11:06 2013 +0200
     4.3 @@ -0,0 +1,8 @@
     4.4 +build.xml.data.CRC32=c75a6f96
     4.5 +build.xml.script.CRC32=ef577a91
     4.6 +build.xml.stylesheet.CRC32=a56c6a5b@2.58
     4.7 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
     4.8 +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
     4.9 +nbproject/build-impl.xml.data.CRC32=c75a6f96
    4.10 +nbproject/build-impl.xml.script.CRC32=9204f652
    4.11 +nbproject/build-impl.xml.stylesheet.CRC32=238281d1@2.58
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/java.hints/hintsimpl/nbproject/project.properties	Thu May 09 23:11:06 2013 +0200
     5.3 @@ -0,0 +1,3 @@
     5.4 +javac.source=1.7
     5.5 +javac.compilerargs=-Xlint -Xlint:-serial
     5.6 +requires.nb.javac=true
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/java.hints/hintsimpl/nbproject/project.xml	Thu May 09 23:11:06 2013 +0200
     6.3 @@ -0,0 +1,60 @@
     6.4 +<?xml version="1.0" encoding="UTF-8"?>
     6.5 +<project xmlns="http://www.netbeans.org/ns/project/1">
     6.6 +    <type>org.netbeans.modules.apisupport.project</type>
     6.7 +    <configuration>
     6.8 +        <data xmlns="http://www.netbeans.org/ns/nb-module-project/3">
     6.9 +            <code-name-base>org.netbeans.modules.jackpot30.hintsimpl</code-name-base>
    6.10 +            <suite-component/>
    6.11 +            <module-dependencies>
    6.12 +                <dependency>
    6.13 +                    <code-name-base>org.netbeans.libs.javacapi</code-name-base>
    6.14 +                    <build-prerequisite/>
    6.15 +                    <compile-dependency/>
    6.16 +                    <run-dependency>
    6.17 +                        <specification-version>8.4.0.3</specification-version>
    6.18 +                    </run-dependency>
    6.19 +                </dependency>
    6.20 +                <dependency>
    6.21 +                    <code-name-base>org.netbeans.modules.java.source</code-name-base>
    6.22 +                    <build-prerequisite/>
    6.23 +                    <compile-dependency/>
    6.24 +                    <run-dependency>
    6.25 +                        <specification-version>0.124.0.24.1.23.6</specification-version>
    6.26 +                    </run-dependency>
    6.27 +                </dependency>
    6.28 +                <dependency>
    6.29 +                    <code-name-base>org.netbeans.spi.editor.hints</code-name-base>
    6.30 +                    <build-prerequisite/>
    6.31 +                    <compile-dependency/>
    6.32 +                    <run-dependency>
    6.33 +                        <release-version>0</release-version>
    6.34 +                        <specification-version>1.31.0.7.42</specification-version>
    6.35 +                    </run-dependency>
    6.36 +                </dependency>
    6.37 +                <dependency>
    6.38 +                    <code-name-base>org.netbeans.spi.java.hints</code-name-base>
    6.39 +                    <build-prerequisite/>
    6.40 +                    <compile-dependency/>
    6.41 +                    <run-dependency>
    6.42 +                        <specification-version>2.0</specification-version>
    6.43 +                    </run-dependency>
    6.44 +                </dependency>
    6.45 +            </module-dependencies>
    6.46 +            <test-dependencies>
    6.47 +                <test-type>
    6.48 +                    <name>unit</name>
    6.49 +                    <test-dependency>
    6.50 +                        <code-name-base>org.netbeans.libs.testng</code-name-base>
    6.51 +                        <compile-dependency/>
    6.52 +                    </test-dependency>
    6.53 +                    <test-dependency>
    6.54 +                        <code-name-base>org.netbeans.modules.java.hints.test</code-name-base>
    6.55 +                        <recursive/>
    6.56 +                        <compile-dependency/>
    6.57 +                    </test-dependency>
    6.58 +                </test-type>
    6.59 +            </test-dependencies>
    6.60 +            <public-packages/>
    6.61 +        </data>
    6.62 +    </configuration>
    6.63 +</project>
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/java.hints/hintsimpl/nbproject/suite.properties	Thu May 09 23:11:06 2013 +0200
     7.3 @@ -0,0 +1,1 @@
     7.4 +suite.dir=${basedir}/..
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/java.hints/hintsimpl/src/org/netbeans/modules/jackpot30/hintsimpl/Bundle.properties	Thu May 09 23:11:06 2013 +0200
     8.3 @@ -0,0 +1,1 @@
     8.4 +OpenIDE-Module-Name=Jackpot 3.0 Experimental Hints Impl
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/java.hints/hintsimpl/src/org/netbeans/modules/jackpot30/hintsimpl/GlobalyUnused.java	Thu May 09 23:11:06 2013 +0200
     9.3 @@ -0,0 +1,120 @@
     9.4 +/*
     9.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     9.6 + *
     9.7 + * Copyright 2013 Oracle and/or its affiliates. All rights reserved.
     9.8 + *
     9.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    9.10 + * Other names may be trademarks of their respective owners.
    9.11 + *
    9.12 + * The contents of this file are subject to the terms of either the GNU
    9.13 + * General Public License Version 2 only ("GPL") or the Common
    9.14 + * Development and Distribution License("CDDL") (collectively, the
    9.15 + * "License"). You may not use this file except in compliance with the
    9.16 + * License. You can obtain a copy of the License at
    9.17 + * http://www.netbeans.org/cddl-gplv2.html
    9.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    9.19 + * specific language governing permissions and limitations under the
    9.20 + * License.  When distributing the software, include this License Header
    9.21 + * Notice in each file and include the License file at
    9.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    9.23 + * particular file as subject to the "Classpath" exception as provided
    9.24 + * by Oracle in the GPL Version 2 section of the License file that
    9.25 + * accompanied this code. If applicable, add the following below the
    9.26 + * License Header, with the fields enclosed by brackets [] replaced by
    9.27 + * your own identifying information:
    9.28 + * "Portions Copyrighted [year] [name of copyright owner]"
    9.29 + *
    9.30 + * If you wish your version of this file to be governed by only the CDDL
    9.31 + * or only the GPL Version 2, indicate your decision by adding
    9.32 + * "[Contributor] elects to include this software in this distribution
    9.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
    9.34 + * single choice of license, a recipient has the option to distribute
    9.35 + * your version of this file under either the CDDL, the GPL Version 2 or
    9.36 + * to extend the choice of license to its licensees as provided above.
    9.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
    9.38 + * Version 2 license, then the option applies only if the new code is
    9.39 + * made subject to such option by the copyright holder.
    9.40 + *
    9.41 + * Contributor(s):
    9.42 + *
    9.43 + * Portions Copyrighted 2013 Sun Microsystems, Inc.
    9.44 + */
    9.45 +package org.netbeans.modules.jackpot30.hintsimpl;
    9.46 +
    9.47 +import com.sun.source.tree.Tree.Kind;
    9.48 +import javax.lang.model.element.Element;
    9.49 +import javax.lang.model.element.ElementKind;
    9.50 +import javax.lang.model.type.TypeKind;
    9.51 +import org.netbeans.api.java.source.TreePathHandle;
    9.52 +import org.netbeans.spi.editor.hints.ErrorDescription;
    9.53 +import org.netbeans.spi.java.hints.Decision;
    9.54 +import org.netbeans.spi.java.hints.Decision.Factory;
    9.55 +import org.netbeans.spi.java.hints.ErrorDescriptionFactory;
    9.56 +import org.netbeans.spi.java.hints.Hint;
    9.57 +import org.netbeans.spi.java.hints.HintContext;
    9.58 +import org.netbeans.spi.java.hints.TriggerDecision;
    9.59 +import org.netbeans.spi.java.hints.TriggerTreeKind;
    9.60 +
    9.61 +/**
    9.62 + *
    9.63 + * @author lahvac
    9.64 + */
    9.65 +@Hint(displayName="Unused", description="Unused", category="general")
    9.66 +public class GlobalyUnused {
    9.67 +    
    9.68 +    @TriggerTreeKind({Kind.IDENTIFIER, Kind.MEMBER_SELECT})
    9.69 +    public static ErrorDescription usage(HintContext ctx) {
    9.70 +        DecisionImpl d = decisionOrNull(ctx);
    9.71 +        
    9.72 +        if (d != null) {
    9.73 +            System.err.println("recording usage");
    9.74 +            d.recordLocalFact(ctx.getInfo(), null);
    9.75 +        }
    9.76 +        
    9.77 +        return null;
    9.78 +    }
    9.79 +    
    9.80 +    @TriggerTreeKind({Kind.CLASS})
    9.81 +    public static ErrorDescription declaration(HintContext ctx) {
    9.82 +        decisionOrNull(ctx);
    9.83 +        return null;
    9.84 +    }
    9.85 +    
    9.86 +    @TriggerDecision(DecisionImpl.class)
    9.87 +    public static ErrorDescription produceWarning(HintContext ctx) {
    9.88 +        if (((DecisionImpl) ctx.decision).getCurrentResult() != Boolean.TRUE) {
    9.89 +            return ErrorDescriptionFactory.forName(ctx, ctx.getPath(), "Unused");
    9.90 +        }
    9.91 +        
    9.92 +        return null;
    9.93 +    }
    9.94 +    
    9.95 +    private static DecisionImpl decisionOrNull(HintContext ctx) {
    9.96 +        Element el = ctx.getInfo().getTrees().getElement(ctx.getPath());
    9.97 +        
    9.98 +        if (el == null || (el.asType() != null && el.asType().getKind() == TypeKind.ERROR) || el.getKind() != ElementKind.CLASS) return null;
    9.99 +        
   9.100 +        TreePathHandle h = TreePathHandle.create(el, ctx.getInfo());
   9.101 +        
   9.102 +        System.err.println("decision for: " + el);
   9.103 +        return ctx.findDecision(h, new Factory<Void, Boolean, DecisionImpl>(DecisionImpl.class) {
   9.104 +            @Override
   9.105 +            public DecisionImpl create(TreePathHandle handle) {
   9.106 +                return new DecisionImpl(handle);
   9.107 +            }
   9.108 +        });
   9.109 +    }
   9.110 +    
   9.111 +    private static final class DecisionImpl extends Decision<Void, Boolean> {
   9.112 +
   9.113 +        public DecisionImpl(TreePathHandle root) {
   9.114 +            super(root);
   9.115 +        }
   9.116 +
   9.117 +        @Override
   9.118 +        protected Boolean makeDecision(Iterable<? extends Void> input) {
   9.119 +            return input.iterator().hasNext();
   9.120 +        }
   9.121 +        
   9.122 +    }
   9.123 +}
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/java.hints/hintsimpl/test/unit/src/org/netbeans/modules/jackpot30/hintsimpl/GlobalyUnusedNGTest.java	Thu May 09 23:11:06 2013 +0200
    10.3 @@ -0,0 +1,84 @@
    10.4 +/*
    10.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    10.6 + *
    10.7 + * Copyright 2013 Oracle and/or its affiliates. All rights reserved.
    10.8 + *
    10.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   10.10 + * Other names may be trademarks of their respective owners.
   10.11 + *
   10.12 + * The contents of this file are subject to the terms of either the GNU
   10.13 + * General Public License Version 2 only ("GPL") or the Common
   10.14 + * Development and Distribution License("CDDL") (collectively, the
   10.15 + * "License"). You may not use this file except in compliance with the
   10.16 + * License. You can obtain a copy of the License at
   10.17 + * http://www.netbeans.org/cddl-gplv2.html
   10.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   10.19 + * specific language governing permissions and limitations under the
   10.20 + * License.  When distributing the software, include this License Header
   10.21 + * Notice in each file and include the License file at
   10.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   10.23 + * particular file as subject to the "Classpath" exception as provided
   10.24 + * by Oracle in the GPL Version 2 section of the License file that
   10.25 + * accompanied this code. If applicable, add the following below the
   10.26 + * License Header, with the fields enclosed by brackets [] replaced by
   10.27 + * your own identifying information:
   10.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   10.29 + *
   10.30 + * If you wish your version of this file to be governed by only the CDDL
   10.31 + * or only the GPL Version 2, indicate your decision by adding
   10.32 + * "[Contributor] elects to include this software in this distribution
   10.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   10.34 + * single choice of license, a recipient has the option to distribute
   10.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   10.36 + * to extend the choice of license to its licensees as provided above.
   10.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   10.38 + * Version 2 license, then the option applies only if the new code is
   10.39 + * made subject to such option by the copyright holder.
   10.40 + *
   10.41 + * Contributor(s):
   10.42 + *
   10.43 + * Portions Copyrighted 2013 Sun Microsystems, Inc.
   10.44 + */
   10.45 +package org.netbeans.modules.jackpot30.hintsimpl;
   10.46 +
   10.47 +import org.netbeans.modules.java.hints.test.api.HintTest;
   10.48 +import org.testng.annotations.Test;
   10.49 +
   10.50 +/**
   10.51 + *
   10.52 + * @author lahvac
   10.53 + */
   10.54 +public class GlobalyUnusedNGTest {
   10.55 +
   10.56 +    @Test
   10.57 +    public void testUsed1() throws Exception {
   10.58 +        HintTest.create()
   10.59 +                .input("test/Test1.java",
   10.60 +                       "package test;\n" +
   10.61 +                       "public class Test1 {\n" +
   10.62 +                       "    private final Test2 test2 = null;\n" +
   10.63 +                       "}\n")
   10.64 +                .input("test/Test2.java",
   10.65 +                       "package test;\n" +
   10.66 +                       "public class Test2 {\n" +
   10.67 +                       "    private final Test1 test1 = null;\n" +
   10.68 +                       "}\n")
   10.69 +                .runGlobal(GlobalyUnused.class)
   10.70 +                .assertWarnings();
   10.71 +    }
   10.72 +    
   10.73 +    @Test
   10.74 +    public void testUnused() throws Exception {
   10.75 +        HintTest.create()
   10.76 +                .input("test/Test1.java",
   10.77 +                       "package test;\n" +
   10.78 +                       "public class Test1 { }\n")
   10.79 +                .input("test/Test2.java",
   10.80 +                       "package test;\n" +
   10.81 +                       "public class Test2 {\n" +
   10.82 +                       "}\n")
   10.83 +                .runGlobal(GlobalyUnused.class)
   10.84 +                .assertWarnings("1:13-1:18:verifier:Unused", "1:13-1:18:verifier:Unused");
   10.85 +    }
   10.86 +
   10.87 +}
    11.1 --- a/java.hints/java.hints.test/nbproject/genfiles.properties	Thu May 09 22:04:33 2013 +0200
    11.2 +++ b/java.hints/java.hints.test/nbproject/genfiles.properties	Thu May 09 23:11:06 2013 +0200
    11.3 @@ -1,8 +1,8 @@
    11.4 -build.xml.data.CRC32=294cad92
    11.5 +build.xml.data.CRC32=867e6f0d
    11.6  build.xml.script.CRC32=fb578ef0
    11.7  build.xml.stylesheet.CRC32=a56c6a5b@2.58
    11.8  # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
    11.9  # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
   11.10 -nbproject/build-impl.xml.data.CRC32=294cad92
   11.11 +nbproject/build-impl.xml.data.CRC32=867e6f0d
   11.12  nbproject/build-impl.xml.script.CRC32=c676886e
   11.13  nbproject/build-impl.xml.stylesheet.CRC32=238281d1@2.58
    12.1 --- a/java.hints/java.hints.test/nbproject/project.properties	Thu May 09 22:04:33 2013 +0200
    12.2 +++ b/java.hints/java.hints.test/nbproject/project.properties	Thu May 09 23:11:06 2013 +0200
    12.3 @@ -5,3 +5,4 @@
    12.4  javadoc.arch=${basedir}/arch.xml
    12.5  javadoc.apichanges=${basedir}/apichanges.xml
    12.6  requires.nb.javac=true
    12.7 +spec.version.base.fatal.warning=false
    13.1 --- a/java.hints/java.hints.test/nbproject/project.xml	Thu May 09 22:04:33 2013 +0200
    13.2 +++ b/java.hints/java.hints.test/nbproject/project.xml	Thu May 09 23:11:06 2013 +0200
    13.3 @@ -34,6 +34,15 @@
    13.4                      </run-dependency>
    13.5                  </dependency>
    13.6                  <dependency>
    13.7 +                    <code-name-base>org.netbeans.api.progress</code-name-base>
    13.8 +                    <build-prerequisite/>
    13.9 +                    <compile-dependency/>
   13.10 +                    <run-dependency>
   13.11 +                        <release-version>1</release-version>
   13.12 +                        <specification-version>1.33</specification-version>
   13.13 +                    </run-dependency>
   13.14 +                </dependency>
   13.15 +                <dependency>
   13.16                      <code-name-base>org.netbeans.core.startup</code-name-base>
   13.17                      <build-prerequisite/>
   13.18                      <compile-dependency/>
   13.19 @@ -59,6 +68,15 @@
   13.20                      </run-dependency>
   13.21                  </dependency>
   13.22                  <dependency>
   13.23 +                    <code-name-base>org.netbeans.modules.code.analysis</code-name-base>
   13.24 +                    <build-prerequisite/>
   13.25 +                    <compile-dependency/>
   13.26 +                    <run-dependency>
   13.27 +                        <release-version>0</release-version>
   13.28 +                        <implementation-version/>
   13.29 +                    </run-dependency>
   13.30 +                </dependency>
   13.31 +                <dependency>
   13.32                      <code-name-base>org.netbeans.modules.editor.mimelookup</code-name-base>
   13.33                      <build-prerequisite/>
   13.34                      <compile-dependency/>
    14.1 --- a/java.hints/java.hints.test/src/org/netbeans/modules/java/hints/test/api/HintTest.java	Thu May 09 22:04:33 2013 +0200
    14.2 +++ b/java.hints/java.hints.test/src/org/netbeans/modules/java/hints/test/api/HintTest.java	Thu May 09 23:11:06 2013 +0200
    14.3 @@ -113,7 +113,15 @@
    14.4  import org.netbeans.modules.java.hints.spiimpl.JavaFixImpl.Accessor;
    14.5  import org.netbeans.modules.java.hints.spiimpl.MessageImpl;
    14.6  import org.netbeans.modules.java.hints.spiimpl.SyntheticFix;
    14.7 +import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch;
    14.8 +import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.BatchResult;
    14.9 +import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.Folder;
   14.10 +import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.Resource;
   14.11 +import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.Scope;
   14.12 +import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.VerifiedSpansCallBack;
   14.13  import org.netbeans.modules.java.hints.spiimpl.batch.BatchUtilities;
   14.14 +import org.netbeans.modules.java.hints.spiimpl.batch.ProgressHandleWrapper;
   14.15 +import org.netbeans.modules.java.hints.spiimpl.batch.Scopes;
   14.16  import org.netbeans.modules.java.hints.spiimpl.hints.HintsInvoker;
   14.17  import org.netbeans.modules.java.hints.spiimpl.options.HintsSettings;
   14.18  import org.netbeans.modules.java.hints.test.Utilities.TestLookup;
   14.19 @@ -193,6 +201,7 @@
   14.20      private final Preferences testPreferences;
   14.21      private final HintsSettings hintSettings;
   14.22      private final List<FileObject> checkCompilable = new ArrayList<FileObject>();
   14.23 +    private final List<FileObject> testFiles = new ArrayList<FileObject>();
   14.24      private String sourceLevel = "1.5";
   14.25      private Character caretMarker;
   14.26      private FileObject testFile;
   14.27 @@ -380,6 +389,8 @@
   14.28              this.caret = caret;
   14.29          }
   14.30          
   14.31 +        testFiles.add(file);
   14.32 +        
   14.33          return this;
   14.34      }
   14.35  
   14.36 @@ -455,6 +466,36 @@
   14.37       * @return a wrapper over the hint output that allows verifying results of the hint
   14.38       */
   14.39      public HintOutput run(Class<?> hint, String hintCode) throws Exception {
   14.40 +        return runImpl(hint, hintCode, new HintComputer() {
   14.41 +            @Override public Collection<ErrorDescription> computeHints(List<HintDescription> total) throws Exception {
   14.42 +                CompilationInfo info = parse(testFile);
   14.43 +
   14.44 +                assertNotNull(info);
   14.45 +
   14.46 +                List<ErrorDescription> result = new ArrayList<ErrorDescription>();
   14.47 +
   14.48 +                Map<HintDescription, List<ErrorDescription>> errors = computeErrors(info, total, new AtomicBoolean());
   14.49 +
   14.50 +                for (Entry<HintDescription, List<ErrorDescription>> e : errors.entrySet()) {
   14.51 +                    result.addAll(e.getValue());
   14.52 +                }
   14.53 +
   14.54 +                Reference<CompilationInfo> infoRef = new WeakReference<CompilationInfo>(info);
   14.55 +                Reference<CompilationUnitTree> cut = new WeakReference<CompilationUnitTree>(info.getCompilationUnit());
   14.56 +
   14.57 +                info = null;
   14.58 +
   14.59 +                DEBUGGING_HELPER.add(result);
   14.60 +                NbTestCase.assertGC("noone holds CompilationInfo", infoRef);
   14.61 +                NbTestCase.assertGC("noone holds javac", cut);
   14.62 +                DEBUGGING_HELPER.remove(result);
   14.63 +
   14.64 +                return result;
   14.65 +            }
   14.66 +        });
   14.67 +    }
   14.68 +
   14.69 +    private HintOutput runImpl(Class<?> hint, String hintCode, HintComputer doComputeErrors) throws Exception {
   14.70          IndexingManager.getDefault().refreshIndexAndWait(sourceRoot.toURL(), null);
   14.71          
   14.72          for (FileObject file : checkCompilable) {
   14.73 @@ -512,12 +553,6 @@
   14.74              }
   14.75          }
   14.76          
   14.77 -        CompilationInfo info = parse(testFile);
   14.78 -
   14.79 -        assertNotNull(info);
   14.80 -
   14.81 -        List<ErrorDescription> result = new ArrayList<ErrorDescription>();
   14.82 -
   14.83          Handler h = new Handler() {
   14.84              @Override public void publish(LogRecord record) {
   14.85                  if (   record.getLevel().intValue() >= Level.WARNING.intValue()
   14.86 @@ -528,28 +563,41 @@
   14.87              @Override public void flush() { }
   14.88              @Override public void close() throws SecurityException { }
   14.89          };
   14.90 +
   14.91          Logger log = Logger.getLogger(Exceptions.class.getName());
   14.92          log.addHandler(h);
   14.93 -        Map<HintDescription, List<ErrorDescription>> errors = computeErrors(info, total, new AtomicBoolean());
   14.94 +        List<ErrorDescription> result = new ArrayList<ErrorDescription>(doComputeErrors.computeHints(total));
   14.95          log.removeHandler(h);
   14.96 -        for (Entry<HintDescription, List<ErrorDescription>> e : errors.entrySet()) {
   14.97 -            result.addAll(e.getValue());
   14.98 -        }
   14.99  
  14.100          Collections.sort(result, ERRORS_COMPARATOR);
  14.101          
  14.102 -        Reference<CompilationInfo> infoRef = new WeakReference<CompilationInfo>(info);
  14.103 -        Reference<CompilationUnitTree> cut = new WeakReference<CompilationUnitTree>(info.getCompilationUnit());
  14.104 -        
  14.105 -        info = null;
  14.106 -        
  14.107 -        DEBUGGING_HELPER.add(result);
  14.108 -        NbTestCase.assertGC("noone holds CompilationInfo", infoRef);
  14.109 -        NbTestCase.assertGC("noone holds javac", cut);
  14.110 -        DEBUGGING_HELPER.remove(result);
  14.111 -        
  14.112          return new HintOutput(result, requiresJavaFix);
  14.113      }
  14.114 +
  14.115 +    private interface HintComputer {
  14.116 +        public Collection<ErrorDescription> computeHints(List<HintDescription> total) throws Exception;
  14.117 +    }
  14.118 +    
  14.119 +    public HintOutput runGlobal(Class<?> hint) throws Exception {
  14.120 +        return runImpl(hint, null, new HintComputer() {
  14.121 +            @Override public Collection<ErrorDescription> computeHints(List<HintDescription> total) throws Exception {
  14.122 +                final List<ErrorDescription> result = new ArrayList<ErrorDescription>();
  14.123 +                Scope s = Scopes.specifiedFoldersScope(Folder.convert(sourceRoot));
  14.124 +                BatchResult batchResult = BatchSearch.findOccurrences(total, s);
  14.125 +                BatchSearch.getVerifiedSpans(batchResult, new ProgressHandleWrapper(1, 1), new VerifiedSpansCallBack() {
  14.126 +                    @Override public void groupStarted() { }
  14.127 +                    @Override public boolean spansVerified(CompilationController wc, Resource r, Collection<? extends ErrorDescription> hints) throws Exception {
  14.128 +                        result.addAll(hints);
  14.129 +                        return true;
  14.130 +                    }
  14.131 +                    @Override public void groupFinished() { }
  14.132 +                    @Override public void cannotVerifySpan(Resource r) { }
  14.133 +                }, false, new ArrayList<MessageImpl>(), new AtomicBoolean());
  14.134 +
  14.135 +                return result;
  14.136 +            }
  14.137 +        });
  14.138 +    }
  14.139      
  14.140      //must keep the error descriptions (and their Fixes through them) in a field
  14.141      //so that assertGC is able to provide a useful trace of references:
    15.1 --- a/java.hints/java.hints.test/test/unit/src/org/netbeans/modules/java/hints/test/api/HintTestTest.java	Thu May 09 22:04:33 2013 +0200
    15.2 +++ b/java.hints/java.hints.test/test/unit/src/org/netbeans/modules/java/hints/test/api/HintTestTest.java	Thu May 09 23:11:06 2013 +0200
    15.3 @@ -304,4 +304,28 @@
    15.4              return ErrorDescriptionFactory.forTree(ctx, ctx.getPath(), "Test", f);
    15.5          }
    15.6      }
    15.7 +
    15.8 +    public void testSourcePathReady() throws Exception {
    15.9 +        HintTest.create()
   15.10 +                .input("test/Test1.java",
   15.11 +                       "package test;\n" +
   15.12 +                       "public class Test1 {\n" +
   15.13 +                       "    private final Test2 test2 = null;\n" +
   15.14 +                       "}\n")
   15.15 +                .input("test/Test2.java",
   15.16 +                       "package test;\n" +
   15.17 +                       "public class Test2 {\n" +
   15.18 +                       "    private final Test1 test1 = null;\n" +
   15.19 +                       "}\n")
   15.20 +                .runGlobal(NoOp.class)
   15.21 +                .assertWarnings();
   15.22 +    }
   15.23 +
   15.24 +    @Hint(displayName="noOp", description="noOp", category="test")
   15.25 +    public static final class NoOp {
   15.26 +        @TriggerTreeKind(Kind.CLASS)
   15.27 +        public static ErrorDescription hint(HintContext ctx) {
   15.28 +            return null;
   15.29 +        }
   15.30 +    }
   15.31  }
    16.1 --- a/java.hints/nbproject/project.properties	Thu May 09 22:04:33 2013 +0200
    16.2 +++ b/java.hints/nbproject/project.properties	Thu May 09 23:11:06 2013 +0200
    16.3 @@ -1,5 +1,7 @@
    16.4  modules=\
    16.5      ${project.org.netbeans.spi.java.hints}:\
    16.6 -    ${project.org.netbeans.modules.java.hints.test}
    16.7 +    ${project.org.netbeans.modules.java.hints.test}:\
    16.8 +    ${project.org.netbeans.modules.jackpot30.hintsimpl}
    16.9 +project.org.netbeans.modules.jackpot30.hintsimpl=hintsimpl
   16.10  project.org.netbeans.modules.java.hints.test=java.hints.test
   16.11  project.org.netbeans.spi.java.hints=spi.java.hints
    17.1 --- a/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/providers/code/CodeHintProviderImpl.java	Thu May 09 22:04:33 2013 +0200
    17.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/providers/code/CodeHintProviderImpl.java	Thu May 09 23:11:06 2013 +0200
    17.3 @@ -74,6 +74,7 @@
    17.4  import org.netbeans.modules.java.hints.providers.spi.HintMetadata;
    17.5  import org.netbeans.modules.java.hints.providers.spi.HintMetadata.Options;
    17.6  import org.netbeans.modules.java.hints.providers.spi.HintProvider;
    17.7 +import org.netbeans.modules.java.hints.providers.spi.Trigger.DecisionTrigger;
    17.8  import org.netbeans.modules.java.hints.providers.spi.Trigger.Kinds;
    17.9  import org.netbeans.modules.java.hints.providers.spi.Trigger.PatternDescription;
   17.10  import org.netbeans.spi.editor.hints.ErrorDescription;
   17.11 @@ -82,6 +83,7 @@
   17.12  import org.netbeans.spi.java.hints.ConstraintVariableType;
   17.13  import org.netbeans.spi.java.hints.Hint;
   17.14  import org.netbeans.spi.java.hints.IntegerOption;
   17.15 +import org.netbeans.spi.java.hints.TriggerDecision;
   17.16  import org.netbeans.spi.java.hints.TriggerPattern;
   17.17  import org.netbeans.spi.java.hints.TriggerPatterns;
   17.18  import org.netbeans.spi.java.hints.TriggerTreeKind;
   17.19 @@ -241,6 +243,7 @@
   17.20          //XXX: combinations of TriggerTreeKind and TriggerPattern?
   17.21          processTreeKindHint(hints, m, metadata);
   17.22          processPatternHint(hints, m, metadata);
   17.23 +        processDecisionHint(hints, m, metadata);
   17.24      }
   17.25      
   17.26      private static void processTreeKindHint(Map<HintMetadata, Collection<HintDescription>> hints, MethodWrapper m, HintMetadata metadata) {
   17.27 @@ -298,6 +301,22 @@
   17.28                                                         .produce());
   17.29      }
   17.30  
   17.31 +    private static void processDecisionHint(Map<HintMetadata, Collection<HintDescription>> hints, MethodWrapper m, HintMetadata metadata) {
   17.32 +        TriggerDecision decisionTrigger = m.getAnnotation(TriggerDecision.class);
   17.33 +
   17.34 +        if (decisionTrigger == null) {
   17.35 +            return ;
   17.36 +        }
   17.37 +
   17.38 +        Worker w = new WorkerImpl(m.getClazz().getName(), m.getName());
   17.39 +
   17.40 +        addHint(hints, metadata, HintDescriptionFactory.create()
   17.41 +                                                       .setTrigger(new DecisionTrigger(decisionTrigger.value()))
   17.42 +                                                       .setWorker(w)
   17.43 +                                                       .setMetadata(metadata)
   17.44 +                                                       .produce());
   17.45 +    }
   17.46 +    
   17.47      private static void addHint(Map<HintMetadata, Collection<HintDescription>> hints, HintMetadata metadata, HintDescription hint) {
   17.48          Collection<HintDescription> list = hints.get(metadata);
   17.49  
    18.1 --- a/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/providers/spi/Trigger.java	Thu May 09 22:04:33 2013 +0200
    18.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/providers/spi/Trigger.java	Thu May 09 23:11:06 2013 +0200
    18.3 @@ -41,12 +41,12 @@
    18.4   */
    18.5  package org.netbeans.modules.java.hints.providers.spi;
    18.6  
    18.7 -import com.sun.source.tree.Tree;
    18.8  import com.sun.source.tree.Tree.Kind;
    18.9  import java.util.Arrays;
   18.10  import java.util.Map;
   18.11  import java.util.Set;
   18.12  import org.netbeans.api.java.source.matching.Pattern;
   18.13 +import org.netbeans.spi.java.hints.Decision;
   18.14  import org.openide.util.Parameters;
   18.15  
   18.16  /**A base class for triggers.
   18.17 @@ -155,5 +155,17 @@
   18.18          }
   18.19  
   18.20      }
   18.21 +    
   18.22 +    public static final class DecisionTrigger extends Trigger {
   18.23 +        private final Class<? extends Decision> decisionClass;
   18.24 +
   18.25 +        public DecisionTrigger(Class<? extends Decision> decisionClass) {
   18.26 +            this.decisionClass = decisionClass;
   18.27 +        }
   18.28 +
   18.29 +        public Class<? extends Decision> getDecisionClass() {
   18.30 +            return decisionClass;
   18.31 +        }
   18.32 +    }
   18.33  
   18.34  }
    19.1 --- a/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/SPIAccessor.java	Thu May 09 22:04:33 2013 +0200
    19.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/SPIAccessor.java	Thu May 09 23:11:06 2013 +0200
    19.3 @@ -48,6 +48,7 @@
    19.4  import javax.lang.model.type.TypeMirror;
    19.5  import org.netbeans.api.java.source.CompilationInfo;
    19.6  import org.netbeans.modules.java.hints.providers.spi.HintMetadata;
    19.7 +import org.netbeans.modules.java.hints.spiimpl.hints.GlobalProcessingContext;
    19.8  import org.netbeans.modules.java.hints.spiimpl.options.HintsSettings;
    19.9  import org.netbeans.spi.java.hints.HintContext;
   19.10  import org.openide.util.Exceptions;
   19.11 @@ -77,8 +78,8 @@
   19.12          accessor = instance;
   19.13      }
   19.14  
   19.15 -    public abstract HintContext createHintContext(CompilationInfo info, HintsSettings settings, HintMetadata metadata, TreePath path, Map<String, TreePath> variables, Map<String, Collection<? extends TreePath>> multiVariables, Map<String, String> variableNames, Map<String, TypeMirror> constraints, Collection<? super MessageImpl> problems, boolean bulkMode, AtomicBoolean cancel, int caret);
   19.16 -    public abstract HintContext createHintContext(CompilationInfo info, HintsSettings settings, HintMetadata metadata, TreePath path, Map<String, TreePath> variables, Map<String, Collection<? extends TreePath>> multiVariables, Map<String, String> variableNames);
   19.17 +    public abstract HintContext createHintContext(CompilationInfo info, HintsSettings settings, HintMetadata metadata, GlobalProcessingContext globalContext, TreePath path, Map<String, TreePath> variables, Map<String, Collection<? extends TreePath>> multiVariables, Map<String, String> variableNames, Map<String, TypeMirror> constraints, Collection<? super MessageImpl> problems, boolean bulkMode, AtomicBoolean cancel, int caret);
   19.18 +    public abstract HintContext createHintContext(CompilationInfo info, HintsSettings settings, HintMetadata metadata, GlobalProcessingContext globalContext, TreePath path, Map<String, TreePath> variables, Map<String, Collection<? extends TreePath>> multiVariables, Map<String, String> variableNames);
   19.19      public abstract HintMetadata getHintMetadata(HintContext ctx);
   19.20      public abstract HintsSettings getHintSettings(HintContext ctx);
   19.21  
    20.1 --- a/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/batch/BatchSearch.java	Thu May 09 22:04:33 2013 +0200
    20.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/batch/BatchSearch.java	Thu May 09 23:11:06 2013 +0200
    20.3 @@ -51,6 +51,7 @@
    20.4  import java.nio.ByteBuffer;
    20.5  import java.util.ArrayList;
    20.6  import java.util.Collection;
    20.7 +import java.util.Collections;
    20.8  import java.util.HashMap;
    20.9  import java.util.HashSet;
   20.10  import java.util.LinkedList;
   20.11 @@ -87,7 +88,12 @@
   20.12  import org.netbeans.spi.editor.hints.ErrorDescription;
   20.13  import org.netbeans.api.java.source.matching.Matcher;
   20.14  import org.netbeans.api.java.source.matching.Pattern;
   20.15 +import org.netbeans.modules.java.hints.providers.spi.Trigger.DecisionTrigger;
   20.16 +import org.netbeans.modules.java.hints.spiimpl.SPIAccessor;
   20.17 +import org.netbeans.modules.java.hints.spiimpl.hints.GlobalProcessingContext;
   20.18  import org.netbeans.modules.java.hints.spiimpl.options.HintsSettings;
   20.19 +import org.netbeans.spi.java.hints.Decision;
   20.20 +import org.netbeans.spi.java.hints.HintContext;
   20.21  import org.openide.filesystems.FileObject;
   20.22  import org.openide.filesystems.FileUtil;
   20.23  import org.openide.util.Exceptions;
   20.24 @@ -166,7 +172,7 @@
   20.25              innerForAll.tick();
   20.26          }
   20.27  
   20.28 -        return new BatchResult(result, problems);
   20.29 +        return new BatchResult(result, patterns, problems);
   20.30      }
   20.31  
   20.32      private static BulkPattern preparePattern(final Iterable<? extends HintDescription> patterns, CompilationInfo info) {
   20.33 @@ -204,11 +210,11 @@
   20.34                  return;
   20.35              inner.startNextPart(e.getValue().size());
   20.36  
   20.37 -            e.getKey().validateResource(e.getValue(), inner, callback, doNotRegisterClassPath, problems, cancel);
   20.38 +            e.getKey().validateResource(candidates, e.getValue(), inner, callback, doNotRegisterClassPath, problems, cancel);
   20.39          }
   20.40      }
   20.41  
   20.42 -    private static void getLocalVerifiedSpans(Collection<? extends Resource> resources, @NonNull final ProgressHandleWrapper progress, final VerifiedSpansCallBack callback, boolean doNotRegisterClassPath, final Collection<? super MessageImpl> problems, final AtomicBoolean cancel) {
   20.43 +    private static void getLocalVerifiedSpans(final BatchResult candidates, Collection<? extends Resource> resources, @NonNull final ProgressHandleWrapper progress, final VerifiedSpansCallBack callback, boolean doNotRegisterClassPath, final Collection<? super MessageImpl> problems, final AtomicBoolean cancel) {
   20.44          Collection<FileObject> files = new LinkedList<FileObject>();
   20.45          final Map<FileObject, Resource> file2Resource = new HashMap<FileObject, Resource>();
   20.46  
   20.47 @@ -247,6 +253,7 @@
   20.48          }
   20.49  
   20.50          try {
   20.51 +            final GlobalProcessingContext gpc = new GlobalProcessingContext();
   20.52              for (Entry<ClasspathInfo, Collection<FileObject>> e : cp2Files.entrySet()) {
   20.53                  try {
   20.54                      List<FileObject> toProcess = new ArrayList<FileObject>(e.getValue());
   20.55 @@ -291,7 +298,7 @@
   20.56                                          enabledHints = r.hints;
   20.57                                      }
   20.58                                      
   20.59 -                                    List<ErrorDescription> hints = new HintsInvoker(settings, true, new AtomicBoolean()).computeHints(parameter, enabledHints, problems);
   20.60 +                                    List<ErrorDescription> hints = new HintsInvoker(settings, gpc, new AtomicBoolean()).computeHints(parameter, r.hints, problems);
   20.61  
   20.62                                      assert hints != null;
   20.63                                      
   20.64 @@ -318,6 +325,64 @@
   20.65                      Exceptions.printStackTrace(ex);
   20.66                  }
   20.67              }
   20.68 +            
   20.69 +            final Map<FileObject, List<Decision>> file2Decision = new HashMap<FileObject, List<Decision>>();
   20.70 +            for (List<Decision<?, ?>> decisions : gpc.decisions.values()) {
   20.71 +                for (Decision<?, ?> d : decisions) {
   20.72 +                    if (d.makeDecision()) {
   20.73 +                        List<Decision> fileDecisions = file2Decision.get(d.root.getFileObject());
   20.74 +                        
   20.75 +                        if (fileDecisions == null) {
   20.76 +                            file2Decision.put(d.root.getFileObject(), fileDecisions = new ArrayList<Decision>());
   20.77 +                        }
   20.78 +                        
   20.79 +                        fileDecisions.add(d);
   20.80 +                    }
   20.81 +                }
   20.82 +            }
   20.83 +            
   20.84 +            Map<ClasspathInfo, Collection<FileObject>> cp2FilesAfterDecision = BatchUtilities.sortFiles(file2Decision.keySet());
   20.85 +            
   20.86 +            for (Entry<ClasspathInfo, Collection<FileObject>> e : cp2FilesAfterDecision.entrySet()) {
   20.87 +                JavaSource js = JavaSource.create(e.getKey(), e.getValue());
   20.88 +                
   20.89 +                try {
   20.90 +                    js.runUserActionTask(new Task<CompilationController>() {
   20.91 +                        @Override public void run(CompilationController parameter) throws Exception {
   20.92 +                            if (parameter.toPhase(Phase.RESOLVED).compareTo(Phase.RESOLVED) < 0)
   20.93 +                                return ;
   20.94 +                            
   20.95 +                            Resource r = file2Resource.get(parameter.getFileObject());
   20.96 +
   20.97 +                            HintsSettings settings = r.settings;
   20.98 +
   20.99 +                            if (settings == null) {
  20.100 +                                settings = HintsSettings.getSettingsFor(parameter.getFileObject());
  20.101 +                            }
  20.102 +
  20.103 +                            for (Decision<?, ?> d : file2Decision.get(parameter.getFileObject())) {
  20.104 +                            for (HintDescription hd : candidates.getPatterns()) {
  20.105 +                                if (!(hd.getTrigger() instanceof DecisionTrigger)) continue;
  20.106 +                                if (!settings.isEnabled(hd.getMetadata())) continue;
  20.107 +                                DecisionTrigger dt = (DecisionTrigger) hd.getTrigger();
  20.108 +                                if (dt.getDecisionClass() != d.getClass()) continue;
  20.109 +                                TreePath tp = d.root.resolve(parameter);
  20.110 +                                HintContext ctx = SPIAccessor.getINSTANCE().createHintContext(parameter, settings, hd.getMetadata(), new GlobalProcessingContext(), tp, Collections.<String, TreePath>emptyMap(), Collections.<String, Collection<? extends TreePath>>emptyMap(), Collections.<String, String>emptyMap());
  20.111 +                                ctx.decision = d;
  20.112 +                                Collection<? extends ErrorDescription> errors = hd.getWorker().createErrors(ctx);
  20.113 +                                
  20.114 +                                if (errors != null) {
  20.115 +                                    callback.spansVerified(parameter, file2Resource.get(parameter.getFileObject()), errors);
  20.116 +                                }
  20.117 +                            }
  20.118 +                            }
  20.119 +                        }
  20.120 +                    }, true);
  20.121 +                } catch (IOException ex) {
  20.122 +                    Exceptions.printStackTrace(ex);
  20.123 +                }
  20.124 +            }
  20.125 +            
  20.126          } finally {
  20.127              if (toRegister != null) {
  20.128                  GlobalPathRegistry.getDefault().unregister(ClassPath.SOURCE, toRegister);
  20.129 @@ -402,10 +467,12 @@
  20.130      public static final class BatchResult {
  20.131          
  20.132          private final Map<? extends IndexEnquirer, ? extends Collection<? extends Resource>> projectId2Resources;
  20.133 +        private final Iterable<? extends HintDescription> patterns;
  20.134          public final Collection<? extends MessageImpl> problems;
  20.135          
  20.136 -        public BatchResult(Map<? extends IndexEnquirer, ? extends Collection<? extends Resource>> projectId2Resources, Collection<? extends MessageImpl> problems) {
  20.137 +        public BatchResult(Map<? extends IndexEnquirer, ? extends Collection<? extends Resource>> projectId2Resources, Iterable<? extends HintDescription> patterns, Collection<? extends MessageImpl> problems) {
  20.138              this.projectId2Resources = projectId2Resources;
  20.139 +            this.patterns = patterns;
  20.140              this.problems = problems;
  20.141          }
  20.142  
  20.143 @@ -422,6 +489,10 @@
  20.144  
  20.145              return result;
  20.146          }
  20.147 +
  20.148 +        public Iterable<? extends HintDescription> getPatterns() {
  20.149 +            return patterns;
  20.150 +        }
  20.151      }
  20.152  
  20.153      public static final class Resource {
  20.154 @@ -562,7 +633,7 @@
  20.155              this.src = src;
  20.156          }
  20.157          public abstract Collection<? extends Resource> findResources(Iterable<? extends HintDescription> hints, ProgressHandleWrapper progress, @NullAllowed Callable<BulkPattern> bulkPattern, Collection<? super MessageImpl> problems, HintsSettings settingsProvider);
  20.158 -        public abstract void validateResource(Collection<? extends Resource> resources, ProgressHandleWrapper progress, VerifiedSpansCallBack callback, boolean doNotRegisterClassPath, Collection<? super MessageImpl> problems, AtomicBoolean cancel);
  20.159 +        public abstract void validateResource(BatchResult candidates, Collection<? extends Resource> resources, ProgressHandleWrapper progress, VerifiedSpansCallBack callback, boolean doNotRegisterClassPath, Collection<? super MessageImpl> problems, AtomicBoolean cancel);
  20.160  //        public int[] getEstimatedSpan(Resource r);
  20.161      }
  20.162  
  20.163 @@ -570,8 +641,8 @@
  20.164          public LocalIndexEnquirer(FileObject src) {
  20.165              super(src);
  20.166          }
  20.167 -        public void validateResource(Collection<? extends Resource> resources, ProgressHandleWrapper progress, VerifiedSpansCallBack callback, boolean doNotRegisterClassPath, Collection<? super MessageImpl> problems, AtomicBoolean cancel) {
  20.168 -            getLocalVerifiedSpans(resources, progress, callback, doNotRegisterClassPath, problems, cancel);
  20.169 +        public void validateResource(BatchResult candidates, Collection<? extends Resource> resources, ProgressHandleWrapper progress, VerifiedSpansCallBack callback, boolean doNotRegisterClassPath, Collection<? super MessageImpl> problems, AtomicBoolean cancel) {
  20.170 +            getLocalVerifiedSpans(candidates, resources, progress, callback, doNotRegisterClassPath, problems, cancel);
  20.171          }
  20.172      }
  20.173  
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/hints/GlobalProcessingContext.java	Thu May 09 23:11:06 2013 +0200
    21.3 @@ -0,0 +1,56 @@
    21.4 +/*
    21.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    21.6 + *
    21.7 + * Copyright 2013 Oracle and/or its affiliates. All rights reserved.
    21.8 + *
    21.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   21.10 + * Other names may be trademarks of their respective owners.
   21.11 + *
   21.12 + * The contents of this file are subject to the terms of either the GNU
   21.13 + * General Public License Version 2 only ("GPL") or the Common
   21.14 + * Development and Distribution License("CDDL") (collectively, the
   21.15 + * "License"). You may not use this file except in compliance with the
   21.16 + * License. You can obtain a copy of the License at
   21.17 + * http://www.netbeans.org/cddl-gplv2.html
   21.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   21.19 + * specific language governing permissions and limitations under the
   21.20 + * License.  When distributing the software, include this License Header
   21.21 + * Notice in each file and include the License file at
   21.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   21.23 + * particular file as subject to the "Classpath" exception as provided
   21.24 + * by Oracle in the GPL Version 2 section of the License file that
   21.25 + * accompanied this code. If applicable, add the following below the
   21.26 + * License Header, with the fields enclosed by brackets [] replaced by
   21.27 + * your own identifying information:
   21.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   21.29 + *
   21.30 + * If you wish your version of this file to be governed by only the CDDL
   21.31 + * or only the GPL Version 2, indicate your decision by adding
   21.32 + * "[Contributor] elects to include this software in this distribution
   21.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   21.34 + * single choice of license, a recipient has the option to distribute
   21.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   21.36 + * to extend the choice of license to its licensees as provided above.
   21.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   21.38 + * Version 2 license, then the option applies only if the new code is
   21.39 + * made subject to such option by the copyright holder.
   21.40 + *
   21.41 + * Contributor(s):
   21.42 + *
   21.43 + * Portions Copyrighted 2013 Sun Microsystems, Inc.
   21.44 + */
   21.45 +package org.netbeans.modules.java.hints.spiimpl.hints;
   21.46 +
   21.47 +import java.util.HashMap;
   21.48 +import java.util.List;
   21.49 +import java.util.Map;
   21.50 +import org.netbeans.api.java.source.TreePathHandle;
   21.51 +import org.netbeans.spi.java.hints.Decision;
   21.52 +
   21.53 +/**
   21.54 + *
   21.55 + * @author lahvac
   21.56 + */
   21.57 +public class GlobalProcessingContext {
   21.58 +    public final Map<TreePathHandle, List<Decision<?, ?>>> decisions = new HashMap<TreePathHandle, List<Decision<?, ?>>>();
   21.59 +}
    22.1 --- a/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/hints/HintsInvoker.java	Thu May 09 22:04:33 2013 +0200
    22.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/hints/HintsInvoker.java	Thu May 09 23:11:06 2013 +0200
    22.3 @@ -102,6 +102,7 @@
    22.4  import org.netbeans.api.java.source.matching.Matcher;
    22.5  import org.netbeans.api.java.source.matching.Occurrence;
    22.6  import org.netbeans.api.java.source.matching.Pattern;
    22.7 +import org.netbeans.modules.java.hints.providers.spi.Trigger.DecisionTrigger;
    22.8  import org.openide.util.Exceptions;
    22.9  
   22.10  /**
   22.11 @@ -116,31 +117,31 @@
   22.12      private final int caret;
   22.13      private final int from;
   22.14      private final int to;
   22.15 -    private final boolean bulkMode;
   22.16 +    private final GlobalProcessingContext globalContext;
   22.17      private final AtomicBoolean cancel;
   22.18  
   22.19      public HintsInvoker(HintsSettings settings, AtomicBoolean cancel) {
   22.20 -        this(settings, false, cancel);
   22.21 +        this(settings, null, cancel);
   22.22      }
   22.23  
   22.24 -    public HintsInvoker(HintsSettings settings, boolean bulkMode, AtomicBoolean cancel) {
   22.25 -        this(settings, -1, -1, -1, bulkMode, cancel);
   22.26 +    public HintsInvoker(HintsSettings settings, GlobalProcessingContext globalContext, AtomicBoolean cancel) {
   22.27 +        this(settings, -1, -1, -1, globalContext, cancel);
   22.28      }
   22.29  
   22.30      public HintsInvoker(HintsSettings settings, int caret, AtomicBoolean cancel) {
   22.31 -        this(settings, caret, -1, -1, false, cancel);
   22.32 +        this(settings, caret, -1, -1, null, cancel);
   22.33      }
   22.34  
   22.35      public HintsInvoker(HintsSettings settings, int from, int to, AtomicBoolean cancel) {
   22.36 -        this(settings, -1, from, to, false, cancel);
   22.37 +        this(settings, -1, from, to, null, cancel);
   22.38      }
   22.39  
   22.40 -    private HintsInvoker(HintsSettings settings, int caret, int from, int to, boolean bulkMode, AtomicBoolean cancel) {
   22.41 +    private HintsInvoker(HintsSettings settings, int caret, int from, int to, GlobalProcessingContext globalContext, AtomicBoolean cancel) {
   22.42          this.settings = settings;
   22.43          this.caret = caret;
   22.44          this.from = from;
   22.45          this.to = to;
   22.46 -        this.bulkMode = bulkMode;
   22.47 +        this.globalContext = globalContext;
   22.48          this.cancel = cancel;
   22.49      }
   22.50  
   22.51 @@ -197,7 +198,7 @@
   22.52          return join(computeHints(info, new TreePath(info.getCompilationUnit()), hints, problems));
   22.53      }
   22.54  
   22.55 -    private static final Iterable<? extends Class<? extends Trigger>> TRIGGER_KINDS = Arrays.asList(Kinds.class, PatternDescription.class);
   22.56 +    private static final Iterable<? extends Class<? extends Trigger>> TRIGGER_KINDS = Arrays.asList(Kinds.class, PatternDescription.class, DecisionTrigger.class);
   22.57      
   22.58      @CheckForNull
   22.59      public Map<HintDescription, List<ErrorDescription>> computeHints(CompilationInfo info,
   22.60 @@ -555,7 +556,7 @@
   22.61  
   22.62                      for (HintDescription hd : patternHints.get(d)) {
   22.63                          HintMetadata hm = hd.getMetadata();
   22.64 -                        HintContext c = SPIAccessor.getINSTANCE().createHintContext(info, settings, hm, candidate, verifiedVariables.getVariables(), verifiedVariables.getMultiVariables(), verifiedVariables.getVariables2Names(), constraints, problems, bulkMode, cancel, caret);
   22.65 +                        HintContext c = SPIAccessor.getINSTANCE().createHintContext(info, settings, hm, globalContext != null ? globalContext : new GlobalProcessingContext(), candidate, verifiedVariables.getVariables(), verifiedVariables.getMultiVariables(), verifiedVariables.getVariables2Names(), constraints, problems, globalContext != null, cancel, caret);
   22.66  
   22.67                          if (!Collections.disjoint(suppressedWarnings, hm.suppressWarnings))
   22.68                              continue;
   22.69 @@ -649,7 +650,7 @@
   22.70                          }
   22.71                      }
   22.72  
   22.73 -                    HintContext c = SPIAccessor.getINSTANCE().createHintContext(info, settings, hm, path, Collections.<String, TreePath>emptyMap(), Collections.<String, Collection<? extends TreePath>>emptyMap(), Collections.<String, String>emptyMap(), Collections.<String, TypeMirror>emptyMap(), new ArrayList<MessageImpl>(), bulkMode, cancel, caret);
   22.74 +                    HintContext c = SPIAccessor.getINSTANCE().createHintContext(info, settings, hm, globalContext != null ? globalContext : new GlobalProcessingContext(), path, Collections.<String, TreePath>emptyMap(), Collections.<String, Collection<? extends TreePath>>emptyMap(), Collections.<String, String>emptyMap(), Collections.<String, TypeMirror>emptyMap(), new ArrayList<MessageImpl>(), globalContext != null, cancel, caret);
   22.75                      Collection<? extends ErrorDescription> errors = runHint(hd, c);
   22.76  
   22.77                      if (errors != null) {
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/Decision.java	Thu May 09 23:11:06 2013 +0200
    23.3 @@ -0,0 +1,106 @@
    23.4 +/*
    23.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    23.6 + *
    23.7 + * Copyright 2013 Oracle and/or its affiliates. All rights reserved.
    23.8 + *
    23.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   23.10 + * Other names may be trademarks of their respective owners.
   23.11 + *
   23.12 + * The contents of this file are subject to the terms of either the GNU
   23.13 + * General Public License Version 2 only ("GPL") or the Common
   23.14 + * Development and Distribution License("CDDL") (collectively, the
   23.15 + * "License"). You may not use this file except in compliance with the
   23.16 + * License. You can obtain a copy of the License at
   23.17 + * http://www.netbeans.org/cddl-gplv2.html
   23.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   23.19 + * specific language governing permissions and limitations under the
   23.20 + * License.  When distributing the software, include this License Header
   23.21 + * Notice in each file and include the License file at
   23.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   23.23 + * particular file as subject to the "Classpath" exception as provided
   23.24 + * by Oracle in the GPL Version 2 section of the License file that
   23.25 + * accompanied this code. If applicable, add the following below the
   23.26 + * License Header, with the fields enclosed by brackets [] replaced by
   23.27 + * your own identifying information:
   23.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   23.29 + *
   23.30 + * If you wish your version of this file to be governed by only the CDDL
   23.31 + * or only the GPL Version 2, indicate your decision by adding
   23.32 + * "[Contributor] elects to include this software in this distribution
   23.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   23.34 + * single choice of license, a recipient has the option to distribute
   23.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   23.36 + * to extend the choice of license to its licensees as provided above.
   23.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   23.38 + * Version 2 license, then the option applies only if the new code is
   23.39 + * made subject to such option by the copyright holder.
   23.40 + *
   23.41 + * Contributor(s):
   23.42 + *
   23.43 + * Portions Copyrighted 2013 Sun Microsystems, Inc.
   23.44 + */
   23.45 +package org.netbeans.spi.java.hints;
   23.46 +
   23.47 +import java.util.ArrayList;
   23.48 +import java.util.HashMap;
   23.49 +import java.util.List;
   23.50 +import java.util.Map;
   23.51 +import org.netbeans.api.java.source.CompilationInfo;
   23.52 +import org.netbeans.api.java.source.TreePathHandle;
   23.53 +import org.openide.filesystems.FileObject;
   23.54 +
   23.55 +/**
   23.56 + *
   23.57 + * @author lahvac
   23.58 + */
   23.59 +public abstract class Decision<V, R> {
   23.60 +    
   23.61 +    /*XXX: should not be public*/public final TreePathHandle root;
   23.62 +    private final Map<FileObject, List<V>> file2Facts = new HashMap<FileObject, List<V>>();
   23.63 +
   23.64 +    protected Decision(TreePathHandle root) {
   23.65 +        this.root = root;
   23.66 +    }
   23.67 +    
   23.68 +    protected abstract R makeDecision(Iterable<? extends V> input);
   23.69 +    
   23.70 +    private R previousResult;
   23.71 +    
   23.72 +    /*XXX: should not be public*/public boolean makeDecision() {
   23.73 +        List<V> inputs = new ArrayList<V>();
   23.74 +        
   23.75 +        for (List<V> v : file2Facts.values()) {
   23.76 +            inputs.addAll(v);
   23.77 +        }
   23.78 +        
   23.79 +        R current = makeDecision(inputs);
   23.80 +        
   23.81 +        boolean changed = !(previousResult == null ? current == null : previousResult.equals(current));
   23.82 +        
   23.83 +        previousResult = current;
   23.84 +        
   23.85 +        return changed;
   23.86 +    }
   23.87 +    
   23.88 +    public R getCurrentResult() {
   23.89 +        return previousResult;
   23.90 +    }
   23.91 +    
   23.92 +    public void recordLocalFact(/*XXX: should not require the CompilationInfo!*/CompilationInfo info, V fact) {
   23.93 +        List<V> facts = file2Facts.get(info.getFileObject());
   23.94 +        
   23.95 +        if (facts == null) {
   23.96 +            file2Facts.put(info.getFileObject(), facts = new ArrayList<V>());
   23.97 +        }
   23.98 +        
   23.99 +        facts.add(fact);
  23.100 +    }
  23.101 +    
  23.102 +    public static abstract class Factory<V, R, DecisionImpl extends Decision<V, R>> {
  23.103 +        /*XXX: should not be public*/public final Class<DecisionImpl> decisionClass;
  23.104 +        public Factory(Class<DecisionImpl> decisionClass) {
  23.105 +            this.decisionClass = decisionClass;
  23.106 +        }
  23.107 +        public abstract DecisionImpl create(TreePathHandle handle);
  23.108 +    }
  23.109 +}
    24.1 --- a/java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/HintContext.java	Thu May 09 22:04:33 2013 +0200
    24.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/HintContext.java	Thu May 09 23:11:06 2013 +0200
    24.3 @@ -43,20 +43,25 @@
    24.4  package org.netbeans.spi.java.hints;
    24.5  
    24.6  import com.sun.source.util.TreePath;
    24.7 +import java.util.ArrayList;
    24.8  import java.util.Collection;
    24.9  import java.util.Collections;
   24.10  import java.util.HashMap;
   24.11  import java.util.LinkedList;
   24.12 +import java.util.List;
   24.13  import java.util.Map;
   24.14  import java.util.concurrent.atomic.AtomicBoolean;
   24.15  import java.util.prefs.Preferences;
   24.16  import javax.lang.model.type.TypeMirror;
   24.17  import org.netbeans.api.java.source.CompilationInfo;
   24.18 +import org.netbeans.api.java.source.TreePathHandle;
   24.19  import org.netbeans.modules.java.hints.providers.spi.HintMetadata;
   24.20  import org.netbeans.modules.java.hints.spiimpl.MessageImpl;
   24.21  import org.netbeans.modules.java.hints.spiimpl.SPIAccessor;
   24.22 +import org.netbeans.modules.java.hints.spiimpl.hints.GlobalProcessingContext;
   24.23  import org.netbeans.modules.java.hints.spiimpl.options.HintsSettings;
   24.24  import org.netbeans.spi.editor.hints.Severity;
   24.25 +import org.netbeans.spi.java.hints.Decision.Factory;
   24.26  import org.netbeans.spi.java.hints.Hint.Kind;
   24.27  
   24.28  /**
   24.29 @@ -70,6 +75,7 @@
   24.30      private final Preferences preferences;
   24.31      private final Severity severity;
   24.32      private final HintMetadata metadata;
   24.33 +    private final GlobalProcessingContext globalContext;
   24.34      private final TreePath path;
   24.35      private final Map<String, TreePath> variables;
   24.36      private final Map<String, Collection<? extends TreePath>> multiVariables;
   24.37 @@ -80,12 +86,13 @@
   24.38      private final AtomicBoolean cancel;
   24.39      private final int caret;
   24.40  
   24.41 -    private HintContext(CompilationInfo info, HintsSettings settings, HintMetadata metadata, TreePath path, Map<String, TreePath> variables, Map<String, Collection<? extends TreePath>> multiVariables, Map<String, String> variableNames, Map<String, TypeMirror> constraints, Collection<? super MessageImpl> problems, boolean bulkMode, AtomicBoolean cancel, int caret) {
   24.42 +    private HintContext(CompilationInfo info, HintsSettings settings, HintMetadata metadata, GlobalProcessingContext globalContext, TreePath path, Map<String, TreePath> variables, Map<String, Collection<? extends TreePath>> multiVariables, Map<String, String> variableNames, Map<String, TypeMirror> constraints, Collection<? super MessageImpl> problems, boolean bulkMode, AtomicBoolean cancel, int caret) {
   24.43          this.info = info;
   24.44          this.settings = settings;
   24.45          this.preferences = metadata != null ? settings.getHintPreferences(metadata) : null;
   24.46          this.severity = preferences != null ? settings.getSeverity(metadata) : Severity.ERROR;
   24.47          this.metadata = metadata;
   24.48 +        this.globalContext = globalContext;
   24.49          this.path = path;
   24.50  
   24.51          variables = new HashMap<String, TreePath>(variables);
   24.52 @@ -174,17 +181,43 @@
   24.53          return metadata.kind == Kind.ACTION ? caret : -1;
   24.54      }
   24.55      
   24.56 +    public <V, R, D extends Decision<V, R>> D findDecision(TreePathHandle forPath, Factory<V, R, D> f) {
   24.57 +        List<Decision<?, ?>> decs = globalContext.decisions.get(forPath);
   24.58 +
   24.59 +        if (decs == null) {
   24.60 +            globalContext.decisions.put(forPath, decs = new ArrayList<Decision<?, ?>>());
   24.61 +        }
   24.62 +
   24.63 +        for (Decision<?, ?> d : decs) {
   24.64 +            if (d.getClass() == f.decisionClass) {
   24.65 +                return f.decisionClass.cast(d);
   24.66 +            }
   24.67 +        }
   24.68 +
   24.69 +        D res = f.create(forPath);
   24.70 +
   24.71 +        decs.add((Decision<?, ?>) res);
   24.72 +
   24.73 +        return res;
   24.74 +    }
   24.75 +
   24.76 +    public Decision<?, ?> decision;
   24.77 +
   24.78 +    public Decision<?, ?> getDecision() {
   24.79 +        return decision;
   24.80 +    }
   24.81 +
   24.82      public enum MessageKind {
   24.83          WARNING, ERROR;
   24.84      }
   24.85      
   24.86      static {
   24.87          SPIAccessor.setINSTANCE(new SPIAccessor() {
   24.88 -            @Override public HintContext createHintContext(CompilationInfo info, HintsSettings settings, HintMetadata metadata, TreePath path, Map<String, TreePath> variables, Map<String, Collection<? extends TreePath>> multiVariables, Map<String, String> variableNames, Map<String, TypeMirror> constraints, Collection<? super MessageImpl> problems, boolean bulkMode, AtomicBoolean cancel, int caret) {
   24.89 -                return new HintContext(info, settings, metadata, path, variables, multiVariables, variableNames, constraints, problems, bulkMode, cancel, caret);
   24.90 +            @Override public HintContext createHintContext(CompilationInfo info, HintsSettings settings, HintMetadata metadata, GlobalProcessingContext globalContext, TreePath path, Map<String, TreePath> variables, Map<String, Collection<? extends TreePath>> multiVariables, Map<String, String> variableNames, Map<String, TypeMirror> constraints, Collection<? super MessageImpl> problems, boolean bulkMode, AtomicBoolean cancel, int caret) {
   24.91 +                return new HintContext(info, settings, metadata, globalContext, path, variables, multiVariables, variableNames, constraints, problems, bulkMode, cancel, caret);
   24.92              }
   24.93 -            @Override public HintContext createHintContext(CompilationInfo info, HintsSettings settings, HintMetadata metadata, TreePath path, Map<String, TreePath> variables, Map<String, Collection<? extends TreePath>> multiVariables, Map<String, String> variableNames) {
   24.94 -                return new HintContext(info, settings, metadata, path, variables, multiVariables, variableNames, Collections.<String, TypeMirror>emptyMap(), new LinkedList<MessageImpl>(), false, new AtomicBoolean(), -1);
   24.95 +            @Override public HintContext createHintContext(CompilationInfo info, HintsSettings settings, HintMetadata metadata, GlobalProcessingContext globalContext, TreePath path, Map<String, TreePath> variables, Map<String, Collection<? extends TreePath>> multiVariables, Map<String, String> variableNames) {
   24.96 +                return new HintContext(info, settings, metadata, globalContext, path, variables, multiVariables, variableNames, Collections.<String, TypeMirror>emptyMap(), new LinkedList<MessageImpl>(), false, new AtomicBoolean(), -1);
   24.97              }
   24.98              @Override public HintMetadata getHintMetadata(HintContext ctx) {
   24.99                  return ctx.getHintMetadata();
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/TriggerDecision.java	Thu May 09 23:11:06 2013 +0200
    25.3 @@ -0,0 +1,59 @@
    25.4 +/*
    25.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    25.6 + *
    25.7 + * Copyright 2008-2010 Oracle and/or its affiliates. All rights reserved.
    25.8 + *
    25.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   25.10 + * Other names may be trademarks of their respective owners.
   25.11 + *
   25.12 + * The contents of this file are subject to the terms of either the GNU
   25.13 + * General Public License Version 2 only ("GPL") or the Common
   25.14 + * Development and Distribution License("CDDL") (collectively, the
   25.15 + * "License"). You may not use this file except in compliance with the
   25.16 + * License. You can obtain a copy of the License at
   25.17 + * http://www.netbeans.org/cddl-gplv2.html
   25.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   25.19 + * specific language governing permissions and limitations under the
   25.20 + * License.  When distributing the software, include this License Header
   25.21 + * Notice in each file and include the License file at
   25.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   25.23 + * particular file as subject to the "Classpath" exception as provided
   25.24 + * by Oracle in the GPL Version 2 section of the License file that
   25.25 + * accompanied this code. If applicable, add the following below the
   25.26 + * License Header, with the fields enclosed by brackets [] replaced by
   25.27 + * your own identifying information:
   25.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   25.29 + *
   25.30 + * If you wish your version of this file to be governed by only the CDDL
   25.31 + * or only the GPL Version 2, indicate your decision by adding
   25.32 + * "[Contributor] elects to include this software in this distribution
   25.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   25.34 + * single choice of license, a recipient has the option to distribute
   25.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   25.36 + * to extend the choice of license to its licensees as provided above.
   25.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   25.38 + * Version 2 license, then the option applies only if the new code is
   25.39 + * made subject to such option by the copyright holder.
   25.40 + *
   25.41 + * Contributor(s):
   25.42 + *
   25.43 + * Portions Copyrighted 2008-2010 Sun Microsystems, Inc.
   25.44 + */
   25.45 +
   25.46 +package org.netbeans.spi.java.hints;
   25.47 +
   25.48 +import java.lang.annotation.ElementType;
   25.49 +import java.lang.annotation.Retention;
   25.50 +import java.lang.annotation.RetentionPolicy;
   25.51 +import java.lang.annotation.Target;
   25.52 +
   25.53 +/**
   25.54 + * @author lahvac
   25.55 + */
   25.56 +@Retention(RetentionPolicy.SOURCE)
   25.57 +@Target(ElementType.METHOD)
   25.58 +public @interface TriggerDecision {
   25.59 +
   25.60 +    public Class<? extends Decision<?, ?>> value();
   25.61 +
   25.62 +}
    26.1 --- a/java.hints/spi.java.hints/test/unit/src/org/netbeans/spi/java/hints/MatcherUtilitiesTest.java	Thu May 09 22:04:33 2013 +0200
    26.2 +++ b/java.hints/spi.java.hints/test/unit/src/org/netbeans/spi/java/hints/MatcherUtilitiesTest.java	Thu May 09 23:11:06 2013 +0200
    26.3 @@ -71,7 +71,7 @@
    26.4          prepareTest("test/Test.java", code);
    26.5  
    26.6          TreePath tp = info.getTreeUtilities().pathFor(pos);
    26.7 -        HintContext ctx = SPIAccessor.getINSTANCE().createHintContext(info, HintsSettings.getGlobalSettings(), null, tp, Collections.<String, TreePath>emptyMap(), Collections.<String, Collection<? extends TreePath>>emptyMap(), Collections.<String, String>emptyMap());
    26.8 +        HintContext ctx = SPIAccessor.getINSTANCE().createHintContext(info, HintsSettings.getGlobalSettings(), null, null, tp, Collections.<String, TreePath>emptyMap(), Collections.<String, Collection<? extends TreePath>>emptyMap(), Collections.<String, String>emptyMap());
    26.9  
   26.10          assertTrue(MatcherUtilities.matches(ctx, ctx.getPath().getParentPath(), "$0 = $_"));
   26.11      }
   26.12 @@ -85,7 +85,7 @@
   26.13          prepareTest("test/Test.java", code);
   26.14  
   26.15          TreePath tp = info.getTreeUtilities().pathFor(pos);
   26.16 -        HintContext ctx = SPIAccessor.getINSTANCE().createHintContext(info, HintsSettings.getGlobalSettings(), null, tp, Collections.<String, TreePath>emptyMap(), Collections.<String, Collection<? extends TreePath>>emptyMap(), Collections.<String, String>emptyMap());
   26.17 +        HintContext ctx = SPIAccessor.getINSTANCE().createHintContext(info, HintsSettings.getGlobalSettings(), null, null, tp, Collections.<String, TreePath>emptyMap(), Collections.<String, Collection<? extends TreePath>>emptyMap(), Collections.<String, String>emptyMap());
   26.18  
   26.19          assertTrue(MatcherUtilities.matches(ctx, ctx.getPath().getParentPath(), "$1 $0 = $_;"));
   26.20      }
   26.21 @@ -99,7 +99,7 @@
   26.22          prepareTest("test/Test.java", code);
   26.23  
   26.24          TreePath tp = info.getTreeUtilities().pathFor(pos);
   26.25 -        HintContext ctx = SPIAccessor.getINSTANCE().createHintContext(info, HintsSettings.getGlobalSettings(), null, tp, Collections.<String, TreePath>emptyMap(), Collections.<String, Collection<? extends TreePath>>emptyMap(), Collections.<String, String>emptyMap());
   26.26 +        HintContext ctx = SPIAccessor.getINSTANCE().createHintContext(info, HintsSettings.getGlobalSettings(), null, null, tp, Collections.<String, TreePath>emptyMap(), Collections.<String, Collection<? extends TreePath>>emptyMap(), Collections.<String, String>emptyMap());
   26.27  
   26.28          Map<String, TreePath> outVariables = new HashMap<String, TreePath>();
   26.29          Map<String, Collection<? extends TreePath>> outMultiVariables = new HashMap<String, Collection<? extends TreePath>>();