Preparing for experiments with enhancing the Java Hints SPI: adding a copy of spi.java.hints and making it usable outside NB proper
authorJan Lahoda <jlahoda@netbeans.org>
Wed, 08 May 2013 21:47:42 +0200
changeset 9546cf93365638c
parent 953 d4587f6e7b02
child 955 bc3b5f486898
Preparing for experiments with enhancing the Java Hints SPI: adding a copy of spi.java.hints and making it usable outside NB proper
hudson/trunk
java.hints/build.sh
java.hints/build.xml
java.hints/nbproject/build-impl.xml
java.hints/nbproject/genfiles.properties
java.hints/nbproject/platform.properties
java.hints/nbproject/platform.xml
java.hints/nbproject/project.properties
java.hints/nbproject/project.xml
java.hints/spi.java.hints/apichanges.xml
java.hints/spi.java.hints/arch.xml
java.hints/spi.java.hints/build.xml
java.hints/spi.java.hints/manifest.mf
java.hints/spi.java.hints/nbproject/build-impl.xml
java.hints/spi.java.hints/nbproject/genfiles.properties
java.hints/spi.java.hints/nbproject/org-netbeans-spi-java-hints.sig
java.hints/spi.java.hints/nbproject/project.properties
java.hints/spi.java.hints/nbproject/project.xml
java.hints/spi.java.hints/nbproject/suite.properties
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/jackpot/spi/Bundle.properties
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/jackpot/spi/HintsRunner.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/jackpot/spi/PatternConvertor.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/jackpot/spi/ProjectDependencyUpgrader.java
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/code/FSWrapper.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/providers/code/ReflectiveCustomizerProvider.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/providers/spi/ClassPathBasedHintProvider.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/providers/spi/ElementBasedHintProvider.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/providers/spi/HintDescription.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/providers/spi/HintDescriptionFactory.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/providers/spi/HintMetadata.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/providers/spi/HintProvider.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/providers/spi/PositionRefresherHelper.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/Bundle.properties
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/Hacks.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/JackpotTrees.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/JavaFixImpl.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/JavaHintsPositionRefresher.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/MessageImpl.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/RulesManager.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/RulesManagerImpl.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/SyntheticFix.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/Utilities.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/batch/BatchUtilities.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/batch/ProgressHandleWrapper.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/batch/Scopes.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/hints/HintsInvoker.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/hints/HintsTask.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/ipi/upgrade/ProjectDependencyUpgrader.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/options/HintsSettings.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/pm/BulkSearch.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/pm/CopyFinderBasedBulkSearch.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/pm/NFA.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/pm/NFABasedBulkSearch.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/pm/PatternCompiler.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/processor/Bundle.properties
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/processor/JavaHintsAnnotationProcessor.java
java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/BooleanOption.java
java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/Bundle.properties
java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/ConstraintVariableType.java
java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/CustomizerProvider.java
java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/ErrorDescriptionFactory.java
java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/Hint.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/HintSeverity.java
java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/IntegerOption.java
java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/JavaFix.java
java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/JavaFixUtilities.java
java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/MatcherUtilities.java
java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/TriggerPattern.java
java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/TriggerPatterns.java
java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/TriggerTreeKind.java
java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/UseOptions.java
java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/support/FixFactory.java
java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/support/TransformationSupport.java
java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/providers/code/CodeHintProviderImplTest.java
java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/providers/code/FSWrapperTest.java
java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/providers/code/TestAnnotations.java
java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/TestBase.java
java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/TestUtilities.java
java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/UtilitiesTest.java
java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/batch/BatchSearchTest.java
java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/batch/BatchUtilitiesTest.java
java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/batch/ProgressHandleWrapperTest.java
java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/batch/TestUtils.java
java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/hints/HintsInvokerTest.java
java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/pm/BulkSearchTestPerformer.java
java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/pm/CopyFinderBasedBulkSearchTest.java
java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/pm/NFABasedBulkSearchTest.java
java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/pm/PatternCompilerTest.java
java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/pm/PatternCompilerUtilities.java
java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/processor/JavaHintsAnnotationProcessorTest.java
java.hints/spi.java.hints/test/unit/src/org/netbeans/spi/java/hints/JavaFixUtilitiesTest.java
java.hints/spi.java.hints/test/unit/src/org/netbeans/spi/java/hints/MatcherUtilitiesTest.java
java.hints/spi.java.hints/test/unit/src/org/netbeans/spi/java/hints/matching/CopyFinderTest.java
java.hints/spi.java.hints/test/unit/src/org/netbeans/spi/java/hints/support/FixFactoryTest.java
remoting/common/borrowedtests/src/org/netbeans/api/java/source/matching/MatchingTestAccessor.java
remoting/common/borrowedtests/src/org/openide/util/test/TestFileUtils.java
     1.1 --- a/hudson/trunk	Wed May 01 21:53:41 2013 +0200
     1.2 +++ b/hudson/trunk	Wed May 08 21:47:42 2013 +0200
     1.3 @@ -41,7 +41,7 @@
     1.4  
     1.5  ant -Dnbplatform.active.dir=$PLATFORM -f lib/download.xml download copy-from-platform
     1.6  
     1.7 -SUBPROJECTS="remoting duplicates language cmdline";
     1.8 +SUBPROJECTS="remoting duplicates language java.hints cmdline";
     1.9  
    1.10  for subproject in $SUBPROJECTS; do
    1.11      (cd $subproject; ./build.sh -Dnbplatform.default.harness.dir=$PLATFORM/harness -Dnbplatform.default.netbeans.dest.dir=$PLATFORM -Dnbplatform.active.dir=$PLATFORM) || exit 1
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/java.hints/build.sh	Wed May 08 21:47:42 2013 +0200
     2.3 @@ -0,0 +1,3 @@
     2.4 +#!/bin/bash
     2.5 +ant "$@" clean && ant "$@" nbms && ant "$@" test || exit 1
     2.6 +
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/java.hints/build.xml	Wed May 08 21:47:42 2013 +0200
     3.3 @@ -0,0 +1,8 @@
     3.4 +<?xml version="1.0" encoding="UTF-8"?>
     3.5 +<!-- You may freely edit this file. See harness/README in the NetBeans platform -->
     3.6 +<!-- for some information on what you could do (e.g. targets to override). -->
     3.7 +<!-- If you delete this file and reopen the project it will be recreated. -->
     3.8 +<project name="java.hints" basedir=".">
     3.9 +    <description>Builds the module suite java.hints.</description>
    3.10 +    <import file="nbproject/build-impl.xml"/>
    3.11 +</project>
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/java.hints/nbproject/build-impl.xml	Wed May 08 21:47:42 2013 +0200
     4.3 @@ -0,0 +1,50 @@
     4.4 +<?xml version="1.0" encoding="UTF-8"?>
     4.5 +<!--
     4.6 +*** GENERATED FROM project.xml - DO NOT EDIT  ***
     4.7 +***         EDIT ../build.xml INSTEAD         ***
     4.8 +-->
     4.9 +<project name="java.hints-impl" basedir=".." xmlns:sproject="http://www.netbeans.org/ns/nb-module-suite-project/1">
    4.10 +    <fail message="Please build using Ant 1.7.1 or higher.">
    4.11 +        <condition>
    4.12 +            <not>
    4.13 +                <antversion atleast="1.7.1"/>
    4.14 +            </not>
    4.15 +        </condition>
    4.16 +    </fail>
    4.17 +    <property file="nbproject/private/platform-private.properties"/>
    4.18 +    <property file="nbproject/platform.properties"/>
    4.19 +    <macrodef name="property" uri="http://www.netbeans.org/ns/nb-module-suite-project/1">
    4.20 +        <attribute name="name"/>
    4.21 +        <attribute name="value"/>
    4.22 +        <sequential>
    4.23 +            <property name="@{name}" value="${@{value}}"/>
    4.24 +        </sequential>
    4.25 +    </macrodef>
    4.26 +    <macrodef name="evalprops" uri="http://www.netbeans.org/ns/nb-module-suite-project/1">
    4.27 +        <attribute name="property"/>
    4.28 +        <attribute name="value"/>
    4.29 +        <sequential>
    4.30 +            <property name="@{property}" value="@{value}"/>
    4.31 +        </sequential>
    4.32 +    </macrodef>
    4.33 +    <property file="${user.properties.file}"/>
    4.34 +    <sproject:property name="harness.dir" value="nbplatform.${nbplatform.active}.harness.dir"/>
    4.35 +    <sproject:property name="nbplatform.active.dir" value="nbplatform.${nbplatform.active}.netbeans.dest.dir"/>
    4.36 +    <sproject:evalprops property="cluster.path.evaluated" value="${cluster.path}"/>
    4.37 +    <fail message="Path to 'platform' cluster missing in $${cluster.path} property or using corrupt Netbeans Platform (missing harness).">
    4.38 +        <condition>
    4.39 +            <not>
    4.40 +                <contains string="${cluster.path.evaluated}" substring="platform"/>
    4.41 +            </not>
    4.42 +        </condition>
    4.43 +    </fail>
    4.44 +    <ant antfile="nbproject/platform.xml"/>
    4.45 +    <fail message="Cannot find NetBeans build harness. ${line.separator}Check that nbplatform.${nbplatform.active}.netbeans.dest.dir and nbplatform.${nbplatform.active}.harness.dir are defined. ${line.separator}On a developer machine these are normally defined in ${user.properties.file}=${netbeans.user}/build.properties ${line.separator}but for automated builds you should pass these properties to Ant explicitly. ${line.separator}You may instead download the harness and platform: -Dbootstrap.url=.../tasks.jar -Dautoupdate.catalog.url=.../updates.xml">
    4.46 +        <condition>
    4.47 +            <not>
    4.48 +                <available file="${harness.dir}/suite.xml"/>
    4.49 +            </not>
    4.50 +        </condition>
    4.51 +    </fail>
    4.52 +    <import file="${harness.dir}/suite.xml"/>
    4.53 +</project>
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/java.hints/nbproject/genfiles.properties	Wed May 08 21:47:42 2013 +0200
     5.3 @@ -0,0 +1,11 @@
     5.4 +build.xml.data.CRC32=85cca5f7
     5.5 +build.xml.script.CRC32=25a1521a
     5.6 +build.xml.stylesheet.CRC32=eaf9f76a@2.58
     5.7 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
     5.8 +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
     5.9 +nbproject/build-impl.xml.data.CRC32=85cca5f7
    5.10 +nbproject/build-impl.xml.script.CRC32=82e0fe0b
    5.11 +nbproject/build-impl.xml.stylesheet.CRC32=0f381476@2.58
    5.12 +nbproject/platform.xml.data.CRC32=85cca5f7
    5.13 +nbproject/platform.xml.script.CRC32=db9e1f43
    5.14 +nbproject/platform.xml.stylesheet.CRC32=df8ac4dd@2.58
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/java.hints/nbproject/platform.properties	Wed May 08 21:47:42 2013 +0200
     6.3 @@ -0,0 +1,18 @@
     6.4 +cluster.path=\
     6.5 +    ${nbplatform.active.dir}/apisupport:\
     6.6 +    ${nbplatform.active.dir}/cnd:\
     6.7 +    ${nbplatform.active.dir}/dlight:\
     6.8 +    ${nbplatform.active.dir}/enterprise:\
     6.9 +    ${nbplatform.active.dir}/extide:\
    6.10 +    ${nbplatform.active.dir}/harness:\
    6.11 +    ${nbplatform.active.dir}/ide:\
    6.12 +    ${nbplatform.active.dir}/java:\
    6.13 +    ${nbplatform.active.dir}/nb:\
    6.14 +    ${nbplatform.active.dir}/platform:\
    6.15 +    ${nbplatform.active.dir}/profiler:\
    6.16 +    ${nbplatform.active.dir}/webcommon:\
    6.17 +    ${nbplatform.active.dir}/websvccommon:\
    6.18 +    ../remoting/common/build/cluster
    6.19 +extcluster.../remoting/common/build/cluster.javadoc=
    6.20 +extcluster.../remoting/common/build/cluster.sources=
    6.21 +nbplatform.active=default
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/java.hints/nbproject/platform.xml	Wed May 08 21:47:42 2013 +0200
     7.3 @@ -0,0 +1,34 @@
     7.4 +<?xml version="1.0" encoding="UTF-8"?>
     7.5 +<project name="platform" default="download" basedir="..">
     7.6 +    <condition property="download.required">
     7.7 +        <and>
     7.8 +            <not>
     7.9 +                <available file="${harness.dir}/suite.xml"/>
    7.10 +            </not>
    7.11 +            <isset property="bootstrap.url"/>
    7.12 +            <isset property="autoupdate.catalog.url"/>
    7.13 +        </and>
    7.14 +    </condition>
    7.15 +    <target name="download" if="download.required">
    7.16 +        <mkdir dir="${harness.dir}"/>
    7.17 +        <pathconvert pathsep="|" property="download.clusters">
    7.18 +            <mapper type="flatten"/>
    7.19 +            <path path="${cluster.path}"/>
    7.20 +        </pathconvert>
    7.21 +        <property name="disabled.modules" value=""/>
    7.22 +        <pathconvert property="module.includes" pathsep="">
    7.23 +            <mapper type="glob" from="${basedir}${file.separator}*" to="(?!\Q*\E)"/>
    7.24 +            <path>
    7.25 +                <filelist files="${disabled.modules}" dir="."/>
    7.26 +            </path>
    7.27 +        </pathconvert>
    7.28 +        <echo message="Downloading clusters ${download.clusters}"/>
    7.29 +        <property name="tasks.jar" location="${java.io.tmpdir}/tasks.jar"/>
    7.30 +        <get src="${bootstrap.url}" dest="${tasks.jar}" usetimestamp="true" verbose="true"/>
    7.31 +        <taskdef name="autoupdate" classname="org.netbeans.nbbuild.AutoUpdate" classpath="${tasks.jar}"/>
    7.32 +        <autoupdate installdir="${nbplatform.active.dir}" updatecenter="${autoupdate.catalog.url}">
    7.33 +            <modules includes="${module.includes}.*" clusters="${download.clusters}"/>
    7.34 +            <modules includes="org[.]netbeans[.]modules[.]apisupport[.]harness" clusters="harness"/>
    7.35 +        </autoupdate>
    7.36 +    </target>
    7.37 +</project>
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/java.hints/nbproject/project.properties	Wed May 08 21:47:42 2013 +0200
     8.3 @@ -0,0 +1,3 @@
     8.4 +modules=\
     8.5 +    ${project.org.netbeans.spi.java.hints}
     8.6 +project.org.netbeans.spi.java.hints=spi.java.hints
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/java.hints/nbproject/project.xml	Wed May 08 21:47:42 2013 +0200
     9.3 @@ -0,0 +1,9 @@
     9.4 +<?xml version="1.0" encoding="UTF-8"?>
     9.5 +<project xmlns="http://www.netbeans.org/ns/project/1">
     9.6 +    <type>org.netbeans.modules.apisupport.project.suite</type>
     9.7 +    <configuration>
     9.8 +        <data xmlns="http://www.netbeans.org/ns/nb-module-suite-project/1">
     9.9 +            <name>java.hints</name>
    9.10 +        </data>
    9.11 +    </configuration>
    9.12 +</project>
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/java.hints/spi.java.hints/apichanges.xml	Wed May 08 21:47:42 2013 +0200
    10.3 @@ -0,0 +1,139 @@
    10.4 +<?xml version="1.0" encoding="UTF-8"?>
    10.5 +<!--
    10.6 +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    10.7 +
    10.8 +Copyright 2012 Oracle and/or its affiliates. All rights reserved.
    10.9 +
   10.10 +Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   10.11 +Other names may be trademarks of their respective owners.
   10.12 +
   10.13 +The contents of this file are subject to the terms of either the GNU
   10.14 +General Public License Version 2 only ("GPL") or the Common
   10.15 +Development and Distribution License("CDDL") (collectively, the
   10.16 +"License"). You may not use this file except in compliance with the
   10.17 +License. You can obtain a copy of the License at
   10.18 +http://www.netbeans.org/cddl-gplv2.html
   10.19 +or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   10.20 +specific language governing permissions and limitations under the
   10.21 +License.  When distributing the software, include this License Header
   10.22 +Notice in each file and include the License file at
   10.23 +nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   10.24 +particular file as subject to the "Classpath" exception as provided
   10.25 +by Oracle in the GPL Version 2 section of the License file that
   10.26 +accompanied this code. If applicable, add the following below the
   10.27 +License Header, with the fields enclosed by brackets [] replaced by
   10.28 +your own identifying information:
   10.29 +"Portions Copyrighted [year] [name of copyright owner]"
   10.30 +
   10.31 +If you wish your version of this file to be governed by only the CDDL
   10.32 +or only the GPL Version 2, indicate your decision by adding
   10.33 +"[Contributor] elects to include this software in this distribution
   10.34 +under the [CDDL or GPL Version 2] license." If you do not indicate a
   10.35 +single choice of license, a recipient has the option to distribute
   10.36 +your version of this file under either the CDDL, the GPL Version 2 or
   10.37 +to extend the choice of license to its licensees as provided above.
   10.38 +However, if you add GPL Version 2 code and therefore, elected the GPL
   10.39 +Version 2 license, then the option applies only if the new code is
   10.40 +made subject to such option by the copyright holder.
   10.41 +
   10.42 +Contributor(s):
   10.43 +
   10.44 +Portions Copyrighted 2012 Sun Microsystems, Inc.
   10.45 +-->
   10.46 +<!DOCTYPE apichanges PUBLIC "-//NetBeans//DTD API changes list 1.0//EN" "../nbbuild/javadoctools/apichanges.dtd">
   10.47 +<apichanges>
   10.48 +    <apidefs>
   10.49 +        <apidef name="JavaHintsSPI">Java Hints SPI</apidef>
   10.50 +    </apidefs>
   10.51 +    <changes>
   10.52 +        <change id="ProjectHintsJava">
   10.53 +            <api name="JavaHintsSPI"/>
   10.54 +            <summary>Defining system filesystem folder for per-project Java hints customizers</summary>
   10.55 +            <version major="1" minor="16"/>
   10.56 +            <date day="24" month="4" year="2013"/>
   10.57 +            <author login="jlahoda"/>
   10.58 +            <compatibility addition="yes"/>
   10.59 +            <description>
   10.60 +                <p>
   10.61 +                    Defining <code>Project/hints/java-based</code> folder, where provider for
   10.62 +                    hints customizers for Java-based projects should be stored.
   10.63 +                </p>    
   10.64 +            </description>
   10.65 +<!--            <issue number="227959"/>-->
   10.66 +        </change>
   10.67 +        <change id="IntegerOption">
   10.68 +            <api name="JavaHintsSPI"/>
   10.69 +            <summary>Added support for integer options. Hints can be declared to appear only in inspect &amp; transform</summary>
   10.70 +            <version major="1" minor="14"/>
   10.71 +            <date day="3" month="4" year="2013"/>
   10.72 +            <author login="sdedic"/>
   10.73 +            <compatibility addition="yes"/>
   10.74 +            <description>
   10.75 +                <p>
   10.76 +                    Added declarative support for integer options. <code>@IntegerOption</code> can
   10.77 +                    be used with option name field, similar to <code>@BooleanOption</code>.
   10.78 +                </p>    
   10.79 +                <p>
   10.80 +                    An option was added to <code>Hint.Options</code>, so that hint can declare
   10.81 +                    to be only shown in Inspect &amp; transform dialog. Useful for computation-intensive
   10.82 +                    hints, which should only run on demand.
   10.83 +                </p>    
   10.84 +            </description>
   10.85 +            <class package="org.netbeans.spi.java.hints" name="IntegerOption"/>
   10.86 +            <class package="org.netbeans.spi.java.hints" name="Hint"/>
   10.87 +            <issue number="227822"/>
   10.88 +            <issue number="227959"/>
   10.89 +        </change>
   10.90 +        <change id="ErrorDescriptionFactory.forSpan">
   10.91 +            <api name="JavaHintsSPI"/>
   10.92 +            <summary>Introducing ErrorDescriptionFactory.forSpan.</summary>
   10.93 +            <version major="1" minor="9"/>
   10.94 +            <date day="19" month="12" year="2012"/>
   10.95 +            <author login="jlahoda"/>
   10.96 +            <compatibility addition="yes"/>
   10.97 +            <description>
   10.98 +                <p>
   10.99 +                    Added ErrorDescriptionFactory.forSpan to create the correct
  10.100 +                    Java-enhanced ErrorDescription from a span.
  10.101 +                </p>    
  10.102 +            </description>
  10.103 +            <class package="org.netbeans.spi.java.hints" name="ErrorDescriptionFactory"/>
  10.104 +            <issue number="223723"/>
  10.105 +        </change>
  10.106 +        <change id="TransformationSupport">
  10.107 +            <api name="JavaHintsSPI"/>
  10.108 +            <summary>Added support for using jackpot patterns from other modules (e.g. refactoring).</summary>
  10.109 +            <version major="1" minor="1"/>
  10.110 +            <date day="29" month="3" year="2012"/>
  10.111 +            <author login="jbecicka"/>
  10.112 +            <compatibility addition="yes"/>
  10.113 +            <description>
  10.114 +                <p>
  10.115 +                    Added support for using jackpot patterns from other modules (e.g. refactoring).
  10.116 +                </p>    
  10.117 +            </description>
  10.118 +            <class package="org.netbeans.spi.java.hints.support" name="TransformationSupport"/>
  10.119 +            <issue number="210262"/>
  10.120 +        </change>
  10.121 +    </changes>
  10.122 +    <htmlcontents>
  10.123 +        <head>
  10.124 +            <title>Change History for the Java Hints SPI</title>
  10.125 +            <link rel="stylesheet" href="prose.css" type="text/css"/>
  10.126 +        </head>
  10.127 +        <body>
  10.128 +            <p class="overviewlink">
  10.129 +                <a href="overview-summary.html">Overview</a>
  10.130 +            </p>
  10.131 +            <h1>Introduction</h1>
  10.132 +            <p>This document lists changes made to the Java Hints SPI.</p>
  10.133 +            
  10.134 +            <!-- The actual lists of changes, as summaries and details: -->
  10.135 +            <hr/>
  10.136 +            <standard-changelists module-code-name="$codebase"/>
  10.137 +            
  10.138 +            <hr/>
  10.139 +            <p>@FOOTER@</p>
  10.140 +        </body>
  10.141 +    </htmlcontents>
  10.142 +</apichanges>
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/java.hints/spi.java.hints/arch.xml	Wed May 08 21:47:42 2013 +0200
    11.3 @@ -0,0 +1,1115 @@
    11.4 +<?xml version="1.0" encoding="UTF-8"?>
    11.5 +<!DOCTYPE api-answers PUBLIC "-//NetBeans//DTD Arch Answers//EN" "../nbbuild/antsrc/org/netbeans/nbbuild/Arch.dtd" [
    11.6 +  <!ENTITY api-questions SYSTEM "../nbbuild/antsrc/org/netbeans/nbbuild/Arch-api-questions.xml">
    11.7 +]>
    11.8 +
    11.9 +<api-answers
   11.10 +  question-version="1.29"
   11.11 +  author="jlahoda@netbeans.org"
   11.12 +>
   11.13 +
   11.14 +  &api-questions;
   11.15 +
   11.16 +
   11.17 +<!--
   11.18 +        <question id="arch-overall" when="init">
   11.19 +            Describe the overall architecture. 
   11.20 +            <hint>
   11.21 +            What will be API for 
   11.22 +            <a href="http://openide.netbeans.org/tutorial/api-design.html#design.apiandspi">
   11.23 +                clients and what support API</a>? 
   11.24 +            What parts will be pluggable?
   11.25 +            How will plug-ins be registered? Please use <code>&lt;api type="export"/&gt;</code>
   11.26 +            to describe your general APIs and specify their
   11.27 +            <a href="http://openide.netbeans.org/tutorial/api-design.html#category-private">
   11.28 +            stability categories</a>.
   11.29 +            If possible please provide simple diagrams.
   11.30 +            </hint>
   11.31 +        </question>
   11.32 +-->
   11.33 + <answer id="arch-overall">
   11.34 +  <p>
   11.35 +   <api type="export" category="devel" group="java" name="spi.java.hints">
   11.36 +       SPI to create custom Java hints, including code smell warnings, productivity tips, etc.
   11.37 +       Please see the Use Cases section for a guide on how to use this SPI.
   11.38 +   </api>
   11.39 +  </p>
   11.40 + </answer>
   11.41 +
   11.42 +
   11.43 +
   11.44 +<!--
   11.45 +        <question id="arch-quality" when="init">
   11.46 +            How will the <a href="http://www.netbeans.org/community/guidelines/q-evangelism.html">quality</a>
   11.47 +            of your code be tested and 
   11.48 +            how are future regressions going to be prevented?
   11.49 +            <hint>
   11.50 +            What kind of testing do
   11.51 +            you want to use? How much functionality, in which areas,
   11.52 +            should be covered by the tests? How you find out that your
   11.53 +            project was successful?
   11.54 +            </hint>
   11.55 +        </question>
   11.56 +-->
   11.57 + <answer id="arch-quality">
   11.58 +  <p>
   11.59 +   XXX no answer for arch-quality
   11.60 +  </p>
   11.61 + </answer>
   11.62 +
   11.63 +
   11.64 +
   11.65 +<!--
   11.66 +        <question id="arch-time" when="init">
   11.67 +            What are the time estimates of the work?
   11.68 +            <hint>
   11.69 +            Please express your estimates of how long the design, implementation,
   11.70 +            stabilization are likely to last. How many people will be needed to
   11.71 +            implement this and what is the expected milestone by which the work should be 
   11.72 +            ready?
   11.73 +            </hint>
   11.74 +        </question>
   11.75 +-->
   11.76 + <answer id="arch-time">
   11.77 +  <p>
   11.78 +   XXX no answer for arch-time
   11.79 +  </p>
   11.80 + </answer>
   11.81 +
   11.82 +
   11.83 +
   11.84 +<!--
   11.85 +        <question id="arch-usecases" when="init">
   11.86 +            <hint>
   11.87 +                Content of this answer will be displayed as part of page at
   11.88 +                http://www.netbeans.org/download/dev/javadoc/usecases.html 
   11.89 +                You can use tags &lt;usecase name="name&gt; regular html description &lt;/usecase&gt;
   11.90 +                and if you want to use an URL you can prefix if with @TOP@ to begin
   11.91 +                at the root of your javadoc
   11.92 +            </hint>
   11.93 +        
   11.94 +            Describe the main <a href="http://openide.netbeans.org/tutorial/api-design.html#usecase">
   11.95 +            use cases</a> of the new API. Who will use it under
   11.96 +            what circumstances? What kind of code would typically need to be written
   11.97 +            to use the module?
   11.98 +        </question>
   11.99 +-->
  11.100 + <answer id="arch-usecases">
  11.101 +  <p>
  11.102 +   <usecase id="creating" name="Creating a new Java Hint">
  11.103 +       Simple way to create a new Java hint is as follows:
  11.104 +       <ul>
  11.105 +           <li>Create a new class, annotate it with the <a href="@TOP@/org/netbeans/spi/java/hints/Hint.html">@Hint</a>
  11.106 +           annotation to it.</li>
  11.107 +           <li>Create a <code>public static ErrorDescription hint(HintContext ctx) {}</code> method in the
  11.108 +           class. Annotate the method either with the <a href="@TOP@/org/netbeans/spi/java/hints/TriggerPattern.html">@TriggerPattern</a>
  11.109 +           annotation (strongly recommended), or with the <a href="@TOP@/org/netbeans/spi/java/hints/TriggerTreeKind.html">@TriggerTreeKind</a>.
  11.110 +           This method will be called when for parts of the code that match the given pattern, of for trees of the specified kinds.</li>
  11.111 +           <li>Perform whatever checks necessary to find out whether a warning should be produced at the given place, and produce the ErrorDescription if needed.</li>
  11.112 +       </ul>
  11.113 +       <br/>
  11.114 +       Tips:
  11.115 +       <ul>
  11.116 +           <li>Always use the java.hints' <a href="@TOP@/org/netbeans/spi/java/hints/ErrorDescriptionFactory.html">ErrorDescriptionFactory</a> to produce the resulting ErrorDescription.</li>
  11.117 +           <li>Never try to produce a custom suppress warnings "fix". Specify suppress warnings keys in the @Hint annotation.</li>
  11.118 +           <li>If an automated transformation is to be prodived from your hint, subclass <a href="@TOP@/org/netbeans/spi/java/hints/JavaFix.html">JavaFix</a> and
  11.119 +               use its <code>toEditorFix()</code> method to get the <code>Fix</code>, if the transformation is going to be used inside Inspect&amp;Transform.
  11.120 +           </li>
  11.121 +           <li>The name of the method is arbitrary, one hint can consist of more that one "triggered" method.</li>
  11.122 +       </ul>
  11.123 +   </usecase>
  11.124 +   <usecase id="no-class" name="Creating a new Java Hint Without a Class">
  11.125 +       For simple hints, it is possible to annotate the hint method with the <a href="@TOP@/org/netbeans/spi/java/hints/Hint.html">@Hint</a> annotation.
  11.126 +       The hint then consists of this sole method. Any number of such hints may be created in a single class.
  11.127 +   </usecase>
  11.128 +   <usecase id="testing" name="Creating a Tests for the Newly Created Java Hint">
  11.129 +       Creating automated tests for the hints is simple: create a test class, and use
  11.130 +       <a href="@TOP@/../org-netbeans-modules-java-hints-test/org/netbeans/modules/java/hints/test/api/HintTest.html">HintTest</a>
  11.131 +       to setup the test, run the hint and verify that its outcomes are correct.
  11.132 +       The tests automatically run with <code>test</code> branding, so create <code>Bundle_test.properties</code>, and add
  11.133 +       bundle keys into it for ErrorDescription and Fix display names, to isolate the test from changes in the production
  11.134 +       <code>Bundle.properties</code>.
  11.135 +   </usecase>
  11.136 +   <usecase id="adding-options" name="Adding options to a Java Hint">
  11.137 +       To add a simple boolean option to your hint, use <a href="@TOP@/org/netbeans/spi/java/hints/BooleanOption.html">@BooleanOption</a>.
  11.138 +   </usecase>
  11.139 +  </p>
  11.140 + </answer>
  11.141 +
  11.142 +
  11.143 +
  11.144 +<!--
  11.145 +        <question id="arch-what" when="init">
  11.146 +            What is this project good for?
  11.147 +            <hint>
  11.148 +            Please provide here a few lines describing the project, 
  11.149 +            what problem it should solve, provide links to documentation, 
  11.150 +            specifications, etc.
  11.151 +            </hint>
  11.152 +        </question>
  11.153 +-->
  11.154 + <answer id="arch-what">
  11.155 +  <p>
  11.156 +   XXX no answer for arch-what
  11.157 +  </p>
  11.158 + </answer>
  11.159 +
  11.160 +
  11.161 +
  11.162 +<!--
  11.163 +        <question id="arch-where" when="impl">
  11.164 +            Where one can find sources for your module?
  11.165 +            <hint>
  11.166 +                Please provide link to the Hg web client at
  11.167 +                http://hg.netbeans.org/
  11.168 +                or just use tag defaultanswer generate='here'
  11.169 +            </hint>
  11.170 +        </question>
  11.171 +-->
  11.172 + <answer id="arch-where">
  11.173 +  <defaultanswer generate='here' />
  11.174 + </answer>
  11.175 +
  11.176 +
  11.177 +
  11.178 +<!--
  11.179 +        <question id="compat-deprecation" when="init">
  11.180 +            How the introduction of your project influences functionality
  11.181 +            provided by previous version of the product?
  11.182 +            <hint>
  11.183 +            If you are planning to deprecate/remove/change any existing APIs,
  11.184 +            list them here accompanied with the reason explaining why you
  11.185 +            are doing so.
  11.186 +            </hint>
  11.187 +        </question>
  11.188 +-->
  11.189 + <answer id="compat-deprecation">
  11.190 +  <p>
  11.191 +   XXX no answer for compat-deprecation
  11.192 +  </p>
  11.193 + </answer>
  11.194 +
  11.195 +
  11.196 +
  11.197 +<!--
  11.198 +        <question id="compat-i18n" when="impl">
  11.199 +            Is your module correctly internationalized?
  11.200 +            <hint>
  11.201 +            Correct internationalization means that it obeys instructions 
  11.202 +            at <a href="http://www.netbeans.org/download/dev/javadoc/org-openide-modules/org/openide/modules/doc-files/i18n-branding.html">
  11.203 +            NetBeans I18N pages</a>.
  11.204 +            </hint>
  11.205 +        </question>
  11.206 +-->
  11.207 + <answer id="compat-i18n">
  11.208 +  <p>
  11.209 +   XXX no answer for compat-i18n
  11.210 +  </p>
  11.211 + </answer>
  11.212 +
  11.213 +
  11.214 +
  11.215 +<!--
  11.216 +        <question id="compat-standards" when="init">
  11.217 +            Does the module implement or define any standards? Is the 
  11.218 +            implementation exact or does it deviate somehow?
  11.219 +        </question>
  11.220 +-->
  11.221 + <answer id="compat-standards">
  11.222 +  <p>
  11.223 +   XXX no answer for compat-standards
  11.224 +  </p>
  11.225 + </answer>
  11.226 +
  11.227 +
  11.228 +
  11.229 +<!--
  11.230 +        <question id="compat-version" when="impl">
  11.231 +            Can your module coexist with earlier and future
  11.232 +            versions of itself? Can you correctly read all old settings? Will future
  11.233 +            versions be able to read your current settings? Can you read
  11.234 +            or politely ignore settings stored by a future version?
  11.235 +            
  11.236 +            <hint>
  11.237 +            Very helpful for reading settings is to store version number
  11.238 +            there, so future versions can decide whether how to read/convert
  11.239 +            the settings and older versions can ignore the new ones.
  11.240 +            </hint>
  11.241 +        </question>
  11.242 +-->
  11.243 + <answer id="compat-version">
  11.244 +  <p>
  11.245 +   XXX no answer for compat-version
  11.246 +  </p>
  11.247 + </answer>
  11.248 +
  11.249 +
  11.250 +
  11.251 +<!--
  11.252 +        <question id="dep-jre" when="final">
  11.253 +            Which version of JRE do you need (1.2, 1.3, 1.4, etc.)?
  11.254 +            <hint>
  11.255 +            It is expected that if your module runs on 1.x that it will run 
  11.256 +            on 1.x+1 if no, state that please. Also describe here cases where
  11.257 +            you run different code on different versions of JRE and why.
  11.258 +            </hint>
  11.259 +        </question>
  11.260 +-->
  11.261 + <answer id="dep-jre">
  11.262 +  <p>
  11.263 +   XXX no answer for dep-jre
  11.264 +  </p>
  11.265 + </answer>
  11.266 +
  11.267 +
  11.268 +
  11.269 +<!--
  11.270 +        <question id="dep-jrejdk" when="final">
  11.271 +            Do you require the JDK or is the JRE enough?
  11.272 +        </question>
  11.273 +-->
  11.274 + <answer id="dep-jrejdk">
  11.275 +  <p>
  11.276 +   XXX no answer for dep-jrejdk
  11.277 +  </p>
  11.278 + </answer>
  11.279 +
  11.280 +
  11.281 +
  11.282 +<!--
  11.283 +        <question id="dep-nb" when="init">
  11.284 +            What other NetBeans projects and modules does this one depend on?
  11.285 +            <hint>
  11.286 +            Depending on other NetBeans projects influnces the ability of
  11.287 +            users of your work to customize their own branded version of
  11.288 +            NetBeans by enabling and disabling some modules. Too
  11.289 +            much dependencies restrict this kind of customization. If that
  11.290 +            is your case, then you may want to split your functionality into
  11.291 +            pieces of autoload, eager and regular modules which can be
  11.292 +            enabled independently. Usually the answer to this question
  11.293 +            is generated from your <code>project.xml</code> file, but
  11.294 +            if it is not guessed correctly, you can suppress it by
  11.295 +            specifying &lt;defaultanswer generate="none"/&gt; and
  11.296 +            write here your own. Please describe such projects as imported APIs using
  11.297 +            the <code>&lt;api name="identification" type="import or export" category="stable" url="where is the description" /&gt;</code>.
  11.298 +            By doing this information gets listed in the summary page of your
  11.299 +            javadoc.
  11.300 +            </hint>
  11.301 +        </question>
  11.302 +-->
  11.303 + <answer id="dep-nb">
  11.304 +  <defaultanswer generate='here' />
  11.305 + </answer>
  11.306 +
  11.307 +
  11.308 +
  11.309 +<!--
  11.310 +        <question id="dep-non-nb" when="init">
  11.311 +            What other projects outside NetBeans does this one depend on?
  11.312 +            
  11.313 +            <hint>
  11.314 +            Depending on 3rd party libraries is always problematic,
  11.315 +            especially if they are not open source, as that complicates
  11.316 +            the licensing scheme of NetBeans. Please enumerate your
  11.317 +            external dependencies here, so it is correctly understood since
  11.318 +            the begining what are the legal implications of your project.
  11.319 +            Also please note that
  11.320 +            some non-NetBeans projects are packaged as NetBeans modules
  11.321 +            (see <a href="http://libs.netbeans.org/">libraries</a>) and
  11.322 +            it is preferred to use this approach when more modules may
  11.323 +            depend and share such third-party libraries.
  11.324 +            </hint>
  11.325 +        </question>
  11.326 +-->
  11.327 + <answer id="dep-non-nb">
  11.328 +  <p>
  11.329 +   XXX no answer for dep-non-nb
  11.330 +  </p>
  11.331 + </answer>
  11.332 +
  11.333 +
  11.334 +
  11.335 +<!--
  11.336 +        <question id="dep-platform" when="init">
  11.337 +            On which platforms does your module run? Does it run in the same
  11.338 +            way on each?
  11.339 +            <hint>
  11.340 +            If you plan any dependency on OS or any usage of native code,
  11.341 +            please describe why you are doing so and describe how you envision
  11.342 +            to enforce the portability of your code.
  11.343 +            Please note that there is a support for <a href="http://www.netbeans.org/download/dev/javadoc/org-openide-modules/org/openide/modules/doc-files/api.html#how-os-specific">OS conditionally
  11.344 +            enabled modules</a> which together with autoload/eager modules
  11.345 +            can allow you to enable to provide the best OS aware support
  11.346 +            on certain OSes while providing compatibility bridge on the not
  11.347 +            supported ones.
  11.348 +            Also please list the supported
  11.349 +            OSes/HW platforms and mentioned the lovest version of JDK required
  11.350 +            for your project to run on. Also state whether JRE is enough or
  11.351 +            you really need JDK.
  11.352 +            </hint>
  11.353 +        </question>
  11.354 +-->
  11.355 + <answer id="dep-platform">
  11.356 +  <p>
  11.357 +   XXX no answer for dep-platform
  11.358 +  </p>
  11.359 + </answer>
  11.360 +
  11.361 +
  11.362 +
  11.363 +<!--
  11.364 +        <question id="deploy-dependencies" when="final">
  11.365 +            What do other modules need to do to declare a dependency on this one,
  11.366 +            in addition to or instead of the normal module dependency declaration
  11.367 +            (e.g. tokens to require)?
  11.368 +            <hint>
  11.369 +                Provide a sample of the actual lines you would add to a module manifest
  11.370 +                to declare a dependency, for example OpenIDE-Module-Requires: some.token.
  11.371 +                If other modules should not depend on this module, or should just use a
  11.372 +                simple regular module dependency, you can just answer "nothing". If you
  11.373 +                intentionally expose a semistable API to clients using implementation
  11.374 +                dependencies, you should mention that here (but there is no need to give
  11.375 +                an example of usage).
  11.376 +            </hint>
  11.377 +        </question>
  11.378 +-->
  11.379 + <answer id="deploy-dependencies">
  11.380 +  <p>
  11.381 +   XXX no answer for deploy-dependencies
  11.382 +  </p>
  11.383 + </answer>
  11.384 +
  11.385 +
  11.386 +
  11.387 +<!--
  11.388 +        <question id="deploy-jar" when="impl">
  11.389 +            Do you deploy just module JAR file(s) or other files as well?
  11.390 +            <hint>
  11.391 +            Usually a module consist of one JAR file (perhaps with Class-Path
  11.392 +            extensions) and also a configuration file that enables it. If you
  11.393 +            have any other files, use
  11.394 +            &lt;api group="java.io.File" name="yourname" type="export" category="friend"&gt;...&lt;/api&gt;
  11.395 +            to define the location, name and stability of your files (of course
  11.396 +            changing "yourname" and "friend" to suit your needs).
  11.397 +            
  11.398 +            If it uses more than one JAR, describe where they are located, how
  11.399 +            they refer to each other. 
  11.400 +            If it consist of module JAR(s) and other files, please describe
  11.401 +            what is their purpose, why other files are necessary. Please 
  11.402 +            make sure that installation/uninstallation leaves the system 
  11.403 +            in state as it was before installation.
  11.404 +            </hint>
  11.405 +        </question>
  11.406 +-->
  11.407 + <answer id="deploy-jar">
  11.408 +  <p>
  11.409 +   XXX no answer for deploy-jar
  11.410 +  </p>
  11.411 + </answer>
  11.412 +
  11.413 +
  11.414 +
  11.415 +<!--
  11.416 +        <question id="deploy-nbm" when="impl">
  11.417 +            Can you deploy an NBM via the Update Center?
  11.418 +            <hint>
  11.419 +            If not why?
  11.420 +            </hint>
  11.421 +        </question>
  11.422 +-->
  11.423 + <answer id="deploy-nbm">
  11.424 +  <p>
  11.425 +   XXX no answer for deploy-nbm
  11.426 +  </p>
  11.427 + </answer>
  11.428 +
  11.429 +
  11.430 +
  11.431 +<!--
  11.432 +        <question id="deploy-packages" when="init">
  11.433 +            Are packages of your module made inaccessible by not declaring them
  11.434 +            public?
  11.435 +            
  11.436 +            <hint>
  11.437 +            By default NetBeans build harness treats all packages are private.
  11.438 +            If you export some of them - either as public or friend packages,
  11.439 +            you should have a reason. If the reason is described elsewhere
  11.440 +            in this document, you can ignore this question.
  11.441 +            </hint>
  11.442 +        </question>
  11.443 +-->
  11.444 + <answer id="deploy-packages">
  11.445 +  <p>
  11.446 +   XXX no answer for deploy-packages
  11.447 +  </p>
  11.448 + </answer>
  11.449 +
  11.450 +
  11.451 +
  11.452 +<!--
  11.453 +        <question id="deploy-shared" when="final">
  11.454 +            Do you need to be installed in the shared location only, or in the user directory only,
  11.455 +            or can your module be installed anywhere?
  11.456 +            <hint>
  11.457 +            Installation location shall not matter, if it does explain why.
  11.458 +            Consider also whether <code>InstalledFileLocator</code> can help.
  11.459 +            </hint>
  11.460 +        </question>
  11.461 +-->
  11.462 + <answer id="deploy-shared">
  11.463 +  <p>
  11.464 +   XXX no answer for deploy-shared
  11.465 +  </p>
  11.466 + </answer>
  11.467 +
  11.468 +
  11.469 +
  11.470 +<!--
  11.471 +        <question id="exec-ant-tasks" when="impl">
  11.472 +            Do you define or register any ant tasks that other can use?
  11.473 +            
  11.474 +            <hint>
  11.475 +            If you provide an ant task that users can use, you need to be very
  11.476 +            careful about its syntax and behaviour, as it most likely forms an
  11.477 +	          API for end users and as there is a lot of end users, their reaction
  11.478 +            when such API gets broken can be pretty strong.
  11.479 +            </hint>
  11.480 +        </question>
  11.481 +-->
  11.482 + <answer id="exec-ant-tasks">
  11.483 +  <p>
  11.484 +   XXX no answer for exec-ant-tasks
  11.485 +  </p>
  11.486 + </answer>
  11.487 +
  11.488 +
  11.489 +
  11.490 +<!--
  11.491 +        <question id="exec-classloader" when="impl">
  11.492 +            Does your code create its own class loader(s)?
  11.493 +            <hint>
  11.494 +            A bit unusual. Please explain why and what for.
  11.495 +            </hint>
  11.496 +        </question>
  11.497 +-->
  11.498 + <answer id="exec-classloader">
  11.499 +  <p>
  11.500 +   XXX no answer for exec-classloader
  11.501 +  </p>
  11.502 + </answer>
  11.503 +
  11.504 +
  11.505 +
  11.506 +<!--
  11.507 +        <question id="exec-component" when="impl">
  11.508 +            Is execution of your code influenced by any (string) property
  11.509 +            of any of your components?
  11.510 +            
  11.511 +            <hint>
  11.512 +            Often <code>JComponent.getClientProperty</code>, <code>Action.getValue</code>
  11.513 +            or <code>PropertyDescriptor.getValue</code>, etc. are used to influence
  11.514 +            a behavior of some code. This of course forms an interface that should
  11.515 +            be documented. Also if one depends on some interface that an object
  11.516 +            implements (<code>component instanceof Runnable</code>) that forms an
  11.517 +            API as well.
  11.518 +            </hint>
  11.519 +        </question>
  11.520 +-->
  11.521 + <answer id="exec-component">
  11.522 +  <p>
  11.523 +   XXX no answer for exec-component
  11.524 +  </p>
  11.525 + </answer>
  11.526 +
  11.527 +
  11.528 +
  11.529 +<!--
  11.530 +        <question id="exec-introspection" when="impl">
  11.531 +            Does your module use any kind of runtime type information (<code>instanceof</code>,
  11.532 +            work with <code>java.lang.Class</code>, etc.)?
  11.533 +            <hint>
  11.534 +            Check for cases when you have an object of type A and you also
  11.535 +            expect it to (possibly) be of type B and do some special action. That
  11.536 +            should be documented. The same applies on operations in meta-level
  11.537 +            (Class.isInstance(...), Class.isAssignableFrom(...), etc.).
  11.538 +            </hint>
  11.539 +        </question>
  11.540 +-->
  11.541 + <answer id="exec-introspection">
  11.542 +  <p>
  11.543 +   XXX no answer for exec-introspection
  11.544 +  </p>
  11.545 + </answer>
  11.546 +
  11.547 +
  11.548 +
  11.549 +<!--
  11.550 +        <question id="exec-privateaccess" when="final">
  11.551 +            Are you aware of any other parts of the system calling some of 
  11.552 +            your methods by reflection?
  11.553 +            <hint>
  11.554 +            If so, describe the "contract" as an API. Likely private or friend one, but
  11.555 +            still API and consider rewrite of it.
  11.556 +            </hint>
  11.557 +        </question>
  11.558 +-->
  11.559 + <answer id="exec-privateaccess">
  11.560 +  <p>
  11.561 +   XXX no answer for exec-privateaccess
  11.562 +  </p>
  11.563 + </answer>
  11.564 +
  11.565 +
  11.566 +
  11.567 +<!--
  11.568 +        <question id="exec-process" when="impl">
  11.569 +            Do you execute an external process from your module? How do you ensure
  11.570 +            that the result is the same on different platforms? Do you parse output?
  11.571 +            Do you depend on result code?
  11.572 +            <hint>
  11.573 +            If you feed an input, parse the output please declare that as an API.
  11.574 +            </hint>
  11.575 +        </question>
  11.576 +-->
  11.577 + <answer id="exec-process">
  11.578 +  <p>
  11.579 +   XXX no answer for exec-process
  11.580 +  </p>
  11.581 + </answer>
  11.582 +
  11.583 +
  11.584 +
  11.585 +<!--
  11.586 +        <question id="exec-property" when="impl">
  11.587 +            Is execution of your code influenced by any environment or
  11.588 +            Java system (<code>System.getProperty</code>) property?
  11.589 +            On a similar note, is there something interesting that you
  11.590 +            pass to <code>java.util.logging.Logger</code>? Or do you observe
  11.591 +            what others log?
  11.592 +            <hint>
  11.593 +            If there is a property that can change the behavior of your 
  11.594 +            code, somebody will likely use it. You should describe what it does 
  11.595 +            and the <a href="http://openide.netbeans.org/tutorial/api-design.html#life">stability category</a>
  11.596 +            of this API. You may use
  11.597 +            <pre>
  11.598 +                &lt;api type="export" group="property" name="id" category="private" url="http://..."&gt;
  11.599 +                    description of the property, where it is used, what it influence, etc.
  11.600 +                &lt;/api&gt;            
  11.601 +            </pre>
  11.602 +            </hint>
  11.603 +        </question>
  11.604 +-->
  11.605 + <answer id="exec-property">
  11.606 +  <p>
  11.607 +   XXX no answer for exec-property
  11.608 +  </p>
  11.609 + </answer>
  11.610 +
  11.611 +
  11.612 +
  11.613 +<!--
  11.614 +        <question id="exec-reflection" when="impl">
  11.615 +            Does your code use Java Reflection to execute other code?
  11.616 +            <hint>
  11.617 +            This usually indicates a missing or insufficient API in the other
  11.618 +            part of the system. If the other side is not aware of your dependency
  11.619 +            this contract can be easily broken.
  11.620 +            </hint>
  11.621 +        </question>
  11.622 +-->
  11.623 + <answer id="exec-reflection">
  11.624 +  <p>
  11.625 +   XXX no answer for exec-reflection
  11.626 +  </p>
  11.627 + </answer>
  11.628 +
  11.629 +
  11.630 +
  11.631 +<!--
  11.632 +        <question id="exec-threading" when="init">
  11.633 +            What threading models, if any, does your module adhere to? How the
  11.634 +            project behaves with respect to threading?
  11.635 +            <hint>
  11.636 +                Is your API threadsafe? Can it be accessed from any threads or
  11.637 +                just from some dedicated ones? Any special relation to AWT and
  11.638 +                its Event Dispatch thread? Also
  11.639 +                if your module calls foreign APIs which have a specific threading model,
  11.640 +                indicate how you comply with the requirements for multithreaded access
  11.641 +                (synchronization, mutexes, etc.) applicable to those APIs.
  11.642 +                If your module defines any APIs, or has complex internal structures
  11.643 +                that might be used from multiple threads, declare how you protect
  11.644 +                data against concurrent access, race conditions, deadlocks, etc.,
  11.645 +                and whether such rules are enforced by runtime warnings, errors, assertions, etc.
  11.646 +                Examples: a class might be non-thread-safe (like Java Collections); might
  11.647 +                be fully thread-safe (internal locking); might require access through a mutex
  11.648 +                (and may or may not automatically acquire that mutex on behalf of a client method);
  11.649 +                might be able to run only in the event queue; etc.
  11.650 +                Also describe when any events are fired: synchronously, asynchronously, etc.
  11.651 +                Ideas: <a href="http://core.netbeans.org/proposals/threading/index.html#recommendations">Threading Recommendations</a> (in progress)
  11.652 +            </hint>
  11.653 +        </question>
  11.654 +-->
  11.655 + <answer id="exec-threading">
  11.656 +  <p>
  11.657 +   XXX no answer for exec-threading
  11.658 +  </p>
  11.659 + </answer>
  11.660 +
  11.661 +
  11.662 +
  11.663 +<!--
  11.664 +        <question id="format-clipboard" when="impl">
  11.665 +            Which data flavors (if any) does your code read from or insert to
  11.666 +            the clipboard (by access to clipboard on means calling methods on <code>java.awt.datatransfer.Transferable</code>?
  11.667 +            
  11.668 +            <hint>
  11.669 +            Often Node's deal with clipboard by usage of <code>Node.clipboardCopy, Node.clipboardCut and Node.pasteTypes</code>.
  11.670 +            Check your code for overriding these methods.
  11.671 +            </hint>
  11.672 +        </question>
  11.673 +-->
  11.674 + <answer id="format-clipboard">
  11.675 +  <p>
  11.676 +   XXX no answer for format-clipboard
  11.677 +  </p>
  11.678 + </answer>
  11.679 +
  11.680 +
  11.681 +
  11.682 +<!--
  11.683 +        <question id="format-dnd" when="impl">
  11.684 +            Which protocols (if any) does your code understand during Drag &amp; Drop?
  11.685 +            <hint>
  11.686 +            Often Node's deal with clipboard by usage of <code>Node.drag, Node.getDropType</code>. 
  11.687 +            Check your code for overriding these methods. Btw. if they are not overridden, they
  11.688 +            by default delegate to <code>Node.clipboardCopy, Node.clipboardCut and Node.pasteTypes</code>.
  11.689 +            </hint>
  11.690 +        </question>
  11.691 +-->
  11.692 + <answer id="format-dnd">
  11.693 +  <p>
  11.694 +   XXX no answer for format-dnd
  11.695 +  </p>
  11.696 + </answer>
  11.697 +
  11.698 +
  11.699 +
  11.700 +<!--
  11.701 +        <question id="format-types" when="impl">
  11.702 +            Which protocols and file formats (if any) does your module read or write on disk,
  11.703 +            or transmit or receive over the network? Do you generate an ant build script?
  11.704 +            Can it be edited and modified? 
  11.705 +            
  11.706 +            <hint>
  11.707 +            <p>
  11.708 +            Files can be read and written by other programs, modules and users. If they influence
  11.709 +            your behaviour, make sure you either document the format or claim that it is a private
  11.710 +            api (using the &lt;api&gt; tag). 
  11.711 +            </p>
  11.712 +            
  11.713 +            <p>
  11.714 +            If you generate an ant build file, this is very likely going to be seen by end users and
  11.715 +            they will be attempted to edit it. You should be ready for that and provide here a link
  11.716 +            to documentation that you have for such purposes and also describe how you are going to
  11.717 +            understand such files during next release, when you (very likely) slightly change the 
  11.718 +            format.
  11.719 +            </p>
  11.720 +            </hint>
  11.721 +        </question>
  11.722 +-->
  11.723 + <answer id="format-types">
  11.724 +  <p>
  11.725 +   XXX no answer for format-types
  11.726 +  </p>
  11.727 + </answer>
  11.728 +
  11.729 +
  11.730 +
  11.731 +<!--
  11.732 +        <question id="lookup-lookup" when="init">
  11.733 +            Does your module use <code>org.openide.util.Lookup</code>
  11.734 +            or any similar technology to find any components to communicate with? Which ones?
  11.735 +            
  11.736 +            <hint>
  11.737 +            NetBeans is build around a generic registry of services called
  11.738 +            lookup. It is preferable to use it for registration and discovery
  11.739 +            if possible. See
  11.740 +            <a href="http://www.netbeans.org/download/dev/javadoc/org-openide-util/org/openide/util/lookup/doc-files/index.html">
  11.741 +            The Solution to Comunication Between Components
  11.742 +            </a>. If you do not plan to use lookup and insist usage
  11.743 +            of other solution, then please describe why it is not working for
  11.744 +            you.
  11.745 +            <br/>
  11.746 +            When filling the final version of your arch document, please
  11.747 +            describe the interfaces you are searching for, where 
  11.748 +            are defined, whether you are searching for just one or more of them,
  11.749 +            if the order is important, etc. Also classify the stability of such
  11.750 +            API contract. Use &lt;api group=&amp;lookup&amp; /&gt; tag, so
  11.751 +            your information gets listed in the summary page of your javadoc.
  11.752 +            </hint>
  11.753 +        </question>
  11.754 +-->
  11.755 + <answer id="lookup-lookup">
  11.756 +  <p>
  11.757 +   XXX no answer for lookup-lookup
  11.758 +  </p>
  11.759 + </answer>
  11.760 +
  11.761 +
  11.762 +
  11.763 +<!--
  11.764 +        <question id="lookup-register" when="final">
  11.765 +            Do you register anything into lookup for other code to find?
  11.766 +            <hint>
  11.767 +            Do you register using layer file or using a declarative annotation such as <code>@ServiceProvider</code>?
  11.768 +            Who is supposed to find your component?
  11.769 +            </hint>
  11.770 +        </question>
  11.771 +-->
  11.772 + <answer id="lookup-register">
  11.773 +  <p>
  11.774 +   XXX no answer for lookup-register
  11.775 +  </p>
  11.776 + </answer>
  11.777 +
  11.778 +
  11.779 +
  11.780 +<!--
  11.781 +        <question id="lookup-remove" when="final">
  11.782 +            Do you remove entries of other modules from lookup?
  11.783 +            <hint>
  11.784 +            Why? Of course, that is possible, but it can be dangerous. Is the module
  11.785 +            your are masking resource from aware of what you are doing?
  11.786 +            </hint>
  11.787 +        </question>
  11.788 +-->
  11.789 + <answer id="lookup-remove">
  11.790 +  <p>
  11.791 +   XXX no answer for lookup-remove
  11.792 +  </p>
  11.793 + </answer>
  11.794 +
  11.795 +
  11.796 +
  11.797 +<!--
  11.798 +        <question id="perf-exit" when="final">
  11.799 +            Does your module run any code on exit?
  11.800 +        </question>
  11.801 +-->
  11.802 + <answer id="perf-exit">
  11.803 +  <p>
  11.804 +   XXX no answer for perf-exit
  11.805 +  </p>
  11.806 + </answer>
  11.807 +
  11.808 +
  11.809 +
  11.810 +<!--
  11.811 +        <question id="perf-huge_dialogs" when="final">
  11.812 +            Does your module contain any dialogs or wizards with a large number of
  11.813 +            GUI controls such as combo boxes, lists, trees, or text areas?
  11.814 +        </question>
  11.815 +-->
  11.816 + <answer id="perf-huge_dialogs">
  11.817 +  <p>
  11.818 +   XXX no answer for perf-huge_dialogs
  11.819 +  </p>
  11.820 + </answer>
  11.821 +
  11.822 +
  11.823 +
  11.824 +<!--
  11.825 +        <question id="perf-limit" when="init">
  11.826 +            Are there any hard-coded or practical limits in the number or size of
  11.827 +            elements your code can handle?
  11.828 +            <hint>
  11.829 +                Most of algorithms have increasing memory and speed complexity
  11.830 +                with respect to size of data they operate on. What is the critical
  11.831 +                part of your project that can be seen as a bottleneck with
  11.832 +                respect to speed or required memory? What are the practical
  11.833 +                sizes of data you tested your project with? What is your estimate
  11.834 +                of potential size of data that would cause visible performance
  11.835 +                problems? Is there some kind of check to detect such situation
  11.836 +                and prevent "hard" crashes - for example the CloneableEditorSupport
  11.837 +                checks for size of a file to be opened in editor
  11.838 +                and if it is larger than 1Mb it shows a dialog giving the
  11.839 +                user the right to decide - e.g. to cancel or commit suicide.
  11.840 +            </hint>
  11.841 +        </question>
  11.842 +-->
  11.843 + <answer id="perf-limit">
  11.844 +  <p>
  11.845 +   XXX no answer for perf-limit
  11.846 +  </p>
  11.847 + </answer>
  11.848 +
  11.849 +
  11.850 +
  11.851 +<!--
  11.852 +        <question id="perf-mem" when="final">
  11.853 +            How much memory does your component consume? Estimate
  11.854 +            with a relation to the number of windows, etc.
  11.855 +        </question>
  11.856 +-->
  11.857 + <answer id="perf-mem">
  11.858 +  <p>
  11.859 +   XXX no answer for perf-mem
  11.860 +  </p>
  11.861 + </answer>
  11.862 +
  11.863 +
  11.864 +
  11.865 +<!--
  11.866 +        <question id="perf-menus" when="final">
  11.867 +            Does your module use dynamically updated context menus, or
  11.868 +            context-sensitive actions with complicated and slow enablement logic?
  11.869 +            <hint>
  11.870 +                If you do a lot of tricks when adding actions to regular or context menus, you can significantly
  11.871 +                slow down display of the menu, even when the user is not using your action. Pay attention to
  11.872 +                actions you add to the main menu bar, and to context menus of foreign nodes or components. If
  11.873 +                the action is conditionally enabled, or changes its display dynamically, you need to check the
  11.874 +                impact on performance. In some cases it may be more appropriate to make a simple action that is
  11.875 +                always enabled but does more detailed checks in a dialog if it is actually run.
  11.876 +            </hint>
  11.877 +        </question>
  11.878 +-->
  11.879 + <answer id="perf-menus">
  11.880 +  <p>
  11.881 +   XXX no answer for perf-menus
  11.882 +  </p>
  11.883 + </answer>
  11.884 +
  11.885 +
  11.886 +
  11.887 +<!--
  11.888 +        <question id="perf-progress" when="final">
  11.889 +            Does your module execute any long-running tasks?
  11.890 +            
  11.891 +            <hint>Long running tasks should never block 
  11.892 +            AWT thread as it badly hurts the UI
  11.893 +            <a href="http://performance.netbeans.org/responsiveness/issues.html">
  11.894 +            responsiveness</a>.
  11.895 +            Tasks like connecting over
  11.896 +            network, computing huge amount of data, compilation
  11.897 +            be done asynchronously (for example
  11.898 +            using <code>RequestProcessor</code>), definitively it should 
  11.899 +            not block AWT thread.
  11.900 +            </hint>
  11.901 +        </question>
  11.902 +-->
  11.903 + <answer id="perf-progress">
  11.904 +  <p>
  11.905 +   XXX no answer for perf-progress
  11.906 +  </p>
  11.907 + </answer>
  11.908 +
  11.909 +
  11.910 +
  11.911 +<!--
  11.912 +        <question id="perf-scale" when="init">
  11.913 +            Which external criteria influence the performance of your
  11.914 +            program (size of file in editor, number of files in menu, 
  11.915 +            in source directory, etc.) and how well your code scales?
  11.916 +            <hint>
  11.917 +            Please include some estimates, there are other more detailed 
  11.918 +            questions to answer in later phases of implementation. 
  11.919 +            </hint>
  11.920 +        </question>
  11.921 +-->
  11.922 + <answer id="perf-scale">
  11.923 +  <p>
  11.924 +   XXX no answer for perf-scale
  11.925 +  </p>
  11.926 + </answer>
  11.927 +
  11.928 +
  11.929 +
  11.930 +<!--
  11.931 +        <question id="perf-spi" when="init">
  11.932 +            How the performance of the plugged in code will be enforced?
  11.933 +            <hint>
  11.934 +            If you allow foreign code to be plugged into your own module, how
  11.935 +            do you enforce that it will behave correctly and quickly and will not
  11.936 +            negatively influence the performance of your own module?
  11.937 +            </hint>
  11.938 +        </question>
  11.939 +-->
  11.940 + <answer id="perf-spi">
  11.941 +  <p>
  11.942 +   XXX no answer for perf-spi
  11.943 +  </p>
  11.944 + </answer>
  11.945 +
  11.946 +
  11.947 +
  11.948 +<!--
  11.949 +        <question id="perf-startup" when="final">
  11.950 +            Does your module run any code on startup?
  11.951 +        </question>
  11.952 +-->
  11.953 + <answer id="perf-startup">
  11.954 +  <p>
  11.955 +   XXX no answer for perf-startup
  11.956 +  </p>
  11.957 + </answer>
  11.958 +
  11.959 +
  11.960 +
  11.961 +<!--
  11.962 +        <question id="perf-wakeup" when="final">
  11.963 +            Does any piece of your code wake up periodically and do something
  11.964 +            even when the system is otherwise idle (no user interaction)?
  11.965 +        </question>
  11.966 +-->
  11.967 + <answer id="perf-wakeup">
  11.968 +  <p>
  11.969 +   XXX no answer for perf-wakeup
  11.970 +  </p>
  11.971 + </answer>
  11.972 +
  11.973 +
  11.974 +
  11.975 +<!--
  11.976 +        <question id="resources-file" when="final">
  11.977 +            Does your module use <code>java.io.File</code> directly?
  11.978 +            
  11.979 +            <hint>
  11.980 +            NetBeans provide a logical wrapper over plain files called 
  11.981 +            <code>org.openide.filesystems.FileObject</code> that
  11.982 +            provides uniform access to such resources and is the preferred
  11.983 +            way that should be used. But of course there can be situations when
  11.984 +            this is not suitable.
  11.985 +            </hint>
  11.986 +        </question>
  11.987 +-->
  11.988 + <answer id="resources-file">
  11.989 +  <p>
  11.990 +   XXX no answer for resources-file
  11.991 +  </p>
  11.992 + </answer>
  11.993 +
  11.994 +
  11.995 +
  11.996 +<!--
  11.997 +        <question id="resources-layer" when="final">
  11.998 +            Does your module provide own layer? Does it create any files or
  11.999 +            folders in it? What it is trying to communicate by that and with which 
 11.1000 +            components?
 11.1001 +            
 11.1002 +            <hint>
 11.1003 +            NetBeans allows automatic and declarative installation of resources 
 11.1004 +            by module layers. Module register files into appropriate places
 11.1005 +            and other components use that information to perform their task
 11.1006 +            (build menu, toolbar, window layout, list of templates, set of
 11.1007 +            options, etc.). 
 11.1008 +            </hint>
 11.1009 +        </question>
 11.1010 +-->
 11.1011 + <answer id="resources-layer">
 11.1012 +  <p>
 11.1013 +   XXX no answer for resources-layer
 11.1014 +  </p>
 11.1015 + </answer>
 11.1016 +
 11.1017 +
 11.1018 +
 11.1019 +<!--
 11.1020 +        <question id="resources-mask" when="final">
 11.1021 +            Does your module mask/hide/override any resources provided by other modules in
 11.1022 +            their layers?
 11.1023 +            
 11.1024 +            <hint>
 11.1025 +            If you mask a file provided by another module, you probably depend
 11.1026 +            on that and do not want the other module to (for example) change
 11.1027 +            the file's name. That module shall thus make that file available as an API
 11.1028 +            of some stability category.
 11.1029 +            </hint>
 11.1030 +        </question>
 11.1031 +-->
 11.1032 + <answer id="resources-mask">
 11.1033 +  <p>
 11.1034 +   XXX no answer for resources-mask
 11.1035 +  </p>
 11.1036 + </answer>
 11.1037 +
 11.1038 +
 11.1039 +
 11.1040 +<!--
 11.1041 +        <question id="resources-preferences" when="final">
 11.1042 +            Does your module uses preferences via Preferences API? Does your module use NbPreferences or
 11.1043 +            or regular JDK Preferences ? Does it read, write or both ? 
 11.1044 +            Does it share preferences with other modules ? If so, then why ?
 11.1045 +            <hint>
 11.1046 +                You may use
 11.1047 +                    &lt;api type="export" group="preferences"
 11.1048 +                    name="preference node name" category="private"&gt;
 11.1049 +                    description of individual keys, where it is used, what it
 11.1050 +                    influences, whether the module reads/write it, etc.
 11.1051 +                    &lt;/api&gt;
 11.1052 +                Due to XML ID restrictions, rather than /org/netbeans/modules/foo give the "name" as org.netbeans.modules.foo.
 11.1053 +                Note that if you use NbPreferences this name will then be the same as the code name base of the module.
 11.1054 +            </hint>
 11.1055 +        </question>
 11.1056 +-->
 11.1057 + <answer id="resources-preferences">
 11.1058 +  <p>
 11.1059 +   XXX no answer for resources-preferences
 11.1060 +  </p>
 11.1061 + </answer>
 11.1062 +
 11.1063 +
 11.1064 +
 11.1065 +<!--
 11.1066 +        <question id="resources-read" when="final">
 11.1067 +            Does your module read any resources from layers? For what purpose?
 11.1068 +            
 11.1069 +            <hint>
 11.1070 +            As this is some kind of intermodule dependency, it is a kind of API.
 11.1071 +            Please describe it and classify according to 
 11.1072 +            <a href="http://openide.netbeans.org/tutorial/api-design.html#categories">
 11.1073 +            common stability categories</a>.
 11.1074 +            </hint>
 11.1075 +        </question>
 11.1076 +-->
 11.1077 + <answer id="resources-read">
 11.1078 +  <p>
 11.1079 +   XXX no answer for resources-read
 11.1080 +  </p>
 11.1081 + </answer>
 11.1082 +
 11.1083 +
 11.1084 +
 11.1085 +<!--
 11.1086 +        <question id="security-grant" when="final">
 11.1087 +            Does your code grant additional rights to some other code?
 11.1088 +            <hint>Avoid using a class loader that adds extra
 11.1089 +            permissions to loaded code unless really necessary.
 11.1090 +            Also note that your API implementation
 11.1091 +            can also expose unneeded permissions to enemy code by
 11.1092 +            calling AccessController.doPrivileged().</hint>
 11.1093 +        </question>
 11.1094 +-->
 11.1095 + <answer id="security-grant">
 11.1096 +  <p>
 11.1097 +   XXX no answer for security-grant
 11.1098 +  </p>
 11.1099 + </answer>
 11.1100 +
 11.1101 +
 11.1102 +
 11.1103 +<!--
 11.1104 +        <question id="security-policy" when="final">
 11.1105 +            Does your functionality require modifications to the standard policy file?
 11.1106 +            <hint>Your code might pass control to third-party code not
 11.1107 +            coming from trusted domains. This could be code downloaded over the
 11.1108 +            network or code coming from libraries that are not bundled
 11.1109 +            with NetBeans. Which permissions need to be granted to which domains?</hint>
 11.1110 +        </question>
 11.1111 +-->
 11.1112 + <answer id="security-policy">
 11.1113 +  <p>
 11.1114 +   XXX no answer for security-policy
 11.1115 +  </p>
 11.1116 + </answer>
 11.1117 +
 11.1118 +</api-answers>
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/java.hints/spi.java.hints/build.xml	Wed May 08 21:47:42 2013 +0200
    12.3 @@ -0,0 +1,8 @@
    12.4 +<?xml version="1.0" encoding="UTF-8"?>
    12.5 +<!-- You may freely edit this file. See harness/README in the NetBeans platform -->
    12.6 +<!-- for some information on what you could do (e.g. targets to override). -->
    12.7 +<!-- If you delete this file and reopen the project it will be recreated. -->
    12.8 +<project name="org.netbeans.spi.java.hints" default="netbeans" basedir=".">
    12.9 +    <description>Builds, tests, and runs the project org.netbeans.spi.java.hints.</description>
   12.10 +    <import file="nbproject/build-impl.xml"/>
   12.11 +</project>
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/java.hints/spi.java.hints/manifest.mf	Wed May 08 21:47:42 2013 +0200
    13.3 @@ -0,0 +1,5 @@
    13.4 +Manifest-Version: 1.0
    13.5 +OpenIDE-Module: org.netbeans.spi.java.hints
    13.6 +OpenIDE-Module-Implementation-Version: 11
    13.7 +OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/java/hints/spiimpl/Bundle.properties
    13.8 +
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/java.hints/spi.java.hints/nbproject/build-impl.xml	Wed May 08 21:47:42 2013 +0200
    14.3 @@ -0,0 +1,45 @@
    14.4 +<?xml version="1.0" encoding="UTF-8"?>
    14.5 +<!--
    14.6 +*** GENERATED FROM project.xml - DO NOT EDIT  ***
    14.7 +***         EDIT ../build.xml INSTEAD         ***
    14.8 +-->
    14.9 +<project name="org.netbeans.spi.java.hints-impl" basedir="..">
   14.10 +    <fail message="Please build using Ant 1.7.1 or higher.">
   14.11 +        <condition>
   14.12 +            <not>
   14.13 +                <antversion atleast="1.7.1"/>
   14.14 +            </not>
   14.15 +        </condition>
   14.16 +    </fail>
   14.17 +    <property file="nbproject/private/suite-private.properties"/>
   14.18 +    <property file="nbproject/suite.properties"/>
   14.19 +    <fail unless="suite.dir">You must set 'suite.dir' to point to your containing module suite</fail>
   14.20 +    <property file="${suite.dir}/nbproject/private/platform-private.properties"/>
   14.21 +    <property file="${suite.dir}/nbproject/platform.properties"/>
   14.22 +    <macrodef name="property" uri="http://www.netbeans.org/ns/nb-module-project/2">
   14.23 +        <attribute name="name"/>
   14.24 +        <attribute name="value"/>
   14.25 +        <sequential>
   14.26 +            <property name="@{name}" value="${@{value}}"/>
   14.27 +        </sequential>
   14.28 +    </macrodef>
   14.29 +    <macrodef name="evalprops" uri="http://www.netbeans.org/ns/nb-module-project/2">
   14.30 +        <attribute name="property"/>
   14.31 +        <attribute name="value"/>
   14.32 +        <sequential>
   14.33 +            <property name="@{property}" value="@{value}"/>
   14.34 +        </sequential>
   14.35 +    </macrodef>
   14.36 +    <property file="${user.properties.file}"/>
   14.37 +    <nbmproject2:property name="harness.dir" value="nbplatform.${nbplatform.active}.harness.dir" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
   14.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"/>
   14.39 +    <nbmproject2:evalprops property="cluster.path.evaluated" value="${cluster.path}" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
   14.40 +    <fail message="Path to 'platform' cluster missing in $${cluster.path} property or using corrupt Netbeans Platform (missing harness).">
   14.41 +        <condition>
   14.42 +            <not>
   14.43 +                <contains string="${cluster.path.evaluated}" substring="platform"/>
   14.44 +            </not>
   14.45 +        </condition>
   14.46 +    </fail>
   14.47 +    <import file="${harness.dir}/build.xml"/>
   14.48 +</project>
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/java.hints/spi.java.hints/nbproject/genfiles.properties	Wed May 08 21:47:42 2013 +0200
    15.3 @@ -0,0 +1,8 @@
    15.4 +build.xml.data.CRC32=81a58345
    15.5 +build.xml.script.CRC32=caab83d9
    15.6 +build.xml.stylesheet.CRC32=a56c6a5b@2.58
    15.7 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
    15.8 +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
    15.9 +nbproject/build-impl.xml.data.CRC32=81a58345
   15.10 +nbproject/build-impl.xml.script.CRC32=7438bc77
   15.11 +nbproject/build-impl.xml.stylesheet.CRC32=238281d1@2.58
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/java.hints/spi.java.hints/nbproject/org-netbeans-spi-java-hints.sig	Wed May 08 21:47:42 2013 +0200
    16.3 @@ -0,0 +1,276 @@
    16.4 +#Signature file v4.1
    16.5 +#Version 1.10.1
    16.6 +
    16.7 +CLSS public abstract interface java.io.Serializable
    16.8 +
    16.9 +CLSS public abstract interface java.lang.Comparable<%0 extends java.lang.Object>
   16.10 +meth public abstract int compareTo({java.lang.Comparable%0})
   16.11 +
   16.12 +CLSS public abstract java.lang.Enum<%0 extends java.lang.Enum<{java.lang.Enum%0}>>
   16.13 +cons protected init(java.lang.String,int)
   16.14 +intf java.io.Serializable
   16.15 +intf java.lang.Comparable<{java.lang.Enum%0}>
   16.16 +meth protected final java.lang.Object clone() throws java.lang.CloneNotSupportedException
   16.17 +meth protected final void finalize()
   16.18 +meth public final boolean equals(java.lang.Object)
   16.19 +meth public final int compareTo({java.lang.Enum%0})
   16.20 +meth public final int hashCode()
   16.21 +meth public final int ordinal()
   16.22 +meth public final java.lang.Class<{java.lang.Enum%0}> getDeclaringClass()
   16.23 +meth public final java.lang.String name()
   16.24 +meth public java.lang.String toString()
   16.25 +meth public static <%0 extends java.lang.Enum<{%%0}>> {%%0} valueOf(java.lang.Class<{%%0}>,java.lang.String)
   16.26 +supr java.lang.Object
   16.27 +hfds name,ordinal
   16.28 +
   16.29 +CLSS public java.lang.Object
   16.30 +cons public init()
   16.31 +meth protected java.lang.Object clone() throws java.lang.CloneNotSupportedException
   16.32 +meth protected void finalize() throws java.lang.Throwable
   16.33 +meth public boolean equals(java.lang.Object)
   16.34 +meth public final java.lang.Class<?> getClass()
   16.35 +meth public final void notify()
   16.36 +meth public final void notifyAll()
   16.37 +meth public final void wait() throws java.lang.InterruptedException
   16.38 +meth public final void wait(long) throws java.lang.InterruptedException
   16.39 +meth public final void wait(long,int) throws java.lang.InterruptedException
   16.40 +meth public int hashCode()
   16.41 +meth public java.lang.String toString()
   16.42 +
   16.43 +CLSS public abstract interface java.lang.annotation.Annotation
   16.44 +meth public abstract boolean equals(java.lang.Object)
   16.45 +meth public abstract int hashCode()
   16.46 +meth public abstract java.lang.Class<? extends java.lang.annotation.Annotation> annotationType()
   16.47 +meth public abstract java.lang.String toString()
   16.48 +
   16.49 +CLSS public abstract interface !annotation java.lang.annotation.Documented
   16.50 + anno 0 java.lang.annotation.Documented()
   16.51 + anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=RUNTIME)
   16.52 + anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[ANNOTATION_TYPE])
   16.53 +intf java.lang.annotation.Annotation
   16.54 +
   16.55 +CLSS public abstract interface !annotation java.lang.annotation.Retention
   16.56 + anno 0 java.lang.annotation.Documented()
   16.57 + anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=RUNTIME)
   16.58 + anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[ANNOTATION_TYPE])
   16.59 +intf java.lang.annotation.Annotation
   16.60 +meth public abstract java.lang.annotation.RetentionPolicy value()
   16.61 +
   16.62 +CLSS public abstract interface !annotation java.lang.annotation.Target
   16.63 + anno 0 java.lang.annotation.Documented()
   16.64 + anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=RUNTIME)
   16.65 + anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[ANNOTATION_TYPE])
   16.66 +intf java.lang.annotation.Annotation
   16.67 +meth public abstract java.lang.annotation.ElementType[] value()
   16.68 +
   16.69 +CLSS public abstract interface !annotation org.netbeans.spi.java.hints.BooleanOption
   16.70 + anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=SOURCE)
   16.71 + anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[FIELD])
   16.72 +intf java.lang.annotation.Annotation
   16.73 +meth public abstract boolean defaultValue()
   16.74 +meth public abstract java.lang.String displayName()
   16.75 +meth public abstract java.lang.String tooltip()
   16.76 +
   16.77 +CLSS public abstract interface !annotation org.netbeans.spi.java.hints.ConstraintVariableType
   16.78 + anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[])
   16.79 +intf java.lang.annotation.Annotation
   16.80 +meth public abstract java.lang.String type()
   16.81 +meth public abstract java.lang.String variable()
   16.82 +
   16.83 +CLSS public abstract interface org.netbeans.spi.java.hints.CustomizerProvider
   16.84 +meth public abstract javax.swing.JComponent getCustomizer(java.util.prefs.Preferences)
   16.85 + anno 0 org.netbeans.api.annotations.common.NonNull()
   16.86 + anno 1 org.netbeans.api.annotations.common.NonNull()
   16.87 +
   16.88 +CLSS public org.netbeans.spi.java.hints.ErrorDescriptionFactory
   16.89 +meth public !varargs static org.netbeans.spi.editor.hints.ErrorDescription forName(org.netbeans.spi.java.hints.HintContext,com.sun.source.tree.Tree,java.lang.String,org.netbeans.spi.editor.hints.Fix[])
   16.90 +meth public !varargs static org.netbeans.spi.editor.hints.ErrorDescription forName(org.netbeans.spi.java.hints.HintContext,com.sun.source.util.TreePath,java.lang.String,org.netbeans.spi.editor.hints.Fix[])
   16.91 +meth public !varargs static org.netbeans.spi.editor.hints.ErrorDescription forSpan(org.netbeans.spi.java.hints.HintContext,int,int,java.lang.String,org.netbeans.spi.editor.hints.Fix[])
   16.92 +meth public !varargs static org.netbeans.spi.editor.hints.ErrorDescription forTree(org.netbeans.spi.java.hints.HintContext,com.sun.source.tree.Tree,java.lang.String,org.netbeans.spi.editor.hints.Fix[])
   16.93 +meth public !varargs static org.netbeans.spi.editor.hints.ErrorDescription forTree(org.netbeans.spi.java.hints.HintContext,com.sun.source.util.TreePath,java.lang.String,org.netbeans.spi.editor.hints.Fix[])
   16.94 +supr java.lang.Object
   16.95 +hfds DECLARATION
   16.96 +hcls DisableConfigure,FixImpl,InspectFix,TopLevelConfigureFix
   16.97 +
   16.98 +CLSS public abstract interface !annotation org.netbeans.spi.java.hints.Hint
   16.99 + anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=SOURCE)
  16.100 + anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[TYPE, METHOD])
  16.101 +innr public final static !enum Kind
  16.102 +innr public final static !enum Options
  16.103 +intf java.lang.annotation.Annotation
  16.104 +meth public abstract !hasdefault boolean enabled()
  16.105 +meth public abstract !hasdefault java.lang.Class<? extends org.netbeans.spi.java.hints.CustomizerProvider> customizerProvider()
  16.106 +meth public abstract !hasdefault java.lang.String id()
  16.107 +meth public abstract !hasdefault java.lang.String[] suppressWarnings()
  16.108 +meth public abstract !hasdefault org.netbeans.spi.editor.hints.Severity severity()
  16.109 +meth public abstract !hasdefault org.netbeans.spi.java.hints.Hint$Kind hintKind()
  16.110 +meth public abstract !hasdefault org.netbeans.spi.java.hints.Hint$Options[] options()
  16.111 +meth public abstract java.lang.String category()
  16.112 +meth public abstract java.lang.String description()
  16.113 +meth public abstract java.lang.String displayName()
  16.114 +
  16.115 +CLSS public final static !enum org.netbeans.spi.java.hints.Hint$Kind
  16.116 + outer org.netbeans.spi.java.hints.Hint
  16.117 +fld public final static org.netbeans.spi.java.hints.Hint$Kind ACTION
  16.118 +fld public final static org.netbeans.spi.java.hints.Hint$Kind INSPECTION
  16.119 +meth public static org.netbeans.spi.java.hints.Hint$Kind valueOf(java.lang.String)
  16.120 +meth public static org.netbeans.spi.java.hints.Hint$Kind[] values()
  16.121 +supr java.lang.Enum<org.netbeans.spi.java.hints.Hint$Kind>
  16.122 +
  16.123 +CLSS public final static !enum org.netbeans.spi.java.hints.Hint$Options
  16.124 + outer org.netbeans.spi.java.hints.Hint
  16.125 +fld public final static org.netbeans.spi.java.hints.Hint$Options NO_BATCH
  16.126 +fld public final static org.netbeans.spi.java.hints.Hint$Options QUERY
  16.127 +meth public static org.netbeans.spi.java.hints.Hint$Options valueOf(java.lang.String)
  16.128 +meth public static org.netbeans.spi.java.hints.Hint$Options[] values()
  16.129 +supr java.lang.Enum<org.netbeans.spi.java.hints.Hint$Options>
  16.130 +
  16.131 +CLSS public org.netbeans.spi.java.hints.HintContext
  16.132 +innr public final static !enum MessageKind
  16.133 +meth public boolean isBulkMode()
  16.134 +meth public boolean isCanceled()
  16.135 +meth public com.sun.source.util.TreePath getPath()
  16.136 +meth public int getCaretLocation()
  16.137 +meth public java.util.Map<java.lang.String,com.sun.source.util.TreePath> getVariables()
  16.138 +meth public java.util.Map<java.lang.String,java.lang.String> getVariableNames()
  16.139 +meth public java.util.Map<java.lang.String,java.util.Collection<? extends com.sun.source.util.TreePath>> getMultiVariables()
  16.140 +meth public java.util.Map<java.lang.String,javax.lang.model.type.TypeMirror> getConstraints()
  16.141 +meth public java.util.prefs.Preferences getPreferences()
  16.142 +meth public org.netbeans.api.java.source.CompilationInfo getInfo()
  16.143 +meth public org.netbeans.spi.editor.hints.Severity getSeverity()
  16.144 +meth public void reportMessage(org.netbeans.spi.java.hints.HintContext$MessageKind,java.lang.String)
  16.145 +supr java.lang.Object
  16.146 +hfds bulkMode,cancel,caret,constraints,info,messages,metadata,multiVariables,path,preferences,severity,variableNames,variables
  16.147 +
  16.148 +CLSS public final static !enum org.netbeans.spi.java.hints.HintContext$MessageKind
  16.149 + outer org.netbeans.spi.java.hints.HintContext
  16.150 +fld public final static org.netbeans.spi.java.hints.HintContext$MessageKind ERROR
  16.151 +fld public final static org.netbeans.spi.java.hints.HintContext$MessageKind WARNING
  16.152 +meth public static org.netbeans.spi.java.hints.HintContext$MessageKind valueOf(java.lang.String)
  16.153 +meth public static org.netbeans.spi.java.hints.HintContext$MessageKind[] values()
  16.154 +supr java.lang.Enum<org.netbeans.spi.java.hints.HintContext$MessageKind>
  16.155 +
  16.156 +CLSS public final !enum org.netbeans.spi.java.hints.HintSeverity
  16.157 +fld public final static org.netbeans.spi.java.hints.HintSeverity CURRENT_LINE_WARNING
  16.158 +fld public final static org.netbeans.spi.java.hints.HintSeverity ERROR
  16.159 +fld public final static org.netbeans.spi.java.hints.HintSeverity WARNING
  16.160 +meth public org.netbeans.spi.editor.hints.Severity toEditorSeverity()
  16.161 +meth public static org.netbeans.spi.java.hints.HintSeverity valueOf(java.lang.String)
  16.162 +meth public static org.netbeans.spi.java.hints.HintSeverity[] values()
  16.163 +supr java.lang.Enum<org.netbeans.spi.java.hints.HintSeverity>
  16.164 +
  16.165 +CLSS public abstract org.netbeans.spi.java.hints.JavaFix
  16.166 +cons protected init(org.netbeans.api.java.source.CompilationInfo,com.sun.source.util.TreePath)
  16.167 + anno 1 org.netbeans.api.annotations.common.NonNull()
  16.168 + anno 2 org.netbeans.api.annotations.common.NonNull()
  16.169 +cons protected init(org.netbeans.api.java.source.TreePathHandle)
  16.170 + anno 1 org.netbeans.api.annotations.common.NonNull()
  16.171 +innr public final static TransformationContext
  16.172 +meth protected abstract java.lang.String getText()
  16.173 + anno 0 org.netbeans.api.annotations.common.NonNull()
  16.174 +meth protected abstract void performRewrite(org.netbeans.spi.java.hints.JavaFix$TransformationContext) throws java.lang.Exception
  16.175 + anno 1 org.netbeans.api.annotations.common.NonNull()
  16.176 +meth public final org.netbeans.spi.editor.hints.Fix toEditorFix()
  16.177 +supr java.lang.Object
  16.178 +hfds LOG,handle,options
  16.179 +
  16.180 +CLSS public final static org.netbeans.spi.java.hints.JavaFix$TransformationContext
  16.181 + outer org.netbeans.spi.java.hints.JavaFix
  16.182 +meth public com.sun.source.util.TreePath getPath()
  16.183 + anno 0 org.netbeans.api.annotations.common.NonNull()
  16.184 +meth public java.io.InputStream getResourceContent(org.openide.filesystems.FileObject) throws java.io.IOException
  16.185 + anno 0 org.netbeans.api.annotations.common.NonNull()
  16.186 + anno 1 org.netbeans.api.annotations.common.NonNull()
  16.187 +meth public java.io.OutputStream getResourceOutput(org.openide.filesystems.FileObject) throws java.io.IOException
  16.188 + anno 0 org.netbeans.api.annotations.common.NonNull()
  16.189 + anno 1 org.netbeans.api.annotations.common.NonNull()
  16.190 +meth public org.netbeans.api.java.source.WorkingCopy getWorkingCopy()
  16.191 + anno 0 org.netbeans.api.annotations.common.NonNull()
  16.192 +supr java.lang.Object
  16.193 +hfds canShowUI,fileChanges,path,resourceContentChanges,workingCopy
  16.194 +
  16.195 +CLSS public org.netbeans.spi.java.hints.JavaFixUtilities
  16.196 +cons public init()
  16.197 +meth public static boolean requiresParenthesis(com.sun.source.tree.Tree,com.sun.source.tree.Tree,com.sun.source.tree.Tree)
  16.198 +meth public static org.netbeans.spi.editor.hints.Fix removeFromParent(org.netbeans.spi.java.hints.HintContext,java.lang.String,com.sun.source.util.TreePath)
  16.199 +meth public static org.netbeans.spi.editor.hints.Fix rewriteFix(org.netbeans.spi.java.hints.HintContext,java.lang.String,com.sun.source.util.TreePath,java.lang.String)
  16.200 +supr java.lang.Object
  16.201 +hfds NUMBER_LITERAL_KINDS,OPERATOR_PRIORITIES,SPEC_VERSION
  16.202 +hcls JavaFixRealImpl,MoveFile,RemoveFromParent,ReplaceParameters
  16.203 +
  16.204 +CLSS public org.netbeans.spi.java.hints.MatcherUtilities
  16.205 +cons public init()
  16.206 +meth public static boolean matches(org.netbeans.spi.java.hints.HintContext,com.sun.source.util.TreePath,java.lang.String)
  16.207 + anno 1 org.netbeans.api.annotations.common.NonNull()
  16.208 + anno 2 org.netbeans.api.annotations.common.NonNull()
  16.209 + anno 3 org.netbeans.api.annotations.common.NonNull()
  16.210 +meth public static boolean matches(org.netbeans.spi.java.hints.HintContext,com.sun.source.util.TreePath,java.lang.String,boolean)
  16.211 + anno 1 org.netbeans.api.annotations.common.NonNull()
  16.212 + anno 2 org.netbeans.api.annotations.common.NonNull()
  16.213 + anno 3 org.netbeans.api.annotations.common.NonNull()
  16.214 +meth public static boolean matches(org.netbeans.spi.java.hints.HintContext,com.sun.source.util.TreePath,java.lang.String,java.util.Map<java.lang.String,com.sun.source.util.TreePath>,java.util.Map<java.lang.String,java.util.Collection<? extends com.sun.source.util.TreePath>>,java.util.Map<java.lang.String,java.lang.String>)
  16.215 + anno 1 org.netbeans.api.annotations.common.NonNull()
  16.216 + anno 2 org.netbeans.api.annotations.common.NonNull()
  16.217 + anno 3 org.netbeans.api.annotations.common.NonNull()
  16.218 +meth public static boolean matches(org.netbeans.spi.java.hints.HintContext,java.util.Collection<? extends com.sun.source.util.TreePath>,java.lang.String,java.util.Map<java.lang.String,com.sun.source.util.TreePath>,java.util.Map<java.lang.String,java.util.Collection<? extends com.sun.source.util.TreePath>>,java.util.Map<java.lang.String,java.lang.String>)
  16.219 + anno 1 org.netbeans.api.annotations.common.NonNull()
  16.220 + anno 2 org.netbeans.api.annotations.common.NonNull()
  16.221 + anno 3 org.netbeans.api.annotations.common.NonNull()
  16.222 +supr java.lang.Object
  16.223 +
  16.224 +CLSS public abstract interface !annotation org.netbeans.spi.java.hints.TriggerPattern
  16.225 + anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=SOURCE)
  16.226 + anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[METHOD])
  16.227 +intf java.lang.annotation.Annotation
  16.228 +meth public abstract !hasdefault org.netbeans.spi.java.hints.ConstraintVariableType[] constraints()
  16.229 +meth public abstract java.lang.String value()
  16.230 +
  16.231 +CLSS public abstract interface !annotation org.netbeans.spi.java.hints.TriggerPatterns
  16.232 + anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=SOURCE)
  16.233 + anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[METHOD])
  16.234 +intf java.lang.annotation.Annotation
  16.235 +meth public abstract org.netbeans.spi.java.hints.TriggerPattern[] value()
  16.236 +
  16.237 +CLSS public abstract interface !annotation org.netbeans.spi.java.hints.TriggerTreeKind
  16.238 + anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=SOURCE)
  16.239 + anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[METHOD])
  16.240 +intf java.lang.annotation.Annotation
  16.241 +meth public abstract com.sun.source.tree.Tree$Kind[] value()
  16.242 +
  16.243 +CLSS public abstract interface !annotation org.netbeans.spi.java.hints.UseOptions
  16.244 + anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=SOURCE)
  16.245 + anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[METHOD])
  16.246 +intf java.lang.annotation.Annotation
  16.247 +meth public abstract java.lang.String[] value()
  16.248 +
  16.249 +CLSS public final org.netbeans.spi.java.hints.support.FixFactory
  16.250 +meth public final static org.netbeans.spi.editor.hints.Fix addModifiersFix(org.netbeans.api.java.source.CompilationInfo,com.sun.source.util.TreePath,java.util.Set<javax.lang.model.element.Modifier>,java.lang.String)
  16.251 +meth public final static org.netbeans.spi.editor.hints.Fix changeModifiersFix(org.netbeans.api.java.source.CompilationInfo,com.sun.source.util.TreePath,java.util.Set<javax.lang.model.element.Modifier>,java.util.Set<javax.lang.model.element.Modifier>,java.lang.String)
  16.252 +meth public final static org.netbeans.spi.editor.hints.Fix removeModifiersFix(org.netbeans.api.java.source.CompilationInfo,com.sun.source.util.TreePath,java.util.Set<javax.lang.model.element.Modifier>,java.lang.String)
  16.253 +supr java.lang.Object
  16.254 +hcls ChangeModifiersFixImpl
  16.255 +
  16.256 +CLSS public final org.netbeans.spi.java.hints.support.TransformationSupport
  16.257 +innr public abstract interface static Transformer
  16.258 +meth public java.util.Collection<? extends org.netbeans.api.java.source.ModificationResult> processAllProjects()
  16.259 + anno 0 org.netbeans.api.annotations.common.NonNull()
  16.260 +meth public org.netbeans.spi.java.hints.support.TransformationSupport setCancel(java.util.concurrent.atomic.AtomicBoolean)
  16.261 + anno 0 org.netbeans.api.annotations.common.NonNull()
  16.262 + anno 1 org.netbeans.api.annotations.common.NonNull()
  16.263 +meth public static org.netbeans.spi.java.hints.support.TransformationSupport create(java.lang.String)
  16.264 + anno 0 org.netbeans.api.annotations.common.NonNull()
  16.265 + anno 1 org.netbeans.api.annotations.common.NonNull()
  16.266 +meth public static org.netbeans.spi.java.hints.support.TransformationSupport create(java.lang.String,org.netbeans.spi.java.hints.support.TransformationSupport$Transformer)
  16.267 + anno 0 org.netbeans.api.annotations.common.NonNull()
  16.268 + anno 1 org.netbeans.api.annotations.common.NonNull()
  16.269 + anno 2 org.netbeans.api.annotations.common.NonNull()
  16.270 +meth public void transformTreePath(org.netbeans.api.java.source.WorkingCopy,com.sun.source.util.TreePath)
  16.271 + anno 1 org.netbeans.api.annotations.common.NonNull()
  16.272 + anno 2 org.netbeans.api.annotations.common.NonNull()
  16.273 +supr java.lang.Object
  16.274 +hfds cancel,jackpotPattern,transformer
  16.275 +
  16.276 +CLSS public abstract interface static org.netbeans.spi.java.hints.support.TransformationSupport$Transformer
  16.277 + outer org.netbeans.spi.java.hints.support.TransformationSupport
  16.278 +meth public abstract void transform(org.netbeans.api.java.source.WorkingCopy,org.netbeans.api.java.source.matching.Occurrence)
  16.279 +
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/java.hints/spi.java.hints/nbproject/project.properties	Wed May 08 21:47:42 2013 +0200
    17.3 @@ -0,0 +1,7 @@
    17.4 +is.autoload=true
    17.5 +javac.source=1.7
    17.6 +javac.compilerargs=-Xlint -Xlint:-serial
    17.7 +spec.version.base=2.0.0
    17.8 +requires.nb.javac=true
    17.9 +javadoc.arch=${basedir}/arch.xml
   17.10 +javadoc.apichanges=${basedir}/apichanges.xml
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/java.hints/spi.java.hints/nbproject/project.xml	Wed May 08 21:47:42 2013 +0200
    18.3 @@ -0,0 +1,456 @@
    18.4 +<?xml version="1.0" encoding="UTF-8"?>
    18.5 +<project xmlns="http://www.netbeans.org/ns/project/1">
    18.6 +    <type>org.netbeans.modules.apisupport.project</type>
    18.7 +    <configuration>
    18.8 +        <data xmlns="http://www.netbeans.org/ns/nb-module-project/3">
    18.9 +            <code-name-base>org.netbeans.spi.java.hints</code-name-base>
   18.10 +            <suite-component/>
   18.11 +            <module-dependencies>
   18.12 +                <dependency>
   18.13 +                    <code-name-base>org.netbeans.api.annotations.common</code-name-base>
   18.14 +                    <build-prerequisite/>
   18.15 +                    <compile-dependency/>
   18.16 +                    <run-dependency>
   18.17 +                        <release-version>1</release-version>
   18.18 +                        <specification-version>1.4</specification-version>
   18.19 +                    </run-dependency>
   18.20 +                </dependency>
   18.21 +                <dependency>
   18.22 +                    <code-name-base>org.netbeans.api.java</code-name-base>
   18.23 +                    <build-prerequisite/>
   18.24 +                    <compile-dependency/>
   18.25 +                    <run-dependency>
   18.26 +                        <release-version>1</release-version>
   18.27 +                        <specification-version>1.18</specification-version>
   18.28 +                    </run-dependency>
   18.29 +                </dependency>
   18.30 +                <dependency>
   18.31 +                    <code-name-base>org.netbeans.api.java.classpath</code-name-base>
   18.32 +                    <build-prerequisite/>
   18.33 +                    <compile-dependency/>
   18.34 +                    <run-dependency>
   18.35 +                        <release-version>1</release-version>
   18.36 +                        <specification-version>1.24</specification-version>
   18.37 +                    </run-dependency>
   18.38 +                </dependency>
   18.39 +                <dependency>
   18.40 +                    <code-name-base>org.netbeans.api.progress</code-name-base>
   18.41 +                    <build-prerequisite/>
   18.42 +                    <compile-dependency/>
   18.43 +                    <run-dependency>
   18.44 +                        <release-version>1</release-version>
   18.45 +                        <specification-version>1.16</specification-version>
   18.46 +                    </run-dependency>
   18.47 +                </dependency>
   18.48 +                <dependency>
   18.49 +                    <code-name-base>org.netbeans.lib.nbjavac</code-name-base>
   18.50 +                    <build-prerequisite/>
   18.51 +                    <compile-dependency/>
   18.52 +                    <run-dependency>
   18.53 +                        <implementation-version/>
   18.54 +                    </run-dependency>
   18.55 +                </dependency>
   18.56 +                <dependency>
   18.57 +                    <code-name-base>org.netbeans.libs.javacapi</code-name-base>
   18.58 +                    <build-prerequisite/>
   18.59 +                    <compile-dependency/>
   18.60 +                    <run-dependency>
   18.61 +                        <specification-version>8.0</specification-version>
   18.62 +                    </run-dependency>
   18.63 +                </dependency>
   18.64 +                <dependency>
   18.65 +                    <code-name-base>org.netbeans.libs.javacimpl</code-name-base>
   18.66 +                    <build-prerequisite/>
   18.67 +                    <compile-dependency/>
   18.68 +                    <run-dependency>
   18.69 +                        <release-version>1</release-version>
   18.70 +                        <implementation-version/>
   18.71 +                    </run-dependency>
   18.72 +                </dependency>
   18.73 +                <dependency>
   18.74 +                    <code-name-base>org.netbeans.libs.lucene</code-name-base>
   18.75 +                    <build-prerequisite/>
   18.76 +                    <compile-dependency/>
   18.77 +                    <run-dependency>
   18.78 +                        <release-version>3</release-version>
   18.79 +                        <specification-version>3.0</specification-version>
   18.80 +                    </run-dependency>
   18.81 +                </dependency>
   18.82 +                <dependency>
   18.83 +                    <code-name-base>org.netbeans.modules.code.analysis</code-name-base>
   18.84 +                    <build-prerequisite/>
   18.85 +                    <compile-dependency/>
   18.86 +                    <run-dependency>
   18.87 +                        <release-version>0</release-version>
   18.88 +                        <specification-version>1.8</specification-version>
   18.89 +                    </run-dependency>
   18.90 +                </dependency>
   18.91 +                <dependency>
   18.92 +                    <code-name-base>org.netbeans.modules.editor</code-name-base>
   18.93 +                    <build-prerequisite/>
   18.94 +                    <compile-dependency/>
   18.95 +                    <run-dependency>
   18.96 +                        <release-version>3</release-version>
   18.97 +                        <specification-version>1.53</specification-version>
   18.98 +                    </run-dependency>
   18.99 +                </dependency>
  18.100 +                <dependency>
  18.101 +                    <code-name-base>org.netbeans.modules.editor.errorstripe.api</code-name-base>
  18.102 +                    <build-prerequisite/>
  18.103 +                    <compile-dependency/>
  18.104 +                    <run-dependency>
  18.105 +                        <release-version>1</release-version>
  18.106 +                        <specification-version>2.3</specification-version>
  18.107 +                    </run-dependency>
  18.108 +                </dependency>
  18.109 +                <dependency>
  18.110 +                    <code-name-base>org.netbeans.modules.editor.lib</code-name-base>
  18.111 +                    <build-prerequisite/>
  18.112 +                    <compile-dependency/>
  18.113 +                    <run-dependency>
  18.114 +                        <release-version>3</release-version>
  18.115 +                        <specification-version>3.1</specification-version>
  18.116 +                    </run-dependency>
  18.117 +                </dependency>
  18.118 +                <dependency>
  18.119 +                    <code-name-base>org.netbeans.modules.editor.lib2</code-name-base>
  18.120 +                    <build-prerequisite/>
  18.121 +                    <compile-dependency/>
  18.122 +                    <run-dependency>
  18.123 +                        <release-version>1</release-version>
  18.124 +                        <specification-version>1.8</specification-version>
  18.125 +                    </run-dependency>
  18.126 +                </dependency>
  18.127 +                <dependency>
  18.128 +                    <code-name-base>org.netbeans.modules.editor.mimelookup</code-name-base>
  18.129 +                    <build-prerequisite/>
  18.130 +                    <compile-dependency/>
  18.131 +                    <run-dependency>
  18.132 +                        <release-version>1</release-version>
  18.133 +                        <specification-version>1.15</specification-version>
  18.134 +                    </run-dependency>
  18.135 +                </dependency>
  18.136 +                <dependency>
  18.137 +                    <code-name-base>org.netbeans.modules.editor.settings</code-name-base>
  18.138 +                    <build-prerequisite/>
  18.139 +                    <compile-dependency/>
  18.140 +                    <run-dependency>
  18.141 +                        <release-version>1</release-version>
  18.142 +                        <specification-version>1.28</specification-version>
  18.143 +                    </run-dependency>
  18.144 +                </dependency>
  18.145 +                <dependency>
  18.146 +                    <code-name-base>org.netbeans.modules.editor.util</code-name-base>
  18.147 +                    <build-prerequisite/>
  18.148 +                    <compile-dependency/>
  18.149 +                    <run-dependency>
  18.150 +                        <release-version>1</release-version>
  18.151 +                        <specification-version>1.33</specification-version>
  18.152 +                    </run-dependency>
  18.153 +                </dependency>
  18.154 +                <dependency>
  18.155 +                    <code-name-base>org.netbeans.modules.java.lexer</code-name-base>
  18.156 +                    <build-prerequisite/>
  18.157 +                    <compile-dependency/>
  18.158 +                    <run-dependency>
  18.159 +                        <release-version>1</release-version>
  18.160 +                        <specification-version>1.0</specification-version>
  18.161 +                    </run-dependency>
  18.162 +                </dependency>
  18.163 +                <dependency>
  18.164 +                    <code-name-base>org.netbeans.modules.java.platform</code-name-base>
  18.165 +                    <build-prerequisite/>
  18.166 +                    <compile-dependency/>
  18.167 +                    <run-dependency>
  18.168 +                        <release-version>1</release-version>
  18.169 +                        <specification-version>1.16</specification-version>
  18.170 +                    </run-dependency>
  18.171 +                </dependency>
  18.172 +                <dependency>
  18.173 +                    <code-name-base>org.netbeans.modules.java.project</code-name-base>
  18.174 +                    <build-prerequisite/>
  18.175 +                    <compile-dependency/>
  18.176 +                    <run-dependency>
  18.177 +                        <release-version>1</release-version>
  18.178 +                        <specification-version>1.41</specification-version>
  18.179 +                    </run-dependency>
  18.180 +                </dependency>
  18.181 +                <dependency>
  18.182 +                    <code-name-base>org.netbeans.modules.java.source</code-name-base>
  18.183 +                    <build-prerequisite/>
  18.184 +                    <compile-dependency/>
  18.185 +                    <run-dependency>
  18.186 +                        <implementation-version/>
  18.187 +                    </run-dependency>
  18.188 +                </dependency>
  18.189 +                <dependency>
  18.190 +                    <code-name-base>org.netbeans.modules.lexer</code-name-base>
  18.191 +                    <build-prerequisite/>
  18.192 +                    <compile-dependency/>
  18.193 +                    <run-dependency>
  18.194 +                        <release-version>2</release-version>
  18.195 +                        <specification-version>1.25</specification-version>
  18.196 +                    </run-dependency>
  18.197 +                </dependency>
  18.198 +                <dependency>
  18.199 +                    <code-name-base>org.netbeans.modules.options.api</code-name-base>
  18.200 +                    <build-prerequisite/>
  18.201 +                    <compile-dependency/>
  18.202 +                    <run-dependency>
  18.203 +                        <release-version>1</release-version>
  18.204 +                        <specification-version>1.5</specification-version>
  18.205 +                    </run-dependency>
  18.206 +                </dependency>
  18.207 +                <dependency>
  18.208 +                    <code-name-base>org.netbeans.modules.options.editor</code-name-base>
  18.209 +                    <build-prerequisite/>
  18.210 +                    <compile-dependency/>
  18.211 +                    <run-dependency>
  18.212 +                        <release-version>1</release-version>
  18.213 +                        <specification-version>1.28</specification-version>
  18.214 +                    </run-dependency>
  18.215 +                </dependency>
  18.216 +                <dependency>
  18.217 +                    <code-name-base>org.netbeans.modules.parsing.api</code-name-base>
  18.218 +                    <build-prerequisite/>
  18.219 +                    <compile-dependency/>
  18.220 +                    <run-dependency>
  18.221 +                        <release-version>1</release-version>
  18.222 +                        <implementation-version/>
  18.223 +                    </run-dependency>
  18.224 +                </dependency>
  18.225 +                <dependency>
  18.226 +                    <code-name-base>org.netbeans.modules.projectapi</code-name-base>
  18.227 +                    <build-prerequisite/>
  18.228 +                    <compile-dependency/>
  18.229 +                    <run-dependency>
  18.230 +                        <release-version>1</release-version>
  18.231 +                        <specification-version>1.42</specification-version>
  18.232 +                    </run-dependency>
  18.233 +                </dependency>
  18.234 +                <dependency>
  18.235 +                    <code-name-base>org.netbeans.modules.queries</code-name-base>
  18.236 +                    <build-prerequisite/>
  18.237 +                    <compile-dependency/>
  18.238 +                    <run-dependency>
  18.239 +                        <release-version>1</release-version>
  18.240 +                        <specification-version>1.18</specification-version>
  18.241 +                    </run-dependency>
  18.242 +                </dependency>
  18.243 +                <dependency>
  18.244 +                    <code-name-base>org.netbeans.modules.refactoring.api</code-name-base>
  18.245 +                    <build-prerequisite/>
  18.246 +                    <compile-dependency/>
  18.247 +                    <run-dependency>
  18.248 +                        <specification-version>1.23</specification-version>
  18.249 +                    </run-dependency>
  18.250 +                </dependency>
  18.251 +                <dependency>
  18.252 +                    <code-name-base>org.netbeans.spi.editor.hints</code-name-base>
  18.253 +                    <build-prerequisite/>
  18.254 +                    <compile-dependency/>
  18.255 +                    <run-dependency>
  18.256 +                        <release-version>0-1</release-version>
  18.257 +                        <specification-version>1.22</specification-version>
  18.258 +                    </run-dependency>
  18.259 +                </dependency>
  18.260 +                <dependency>
  18.261 +                    <code-name-base>org.openide.actions</code-name-base>
  18.262 +                    <build-prerequisite/>
  18.263 +                    <compile-dependency/>
  18.264 +                    <run-dependency>
  18.265 +                        <specification-version>6.15</specification-version>
  18.266 +                    </run-dependency>
  18.267 +                </dependency>
  18.268 +                <dependency>
  18.269 +                    <code-name-base>org.openide.awt</code-name-base>
  18.270 +                    <build-prerequisite/>
  18.271 +                    <compile-dependency/>
  18.272 +                    <run-dependency>
  18.273 +                        <specification-version>6.10</specification-version>
  18.274 +                    </run-dependency>
  18.275 +                </dependency>
  18.276 +                <dependency>
  18.277 +                    <code-name-base>org.openide.dialogs</code-name-base>
  18.278 +                    <build-prerequisite/>
  18.279 +                    <compile-dependency/>
  18.280 +                    <run-dependency>
  18.281 +                        <specification-version>7.0</specification-version>
  18.282 +                    </run-dependency>
  18.283 +                </dependency>
  18.284 +                <dependency>
  18.285 +                    <code-name-base>org.openide.explorer</code-name-base>
  18.286 +                    <build-prerequisite/>
  18.287 +                    <compile-dependency/>
  18.288 +                    <run-dependency>
  18.289 +                        <specification-version>6.22</specification-version>
  18.290 +                    </run-dependency>
  18.291 +                </dependency>
  18.292 +                <dependency>
  18.293 +                    <code-name-base>org.openide.filesystems</code-name-base>
  18.294 +                    <build-prerequisite/>
  18.295 +                    <compile-dependency/>
  18.296 +                    <run-dependency>
  18.297 +                        <specification-version>7.19</specification-version>
  18.298 +                    </run-dependency>
  18.299 +                </dependency>
  18.300 +                <dependency>
  18.301 +                    <code-name-base>org.openide.loaders</code-name-base>
  18.302 +                    <build-prerequisite/>
  18.303 +                    <compile-dependency/>
  18.304 +                    <run-dependency/>
  18.305 +                </dependency>
  18.306 +                <dependency>
  18.307 +                    <code-name-base>org.openide.modules</code-name-base>
  18.308 +                    <build-prerequisite/>
  18.309 +                    <compile-dependency/>
  18.310 +                    <run-dependency>
  18.311 +                        <specification-version>7.3</specification-version>
  18.312 +                    </run-dependency>
  18.313 +                </dependency>
  18.314 +                <dependency>
  18.315 +                    <code-name-base>org.openide.nodes</code-name-base>
  18.316 +                    <build-prerequisite/>
  18.317 +                    <compile-dependency/>
  18.318 +                    <run-dependency>
  18.319 +                        <specification-version>6.2</specification-version>
  18.320 +                    </run-dependency>
  18.321 +                </dependency>
  18.322 +                <dependency>
  18.323 +                    <code-name-base>org.openide.text</code-name-base>
  18.324 +                    <build-prerequisite/>
  18.325 +                    <compile-dependency/>
  18.326 +                    <run-dependency>
  18.327 +                        <specification-version>6.16</specification-version>
  18.328 +                    </run-dependency>
  18.329 +                </dependency>
  18.330 +                <dependency>
  18.331 +                    <code-name-base>org.openide.util</code-name-base>
  18.332 +                    <build-prerequisite/>
  18.333 +                    <compile-dependency/>
  18.334 +                    <run-dependency>
  18.335 +                        <specification-version>8.32</specification-version>
  18.336 +                    </run-dependency>
  18.337 +                </dependency>
  18.338 +                <dependency>
  18.339 +                    <code-name-base>org.openide.util.lookup</code-name-base>
  18.340 +                    <build-prerequisite/>
  18.341 +                    <compile-dependency/>
  18.342 +                    <run-dependency>
  18.343 +                        <specification-version>8.0</specification-version>
  18.344 +                    </run-dependency>
  18.345 +                </dependency>
  18.346 +                <dependency>
  18.347 +                    <code-name-base>org.openide.windows</code-name-base>
  18.348 +                    <build-prerequisite/>
  18.349 +                    <compile-dependency/>
  18.350 +                    <run-dependency>
  18.351 +                        <specification-version>6.16</specification-version>
  18.352 +                    </run-dependency>
  18.353 +                </dependency>
  18.354 +            </module-dependencies>
  18.355 +            <test-dependencies>
  18.356 +                <test-type>
  18.357 +                    <name>unit</name>
  18.358 +                    <test-dependency>
  18.359 +                        <code-name-base>org.netbeans.core</code-name-base>
  18.360 +                        <compile-dependency/>
  18.361 +                    </test-dependency>
  18.362 +                    <test-dependency>
  18.363 +                        <code-name-base>org.netbeans.insane</code-name-base>
  18.364 +                        <compile-dependency/>
  18.365 +                    </test-dependency>
  18.366 +                    <test-dependency>
  18.367 +                        <code-name-base>org.netbeans.libs.freemarker</code-name-base>
  18.368 +                        <recursive/>
  18.369 +                        <compile-dependency/>
  18.370 +                    </test-dependency>
  18.371 +                    <test-dependency>
  18.372 +                        <code-name-base>org.netbeans.libs.junit4</code-name-base>
  18.373 +                        <compile-dependency/>
  18.374 +                    </test-dependency>
  18.375 +                    <test-dependency>
  18.376 +                        <code-name-base>org.netbeans.modules.classfile</code-name-base>
  18.377 +                    </test-dependency>
  18.378 +                    <test-dependency>
  18.379 +                        <code-name-base>org.netbeans.modules.defaults</code-name-base>
  18.380 +                    </test-dependency>
  18.381 +                    <test-dependency>
  18.382 +                        <code-name-base>org.netbeans.modules.editor</code-name-base>
  18.383 +                        <test/>
  18.384 +                    </test-dependency>
  18.385 +                    <test-dependency>
  18.386 +                        <code-name-base>org.netbeans.modules.editor.mimelookup</code-name-base>
  18.387 +                        <compile-dependency/>
  18.388 +                        <test/>
  18.389 +                    </test-dependency>
  18.390 +                    <test-dependency>
  18.391 +                        <code-name-base>org.netbeans.modules.editor.settings</code-name-base>
  18.392 +                    </test-dependency>
  18.393 +                    <test-dependency>
  18.394 +                        <code-name-base>org.netbeans.modules.editor.settings.storage</code-name-base>
  18.395 +                    </test-dependency>
  18.396 +                    <test-dependency>
  18.397 +                        <code-name-base>org.netbeans.modules.editor.util</code-name-base>
  18.398 +                    </test-dependency>
  18.399 +                    <test-dependency>
  18.400 +                        <code-name-base>org.netbeans.modules.jackpot30.test.borrowed</code-name-base>
  18.401 +                        <compile-dependency/>
  18.402 +                    </test-dependency>
  18.403 +                    <test-dependency>
  18.404 +                        <code-name-base>org.netbeans.modules.java.editor</code-name-base>
  18.405 +                        <recursive/>
  18.406 +                        <compile-dependency/>
  18.407 +                    </test-dependency>
  18.408 +                    <test-dependency>
  18.409 +                        <code-name-base>org.netbeans.modules.java.hints</code-name-base>
  18.410 +                        <compile-dependency/>
  18.411 +                    </test-dependency>
  18.412 +                    <test-dependency>
  18.413 +                        <code-name-base>org.netbeans.modules.java.hints.declarative</code-name-base>
  18.414 +                        <compile-dependency/>
  18.415 +                    </test-dependency>
  18.416 +                    <test-dependency>
  18.417 +                        <code-name-base>org.netbeans.modules.java.source</code-name-base>
  18.418 +                        <compile-dependency/>
  18.419 +                        <test/>
  18.420 +                    </test-dependency>
  18.421 +                    <test-dependency>
  18.422 +                        <code-name-base>org.netbeans.modules.masterfs</code-name-base>
  18.423 +                    </test-dependency>
  18.424 +                    <test-dependency>
  18.425 +                        <code-name-base>org.netbeans.modules.nbjunit</code-name-base>
  18.426 +                        <compile-dependency/>
  18.427 +                    </test-dependency>
  18.428 +                    <test-dependency>
  18.429 +                        <code-name-base>org.netbeans.modules.parsing.api</code-name-base>
  18.430 +                        <compile-dependency/>
  18.431 +                        <test/>
  18.432 +                    </test-dependency>
  18.433 +                    <test-dependency>
  18.434 +                        <code-name-base>org.netbeans.modules.progress.ui</code-name-base>
  18.435 +                    </test-dependency>
  18.436 +                    <test-dependency>
  18.437 +                        <code-name-base>org.netbeans.modules.projectui</code-name-base>
  18.438 +                    </test-dependency>
  18.439 +                    <test-dependency>
  18.440 +                        <code-name-base>org.openide.util</code-name-base>
  18.441 +                        <compile-dependency/>
  18.442 +                        <test/>
  18.443 +                    </test-dependency>
  18.444 +                    <test-dependency>
  18.445 +                        <code-name-base>org.openide.util.lookup</code-name-base>
  18.446 +                        <compile-dependency/>
  18.447 +                        <test/>
  18.448 +                    </test-dependency>
  18.449 +                </test-type>
  18.450 +            </test-dependencies>
  18.451 +            <public-packages>
  18.452 +                <package>org.netbeans.spi.java.hints</package>
  18.453 +                <package>org.netbeans.spi.java.hints.annotations</package>
  18.454 +                <package>org.netbeans.spi.java.hints.matching</package>
  18.455 +                <package>org.netbeans.spi.java.hints.support</package>
  18.456 +            </public-packages>
  18.457 +        </data>
  18.458 +    </configuration>
  18.459 +</project>
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/java.hints/spi.java.hints/nbproject/suite.properties	Wed May 08 21:47:42 2013 +0200
    19.3 @@ -0,0 +1,1 @@
    19.4 +suite.dir=${basedir}/..
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/jackpot/spi/Bundle.properties	Wed May 08 21:47:42 2013 +0200
    20.3 @@ -0,0 +1,42 @@
    20.4 +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    20.5 +#
    20.6 +# Copyright 2008-2010 Oracle and/or its affiliates. All rights reserved.
    20.7 +#
    20.8 +# Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    20.9 +# Other names may be trademarks of their respective owners.
   20.10 +#
   20.11 +# The contents of this file are subject to the terms of either the GNU
   20.12 +# General Public License Version 2 only ("GPL") or the Common
   20.13 +# Development and Distribution License("CDDL") (collectively, the
   20.14 +# "License"). You may not use this file except in compliance with the
   20.15 +# License. You can obtain a copy of the License at
   20.16 +# http://www.netbeans.org/cddl-gplv2.html
   20.17 +# or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   20.18 +# specific language governing permissions and limitations under the
   20.19 +# License.  When distributing the software, include this License Header
   20.20 +# Notice in each file and include the License file at
   20.21 +# nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   20.22 +# particular file as subject to the "Classpath" exception as provided
   20.23 +# by Oracle in the GPL Version 2 section of the License file that
   20.24 +# accompanied this code. If applicable, add the following below the
   20.25 +# License Header, with the fields enclosed by brackets [] replaced by
   20.26 +# your own identifying information:
   20.27 +# "Portions Copyrighted [year] [name of copyright owner]"
   20.28 +#
   20.29 +# Contributor(s):
   20.30 +#
   20.31 +# The Original Software is NetBeans. The Initial Developer of the Original
   20.32 +# Software is Sun Microsystems, Inc. Portions Copyright 2008-2009 Sun
   20.33 +# Microsystems, Inc. All Rights Reserved.
   20.34 +#
   20.35 +# If you wish your version of this file to be governed by only the CDDL
   20.36 +# or only the GPL Version 2, indicate your decision by adding
   20.37 +# "[Contributor] elects to include this software in this distribution
   20.38 +# under the [CDDL or GPL Version 2] license." If you do not indicate a
   20.39 +# single choice of license, a recipient has the option to distribute
   20.40 +# your version of this file under either the CDDL, the GPL Version 2 or
   20.41 +# to extend the choice of license to its licensees as provided above.
   20.42 +# However, if you add GPL Version 2 code and therefore, elected the GPL
   20.43 +# Version 2 license, then the option applies only if the new code is
   20.44 +# made subject to such option by the copyright holder.
   20.45 +LBL_UpdateDependencyQuestion=Update dependency on module {0} to specification version {1}?
   20.46 \ No newline at end of file
    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/jackpot/spi/HintsRunner.java	Wed May 08 21:47:42 2013 +0200
    21.3 @@ -0,0 +1,69 @@
    21.4 +/*
    21.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    21.6 + *
    21.7 + * Copyright 2009-2010 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 2009-2010 Sun Microsystems, Inc.
   21.44 + */
   21.45 +
   21.46 +package org.netbeans.modules.java.hints.jackpot.spi;
   21.47 +
   21.48 +import org.netbeans.modules.java.hints.providers.spi.HintDescription;
   21.49 +import com.sun.source.util.TreePath;
   21.50 +import java.util.LinkedList;
   21.51 +import java.util.List;
   21.52 +import java.util.Map;
   21.53 +import java.util.concurrent.atomic.AtomicBoolean;
   21.54 +import org.netbeans.api.annotations.common.CheckForNull;
   21.55 +import org.netbeans.api.java.source.CompilationInfo;
   21.56 +import org.netbeans.modules.java.hints.spiimpl.MessageImpl;
   21.57 +import org.netbeans.modules.java.hints.spiimpl.hints.HintsInvoker;
   21.58 +import org.netbeans.modules.java.hints.spiimpl.options.HintsSettings;
   21.59 +import org.netbeans.spi.editor.hints.ErrorDescription;
   21.60 +
   21.61 +/**XXX: probably unused
   21.62 + *
   21.63 + * @author lahvac
   21.64 + */
   21.65 +public class HintsRunner {
   21.66 +
   21.67 +    @CheckForNull
   21.68 +    public static Map<HintDescription, List<ErrorDescription>> computeErrors(CompilationInfo info, Iterable<? extends HintDescription> hints, AtomicBoolean cancel) {
   21.69 +        return new HintsInvoker(HintsSettings.getSettingsFor(info.getFileObject()), cancel).computeHints(info, new TreePath(info.getCompilationUnit()), hints, new LinkedList<MessageImpl>());
   21.70 +    }
   21.71 +
   21.72 +}
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/jackpot/spi/PatternConvertor.java	Wed May 08 21:47:42 2013 +0200
    22.3 @@ -0,0 +1,113 @@
    22.4 +/*
    22.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    22.6 + *
    22.7 + * Copyright 2009-2011 Sun Microsystems, Inc. All rights reserved.
    22.8 + *
    22.9 + * The contents of this file are subject to the terms of either the GNU
   22.10 + * General Public License Version 2 only ("GPL") or the Common
   22.11 + * Development and Distribution License("CDDL") (collectively, the
   22.12 + * "License"). You may not use this file except in compliance with the
   22.13 + * License. You can obtain a copy of the License at
   22.14 + * http://www.netbeans.org/cddl-gplv2.html
   22.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   22.16 + * specific language governing permissions and limitations under the
   22.17 + * License.  When distributing the software, include this License Header
   22.18 + * Notice in each file and include the License file at
   22.19 + * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
   22.20 + * particular file as subject to the "Classpath" exception as provided
   22.21 + * by Sun in the GPL Version 2 section of the License file that
   22.22 + * accompanied this code. If applicable, add the following below the
   22.23 + * License Header, with the fields enclosed by brackets [] replaced by
   22.24 + * your own identifying information:
   22.25 + * "Portions Copyrighted [year] [name of copyright owner]"
   22.26 + *
   22.27 + * If you wish your version of this file to be governed by only the CDDL
   22.28 + * or only the GPL Version 2, indicate your decision by adding
   22.29 + * "[Contributor] elects to include this software in this distribution
   22.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   22.31 + * single choice of license, a recipient has the option to distribute
   22.32 + * your version of this file under either the CDDL, the GPL Version 2 or
   22.33 + * to extend the choice of license to its licensees as provided above.
   22.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   22.35 + * Version 2 license, then the option applies only if the new code is
   22.36 + * made subject to such option by the copyright holder.
   22.37 + *
   22.38 + * Contributor(s):
   22.39 + *
   22.40 + * Portions Copyrighted 2009-2011 Sun Microsystems, Inc.
   22.41 + */
   22.42 +
   22.43 +package org.netbeans.modules.java.hints.jackpot.spi;
   22.44 +
   22.45 +import org.netbeans.modules.java.hints.providers.spi.HintDescriptionFactory;
   22.46 +import org.netbeans.spi.java.hints.HintContext;
   22.47 +import java.util.ArrayList;
   22.48 +import java.util.Collection;
   22.49 +import java.util.Collections;
   22.50 +import org.netbeans.api.annotations.common.CheckForNull;
   22.51 +import org.netbeans.api.annotations.common.NonNull;
   22.52 +import org.netbeans.modules.java.hints.providers.spi.HintDescription.Worker;
   22.53 +import org.netbeans.modules.java.hints.providers.spi.Trigger.PatternDescription;
   22.54 +import org.netbeans.spi.java.hints.ErrorDescriptionFactory;
   22.55 +import org.netbeans.spi.editor.hints.ErrorDescription;
   22.56 +import org.netbeans.modules.java.hints.providers.spi.HintDescription;
   22.57 +import org.openide.util.Lookup;
   22.58 +
   22.59 +/**XXX: big hack?
   22.60 + *
   22.61 + * @author lahvac
   22.62 + */
   22.63 +public abstract class PatternConvertor {
   22.64 +
   22.65 +    protected abstract @CheckForNull Iterable<? extends HintDescription> parseString(@NonNull String code);
   22.66 +
   22.67 +    public static @CheckForNull Iterable<? extends HintDescription> create(@NonNull String code) {
   22.68 +        Collection<String> patterns = new ArrayList<String>();
   22.69 +        
   22.70 +        //XXX:
   22.71 +        if (code.contains(";;")) {
   22.72 +            PatternConvertor c = Lookup.getDefault().lookup(PatternConvertor.class);
   22.73 +
   22.74 +            if (c != null) {
   22.75 +                return c.parseString(code);
   22.76 +            }
   22.77 +
   22.78 +            for (String s : code.split(";;")) {
   22.79 +                s = s.trim();
   22.80 +                if (s.isEmpty()) {
   22.81 +                    continue;
   22.82 +                }
   22.83 +                
   22.84 +                patterns.add(s);
   22.85 +            }
   22.86 +        } else {
   22.87 +            patterns.add(code);
   22.88 +        }
   22.89 +
   22.90 +        Collection<HintDescription> result = new ArrayList<HintDescription>(patterns.size());
   22.91 +
   22.92 +        for (String pattern : patterns) {
   22.93 +            PatternDescription pd = PatternDescription.create(pattern, Collections.<String, String>emptyMap());
   22.94 +
   22.95 +            HintDescription desc = HintDescriptionFactory.create()
   22.96 +    //                                                     .setDisplayName("Pattern Matches")
   22.97 +                                                         .setTrigger(pd)
   22.98 +                                                         .setWorker(new WorkerImpl())
   22.99 +                                                         .produce();
  22.100 +            
  22.101 +            result.add(desc);
  22.102 +        }
  22.103 +
  22.104 +        return result;
  22.105 +    }
  22.106 +
  22.107 +    private static final class WorkerImpl implements Worker {
  22.108 +
  22.109 +        public Collection<? extends ErrorDescription> createErrors(HintContext ctx) {
  22.110 +            ErrorDescription ed = ErrorDescriptionFactory.forTree(ctx, ctx.getPath(), "Found pattern occurrence");
  22.111 +
  22.112 +            return Collections.singleton(ed);
  22.113 +        }
  22.114 +        
  22.115 +    }
  22.116 +}
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/jackpot/spi/ProjectDependencyUpgrader.java	Wed May 08 21:47:42 2013 +0200
    23.3 @@ -0,0 +1,64 @@
    23.4 +/*
    23.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    23.6 + *
    23.7 + * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
    23.8 + *
    23.9 + * The contents of this file are subject to the terms of either the GNU
   23.10 + * General Public License Version 2 only ("GPL") or the Common
   23.11 + * Development and Distribution License("CDDL") (collectively, the
   23.12 + * "License"). You may not use this file except in compliance with the
   23.13 + * License. You can obtain a copy of the License at
   23.14 + * http://www.netbeans.org/cddl-gplv2.html
   23.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   23.16 + * specific language governing permissions and limitations under the
   23.17 + * License.  When distributing the software, include this License Header
   23.18 + * Notice in each file and include the License file at
   23.19 + * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
   23.20 + * particular file as subject to the "Classpath" exception as provided
   23.21 + * by Sun in the GPL Version 2 section of the License file that
   23.22 + * accompanied this code. If applicable, add the following below the
   23.23 + * License Header, with the fields enclosed by brackets [] replaced by
   23.24 + * your own identifying information:
   23.25 + * "Portions Copyrighted [year] [name of copyright owner]"
   23.26 + *
   23.27 + * If you wish your version of this file to be governed by only the CDDL
   23.28 + * or only the GPL Version 2, indicate your decision by adding
   23.29 + * "[Contributor] elects to include this software in this distribution
   23.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   23.31 + * single choice of license, a recipient has the option to distribute
   23.32 + * your version of this file under either the CDDL, the GPL Version 2 or
   23.33 + * to extend the choice of license to its licensees as provided above.
   23.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   23.35 + * Version 2 license, then the option applies only if the new code is
   23.36 + * made subject to such option by the copyright holder.
   23.37 + *
   23.38 + * Contributor(s):
   23.39 + *
   23.40 + * Portions Copyrighted 2010 Sun Microsystems, Inc.
   23.41 + */
   23.42 +package org.netbeans.modules.java.hints.jackpot.spi;
   23.43 +
   23.44 +import org.netbeans.api.project.Project;
   23.45 +import org.openide.DialogDisplayer;
   23.46 +import org.openide.NotifyDescriptor;
   23.47 +import org.openide.filesystems.FileObject;
   23.48 +import org.openide.modules.SpecificationVersion;
   23.49 +
   23.50 +/**
   23.51 + *
   23.52 + * @author lahvac
   23.53 + */
   23.54 +public abstract class ProjectDependencyUpgrader {
   23.55 +
   23.56 +    public abstract boolean ensureDependency(Project p, FileObject dep, SpecificationVersion spec, boolean canShowUI);
   23.57 +    public abstract boolean ensureDependency(Project p, String specification, boolean b);
   23.58 +
   23.59 +    protected final boolean showDependencyUpgradeDialog(Project p, String dep, SpecificationVersion currentDependency, SpecificationVersion spec, boolean newDepenency, boolean canShowUI) {
   23.60 +        if (!canShowUI) return true;
   23.61 +        
   23.62 +        NotifyDescriptor nd = new NotifyDescriptor.Confirmation("New version: " + spec, "Update spec version.", NotifyDescriptor.YES_NO_OPTION);
   23.63 +
   23.64 +        return DialogDisplayer.getDefault().notify(nd) == NotifyDescriptor.YES_OPTION;
   23.65 +    }
   23.66 +
   23.67 +}
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/providers/code/CodeHintProviderImpl.java	Wed May 08 21:47:42 2013 +0200
    24.3 @@ -0,0 +1,456 @@
    24.4 +/*
    24.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    24.6 + *
    24.7 + * Copyright 2008-2010 Oracle and/or its affiliates. All rights reserved.
    24.8 + *
    24.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   24.10 + * Other names may be trademarks of their respective owners.
   24.11 + *
   24.12 + * The contents of this file are subject to the terms of either the GNU
   24.13 + * General Public License Version 2 only ("GPL") or the Common
   24.14 + * Development and Distribution License("CDDL") (collectively, the
   24.15 + * "License"). You may not use this file except in compliance with the
   24.16 + * License. You can obtain a copy of the License at
   24.17 + * http://www.netbeans.org/cddl-gplv2.html
   24.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   24.19 + * specific language governing permissions and limitations under the
   24.20 + * License.  When distributing the software, include this License Header
   24.21 + * Notice in each file and include the License file at
   24.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   24.23 + * particular file as subject to the "Classpath" exception as provided
   24.24 + * by Oracle in the GPL Version 2 section of the License file that
   24.25 + * accompanied this code. If applicable, add the following below the
   24.26 + * License Header, with the fields enclosed by brackets [] replaced by
   24.27 + * your own identifying information:
   24.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   24.29 + *
   24.30 + * If you wish your version of this file to be governed by only the CDDL
   24.31 + * or only the GPL Version 2, indicate your decision by adding
   24.32 + * "[Contributor] elects to include this software in this distribution
   24.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   24.34 + * single choice of license, a recipient has the option to distribute
   24.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   24.36 + * to extend the choice of license to its licensees as provided above.
   24.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   24.38 + * Version 2 license, then the option applies only if the new code is
   24.39 + * made subject to such option by the copyright holder.
   24.40 + *
   24.41 + * Contributor(s):
   24.42 + *
   24.43 + * Portions Copyrighted 2008-2010 Sun Microsystems, Inc.
   24.44 + */
   24.45 +
   24.46 +package org.netbeans.modules.java.hints.providers.code;
   24.47 +
   24.48 +import com.sun.source.tree.Tree.Kind;
   24.49 +import java.lang.annotation.Annotation;
   24.50 +import java.lang.reflect.InvocationTargetException;
   24.51 +import java.lang.reflect.Method;
   24.52 +import java.util.ArrayList;
   24.53 +import java.util.Arrays;
   24.54 +import java.util.Collection;
   24.55 +import java.util.Collections;
   24.56 +import java.util.EnumSet;
   24.57 +import java.util.HashMap;
   24.58 +import java.util.HashSet;
   24.59 +import java.util.LinkedList;
   24.60 +import java.util.List;
   24.61 +import java.util.Map;
   24.62 +import java.util.Set;
   24.63 +import java.util.concurrent.atomic.AtomicReference;
   24.64 +import java.util.logging.Level;
   24.65 +import java.util.logging.Logger;
   24.66 +import java.util.prefs.Preferences;
   24.67 +import javax.swing.JComponent;
   24.68 +import javax.swing.JPanel;
   24.69 +import org.netbeans.modules.java.hints.providers.code.FSWrapper.ClassWrapper;
   24.70 +import org.netbeans.modules.java.hints.providers.code.FSWrapper.FieldWrapper;
   24.71 +import org.netbeans.modules.java.hints.providers.code.FSWrapper.MethodWrapper;
   24.72 +import org.netbeans.modules.java.hints.providers.code.ReflectiveCustomizerProvider.OptionDescriptor;
   24.73 +import org.netbeans.spi.java.hints.CustomizerProvider;
   24.74 +import org.netbeans.modules.java.hints.providers.spi.HintDescription;
   24.75 +import org.netbeans.modules.java.hints.providers.spi.HintDescription.Worker;
   24.76 +import org.netbeans.modules.java.hints.providers.spi.HintDescriptionFactory;
   24.77 +import org.netbeans.modules.java.hints.providers.spi.HintMetadata;
   24.78 +import org.netbeans.modules.java.hints.providers.spi.HintMetadata.Options;
   24.79 +import org.netbeans.modules.java.hints.providers.spi.HintProvider;
   24.80 +import org.netbeans.modules.java.hints.providers.spi.Trigger.Kinds;
   24.81 +import org.netbeans.modules.java.hints.providers.spi.Trigger.PatternDescription;
   24.82 +import org.netbeans.spi.editor.hints.ErrorDescription;
   24.83 +import org.netbeans.spi.editor.hints.Severity;
   24.84 +import org.netbeans.spi.java.hints.BooleanOption;
   24.85 +import org.netbeans.spi.java.hints.ConstraintVariableType;
   24.86 +import org.netbeans.spi.java.hints.Hint;
   24.87 +import org.netbeans.spi.java.hints.IntegerOption;
   24.88 +import org.netbeans.spi.java.hints.TriggerPattern;
   24.89 +import org.netbeans.spi.java.hints.TriggerPatterns;
   24.90 +import org.netbeans.spi.java.hints.TriggerTreeKind;
   24.91 +import org.netbeans.spi.java.hints.UseOptions;
   24.92 +import org.openide.util.Exceptions;
   24.93 +import org.openide.util.Lookup;
   24.94 +import org.openide.util.NbCollections;
   24.95 +import org.openide.util.lookup.ServiceProvider;
   24.96 +
   24.97 +/**
   24.98 + *
   24.99 + * @author lahvac
  24.100 + */
  24.101 +@ServiceProvider(service=HintProvider.class)
  24.102 +public class CodeHintProviderImpl implements HintProvider {
  24.103 +
  24.104 +    private static final Logger LOG = Logger.getLogger(WorkerImpl.class.getName());
  24.105 +    
  24.106 +    public Map<HintMetadata, ? extends Collection<? extends HintDescription>> computeHints() {
  24.107 +        return computeHints(findLoader(), "META-INF/nb-hints/hints");
  24.108 +    }
  24.109 +
  24.110 +    private Map<HintMetadata, ? extends Collection<? extends HintDescription>> computeHints(ClassLoader l, String path) {
  24.111 +        Map<HintMetadata, Collection<HintDescription>> result = new HashMap<HintMetadata, Collection<HintDescription>>();
  24.112 +        
  24.113 +        for (ClassWrapper c : FSWrapper.listClasses()) {
  24.114 +            try {
  24.115 +                processClass(c, result);
  24.116 +            } catch (ThreadDeath td) {
  24.117 +                throw td;
  24.118 +            } catch (Throwable t) {
  24.119 +                Exceptions.printStackTrace(t);
  24.120 +            }
  24.121 +        }
  24.122 +
  24.123 +        return result;
  24.124 +    }
  24.125 +
  24.126 +    static ClassLoader findLoader() {
  24.127 +        ClassLoader l = Lookup.getDefault().lookup(ClassLoader.class);
  24.128 +
  24.129 +        if (l == null) {
  24.130 +            return CodeHintProviderImpl.class.getClassLoader();
  24.131 +        }
  24.132 +
  24.133 +        return l;
  24.134 +    }
  24.135 +
  24.136 +    public static void processClass(ClassWrapper clazz, Map<HintMetadata, Collection<HintDescription>> result) throws SecurityException {
  24.137 +        Hint metadata = clazz.getAnnotation(Hint.class);
  24.138 +        HintMetadata hm;
  24.139 +        
  24.140 +        if (metadata != null) {
  24.141 +            String id = metadata.id();
  24.142 +
  24.143 +            if (id == null || id.length() == 0) {
  24.144 +                id = clazz.getName();
  24.145 +            }
  24.146 +            hm = fromAnnotation(id, clazz, null, metadata);
  24.147 +        } else {
  24.148 +            hm = null;
  24.149 +        }
  24.150 +        
  24.151 +        for (MethodWrapper m : clazz.getMethods()) {
  24.152 +            Hint localMetadataAnnotation = m.getAnnotation(Hint.class);
  24.153 +            HintMetadata localMetadata;
  24.154 +
  24.155 +            if (localMetadataAnnotation != null) {
  24.156 +                String localID = localMetadataAnnotation.id();
  24.157 +
  24.158 +                if (localID == null || localID.length() == 0) {
  24.159 +                    localID = clazz.getName() + "." + m.getName();
  24.160 +                }
  24.161 +
  24.162 +                localMetadata = fromAnnotation(localID, clazz, m, localMetadataAnnotation);
  24.163 +            } else {
  24.164 +                localMetadata = hm;
  24.165 +            }
  24.166 +
  24.167 +            if (localMetadata != null) {
  24.168 +                processMethod(result, m, localMetadata);
  24.169 +            }
  24.170 +        }
  24.171 +    }
  24.172 +
  24.173 +    private static HintMetadata fromAnnotation(String id, ClassWrapper clazz, MethodWrapper method, Hint metadata) {
  24.174 +        HintMetadata hm = HintMetadata.Builder.create(id)
  24.175 +                                              .setDescription(metadata.displayName(), metadata.description())
  24.176 +                                              .setCategory(metadata.category())
  24.177 +                                              .setEnabled(metadata.enabled())
  24.178 +                                              .setSeverity(metadata.severity())
  24.179 +                                              .setKind(metadata.hintKind())
  24.180 +                                              .setCustomizerProvider(createCustomizerProvider(clazz, method, id, metadata))
  24.181 +                                              .addSuppressWarnings(metadata.suppressWarnings())
  24.182 +                                              .addOptions(Options.fromHintOptions(metadata.options()).toArray(new Options[0]))
  24.183 +                                              .build();
  24.184 +        return hm;
  24.185 +    }
  24.186 +
  24.187 +    private static CustomizerProvider createCustomizerProvider(ClassWrapper clazz, MethodWrapper method, String id, Hint hint) {
  24.188 +        Class<? extends CustomizerProvider> customizerClass = hint.customizerProvider();
  24.189 +
  24.190 +        if (customizerClass != CustomizerProvider.class) {
  24.191 +            return new DelegatingCustomizerProvider(customizerClass);
  24.192 +        }
  24.193 +
  24.194 +        Set<String> allowedOptions = null;
  24.195 +
  24.196 +        if (method != null) {
  24.197 +            UseOptions useOptions = method.getAnnotation(UseOptions.class);
  24.198 +
  24.199 +            if (useOptions == null) return null;
  24.200 +
  24.201 +            allowedOptions = new HashSet<String>(Arrays.asList(useOptions.value()));
  24.202 +        }
  24.203 +
  24.204 +        List<OptionDescriptor> declarativeOptions = new ArrayList<OptionDescriptor>();
  24.205 +
  24.206 +        for (FieldWrapper fw : clazz.getFields()) {
  24.207 +            BooleanOption option = fw.getAnnotation(BooleanOption.class);
  24.208 +            IntegerOption iOption = fw.getAnnotation(IntegerOption.class);
  24.209 +            
  24.210 +            String key = fw.getConstantValue();
  24.211 +
  24.212 +            if (key == null) continue;
  24.213 +            if (allowedOptions != null && !allowedOptions.contains(key)) continue;
  24.214 +            
  24.215 +            Object defValue;
  24.216 +            String displayName;
  24.217 +            String tooltip;
  24.218 +            if (option != null) {
  24.219 +                defValue = option.defaultValue();
  24.220 +                displayName = option.displayName();
  24.221 +                tooltip = option.tooltip();
  24.222 +            } else if (iOption != null) {
  24.223 +                defValue = iOption.defaultValue();
  24.224 +                displayName = iOption.displayName();
  24.225 +                tooltip = iOption.tooltip();
  24.226 +            } else {
  24.227 +                return null;
  24.228 +            }
  24.229 +            
  24.230 +            declarativeOptions.add(
  24.231 +                new OptionDescriptor(
  24.232 +                    key, 
  24.233 +                    defValue,
  24.234 +                    displayName,
  24.235 +                    tooltip,
  24.236 +                    option != null ? option : iOption)
  24.237 +            );
  24.238 +        }
  24.239 +
  24.240 +        return !declarativeOptions.isEmpty() ? new ReflectiveCustomizerProvider(clazz.getName(), id, declarativeOptions) : null;
  24.241 +    }
  24.242 +    
  24.243 +    static void processMethod(Map<HintMetadata, Collection<HintDescription>> hints, MethodWrapper m, HintMetadata metadata) {
  24.244 +        //XXX: combinations of TriggerTreeKind and TriggerPattern?
  24.245 +        processTreeKindHint(hints, m, metadata);
  24.246 +        processPatternHint(hints, m, metadata);
  24.247 +    }
  24.248 +    
  24.249 +    private static void processTreeKindHint(Map<HintMetadata, Collection<HintDescription>> hints, MethodWrapper m, HintMetadata metadata) {
  24.250 +        TriggerTreeKind kindTrigger = m.getAnnotation(TriggerTreeKind.class);
  24.251 +
  24.252 +        if (kindTrigger == null) {
  24.253 +            return ;
  24.254 +        }
  24.255 +
  24.256 +        Worker w = new WorkerImpl(m.getClazz().getName(), m.getName());
  24.257 +
  24.258 +        Set<Kind> kinds = EnumSet.noneOf(Kind.class);
  24.259 +        
  24.260 +        kinds.addAll(Arrays.asList(kindTrigger.value()));
  24.261 +
  24.262 +        addHint(hints, metadata, HintDescriptionFactory.create()
  24.263 +                                                       .setTrigger(new Kinds(kinds))
  24.264 +                                                       .setWorker(w)
  24.265 +                                                       .setMetadata(metadata)
  24.266 +                                                       .produce());
  24.267 +    }
  24.268 +    
  24.269 +    private static void processPatternHint(Map<HintMetadata, Collection<HintDescription>> hints, MethodWrapper m, HintMetadata metadata) {
  24.270 +        TriggerPattern patternTrigger = m.getAnnotation(TriggerPattern.class);
  24.271 +
  24.272 +        if (patternTrigger != null) {
  24.273 +            processPatternHint(hints, patternTrigger, m, metadata);
  24.274 +            return ;
  24.275 +        }
  24.276 +
  24.277 +        TriggerPatterns patternTriggers = m.getAnnotation(TriggerPatterns.class);
  24.278 +
  24.279 +        if (patternTriggers != null) {
  24.280 +            for (TriggerPattern pattern : patternTriggers.value()) {
  24.281 +                processPatternHint(hints, pattern, m, metadata);
  24.282 +            }
  24.283 +            return ;
  24.284 +        }
  24.285 +    }
  24.286 +
  24.287 +    private static void processPatternHint(Map<HintMetadata, Collection<HintDescription>> hints, TriggerPattern patternTrigger, MethodWrapper m, HintMetadata metadata) {
  24.288 +        String pattern = patternTrigger.value();
  24.289 +        Map<String, String> constraints = new HashMap<String, String>();
  24.290 +
  24.291 +        for (ConstraintVariableType c : patternTrigger.constraints()) {
  24.292 +            constraints.put(c.variable(), c.type());
  24.293 +        }
  24.294 +
  24.295 +        PatternDescription pd = PatternDescription.create(pattern, constraints);
  24.296 +
  24.297 +        addHint(hints, metadata, HintDescriptionFactory.create()
  24.298 +                                                       .setTrigger(pd)
  24.299 +                                                       .setWorker(new WorkerImpl(m.getClazz().getName(), m.getName()))
  24.300 +                                                       .setMetadata(metadata)
  24.301 +                                                       .produce());
  24.302 +    }
  24.303 +
  24.304 +    private static void addHint(Map<HintMetadata, Collection<HintDescription>> hints, HintMetadata metadata, HintDescription hint) {
  24.305 +        Collection<HintDescription> list = hints.get(metadata);
  24.306 +
  24.307 +        if (list == null) {
  24.308 +            hints.put(metadata, list = new LinkedList<HintDescription>());
  24.309 +        }
  24.310 +
  24.311 +        list.add(hint);
  24.312 +    }
  24.313 +
  24.314 +    //accessed by tests:
  24.315 +    static final class WorkerImpl implements Worker {
  24.316 +
  24.317 +        private final String className;
  24.318 +        private final String methodName;
  24.319 +
  24.320 +        public WorkerImpl(String className, String methodName) {
  24.321 +            this.className = className;
  24.322 +            this.methodName = methodName;
  24.323 +        }
  24.324 +
  24.325 +        private final AtomicReference<Method> methodRef = new AtomicReference<Method>();
  24.326 +
  24.327 +        public Collection<? extends ErrorDescription> createErrors(org.netbeans.spi.java.hints.HintContext ctx) {
  24.328 +            try {
  24.329 +                Method method = methodRef.get();
  24.330 +
  24.331 +                if (method == null) {
  24.332 +                    methodRef.set(method = getMethod());
  24.333 +                }
  24.334 +                
  24.335 +                Object result = method.invoke(null, ctx);
  24.336 +
  24.337 +                if (result == null) {
  24.338 +                    return null;
  24.339 +                }
  24.340 +
  24.341 +                if (result instanceof Iterable) {
  24.342 +                    List<ErrorDescription> out = new LinkedList<ErrorDescription>();
  24.343 +
  24.344 +                    for (ErrorDescription ed : NbCollections.iterable(NbCollections.checkedIteratorByFilter(((Iterable) result).iterator(), ErrorDescription.class, false))) {
  24.345 +                        out.add(ed);
  24.346 +                    }
  24.347 +
  24.348 +                    return out;
  24.349 +                }
  24.350 +
  24.351 +                if (result instanceof ErrorDescription) {
  24.352 +                    return Collections.singletonList((ErrorDescription) result);
  24.353 +                }
  24.354 +
  24.355 +                //XXX: log if result was ignored...
  24.356 +            } catch (IllegalAccessException ex) {
  24.357 +                Exceptions.printStackTrace(ex);
  24.358 +            } catch (IllegalArgumentException ex) {
  24.359 +                Exceptions.printStackTrace(ex);
  24.360 +            } catch (ClassNotFoundException ex) {
  24.361 +                Exceptions.printStackTrace(ex);
  24.362 +            } catch (NoSuchMethodException ex) {
  24.363 +                Exceptions.printStackTrace(ex);
  24.364 +            } catch (InvocationTargetException ex) {
  24.365 +                LOG.log(Level.INFO, className + "." + methodName, ex);
  24.366 +                //so that the exceptions are categorized better:
  24.367 +                Exceptions.printStackTrace(ex.getCause());
  24.368 +            }
  24.369 +
  24.370 +            return null;
  24.371 +        }
  24.372 +
  24.373 +        //used by tests:
  24.374 +        Method getMethod() throws NoSuchMethodException, ClassNotFoundException {
  24.375 +            return FSWrapper.resolveMethod(className, methodName);
  24.376 +        }
  24.377 +
  24.378 +    }
  24.379 +
  24.380 +    private static final class EmptyHintMetadataDescription implements Hint {
  24.381 +
  24.382 +        public String id() {
  24.383 +            return "";
  24.384 +        }
  24.385 +
  24.386 +        public String category() {
  24.387 +            return "general";
  24.388 +        }
  24.389 +
  24.390 +        public boolean enabled() {
  24.391 +            return true;
  24.392 +        }
  24.393 +
  24.394 +        public Severity severity() {
  24.395 +            return Severity.VERIFIER;
  24.396 +        }
  24.397 +
  24.398 +        private static final String[] EMPTY_SW = new String[0];
  24.399 +        
  24.400 +        public String[] suppressWarnings() {
  24.401 +            return EMPTY_SW;
  24.402 +        }
  24.403 +
  24.404 +        public Class<? extends Annotation> annotationType() {
  24.405 +            return Hint.class;
  24.406 +        }
  24.407 +
  24.408 +        public Class<? extends CustomizerProvider> customizerProvider() {
  24.409 +            return CustomizerProvider.class;
  24.410 +        }
  24.411 +
  24.412 +        public Kind hintKind() {
  24.413 +            return Kind.INSPECTION;
  24.414 +        }
  24.415 +
  24.416 +        private static final Options[] EMPTY_OPTIONS = new Options[0];
  24.417 +
  24.418 +        public Options[] options() {
  24.419 +            return EMPTY_OPTIONS;
  24.420 +        }
  24.421 +
  24.422 +        @Override public String displayName() {
  24.423 +            return "";
  24.424 +        }
  24.425 +
  24.426 +        @Override public String description() {
  24.427 +            return "";
  24.428 +        }
  24.429 +
  24.430 +    }
  24.431 +
  24.432 +    private static final class DelegatingCustomizerProvider implements CustomizerProvider {
  24.433 +
  24.434 +        private final Class<? extends CustomizerProvider> component;
  24.435 +
  24.436 +        public DelegatingCustomizerProvider(Class<? extends CustomizerProvider> component) {
  24.437 +            this.component = component;
  24.438 +        }
  24.439 +
  24.440 +        @Override
  24.441 +        public JComponent getCustomizer(Preferences prefs) {
  24.442 +            try {
  24.443 +                return component.newInstance().getCustomizer(prefs);
  24.444 +            } catch (SecurityException ex) {
  24.445 +                Exceptions.printStackTrace(ex);
  24.446 +            } catch (InstantiationException ex) {
  24.447 +                Exceptions.printStackTrace(ex);
  24.448 +            } catch (IllegalAccessException ex) {
  24.449 +                Exceptions.printStackTrace(ex);
  24.450 +            } catch (IllegalArgumentException ex) {
  24.451 +                Exceptions.printStackTrace(ex);
  24.452 +            }
  24.453 +
  24.454 +            return new JPanel();
  24.455 +        }
  24.456 +
  24.457 +    }
  24.458 +
  24.459 +}
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/providers/code/FSWrapper.java	Wed May 08 21:47:42 2013 +0200
    25.3 @@ -0,0 +1,319 @@
    25.4 +/*
    25.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    25.6 + *
    25.7 + * Copyright 2010-2011 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 2010-2011 Sun Microsystems, Inc.
   25.44 + */
   25.45 +
   25.46 +package org.netbeans.modules.java.hints.providers.code;
   25.47 +
   25.48 +import java.lang.annotation.Annotation;
   25.49 +import java.lang.reflect.Array;
   25.50 +import java.lang.reflect.InvocationHandler;
   25.51 +import java.lang.reflect.Method;
   25.52 +import java.lang.reflect.Proxy;
   25.53 +import java.util.HashMap;
   25.54 +import java.util.LinkedList;
   25.55 +import java.util.List;
   25.56 +import java.util.Map;
   25.57 +import java.util.logging.Level;
   25.58 +import java.util.logging.Logger;
   25.59 +import org.netbeans.spi.java.hints.HintContext;
   25.60 +import org.openide.filesystems.FileObject;
   25.61 +import org.openide.filesystems.FileUtil;
   25.62 +import org.openide.util.Exceptions;
   25.63 +
   25.64 +/**
   25.65 + *
   25.66 + * @author lahvac
   25.67 + */
   25.68 +public class FSWrapper {
   25.69 +
   25.70 +    public static Iterable<? extends ClassWrapper> listClasses() {
   25.71 +        ClassLoader loader = FSWrapper.class.getClassLoader();
   25.72 +
   25.73 +        if (loader == null) {
   25.74 +            loader = ClassLoader.getSystemClassLoader();
   25.75 +        }
   25.76 +
   25.77 +        List<ClassWrapper> result = new LinkedList<ClassWrapper>();
   25.78 +        FileObject main = FileUtil.getConfigFile("org-netbeans-modules-java-hints/code-hints/");
   25.79 +
   25.80 +        if (main != null) {
   25.81 +            for (FileObject c : main.getChildren()) {
   25.82 +                result.add(new ClassWrapper(loader, c));
   25.83 +            }
   25.84 +        }
   25.85 +
   25.86 +        return result;
   25.87 +    }
   25.88 +
   25.89 +    public static Method resolveMethod(String className, String methodName) throws NoSuchMethodException, ClassNotFoundException {
   25.90 +        Class<?> clazz = CodeHintProviderImpl.findLoader().loadClass(className);
   25.91 +
   25.92 +        return clazz.getDeclaredMethod(methodName, HintContext.class);
   25.93 +    }
   25.94 +
   25.95 +    public static class AnnotatableWrapper {
   25.96 +        protected final ClassLoader loader;
   25.97 +        protected final FileObject folder;
   25.98 +        protected AnnotatableWrapper(ClassLoader loader, FileObject folder) {
   25.99 +            this.loader = loader;
  25.100 +            this.folder = folder;
  25.101 +        }
  25.102 +
  25.103 +        private final Map<Class<? extends Annotation>, Annotation> annotations = new HashMap<Class<? extends Annotation>, Annotation>();
  25.104 +
  25.105 +        public synchronized <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
  25.106 +            if (!this.annotations.containsKey(annotationClass)) {
  25.107 +                FileObject f = folder.getFileObject(annotationClass.getName().replace('.', '-') + ".annotation");
  25.108 +                T result = null;
  25.109 +
  25.110 +                if (f != null) {
  25.111 +                    try {
  25.112 +                        Annotation a = loadAnnotation(loader, f);
  25.113 +
  25.114 +                        result = annotationClass.cast(a);
  25.115 +                    } catch (ClassNotFoundException ex) {
  25.116 +                        Exceptions.printStackTrace(ex);
  25.117 +                    }
  25.118 +                }
  25.119 +
  25.120 +                this.annotations.put(annotationClass, result);
  25.121 +            }
  25.122 +
  25.123 +            return annotationClass.cast(this.annotations.get(annotationClass));
  25.124 +        }
  25.125 +    }
  25.126 +
  25.127 +    public static class ClassWrapper extends AnnotatableWrapper {
  25.128 +        private final String className;
  25.129 +        public ClassWrapper(ClassLoader loader, FileObject folder) {
  25.130 +            super(loader, folder);
  25.131 +            className = folder.getName().replace('-', '.');
  25.132 +        }
  25.133 +
  25.134 +        private Iterable<? extends MethodWrapper> methods;
  25.135 +
  25.136 +        public synchronized Iterable<? extends MethodWrapper> getMethods() {
  25.137 +            if (this.methods == null) {
  25.138 +                List<MethodWrapper> methods = new LinkedList<MethodWrapper>();
  25.139 +
  25.140 +                for (FileObject c : folder.getChildren()) {
  25.141 +                    if (c.getExt().equals("method")) {
  25.142 +                        methods.add(new MethodWrapper(loader, c, this));
  25.143 +                    }
  25.144 +                }
  25.145 +
  25.146 +                this.methods = methods;
  25.147 +            }
  25.148 +
  25.149 +            return this.methods;
  25.150 +        }
  25.151 +
  25.152 +        private Iterable<? extends FieldWrapper> fields;
  25.153 +
  25.154 +        public synchronized Iterable<? extends FieldWrapper> getFields() {
  25.155 +            if (this.fields == null) {
  25.156 +                List<FieldWrapper> fields = new LinkedList<FieldWrapper>();
  25.157 +
  25.158 +                for (FileObject c : folder.getChildren()) {
  25.159 +                    if (c.getExt().equals("field")) {
  25.160 +                        fields.add(new FieldWrapper(loader, c, this));
  25.161 +                    }
  25.162 +                }
  25.163 +
  25.164 +                this.fields = fields;
  25.165 +            }
  25.166 +
  25.167 +            return this.fields;
  25.168 +        }
  25.169 +
  25.170 +        public String getName() {
  25.171 +            return className;
  25.172 +        }
  25.173 +
  25.174 +        private Class<?> clazz;
  25.175 +        public synchronized Class<?> getDeclaredClass() {
  25.176 +            if (clazz != null) {
  25.177 +                return clazz;
  25.178 +            }
  25.179 +
  25.180 +            try {
  25.181 +                return this.clazz = loader.loadClass(className);
  25.182 +            } catch (ClassNotFoundException ex) {
  25.183 +                Exceptions.printStackTrace(ex);
  25.184 +            }
  25.185 +
  25.186 +            return null; //XXX
  25.187 +        }
  25.188 +    }
  25.189 +
  25.190 +    public static class MethodWrapper extends AnnotatableWrapper {
  25.191 +        private final ClassWrapper clazz;
  25.192 +        public MethodWrapper(ClassLoader loader, FileObject folder, ClassWrapper clazz) {
  25.193 +            super(loader, folder);
  25.194 +            this.clazz = clazz;
  25.195 +        }
  25.196 +
  25.197 +        ClassWrapper getClazz() {
  25.198 +            return clazz;
  25.199 +        }
  25.200 +        
  25.201 +        String getName() {
  25.202 +            return folder.getName();
  25.203 +        }
  25.204 +    }
  25.205 +
  25.206 +    public static class FieldWrapper extends AnnotatableWrapper {
  25.207 +        private final ClassWrapper clazz;
  25.208 +        public FieldWrapper(ClassLoader loader, FileObject folder, ClassWrapper clazz) {
  25.209 +            super(loader, folder);
  25.210 +            this.clazz = clazz;
  25.211 +        }
  25.212 +
  25.213 +        ClassWrapper getClazz() {
  25.214 +            return clazz;
  25.215 +        }
  25.216 +
  25.217 +        String getName() {
  25.218 +            return folder.getName();
  25.219 +        }
  25.220 +
  25.221 +        String getConstantValue() {
  25.222 +            Object constantValue = folder.getAttribute("constantValue");
  25.223 +
  25.224 +            if (constantValue instanceof String) {
  25.225 +                return (String) constantValue;
  25.226 +            }
  25.227 +
  25.228 +            return null;
  25.229 +        }
  25.230 +    }
  25.231 +
  25.232 +    private static final Object MARKER = new Object();
  25.233 +    
  25.234 +    private static Object computeAttributeValue(ClassLoader loader, FileObject folder, String attributeName, Class<?> returnType, Object defaulValue) throws ClassNotFoundException {
  25.235 +        Object result = folder.getAttribute(attributeName);
  25.236 +
  25.237 +        if (result == null) {
  25.238 +            FileObject embedded = folder.getFileObject(attributeName);
  25.239 +
  25.240 +            if (embedded == null) {
  25.241 +                result = defaulValue;
  25.242 +            } else {
  25.243 +                if (returnType.isArray()) {
  25.244 +                    List<Object> items = new LinkedList<Object>();
  25.245 +                    int c = 0;
  25.246 +
  25.247 +                    while (true) {
  25.248 +                        Object val = computeAttributeValue(loader, embedded, "item" + c, returnType.getComponentType(), MARKER);
  25.249 +
  25.250 +                        if (val == MARKER) {
  25.251 +                            break;
  25.252 +                        }
  25.253 +
  25.254 +                        items.add(val);
  25.255 +                        c++;
  25.256 +                    }
  25.257 +
  25.258 +                    Object res = Array.newInstance(returnType.getComponentType(), items.size());
  25.259 +                    int ci = 0;
  25.260 +
  25.261 +                    for (Object i : items) {
  25.262 +                        Array.set(res, ci++, i);
  25.263 +                    }
  25.264 +
  25.265 +                    result = res;
  25.266 +                } else if (returnType.isAnnotation()) {
  25.267 +                    result = loadAnnotation(loader, embedded.getChildren()[0]);
  25.268 +                }
  25.269 +            }
  25.270 +        } else {
  25.271 +            if (returnType.isEnum()) {
  25.272 +                String fqn = (String) result;
  25.273 +                int lastDot = fqn.lastIndexOf('.');
  25.274 +                Class<? extends Enum> enumClass = (Class<? extends Enum>) loader.loadClass(fqn.substring(0, lastDot));
  25.275 +
  25.276 +                result = Enum.valueOf(enumClass, fqn.substring(lastDot + 1));
  25.277 +            } else if (returnType == Class.class) {
  25.278 +                String fqn = (String) result;
  25.279 +
  25.280 +                try {
  25.281 +                    result = loader.loadClass(fqn);
  25.282 +                } catch (ClassNotFoundException ex) {
  25.283 +                    Logger.getLogger(FSWrapper.class.getName()).log(Level.FINE, null, ex);
  25.284 +                    result = CodeHintProviderImpl.findLoader().loadClass(fqn);
  25.285 +                }
  25.286 +            }
  25.287 +        }
  25.288 +
  25.289 +        return result;
  25.290 +    }
  25.291 +
  25.292 +    
  25.293 +    private static <T extends Annotation> T loadAnnotation(ClassLoader l, FileObject annotationFolder) throws ClassNotFoundException {
  25.294 +        Class<?> clazz = l.loadClass(annotationFolder.getName().replace('-', '.'));
  25.295 +
  25.296 +        return (T) Proxy.newProxyInstance(l, new Class[] {clazz}, new InvocationHandlerImpl(l, annotationFolder));
  25.297 +    }
  25.298 +    
  25.299 +    private static final class InvocationHandlerImpl implements InvocationHandler {
  25.300 +
  25.301 +        private final ClassLoader loader;
  25.302 +        private final FileObject folder;
  25.303 +        private final Map<String, Object> attributes = new HashMap<String, Object>();
  25.304 +
  25.305 +        public InvocationHandlerImpl(ClassLoader loader, FileObject folder) {
  25.306 +            this.loader = loader;
  25.307 +            this.folder = folder;
  25.308 +        }
  25.309 +
  25.310 +        public synchronized Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  25.311 +            if (!attributes.containsKey(method.getName())) {
  25.312 +                Object result = computeAttributeValue(loader, folder, method.getName(), method.getReturnType(), method.getDefaultValue());
  25.313 +
  25.314 +                attributes.put(method.getName(), result);
  25.315 +            }
  25.316 +
  25.317 +            return attributes.get(method.getName());
  25.318 +        }
  25.319 +
  25.320 +    }
  25.321 +
  25.322 +}
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/providers/code/ReflectiveCustomizerProvider.java	Wed May 08 21:47:42 2013 +0200
    26.3 @@ -0,0 +1,261 @@
    26.4 +/*
    26.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    26.6 + *
    26.7 + * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
    26.8 + *
    26.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   26.10 + * Other names may be trademarks of their respective owners.
   26.11 + *
   26.12 + * The contents of this file are subject to the terms of either the GNU
   26.13 + * General Public License Version 2 only ("GPL") or the Common
   26.14 + * Development and Distribution License("CDDL") (collectively, the
   26.15 + * "License"). You may not use this file except in compliance with the
   26.16 + * License. You can obtain a copy of the License at
   26.17 + * http://www.netbeans.org/cddl-gplv2.html
   26.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   26.19 + * specific language governing permissions and limitations under the
   26.20 + * License.  When distributing the software, include this License Header
   26.21 + * Notice in each file and include the License file at
   26.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   26.23 + * particular file as subject to the "Classpath" exception as provided
   26.24 + * by Oracle in the GPL Version 2 section of the License file that
   26.25 + * accompanied this code. If applicable, add the following below the
   26.26 + * License Header, with the fields enclosed by brackets [] replaced by
   26.27 + * your own identifying information:
   26.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   26.29 + *
   26.30 + * If you wish your version of this file to be governed by only the CDDL
   26.31 + * or only the GPL Version 2, indicate your decision by adding
   26.32 + * "[Contributor] elects to include this software in this distribution
   26.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   26.34 + * single choice of license, a recipient has the option to distribute
   26.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   26.36 + * to extend the choice of license to its licensees as provided above.
   26.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   26.38 + * Version 2 license, then the option applies only if the new code is
   26.39 + * made subject to such option by the copyright holder.
   26.40 + *
   26.41 + * Contributor(s):
   26.42 + *
   26.43 + * Portions Copyrighted 2012 Sun Microsystems, Inc.
   26.44 + */
   26.45 +package org.netbeans.modules.java.hints.providers.code;
   26.46 +
   26.47 +import java.awt.GridBagConstraints;
   26.48 +import java.awt.GridBagLayout;
   26.49 +import java.awt.Insets;
   26.50 +import java.awt.event.ActionEvent;
   26.51 +import java.awt.event.ActionListener;
   26.52 +import java.util.List;
   26.53 +import java.util.prefs.Preferences;
   26.54 +import javax.swing.JCheckBox;
   26.55 +import javax.swing.JComponent;
   26.56 +import javax.swing.JFormattedTextField;
   26.57 +import javax.swing.JLabel;
   26.58 +import javax.swing.JPanel;
   26.59 +import javax.swing.JSpinner;
   26.60 +import javax.swing.SpinnerNumberModel;
   26.61 +import javax.swing.event.ChangeEvent;
   26.62 +import javax.swing.event.ChangeListener;
   26.63 +import javax.swing.text.NumberFormatter;
   26.64 +import org.netbeans.spi.java.hints.BooleanOption;
   26.65 +import org.netbeans.spi.java.hints.CustomizerProvider;
   26.66 +import org.netbeans.spi.java.hints.IntegerOption;
   26.67 +import org.openide.util.Exceptions;
   26.68 +
   26.69 +/**
   26.70 + *
   26.71 + * @author lahvac
   26.72 + */
   26.73 +public class ReflectiveCustomizerProvider implements CustomizerProvider {
   26.74 +    private final String hintClassName;
   26.75 +    private final String hintId;
   26.76 +    private final List<OptionDescriptor> options;
   26.77 +
   26.78 +    public ReflectiveCustomizerProvider(String hintClassName, String hintId, List<OptionDescriptor> options) {
   26.79 +        this.hintClassName = hintClassName;
   26.80 +        this.hintId = hintId;
   26.81 +        this.options = options;
   26.82 +    }
   26.83 +
   26.84 +    @Override
   26.85 +    public JComponent getCustomizer(Preferences prefs) {
   26.86 +        return new CustomizerImpl(prefs, hintClassName, hintId, options);
   26.87 +    }
   26.88 +
   26.89 +    private static final class CustomizerImpl extends JPanel {
   26.90 +        private int row;
   26.91 +        
   26.92 +        public CustomizerImpl(Preferences prefs, String hintClassName, String hintId, List<OptionDescriptor> options) {
   26.93 +            try {
   26.94 +                setLayout(new GridBagLayout());
   26.95 +                row = 0;
   26.96 +                
   26.97 +                for (OptionDescriptor option : options) {
   26.98 +                    if (option.parameters instanceof IntegerOption) {
   26.99 +                        createIntegerOption(option, prefs);
  26.100 +                    }
  26.101 +                }
  26.102 +
  26.103 +                for (OptionDescriptor option : options) {
  26.104 +                    if (option.parameters instanceof BooleanOption) {
  26.105 +                        createBooleanOption(option, prefs);
  26.106 +                    }
  26.107 +                }
  26.108 +
  26.109 +                GridBagConstraints constraints = new GridBagConstraints();
  26.110 +
  26.111 +                constraints.anchor = GridBagConstraints.NORTHWEST;
  26.112 +                constraints.fill = GridBagConstraints.BOTH;
  26.113 +                constraints.gridheight = 1;
  26.114 +                constraints.gridwidth = GridBagConstraints.REMAINDER;
  26.115 +                constraints.gridx = 0;
  26.116 +                constraints.gridy = row++;
  26.117 +                constraints.weightx = 1;
  26.118 +                constraints.weighty = 1;
  26.119 +
  26.120 +                add(new JPanel(), constraints);
  26.121 +            } catch (IllegalArgumentException ex) {
  26.122 +                Exceptions.printStackTrace(ex);
  26.123 +            } catch (SecurityException ex) {
  26.124 +                Exceptions.printStackTrace(ex);
  26.125 +            }
  26.126 +        }
  26.127 +        
  26.128 +        private void createIntegerOption(OptionDescriptor option, Preferences prefs) {
  26.129 +            IntegerOption iopt = (IntegerOption)option.parameters;
  26.130 +            JLabel l = new JLabel();
  26.131 +            org.openide.awt.Mnemonics.setLocalizedText(l, option.displayName + ":");
  26.132 +            
  26.133 +            GridBagConstraints constraints = new GridBagConstraints();
  26.134 +            constraints.anchor = GridBagConstraints.WEST;
  26.135 +            constraints.fill = GridBagConstraints.NONE;
  26.136 +            constraints.gridheight = 1;
  26.137 +            constraints.gridwidth = 1;
  26.138 +            constraints.gridx = 0;
  26.139 +            constraints.gridy = row;
  26.140 +            constraints.weightx = 0;
  26.141 +            constraints.weighty = 0;
  26.142 +            constraints.insets = new Insets(0, 0, 0, 8);
  26.143 +            
  26.144 +            add(l, constraints);
  26.145 +            
  26.146 +            JComponent field;
  26.147 +            int val = prefs.getInt(option.preferencesKey, ((Integer)option.defaultValue).intValue());
  26.148 +            if (iopt.step() > 0) {
  26.149 +                val = Math.min(iopt.maxValue(), Math.max(iopt.minValue(), val));
  26.150 +                JSpinner spinner = new JSpinner(
  26.151 +                        new SpinnerNumberModel(val, iopt.minValue(), iopt.maxValue(), iopt.step()));
  26.152 +                spinner.addChangeListener(new ActionListenerImpl(option.preferencesKey, prefs));
  26.153 +                field = spinner;
  26.154 +            } else {
  26.155 +                NumberFormatter nf = new NumberFormatter();
  26.156 +                nf.setValueClass(Integer.class);
  26.157 +                nf.setMaximum(iopt.maxValue());
  26.158 +                nf.setMinimum(iopt.minValue());
  26.159 +                JFormattedTextField formatted = new JFormattedTextField(nf);
  26.160 +                field = formatted;
  26.161 +            }
  26.162 +            if (option.tooltip != null && !option.tooltip.isEmpty()) {
  26.163 +                field.setToolTipText(option.tooltip);
  26.164 +            }
  26.165 +            constraints = new GridBagConstraints();
  26.166 +            constraints.anchor = GridBagConstraints.WEST;
  26.167 +            constraints.fill = GridBagConstraints.HORIZONTAL;
  26.168 +            constraints.gridheight = 1;
  26.169 +            constraints.gridwidth = 1;
  26.170 +            constraints.gridx = 1;
  26.171 +            constraints.gridy = row;
  26.172 +            constraints.weightx = 0;
  26.173 +            constraints.weighty = 0;
  26.174 +            
  26.175 +            add(field, constraints);
  26.176 +
  26.177 +            constraints = new GridBagConstraints();
  26.178 +            constraints.anchor = GridBagConstraints.WEST;
  26.179 +            constraints.fill = GridBagConstraints.HORIZONTAL;
  26.180 +            constraints.gridheight = 1;
  26.181 +            constraints.gridwidth = GridBagConstraints.REMAINDER;
  26.182 +            constraints.gridx = 2;
  26.183 +            constraints.gridy = row++;
  26.184 +            constraints.weightx = 1;
  26.185 +            constraints.weighty = 0;
  26.186 +            
  26.187 +            add(new JPanel(), constraints);
  26.188 +        }
  26.189 +        
  26.190 +        private JComponent createBooleanOption(OptionDescriptor option, Preferences prefs)  {
  26.191 +            JCheckBox checkBox = new JCheckBox();
  26.192 +
  26.193 +            org.openide.awt.Mnemonics.setLocalizedText(checkBox, option.displayName);
  26.194 +            checkBox.setToolTipText(option.tooltip);
  26.195 +            checkBox.addActionListener(new ActionListenerImpl(option.preferencesKey, prefs));
  26.196 +
  26.197 +            checkBox.setSelected(prefs.getBoolean(option.preferencesKey, 
  26.198 +                    Boolean.TRUE == option.defaultValue));
  26.199 +            GridBagConstraints constraints = new GridBagConstraints();
  26.200 +
  26.201 +            constraints.anchor = GridBagConstraints.WEST;
  26.202 +            constraints.fill = GridBagConstraints.NONE;
  26.203 +            constraints.gridheight = 1;
  26.204 +            constraints.gridwidth = 2;
  26.205 +            constraints.gridx = 0;
  26.206 +            constraints.gridy = row++;
  26.207 +            constraints.weightx = 0;
  26.208 +            constraints.weighty = 0;
  26.209 +
  26.210 +            add(checkBox, constraints);
  26.211 +            return checkBox;
  26.212 +        }
  26.213 +                
  26.214 +        
  26.215 +        private static final class ActionListenerImpl implements ActionListener, ChangeListener {
  26.216 +            private final String key;
  26.217 +            private final Preferences prefs;
  26.218 +
  26.219 +            public ActionListenerImpl(String key, Preferences prefs) {
  26.220 +                this.key = key;
  26.221 +                this.prefs = prefs;
  26.222 +            }
  26.223 +
  26.224 +            @Override
  26.225 +            public void actionPerformed(ActionEvent e) {
  26.226 +                JCheckBox checkBox = ((JCheckBox)e.getSource());
  26.227 +                prefs.putBoolean(key, checkBox.isSelected());
  26.228 +            }
  26.229 +
  26.230 +            @Override
  26.231 +            public void stateChanged(ChangeEvent e) {
  26.232 +                Integer i = (Integer)((JSpinner)e.getSource()).getValue();
  26.233 +                prefs.putInt(key, i);
  26.234 +            }
  26.235 +
  26.236 +        }
  26.237 +        
  26.238 +    }
  26.239 +
  26.240 +    public static final class OptionDescriptor {
  26.241 +        public final String preferencesKey;
  26.242 +        public final Object defaultValue;
  26.243 +        public final String displayName;
  26.244 +        public final String tooltip;
  26.245 +        /**
  26.246 +         * The original Annotation object, type-specific parameters.
  26.247 +         */
  26.248 +        public final Object parameters;
  26.249 +
  26.250 +        public OptionDescriptor(
  26.251 +                String preferencesKey, 
  26.252 +                Object defaultValue, 
  26.253 +                String displayName, String tooltip, 
  26.254 +                Object parameters) {
  26.255 +            this.preferencesKey = preferencesKey;
  26.256 +            this.defaultValue = defaultValue;
  26.257 +            this.displayName = displayName;
  26.258 +            this.tooltip = tooltip;
  26.259 +            this.parameters = parameters;
  26.260 +        }
  26.261 +
  26.262 +    }
  26.263 +
  26.264 +}
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/providers/spi/ClassPathBasedHintProvider.java	Wed May 08 21:47:42 2013 +0200
    27.3 @@ -0,0 +1,57 @@
    27.4 +/*
    27.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    27.6 + *
    27.7 + * Copyright 2010 Oracle and/or its affiliates. All rights reserved.
    27.8 + *
    27.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   27.10 + * Other names may be trademarks of their respective owners.
   27.11 + *
   27.12 + * The contents of this file are subject to the terms of either the GNU
   27.13 + * General Public License Version 2 only ("GPL") or the Common
   27.14 + * Development and Distribution License("CDDL") (collectively, the
   27.15 + * "License"). You may not use this file except in compliance with the
   27.16 + * License. You can obtain a copy of the License at
   27.17 + * http://www.netbeans.org/cddl-gplv2.html
   27.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   27.19 + * specific language governing permissions and limitations under the
   27.20 + * License.  When distributing the software, include this License Header
   27.21 + * Notice in each file and include the License file at
   27.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   27.23 + * particular file as subject to the "Classpath" exception as provided
   27.24 + * by Oracle in the GPL Version 2 section of the License file that
   27.25 + * accompanied this code. If applicable, add the following below the
   27.26 + * License Header, with the fields enclosed by brackets [] replaced by
   27.27 + * your own identifying information:
   27.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   27.29 + *
   27.30 + * If you wish your version of this file to be governed by only the CDDL
   27.31 + * or only the GPL Version 2, indicate your decision by adding
   27.32 + * "[Contributor] elects to include this software in this distribution
   27.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   27.34 + * single choice of license, a recipient has the option to distribute
   27.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   27.36 + * to extend the choice of license to its licensees as provided above.
   27.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   27.38 + * Version 2 license, then the option applies only if the new code is
   27.39 + * made subject to such option by the copyright holder.
   27.40 + *
   27.41 + * Contributor(s):
   27.42 + *
   27.43 + * Portions Copyrighted 2009 Sun Microsystems, Inc.
   27.44 + */
   27.45 +
   27.46 +package org.netbeans.modules.java.hints.providers.spi;
   27.47 +
   27.48 +import java.util.Collection;
   27.49 +import org.netbeans.api.java.classpath.ClassPath;
   27.50 +import org.netbeans.modules.java.hints.providers.spi.HintDescription;
   27.51 +
   27.52 +/**
   27.53 + * XXX: this is another ugly hack!
   27.54 + * @author lahvac
   27.55 + */
   27.56 +public interface ClassPathBasedHintProvider {
   27.57 +
   27.58 +    public Collection<? extends HintDescription> computeHints(ClassPath cp);
   27.59 +
   27.60 +}
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/providers/spi/ElementBasedHintProvider.java	Wed May 08 21:47:42 2013 +0200
    28.3 @@ -0,0 +1,57 @@
    28.4 +/*
    28.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    28.6 + *
    28.7 + * Copyright 2010 Oracle and/or its affiliates. All rights reserved.
    28.8 + *
    28.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   28.10 + * Other names may be trademarks of their respective owners.
   28.11 + *
   28.12 + * The contents of this file are subject to the terms of either the GNU
   28.13 + * General Public License Version 2 only ("GPL") or the Common
   28.14 + * Development and Distribution License("CDDL") (collectively, the
   28.15 + * "License"). You may not use this file except in compliance with the
   28.16 + * License. You can obtain a copy of the License at
   28.17 + * http://www.netbeans.org/cddl-gplv2.html
   28.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   28.19 + * specific language governing permissions and limitations under the
   28.20 + * License.  When distributing the software, include this License Header
   28.21 + * Notice in each file and include the License file at
   28.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   28.23 + * particular file as subject to the "Classpath" exception as provided
   28.24 + * by Oracle in the GPL Version 2 section of the License file that
   28.25 + * accompanied this code. If applicable, add the following below the
   28.26 + * License Header, with the fields enclosed by brackets [] replaced by
   28.27 + * your own identifying information:
   28.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   28.29 + *
   28.30 + * If you wish your version of this file to be governed by only the CDDL
   28.31 + * or only the GPL Version 2, indicate your decision by adding
   28.32 + * "[Contributor] elects to include this software in this distribution
   28.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   28.34 + * single choice of license, a recipient has the option to distribute
   28.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   28.36 + * to extend the choice of license to its licensees as provided above.
   28.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   28.38 + * Version 2 license, then the option applies only if the new code is
   28.39 + * made subject to such option by the copyright holder.
   28.40 + *
   28.41 + * Contributor(s):
   28.42 + *
   28.43 + * Portions Copyrighted 2009 Sun Microsystems, Inc.
   28.44 + */
   28.45 +
   28.46 +package org.netbeans.modules.java.hints.providers.spi;
   28.47 +
   28.48 +import java.util.Collection;
   28.49 +import org.netbeans.api.java.source.CompilationInfo;
   28.50 +import org.netbeans.modules.java.hints.providers.spi.HintDescription;
   28.51 +
   28.52 +/**
   28.53 + * XXX: this is an ugly hack!
   28.54 + * @author lahvac
   28.55 + */
   28.56 +public interface ElementBasedHintProvider {
   28.57 +
   28.58 +    public Collection<? extends HintDescription> computeHints(CompilationInfo info);
   28.59 +
   28.60 +}
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/providers/spi/HintDescription.java	Wed May 08 21:47:42 2013 +0200
    29.3 @@ -0,0 +1,127 @@
    29.4 +/*
    29.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    29.6 + *
    29.7 + * Copyright 2009-2010 Oracle and/or its affiliates. All rights reserved.
    29.8 + *
    29.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   29.10 + * Other names may be trademarks of their respective owners.
   29.11 + *
   29.12 + * The contents of this file are subject to the terms of either the GNU
   29.13 + * General Public License Version 2 only ("GPL") or the Common
   29.14 + * Development and Distribution License("CDDL") (collectively, the
   29.15 + * "License"). You may not use this file except in compliance with the
   29.16 + * License. You can obtain a copy of the License at
   29.17 + * http://www.netbeans.org/cddl-gplv2.html
   29.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   29.19 + * specific language governing permissions and limitations under the
   29.20 + * License.  When distributing the software, include this License Header
   29.21 + * Notice in each file and include the License file at
   29.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   29.23 + * particular file as subject to the "Classpath" exception as provided
   29.24 + * by Oracle in the GPL Version 2 section of the License file that
   29.25 + * accompanied this code. If applicable, add the following below the
   29.26 + * License Header, with the fields enclosed by brackets [] replaced by
   29.27 + * your own identifying information:
   29.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   29.29 + *
   29.30 + * If you wish your version of this file to be governed by only the CDDL
   29.31 + * or only the GPL Version 2, indicate your decision by adding
   29.32 + * "[Contributor] elects to include this software in this distribution
   29.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   29.34 + * single choice of license, a recipient has the option to distribute
   29.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   29.36 + * to extend the choice of license to its licensees as provided above.
   29.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   29.38 + * Version 2 license, then the option applies only if the new code is
   29.39 + * made subject to such option by the copyright holder.
   29.40 + *
   29.41 + * Contributor(s):
   29.42 + *
   29.43 + * Portions Copyrighted 2009-2010 Sun Microsystems, Inc.
   29.44 + */
   29.45 +
   29.46 +package org.netbeans.modules.java.hints.providers.spi;
   29.47 +
   29.48 +import java.util.Collection;
   29.49 +import java.util.Collections;
   29.50 +import java.util.HashSet;
   29.51 +import java.util.Set;
   29.52 +import org.netbeans.modules.java.hints.providers.spi.HintMetadata.Options;
   29.53 +import org.netbeans.spi.editor.hints.ErrorDescription;
   29.54 +import org.netbeans.spi.java.hints.HintContext;
   29.55 +
   29.56 +/**
   29.57 + *
   29.58 + * @author Jan Lahoda
   29.59 + */
   29.60 +public final class HintDescription {
   29.61 +
   29.62 +    private final HintMetadata metadata;
   29.63 +    private final Trigger trigger;
   29.64 +    private final Worker worker;
   29.65 +    private final AdditionalQueryConstraints additionalConstraints;
   29.66 +    private final String hintText;
   29.67 +    private final Set<Options> options;
   29.68 +
   29.69 +    private HintDescription(HintMetadata metadata, Trigger trigger, Worker worker, AdditionalQueryConstraints additionalConstraints, String hintText, Set<Options> options) {
   29.70 +        this.metadata = metadata;
   29.71 +        this.trigger = trigger;
   29.72 +        this.worker = worker;
   29.73 +        this.additionalConstraints = additionalConstraints;
   29.74 +        this.hintText = hintText;
   29.75 +        this.options = options;
   29.76 +    }
   29.77 +
   29.78 +    static HintDescription create(HintMetadata metadata, Trigger trigger, Worker worker, AdditionalQueryConstraints additionalConstraints, String hintText, Set<Options> options) {
   29.79 +        return new HintDescription(metadata, trigger, worker, additionalConstraints, hintText, options);
   29.80 +    }
   29.81 +
   29.82 +    @Override
   29.83 +    public String toString() {
   29.84 +        return "[HintDescription:" + trigger + "]";
   29.85 +    }
   29.86 +
   29.87 +    public AdditionalQueryConstraints getAdditionalConstraints() {
   29.88 +        return additionalConstraints;
   29.89 +    }
   29.90 +
   29.91 +    public String getHintText() {
   29.92 +        return hintText;
   29.93 +    }
   29.94 +
   29.95 +    public HintMetadata getMetadata() {
   29.96 +        return metadata;
   29.97 +    }
   29.98 +
   29.99 +    public Trigger getTrigger() {
  29.100 +        return trigger;
  29.101 +    }
  29.102 +
  29.103 +    public Worker getWorker() {
  29.104 +        return worker;
  29.105 +    }
  29.106 +
  29.107 +    public Set<Options> getOptions() {
  29.108 +        return options;
  29.109 +    }
  29.110 +
  29.111 +    public static interface Worker {
  29.112 +
  29.113 +        public Collection<? extends ErrorDescription> createErrors(HintContext ctx);
  29.114 +
  29.115 +    }
  29.116 +
  29.117 +    public static final class AdditionalQueryConstraints {
  29.118 +        public final Set<String> requiredErasedTypes;
  29.119 +
  29.120 +        public AdditionalQueryConstraints(Set<String> requiredErasedTypes) {
  29.121 +            this.requiredErasedTypes = Collections.unmodifiableSet(new HashSet<String>(requiredErasedTypes));
  29.122 +        }
  29.123 +
  29.124 +        private static final AdditionalQueryConstraints EMPTY = new AdditionalQueryConstraints(Collections.<String>emptySet());
  29.125 +        public static AdditionalQueryConstraints empty() {
  29.126 +            return EMPTY;
  29.127 +        }
  29.128 +    }
  29.129 +
  29.130 +}
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/providers/spi/HintDescriptionFactory.java	Wed May 08 21:47:42 2013 +0200
    30.3 @@ -0,0 +1,127 @@
    30.4 +/*
    30.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    30.6 + *
    30.7 + * Copyright 2009-2010 Oracle and/or its affiliates. All rights reserved.
    30.8 + *
    30.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   30.10 + * Other names may be trademarks of their respective owners.
   30.11 + *
   30.12 + * The contents of this file are subject to the terms of either the GNU
   30.13 + * General Public License Version 2 only ("GPL") or the Common
   30.14 + * Development and Distribution License("CDDL") (collectively, the
   30.15 + * "License"). You may not use this file except in compliance with the
   30.16 + * License. You can obtain a copy of the License at
   30.17 + * http://www.netbeans.org/cddl-gplv2.html
   30.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   30.19 + * specific language governing permissions and limitations under the
   30.20 + * License.  When distributing the software, include this License Header
   30.21 + * Notice in each file and include the License file at
   30.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   30.23 + * particular file as subject to the "Classpath" exception as provided
   30.24 + * by Oracle in the GPL Version 2 section of the License file that
   30.25 + * accompanied this code. If applicable, add the following below the
   30.26 + * License Header, with the fields enclosed by brackets [] replaced by
   30.27 + * your own identifying information:
   30.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   30.29 + *
   30.30 + * If you wish your version of this file to be governed by only the CDDL
   30.31 + * or only the GPL Version 2, indicate your decision by adding
   30.32 + * "[Contributor] elects to include this software in this distribution
   30.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   30.34 + * single choice of license, a recipient has the option to distribute
   30.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   30.36 + * to extend the choice of license to its licensees as provided above.
   30.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   30.38 + * Version 2 license, then the option applies only if the new code is
   30.39 + * made subject to such option by the copyright holder.
   30.40 + *
   30.41 + * Contributor(s):
   30.42 + *
   30.43 + * Portions Copyrighted 2009-2010 Sun Microsystems, Inc.
   30.44 + */
   30.45 +
   30.46 +package org.netbeans.modules.java.hints.providers.spi;
   30.47 +
   30.48 +import java.util.Arrays;
   30.49 +import java.util.Collections;
   30.50 +import java.util.EnumSet;
   30.51 +import java.util.Set;
   30.52 +import org.netbeans.api.annotations.common.NonNull;
   30.53 +import org.netbeans.modules.java.hints.providers.spi.HintDescription.AdditionalQueryConstraints;
   30.54 +import org.netbeans.modules.java.hints.providers.spi.HintDescription.Worker;
   30.55 +import org.netbeans.modules.java.hints.providers.spi.HintMetadata.Options;
   30.56 +
   30.57 +/**
   30.58 + *
   30.59 + * @author lahvac
   30.60 + */
   30.61 +public class HintDescriptionFactory {
   30.62 +
   30.63 +    private       HintMetadata metadata;
   30.64 +    private       Trigger trigger;
   30.65 +    private       Worker worker;
   30.66 +    private       AdditionalQueryConstraints additionalConstraints;
   30.67 +    private       String hintText;
   30.68 +    private       Set<Options> options;
   30.69 +    private       boolean finished;
   30.70 +
   30.71 +    private HintDescriptionFactory() {
   30.72 +    }
   30.73 +
   30.74 +    public static HintDescriptionFactory create() {
   30.75 +        return new HintDescriptionFactory();
   30.76 +    }
   30.77 +
   30.78 +    /**TODO: move to create?
   30.79 +     *
   30.80 +     * @param metadata
   30.81 +     * @return
   30.82 +     */
   30.83 +    public HintDescriptionFactory setMetadata(HintMetadata metadata) {
   30.84 +        this.metadata = metadata;
   30.85 +        return this;
   30.86 +    }
   30.87 +
   30.88 +    public HintDescriptionFactory setTrigger(Trigger trigger) {
   30.89 +        if (this.trigger != null) {
   30.90 +            throw new IllegalStateException(this.trigger.toString());
   30.91 +        }
   30.92 +
   30.93 +        this.trigger = trigger;
   30.94 +        return this;
   30.95 +    }
   30.96 +
   30.97 +    public HintDescriptionFactory setWorker(Worker worker) {
   30.98 +        this.worker = worker;
   30.99 +        return this;
  30.100 +    }
  30.101 +
  30.102 +    public HintDescriptionFactory setAdditionalConstraints(AdditionalQueryConstraints additionalConstraints) {
  30.103 +        this.additionalConstraints = additionalConstraints;
  30.104 +        return this;
  30.105 +    }
  30.106 +
  30.107 +    public HintDescriptionFactory setHintText(@NonNull String hintText) {
  30.108 +        this.hintText = hintText;
  30.109 +        return this;
  30.110 +    }
  30.111 +
  30.112 +    public HintDescriptionFactory addOptions(Options... options) {
  30.113 +        if (this.options == null) {
  30.114 +            this.options = EnumSet.noneOf(Options.class);
  30.115 +        }
  30.116 +        this.options.addAll(Arrays.asList(options));
  30.117 +        return this;
  30.118 +    }
  30.119 +        
  30.120 +    public HintDescription produce() {
  30.121 +        if (metadata == null) {
  30.122 +            metadata = HintMetadata.Builder.create("no-id").addOptions(Options.NON_GUI).build();
  30.123 +        }
  30.124 +        if (this.additionalConstraints == null) {
  30.125 +            this.additionalConstraints = AdditionalQueryConstraints.empty();
  30.126 +        }
  30.127 +        return HintDescription.create(metadata, trigger, worker, additionalConstraints, hintText, options != null ? options : Collections.<Options>emptySet());
  30.128 +    }
  30.129 +    
  30.130 +}
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/providers/spi/HintMetadata.java	Wed May 08 21:47:42 2013 +0200
    31.3 @@ -0,0 +1,224 @@
    31.4 +/*
    31.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    31.6 + *
    31.7 + * Copyright 2010 Oracle and/or its affiliates. All rights reserved.
    31.8 + *
    31.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   31.10 + * Other names may be trademarks of their respective owners.
   31.11 + *
   31.12 + * The contents of this file are subject to the terms of either the GNU
   31.13 + * General Public License Version 2 only ("GPL") or the Common
   31.14 + * Development and Distribution License("CDDL") (collectively, the
   31.15 + * "License"). You may not use this file except in compliance with the
   31.16 + * License. You can obtain a copy of the License at
   31.17 + * http://www.netbeans.org/cddl-gplv2.html
   31.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   31.19 + * specific language governing permissions and limitations under the
   31.20 + * License.  When distributing the software, include this License Header
   31.21 + * Notice in each file and include the License file at
   31.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   31.23 + * particular file as subject to the "Classpath" exception as provided
   31.24 + * by Oracle in the GPL Version 2 section of the License file that
   31.25 + * accompanied this code. If applicable, add the following below the
   31.26 + * License Header, with the fields enclosed by brackets [] replaced by
   31.27 + * your own identifying information:
   31.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   31.29 + *
   31.30 + * If you wish your version of this file to be governed by only the CDDL
   31.31 + * or only the GPL Version 2, indicate your decision by adding
   31.32 + * "[Contributor] elects to include this software in this distribution
   31.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   31.34 + * single choice of license, a recipient has the option to distribute
   31.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   31.36 + * to extend the choice of license to its licensees as provided above.
   31.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   31.38 + * Version 2 license, then the option applies only if the new code is
   31.39 + * made subject to such option by the copyright holder.
   31.40 + *
   31.41 + * Contributor(s):
   31.42 + *
   31.43 + * Portions Copyrighted 2010 Sun Microsystems, Inc.
   31.44 + */
   31.45 +
   31.46 +package org.netbeans.modules.java.hints.providers.spi;
   31.47 +
   31.48 +import java.util.ArrayList;
   31.49 +import java.util.Arrays;
   31.50 +import java.util.Collection;
   31.51 +import java.util.EnumSet;
   31.52 +import java.util.HashSet;
   31.53 +import java.util.MissingResourceException;
   31.54 +import java.util.ResourceBundle;
   31.55 +import java.util.Set;
   31.56 +import java.util.logging.Level;
   31.57 +import java.util.logging.Logger;
   31.58 +import org.netbeans.spi.editor.hints.Severity;
   31.59 +import org.netbeans.spi.java.hints.CustomizerProvider;
   31.60 +import org.netbeans.spi.java.hints.Hint;
   31.61 +import org.openide.util.NbBundle;
   31.62 +
   31.63 +/**
   31.64 + *
   31.65 + * @author lahvac
   31.66 + */
   31.67 +public class HintMetadata {
   31.68 +
   31.69 +    public final String id;
   31.70 +    public final String displayName;
   31.71 +    public final String description;
   31.72 +    public final String category;
   31.73 +    public final boolean enabled;
   31.74 +    public final Hint.Kind kind;
   31.75 +    public final Severity severity;
   31.76 +    public final Collection<? extends String> suppressWarnings;
   31.77 +    public final CustomizerProvider customizer;
   31.78 +    public final boolean showInTaskList = false;
   31.79 +    public final Set<Options> options;
   31.80 +
   31.81 +    HintMetadata(String id, String displayName, String description, String category, boolean enabled, Hint.Kind kind, Severity severity, Collection<? extends String> suppressWarnings, CustomizerProvider customizer, Set<Options> options) {
   31.82 +        this.id = id;
   31.83 +        this.displayName = displayName;
   31.84 +        this.description = description;
   31.85 +        this.category = category;
   31.86 +        this.enabled = enabled;
   31.87 +        this.kind = kind;
   31.88 +        this.severity = severity;
   31.89 +        this.suppressWarnings = suppressWarnings;
   31.90 +        this.customizer = customizer;
   31.91 +        this.options = options;
   31.92 +    }
   31.93 +
   31.94 +    @Override
   31.95 +    public String toString() {
   31.96 +        return this.displayName;
   31.97 +    }
   31.98 +
   31.99 +    private static String lookup(ResourceBundle bundle, String key, String def) {
  31.100 +        try {
  31.101 +            return bundle != null ? bundle.getString(key) : def;
  31.102 +        } catch (MissingResourceException mre) {
  31.103 +            Logger.getLogger(HintMetadata.class.getName()).log(Level.FINE, null, mre);
  31.104 +            return def;
  31.105 +        }
  31.106 +    }
  31.107 +
  31.108 +    public static final class Builder {
  31.109 +        private final String id;
  31.110 +        private String displayName;
  31.111 +        private String description;
  31.112 +        private String category;
  31.113 +        private boolean enabled;
  31.114 +        private Hint.Kind kind;
  31.115 +        private Severity severity;
  31.116 +        private final Collection<String> suppressWarnings = new ArrayList<String>();
  31.117 +        private CustomizerProvider customizer;
  31.118 +        private final Set<Options> options = EnumSet.noneOf(Options.class);
  31.119 +
  31.120 +        private Builder(String id) {
  31.121 +            this.id = id;
  31.122 +            this.displayName = "";
  31.123 +            this.description = "";
  31.124 +            this.category = "";
  31.125 +            this.enabled = true;
  31.126 +            this.kind = Hint.Kind.INSPECTION;
  31.127 +            this.severity = Severity.VERIFIER;
  31.128 +        }
  31.129 +
  31.130 +        public static Builder create(String id) {
  31.131 +            return new Builder(id);
  31.132 +        }
  31.133 +
  31.134 +        public Builder setDescription(String displayName, String description) {
  31.135 +            this.displayName = displayName;
  31.136 +            this.description = description;
  31.137 +            return this;
  31.138 +        }
  31.139 +
  31.140 +        public Builder setBundle(ResourceBundle bundle) {
  31.141 +            return setBundle(bundle, null, null);
  31.142 +        }
  31.143 +
  31.144 +        public Builder setBundle(ResourceBundle bundle, String fallbackDisplayName, String fallbackDescription) {
  31.145 +            if (fallbackDisplayName == null) fallbackDisplayName = "No Display Name";
  31.146 +            if (fallbackDescription == null) fallbackDescription = "No Description";
  31.147 +            
  31.148 +            this.displayName = lookup(bundle, "DN_" + id.replace('$', '.'), fallbackDisplayName);
  31.149 +            this.description = lookup(bundle, "DESC_" + id.replace('$', '.'), fallbackDescription);
  31.150 +            return this;
  31.151 +        }
  31.152 +
  31.153 +        public Builder setBundle(String bundleForFQN) {
  31.154 +            ResourceBundle bundle;
  31.155 +
  31.156 +            try {
  31.157 +                int lastDot = bundleForFQN.lastIndexOf('.');
  31.158 +
  31.159 +                assert lastDot >= 0;
  31.160 +
  31.161 +                bundle = NbBundle.getBundle(bundleForFQN.substring(0, lastDot + 1) + "Bundle");
  31.162 +            } catch (MissingResourceException mre) {
  31.163 +                Logger.getLogger(HintMetadata.class.getName()).log(Level.FINE, null, mre);
  31.164 +                bundle = null;
  31.165 +            }
  31.166 +            return setBundle(bundle);
  31.167 +        }
  31.168 +
  31.169 +        public Builder setCategory(String category) {
  31.170 +            this.category = category;
  31.171 +            return this;
  31.172 +        }
  31.173 +
  31.174 +        public Builder setEnabled(boolean enabled) {
  31.175 +            this.enabled = enabled;
  31.176 +            return this;
  31.177 +        }
  31.178 +
  31.179 +        public Builder setKind(Hint.Kind kind) {
  31.180 +            this.kind = kind;
  31.181 +            return this;
  31.182 +        }
  31.183 +
  31.184 +        public Builder setSeverity(Severity severity) {
  31.185 +            this.severity = severity;
  31.186 +            return this;
  31.187 +        }
  31.188 +
  31.189 +
  31.190 +        public Builder addSuppressWarnings(String... keys) {
  31.191 +            this.suppressWarnings.addAll(Arrays.asList(keys));
  31.192 +            return this;
  31.193 +        }
  31.194 +
  31.195 +        public Builder setCustomizerProvider(CustomizerProvider customizer) {
  31.196 +            this.customizer = customizer;
  31.197 +            return this;
  31.198 +        }
  31.199 +
  31.200 +        public Builder addOptions(Options... options) {
  31.201 +            this.options.addAll(Arrays.asList(options));
  31.202 +            return this;
  31.203 +        }
  31.204 +
  31.205 +        public HintMetadata build() {
  31.206 +            return new HintMetadata(id, displayName, description, category, enabled, kind, severity, suppressWarnings, customizer, options);
  31.207 +        }
  31.208 +
  31.209 +    }
  31.210 +
  31.211 +    public enum Options {
  31.212 +        NON_GUI,
  31.213 +        QUERY,
  31.214 +        NO_BATCH,
  31.215 +        HEAVY;
  31.216 +
  31.217 +        public static Set<Options> fromHintOptions(Hint.Options... options) {
  31.218 +            Set<Options> result = new HashSet<Options>();
  31.219 +
  31.220 +            for (Hint.Options opt : options) {
  31.221 +                result.add(valueOf(opt.name()));
  31.222 +            }
  31.223 +
  31.224 +            return result;
  31.225 +        }
  31.226 +    }
  31.227 +}
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/providers/spi/HintProvider.java	Wed May 08 21:47:42 2013 +0200
    32.3 @@ -0,0 +1,54 @@
    32.4 +/*
    32.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    32.6 + *
    32.7 + * Copyright 2009-2010 Oracle and/or its affiliates. All rights reserved.
    32.8 + *
    32.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   32.10 + * Other names may be trademarks of their respective owners.
   32.11 + *
   32.12 + * The contents of this file are subject to the terms of either the GNU
   32.13 + * General Public License Version 2 only ("GPL") or the Common
   32.14 + * Development and Distribution License("CDDL") (collectively, the
   32.15 + * "License"). You may not use this file except in compliance with the
   32.16 + * License. You can obtain a copy of the License at
   32.17 + * http://www.netbeans.org/cddl-gplv2.html
   32.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   32.19 + * specific language governing permissions and limitations under the
   32.20 + * License.  When distributing the software, include this License Header
   32.21 + * Notice in each file and include the License file at
   32.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   32.23 + * particular file as subject to the "Classpath" exception as provided
   32.24 + * by Oracle in the GPL Version 2 section of the License file that
   32.25 + * accompanied this code. If applicable, add the following below the
   32.26 + * License Header, with the fields enclosed by brackets [] replaced by
   32.27 + * your own identifying information:
   32.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   32.29 + *
   32.30 + * If you wish your version of this file to be governed by only the CDDL
   32.31 + * or only the GPL Version 2, indicate your decision by adding
   32.32 + * "[Contributor] elects to include this software in this distribution
   32.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   32.34 + * single choice of license, a recipient has the option to distribute
   32.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   32.36 + * to extend the choice of license to its licensees as provided above.
   32.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   32.38 + * Version 2 license, then the option applies only if the new code is
   32.39 + * made subject to such option by the copyright holder.
   32.40 + *
   32.41 + * Contributor(s):
   32.42 + *
   32.43 + * Portions Copyrighted 2009-2010 Sun Microsystems, Inc.
   32.44 + */
   32.45 +
   32.46 +package org.netbeans.modules.java.hints.providers.spi;
   32.47 +
   32.48 +import java.util.Collection;
   32.49 +import java.util.Map;
   32.50 +import org.netbeans.modules.java.hints.providers.spi.HintDescription;
   32.51 +import org.netbeans.modules.java.hints.providers.spi.HintMetadata;
   32.52 +
   32.53 +public interface HintProvider {
   32.54 +
   32.55 +    public Map<HintMetadata, ? extends Collection<? extends HintDescription>> computeHints();
   32.56 +
   32.57 +}
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/providers/spi/PositionRefresherHelper.java	Wed May 08 21:47:42 2013 +0200
    33.3 @@ -0,0 +1,105 @@
    33.4 +/*
    33.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    33.6 + *
    33.7 + * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
    33.8 + *
    33.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   33.10 + * Other names may be trademarks of their respective owners.
   33.11 + *
   33.12 + * The contents of this file are subject to the terms of either the GNU
   33.13 + * General Public License Version 2 only ("GPL") or the Common
   33.14 + * Development and Distribution License("CDDL") (collectively, the
   33.15 + * "License"). You may not use this file except in compliance with the
   33.16 + * License. You can obtain a copy of the License at
   33.17 + * http://www.netbeans.org/cddl-gplv2.html
   33.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   33.19 + * specific language governing permissions and limitations under the
   33.20 + * License.  When distributing the software, include this License Header
   33.21 + * Notice in each file and include the License file at
   33.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   33.23 + * particular file as subject to the "Classpath" exception as provided
   33.24 + * by Oracle in the GPL Version 2 section of the License file that
   33.25 + * accompanied this code. If applicable, add the following below the
   33.26 + * License Header, with the fields enclosed by brackets [] replaced by
   33.27 + * your own identifying information:
   33.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   33.29 + *
   33.30 + * If you wish your version of this file to be governed by only the CDDL
   33.31 + * or only the GPL Version 2, indicate your decision by adding
   33.32 + * "[Contributor] elects to include this software in this distribution
   33.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   33.34 + * single choice of license, a recipient has the option to distribute
   33.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   33.36 + * to extend the choice of license to its licensees as provided above.
   33.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   33.38 + * Version 2 license, then the option applies only if the new code is
   33.39 + * made subject to such option by the copyright holder.
   33.40 + *
   33.41 + * Contributor(s):
   33.42 + *
   33.43 + * Portions Copyrighted 2012 Sun Microsystems, Inc.
   33.44 + */
   33.45 +package org.netbeans.modules.java.hints.providers.spi;
   33.46 +
   33.47 +import java.util.List;
   33.48 +import javax.swing.text.Document;
   33.49 +import org.netbeans.api.annotations.common.CheckForNull;
   33.50 +import org.netbeans.api.java.source.CompilationInfo;
   33.51 +import org.netbeans.lib.editor.util.swing.DocumentUtilities;
   33.52 +import org.netbeans.spi.editor.hints.Context;
   33.53 +import org.netbeans.spi.editor.hints.ErrorDescription;
   33.54 +import org.netbeans.modules.java.hints.providers.spi.PositionRefresherHelper.DocumentVersion;
   33.55 +
   33.56 +/**TODO: should be public?
   33.57 + *
   33.58 + * @author lahvac
   33.59 + */
   33.60 +public abstract class PositionRefresherHelper<V extends DocumentVersion> {
   33.61 +
   33.62 +    private final Object documentKey = new Object();
   33.63 +    private final String key;
   33.64 +
   33.65 +    protected PositionRefresherHelper(String key) {
   33.66 +        this.key = key;
   33.67 +    }
   33.68 +
   33.69 +    protected abstract boolean isUpToDate(Context context, Document doc, V oldVersion);
   33.70 +    /**XXX: should be protected*/public abstract List<ErrorDescription> getErrorDescriptionsAt(CompilationInfo info, Context context, Document doc) throws Exception;
   33.71 +
   33.72 +    protected final void setVersion(Document doc, V version) {
   33.73 +        if (doc != null) {
   33.74 +            doc.putProperty(documentKey, version);
   33.75 +        }
   33.76 +    }
   33.77 +
   33.78 +    protected @CheckForNull V getUpToDateDocumentVersion(Context context, Document doc) {
   33.79 +        V oldVersion = (V) doc.getProperty(documentKey);
   33.80 +
   33.81 +        if (oldVersion == null) return null;
   33.82 +
   33.83 +        if (((DocumentVersion) oldVersion).version != DocumentUtilities.getDocumentVersion(doc)) return null;
   33.84 +        
   33.85 +        return oldVersion;
   33.86 +    }
   33.87 +    
   33.88 +    /**XXX*/ public boolean upToDateCheck(Context context, Document doc) {
   33.89 +        V oldVersion = getUpToDateDocumentVersion(context, doc);
   33.90 +
   33.91 +        if (oldVersion == null) return false;
   33.92 +
   33.93 +        return isUpToDate(context, doc, oldVersion);
   33.94 +    }
   33.95 +
   33.96 +    /**XXX*/ public String getKey() {
   33.97 +        return key;
   33.98 +    }
   33.99 +
  33.100 +    public static class DocumentVersion {
  33.101 +        private final long version;
  33.102 +
  33.103 +        public DocumentVersion(Document doc) {
  33.104 +            this.version = doc != null ? DocumentUtilities.getDocumentVersion(doc) : 0;
  33.105 +        }
  33.106 +
  33.107 +    }
  33.108 +}
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/providers/spi/Trigger.java	Wed May 08 21:47:42 2013 +0200
    34.3 @@ -0,0 +1,159 @@
    34.4 +/*
    34.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    34.6 + *
    34.7 + * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
    34.8 + *
    34.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   34.10 + * Other names may be trademarks of their respective owners.
   34.11 + *
   34.12 + * The contents of this file are subject to the terms of either the GNU
   34.13 + * General Public License Version 2 only ("GPL") or the Common
   34.14 + * Development and Distribution License("CDDL") (collectively, the
   34.15 + * "License"). You may not use this file except in compliance with the
   34.16 + * License. You can obtain a copy of the License at
   34.17 + * http://www.netbeans.org/cddl-gplv2.html
   34.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   34.19 + * specific language governing permissions and limitations under the
   34.20 + * License.  When distributing the software, include this License Header
   34.21 + * Notice in each file and include the License file at
   34.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   34.23 + * particular file as subject to the "Classpath" exception as provided
   34.24 + * by Oracle in the GPL Version 2 section of the License file that
   34.25 + * accompanied this code. If applicable, add the following below the
   34.26 + * License Header, with the fields enclosed by brackets [] replaced by
   34.27 + * your own identifying information:
   34.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   34.29 + *
   34.30 + * If you wish your version of this file to be governed by only the CDDL
   34.31 + * or only the GPL Version 2, indicate your decision by adding
   34.32 + * "[Contributor] elects to include this software in this distribution
   34.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   34.34 + * single choice of license, a recipient has the option to distribute
   34.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   34.36 + * to extend the choice of license to its licensees as provided above.
   34.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   34.38 + * Version 2 license, then the option applies only if the new code is
   34.39 + * made subject to such option by the copyright holder.
   34.40 + *
   34.41 + * Contributor(s):
   34.42 + *
   34.43 + * Portions Copyrighted 2011 Sun Microsystems, Inc.
   34.44 + */
   34.45 +package org.netbeans.modules.java.hints.providers.spi;
   34.46 +
   34.47 +import com.sun.source.tree.Tree;
   34.48 +import com.sun.source.tree.Tree.Kind;
   34.49 +import java.util.Arrays;
   34.50 +import java.util.Map;
   34.51 +import java.util.Set;
   34.52 +import org.netbeans.api.java.source.matching.Pattern;
   34.53 +import org.openide.util.Parameters;
   34.54 +
   34.55 +/**A base class for triggers.
   34.56 + *
   34.57 + * @author lahvac
   34.58 + */
   34.59 +public abstract class Trigger {
   34.60 +
   34.61 +    Trigger() {}
   34.62 +
   34.63 +    /**Invoke the given hint's worker on the specified {@link Tree.Kind}(s).
   34.64 +     *
   34.65 +     */
   34.66 +    public static final class Kinds extends Trigger {
   34.67 +        private final Set<Kind> kinds;
   34.68 +
   34.69 +        /**Create the trigger for the specified set of {@link Tree.Kind}s.
   34.70 +         *
   34.71 +         * @param kinds on which the hint's worker should be invoked.
   34.72 +         */
   34.73 +        public Kinds(Set<Kind> kinds) {
   34.74 +            this.kinds = kinds;
   34.75 +        }
   34.76 +
   34.77 +        public Iterable<? extends Kind> getKinds() {
   34.78 +            return kinds;
   34.79 +        }
   34.80 +
   34.81 +        @Override
   34.82 +        public String toString() {
   34.83 +            return kinds.toString();
   34.84 +        }
   34.85 +    }
   34.86 +
   34.87 +    /**Invoke the hint's worker on tree nodes that match the given pattern.
   34.88 +     *
   34.89 +     */
   34.90 +    public static final class PatternDescription extends Trigger {
   34.91 +
   34.92 +        private final String pattern;
   34.93 +        private final Map<String, String> constraints;
   34.94 +        private final Iterable<? extends String> imports;
   34.95 +
   34.96 +        private PatternDescription(String pattern, Map<String, String> constraints, String... imports) {
   34.97 +            this.pattern = pattern;
   34.98 +            this.constraints = constraints;
   34.99 +            this.imports = Arrays.asList(imports);
  34.100 +        }
  34.101 +
  34.102 +        /** Create the trigger to invoke the hint's worker on tree nodes that match the given pattern.
  34.103 +         *
  34.104 +         * @param pattern which will be interpreted as a pattern with free variables ({@link Pattern#createPatternWithFreeVariables(com.sun.source.util.TreePath, java.util.Map) }.
  34.105 +         * @param constraints are expected to be mapping from a free variable name to the expected type.
  34.106 +         * @param XXX: document the imports
  34.107 +         * @return the created trigger.
  34.108 +         */
  34.109 +        public static PatternDescription create(String pattern, Map<String, String> constraints, String... imports) {
  34.110 +            Parameters.notNull("pattern", pattern);
  34.111 +            Parameters.notNull("constraints", constraints);
  34.112 +            Parameters.notNull("imports", imports);
  34.113 +
  34.114 +            return new PatternDescription(pattern, constraints, imports);
  34.115 +        }
  34.116 +
  34.117 +        @Override
  34.118 +        public boolean equals(Object obj) {
  34.119 +            if (obj == null) {
  34.120 +                return false;
  34.121 +            }
  34.122 +            if (getClass() != obj.getClass()) {
  34.123 +                return false;
  34.124 +            }
  34.125 +            final PatternDescription other = (PatternDescription) obj;
  34.126 +            if ((this.pattern == null) ? (other.pattern != null) : !this.pattern.equals(other.pattern)) {
  34.127 +                return false;
  34.128 +            }
  34.129 +            if (this.constraints != other.constraints && (this.constraints == null || !this.constraints.equals(other.constraints))) {
  34.130 +                return false;
  34.131 +            }
  34.132 +            return true;
  34.133 +        }
  34.134 +
  34.135 +        @Override
  34.136 +        public int hashCode() {
  34.137 +            int hash = 7;
  34.138 +            hash = 71 * hash + (this.pattern != null ? this.pattern.hashCode() : 0);
  34.139 +            hash = 71 * hash + (this.constraints != null ? this.constraints.hashCode() : 0);
  34.140 +            return hash;
  34.141 +        }
  34.142 +
  34.143 +        public String getPattern() {
  34.144 +            return pattern;
  34.145 +        }
  34.146 +
  34.147 +        public Map<String, String> getConstraints() {
  34.148 +            return constraints;
  34.149 +        }
  34.150 +
  34.151 +        public Iterable<? extends String> getImports() {
  34.152 +            return imports;
  34.153 +        }
  34.154 +
  34.155 +        @Override
  34.156 +        public String toString() {
  34.157 +            return pattern;
  34.158 +        }
  34.159 +
  34.160 +    }
  34.161 +
  34.162 +}
    35.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/Bundle.properties	Wed May 08 21:47:42 2013 +0200
    35.3 @@ -0,0 +1,4 @@
    35.4 +OpenIDE-Module-Name=Java Hints SPI
    35.5 +
    35.6 +#refresh hints
    35.7 +Refresh_hints=Refresh Hints
    36.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/Hacks.java	Wed May 08 21:47:42 2013 +0200
    36.3 @@ -0,0 +1,219 @@
    36.4 +/*
    36.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    36.6 + *
    36.7 + * Copyright 2010 Oracle and/or its affiliates. All rights reserved.
    36.8 + *
    36.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   36.10 + * Other names may be trademarks of their respective owners.
   36.11 + *
   36.12 + * The contents of this file are subject to the terms of either the GNU
   36.13 + * General Public License Version 2 only ("GPL") or the Common
   36.14 + * Development and Distribution License("CDDL") (collectively, the
   36.15 + * "License"). You may not use this file except in compliance with the
   36.16 + * License. You can obtain a copy of the License at
   36.17 + * http://www.netbeans.org/cddl-gplv2.html
   36.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   36.19 + * specific language governing permissions and limitations under the
   36.20 + * License.  When distributing the software, include this License Header
   36.21 + * Notice in each file and include the License file at
   36.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   36.23 + * particular file as subject to the "Classpath" exception as provided
   36.24 + * by Oracle in the GPL Version 2 section of the License file that
   36.25 + * accompanied this code. If applicable, add the following below the
   36.26 + * License Header, with the fields enclosed by brackets [] replaced by
   36.27 + * your own identifying information:
   36.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   36.29 + *
   36.30 + * If you wish your version of this file to be governed by only the CDDL
   36.31 + * or only the GPL Version 2, indicate your decision by adding
   36.32 + * "[Contributor] elects to include this software in this distribution
   36.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   36.34 + * single choice of license, a recipient has the option to distribute
   36.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   36.36 + * to extend the choice of license to its licensees as provided above.
   36.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   36.38 + * Version 2 license, then the option applies only if the new code is
   36.39 + * made subject to such option by the copyright holder.
   36.40 + *
   36.41 + * Contributor(s):
   36.42 + *
   36.43 + * Portions Copyrighted 2009 Sun Microsystems, Inc.
   36.44 + */
   36.45 +
   36.46 +package org.netbeans.modules.java.hints.spiimpl;
   36.47 +
   36.48 +import com.sun.source.tree.BlockTree;
   36.49 +import com.sun.source.tree.CompilationUnitTree;
   36.50 +import com.sun.source.tree.MethodTree;
   36.51 +import com.sun.source.tree.Scope;
   36.52 +import com.sun.source.tree.Tree;
   36.53 +import com.sun.source.util.TreePath;
   36.54 +import com.sun.source.util.TreePathScanner;
   36.55 +import com.sun.tools.javac.api.JavacTaskImpl;
   36.56 +import com.sun.tools.javac.code.Symbol.ClassSymbol;
   36.57 +import com.sun.tools.javac.comp.AttrContext;
   36.58 +import com.sun.tools.javac.comp.Enter;
   36.59 +import com.sun.tools.javac.comp.Env;
   36.60 +import com.sun.tools.javac.main.JavaCompiler;
   36.61 +import com.sun.tools.javac.tree.JCTree;
   36.62 +import com.sun.tools.javac.tree.JCTree.JCErroneous;
   36.63 +import com.sun.tools.javac.util.Context;
   36.64 +import com.sun.tools.javac.util.Log;
   36.65 +import java.io.File;
   36.66 +import java.io.IOException;
   36.67 +import javax.lang.model.element.Element;
   36.68 +import javax.lang.model.element.TypeElement;
   36.69 +import javax.lang.model.element.VariableElement;
   36.70 +import javax.lang.model.type.TypeMirror;
   36.71 +import javax.tools.JavaFileObject;
   36.72 +import org.netbeans.api.annotations.common.CheckForNull;
   36.73 +import org.netbeans.api.annotations.common.NonNull;
   36.74 +import org.netbeans.api.java.source.CompilationInfo;
   36.75 +import org.netbeans.api.java.source.TreeUtilities;
   36.76 +import org.netbeans.modules.java.hints.providers.spi.HintMetadata;
   36.77 +import org.netbeans.modules.java.source.JavaSourceAccessor;
   36.78 +import org.netbeans.modules.java.source.parsing.FileObjects;
   36.79 +import org.openide.util.Exceptions;
   36.80 +
   36.81 +/**
   36.82 + *
   36.83 + * @author lahvac
   36.84 + */
   36.85 +public class Hacks {
   36.86 +
   36.87 +    //XXX: copied from Utilities, for declarative hints, different import management:
   36.88 +    private static long inc;
   36.89 +
   36.90 +    public static Scope constructScope(CompilationInfo info, String... importedClasses) {
   36.91 +        StringBuilder clazz = new StringBuilder();
   36.92 +
   36.93 +        clazz.append("package $$;\n");
   36.94 +
   36.95 +        for (String i : importedClasses) {
   36.96 +            clazz.append("import ").append(i).append(";\n");
   36.97 +        }
   36.98 +
   36.99 +        clazz.append("public class $").append(inc++).append("{");
  36.100 +
  36.101 +        clazz.append("private void test() {\n");
  36.102 +        clazz.append("}\n");
  36.103 +        clazz.append("}\n");
  36.104 +
  36.105 +        JavacTaskImpl jti = JavaSourceAccessor.getINSTANCE().getJavacTask(info);
  36.106 +        Context context = jti.getContext();
  36.107 +
  36.108 +        JavaCompiler jc = JavaCompiler.instance(context);
  36.109 +        Log.instance(context).nerrors = 0;
  36.110 +
  36.111 +        JavaFileObject jfo = FileObjects.memoryFileObject("$$", "$", new File("/tmp/t.java").toURI(), System.currentTimeMillis(), clazz.toString());
  36.112 +        boolean oldSkipAPs = jc.skipAnnotationProcessing;
  36.113 +
  36.114 +        try {
  36.115 +            jc.skipAnnotationProcessing = true;
  36.116 +
  36.117 +            Iterable<? extends CompilationUnitTree> parsed = jti.parse(jfo);
  36.118 +            CompilationUnitTree cut = parsed.iterator().next();
  36.119 +
  36.120 +            jti.analyze(jti.enter(parsed));
  36.121 +
  36.122 +            return new ScannerImpl().scan(cut, info);
  36.123 +        } catch (IOException ex) {
  36.124 +            Exceptions.printStackTrace(ex);
  36.125 +            return null;
  36.126 +        } finally {
  36.127 +            jc.skipAnnotationProcessing = oldSkipAPs;
  36.128 +        }
  36.129 +    }
  36.130 +
  36.131 +    private static final class ScannerImpl extends TreePathScanner<Scope, CompilationInfo> {
  36.132 +
  36.133 +        @Override
  36.134 +        public Scope visitBlock(BlockTree node, CompilationInfo p) {
  36.135 +            return p.getTrees().getScope(getCurrentPath());
  36.136 +        }
  36.137 +
  36.138 +        @Override
  36.139 +        public Scope visitMethod(MethodTree node, CompilationInfo p) {
  36.140 +            if (node.getReturnType() == null) {
  36.141 +                return null;
  36.142 +            }
  36.143 +            return super.visitMethod(node, p);
  36.144 +        }
  36.145 +
  36.146 +        @Override
  36.147 +        public Scope reduce(Scope r1, Scope r2) {
  36.148 +            return r1 != null ? r1 : r2;
  36.149 +        }
  36.150 +
  36.151 +    }
  36.152 +
  36.153 +
  36.154 +    public static Tree createRenameTree(@NonNull Tree originalTree, @NonNull String newName) {
  36.155 +        return new RenameTree(originalTree, newName);
  36.156 +    }
  36.157 +
  36.158 +    public static final class RenameTree extends JCErroneous {
  36.159 +
  36.160 +        public final Tree originalTree;
  36.161 +        public final String newName;
  36.162 +
  36.163 +        public RenameTree(@NonNull Tree originalTree, @NonNull String newName) {
  36.164 +            super(com.sun.tools.javac.util.List.<JCTree>nil());
  36.165 +            this.originalTree = originalTree;
  36.166 +            this.newName = newName;
  36.167 +        }
  36.168 +
  36.169 +    }
  36.170 +
  36.171 +    public static @CheckForNull TypeMirror parseFQNType(@NonNull CompilationInfo info, @NonNull String spec) {
  36.172 +        if (spec.length() == 0) {
  36.173 +            return null;
  36.174 +        }
  36.175 +        
  36.176 +        TypeElement jlObject = info.getElements().getTypeElement("java.lang.Object");
  36.177 +        
  36.178 +        //XXX:
  36.179 +        TypeElement scope;
  36.180 +
  36.181 +        if (info.getTopLevelElements().isEmpty()) {
  36.182 +            scope = jlObject;
  36.183 +        } else {
  36.184 +            scope = info.getTopLevelElements().iterator().next();
  36.185 +        }
  36.186 +        //XXX end
  36.187 +        
  36.188 +        return info.getTreeUtilities().parseType(spec, /*XXX: jlObject*/scope);
  36.189 +    }
  36.190 +
  36.191 +    public static VariableElement attributeThis(CompilationInfo info, TreePath tp) {
  36.192 +        //XXX:
  36.193 +        while (tp != null) {
  36.194 +            if (TreeUtilities.CLASS_TREE_KINDS.contains(tp.getLeaf().getKind())) {
  36.195 +                Element currentElement = info.getTrees().getElement(tp);
  36.196 +
  36.197 +                if (currentElement == null || !(currentElement instanceof ClassSymbol)) return null;
  36.198 +
  36.199 +                Enter enter = Enter.instance(JavaSourceAccessor.getINSTANCE().getJavacTask(info).getContext());
  36.200 +                Env<AttrContext> env = enter.getEnv((ClassSymbol) currentElement);
  36.201 +
  36.202 +                if (env == null) return null;
  36.203 +
  36.204 +                for (Element el : env.info.getLocalElements()) {
  36.205 +                    if (el.getSimpleName().contentEquals("this")) {
  36.206 +                        return (VariableElement) el;
  36.207 +                    }
  36.208 +                }
  36.209 +
  36.210 +                return null;
  36.211 +            }
  36.212 +
  36.213 +            tp = tp.getParentPath();
  36.214 +        }
  36.215 +
  36.216 +        return null;
  36.217 +    }
  36.218 +    
  36.219 +    public static interface InspectAndTransformOpener {
  36.220 +        public void openIAT(HintMetadata hm);
  36.221 +    }
  36.222 +}
    37.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/JackpotTrees.java	Wed May 08 21:47:42 2013 +0200
    37.3 @@ -0,0 +1,246 @@
    37.4 +/*
    37.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    37.6 + *
    37.7 + * Copyright 2010 Oracle and/or its affiliates. All rights reserved.
    37.8 + *
    37.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   37.10 + * Other names may be trademarks of their respective owners.
   37.11 + *
   37.12 + * The contents of this file are subject to the terms of either the GNU
   37.13 + * General Public License Version 2 only ("GPL") or the Common
   37.14 + * Development and Distribution License("CDDL") (collectively, the
   37.15 + * "License"). You may not use this file except in compliance with the
   37.16 + * License. You can obtain a copy of the License at
   37.17 + * http://www.netbeans.org/cddl-gplv2.html
   37.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   37.19 + * specific language governing permissions and limitations under the
   37.20 + * License.  When distributing the software, include this License Header
   37.21 + * Notice in each file and include the License file at
   37.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   37.23 + * particular file as subject to the "Classpath" exception as provided
   37.24 + * by Oracle in the GPL Version 2 section of the License file that
   37.25 + * accompanied this code. If applicable, add the following below the
   37.26 + * License Header, with the fields enclosed by brackets [] replaced by
   37.27 + * your own identifying information:
   37.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   37.29 + *
   37.30 + * If you wish your version of this file to be governed by only the CDDL
   37.31 + * or only the GPL Version 2, indicate your decision by adding
   37.32 + * "[Contributor] elects to include this software in this distribution
   37.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   37.34 + * single choice of license, a recipient has the option to distribute
   37.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   37.36 + * to extend the choice of license to its licensees as provided above.
   37.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   37.38 + * Version 2 license, then the option applies only if the new code is
   37.39 + * made subject to such option by the copyright holder.
   37.40 + *
   37.41 + * Contributor(s):
   37.42 + *
   37.43 + * Portions Copyrighted 2010 Sun Microsystems, Inc.
   37.44 + */
   37.45 +
   37.46 +package org.netbeans.modules.java.hints.spiimpl;
   37.47 +
   37.48 +import com.sun.source.tree.IdentifierTree;
   37.49 +import com.sun.source.tree.TreeVisitor;
   37.50 +import com.sun.tools.javac.code.Symbol.VarSymbol;
   37.51 +import com.sun.tools.javac.code.Symtab;
   37.52 +import com.sun.tools.javac.tree.JCTree;
   37.53 +import com.sun.tools.javac.tree.JCTree.JCAnnotation;
   37.54 +import com.sun.tools.javac.tree.JCTree.JCBlock;
   37.55 +import com.sun.tools.javac.tree.JCTree.JCCase;
   37.56 +import com.sun.tools.javac.tree.JCTree.JCCatch;
   37.57 +import com.sun.tools.javac.tree.JCTree.JCModifiers;
   37.58 +import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
   37.59 +import com.sun.tools.javac.tree.TreeMaker;
   37.60 +import com.sun.tools.javac.util.Context;
   37.61 +import com.sun.tools.javac.util.List;
   37.62 +import com.sun.tools.javac.util.Name;
   37.63 +
   37.64 +
   37.65 +/**
   37.66 + *
   37.67 + * @author lahvac
   37.68 + */
   37.69 +public class JackpotTrees {
   37.70 +    public static class AnnotationWildcard extends JCAnnotation implements IdentifierTree {
   37.71 +
   37.72 +        private final Name ident;
   37.73 +        private final JCIdent jcIdent;
   37.74 +
   37.75 +        public AnnotationWildcard(Name ident, JCIdent jcIdent) {
   37.76 +            super(Tag.ANNOTATION, jcIdent, List.<JCExpression>nil());
   37.77 +            this.ident = ident;
   37.78 +            this.jcIdent = jcIdent;
   37.79 +        }
   37.80 +
   37.81 +        public Name getName() {
   37.82 +            return ident;
   37.83 +        }
   37.84 +
   37.85 +        @Override
   37.86 +        public Kind getKind() {
   37.87 +            return Kind.IDENTIFIER;
   37.88 +        }
   37.89 +
   37.90 +        @Override
   37.91 +        public void accept(Visitor v) {
   37.92 +            v.visitIdent(jcIdent);
   37.93 +        }
   37.94 +
   37.95 +        @Override
   37.96 +        public <R, D> R accept(TreeVisitor<R, D> v, D d) {
   37.97 +            return v.visitIdentifier(this, d);
   37.98 +        }
   37.99 +
  37.100 +        @Override
  37.101 +        public String toString() {
  37.102 +            return ident.toString();
  37.103 +        }
  37.104 +
  37.105 +    }
  37.106 +    
  37.107 +    public static class CatchWildcard extends JCCatch implements IdentifierTree {
  37.108 +
  37.109 +        private final Name ident;
  37.110 +        private final JCIdent jcIdent;
  37.111 +
  37.112 +        public CatchWildcard(Context ctx, Name ident, JCIdent jcIdent) {
  37.113 +            super(new FakeVariable(ctx, ident, jcIdent), TreeMaker.instance(ctx).Block(0, List.<JCStatement>nil()));
  37.114 +            this.ident = ident;
  37.115 +            this.jcIdent = jcIdent;
  37.116 +        }
  37.117 +
  37.118 +        public Name getName() {
  37.119 +            return ident;
  37.120 +        }
  37.121 +
  37.122 +        @Override
  37.123 +        public Kind getKind() {
  37.124 +            return Kind.IDENTIFIER;
  37.125 +        }
  37.126 +
  37.127 +        @Override
  37.128 +        public void accept(Visitor v) {
  37.129 +            v.visitIdent(jcIdent);
  37.130 +        }
  37.131 +
  37.132 +        @Override
  37.133 +        public <R, D> R accept(TreeVisitor<R, D> v, D d) {
  37.134 +            return v.visitIdentifier(this, d);
  37.135 +        }
  37.136 +
  37.137 +        @Override
  37.138 +        public String toString() {
  37.139 +            return "catch " + ident.toString();
  37.140 +        }
  37.141 +
  37.142 +    }
  37.143 +    
  37.144 +    public static class VariableWildcard extends FakeVariable implements IdentifierTree {
  37.145 +
  37.146 +        private final Name ident;
  37.147 +
  37.148 +        public VariableWildcard(Context ctx, Name ident, JCIdent jcIdent) {
  37.149 +            super(ctx, ident, jcIdent);
  37.150 +            this.ident = ident;
  37.151 +        }
  37.152 +
  37.153 +        public Name getName() {
  37.154 +            return ident;
  37.155 +        }
  37.156 +
  37.157 +        @Override
  37.158 +        public Kind getKind() {
  37.159 +            return Kind.IDENTIFIER;
  37.160 +        }
  37.161 +
  37.162 +        @Override
  37.163 +        public <R, D> R accept(TreeVisitor<R, D> v, D d) {
  37.164 +            return v.visitIdentifier(this, d);
  37.165 +        }
  37.166 +
  37.167 +        @Override
  37.168 +        public String toString() {
  37.169 +            return ident.toString();
  37.170 +        }
  37.171 +    }
  37.172 +
  37.173 +    private static class FakeVariable extends JCVariableDecl {
  37.174 +        
  37.175 +        private final JCIdent jcIdent;
  37.176 +
  37.177 +        public FakeVariable(Context ctx, Name ident, JCIdent jcIdent) {
  37.178 +            super(new FakeModifiers(), ident, createType(ctx), null, null);
  37.179 +            this.sym = new VarSymbol(0, name, type, Symtab.instance(ctx).errSymbol);
  37.180 +            this.type = vartype.type;
  37.181 +            this.jcIdent = jcIdent;
  37.182 +        }
  37.183 +
  37.184 +        private static JCErroneous createType(Context ctx) {
  37.185 +            JCErroneous err = new JCErroneous(List.<JCTree>nil()) {};
  37.186 +
  37.187 +            err.type = Symtab.instance(ctx).errType;
  37.188 +
  37.189 +            return err;
  37.190 +        }
  37.191 +
  37.192 +        @Override
  37.193 +        public void accept(Visitor v) {
  37.194 +            v.visitIdent(jcIdent);
  37.195 +        }
  37.196 +
  37.197 +    }
  37.198 +
  37.199 +    private static class FakeModifiers extends JCModifiers {
  37.200 +        public FakeModifiers() {
  37.201 +            super(0, List.<JCAnnotation>nil());
  37.202 +        }
  37.203 +    }
  37.204 +
  37.205 +    public static class CaseWildcard extends JCCase implements IdentifierTree {
  37.206 +
  37.207 +        private final Name ident;
  37.208 +        private final JCIdent jcIdent;
  37.209 +
  37.210 +        public CaseWildcard(Context ctx, Name ident, JCIdent jcIdent) {
  37.211 +            super(jcIdent, List.<JCStatement>nil());
  37.212 +            this.ident = ident;
  37.213 +            this.jcIdent = jcIdent;
  37.214 +        }
  37.215 +
  37.216 +        public Name getName() {
  37.217 +            return ident;
  37.218 +        }
  37.219 +
  37.220 +        @Override
  37.221 +        public Kind getKind() {
  37.222 +            return Kind.IDENTIFIER;
  37.223 +        }
  37.224 +
  37.225 +        @Override
  37.226 +        public void accept(Visitor v) {
  37.227 +            v.visitIdent(jcIdent);
  37.228 +        }
  37.229 +
  37.230 +        @Override
  37.231 +        public <R, D> R accept(TreeVisitor<R, D> v, D d) {
  37.232 +            return v.visitIdentifier(this, d);
  37.233 +        }
  37.234 +
  37.235 +        @Override
  37.236 +        public String toString() {
  37.237 +            return "case " + ident.toString();
  37.238 +        }
  37.239 +
  37.240 +    }
  37.241 +    
  37.242 +    public static class FakeBlock extends JCBlock {
  37.243 +
  37.244 +        public FakeBlock(long flags, List<JCStatement> stats) {
  37.245 +            super(flags, stats);
  37.246 +        }
  37.247 +        
  37.248 +    }
  37.249 +}
    38.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/JavaFixImpl.java	Wed May 08 21:47:42 2013 +0200
    38.3 @@ -0,0 +1,146 @@
    38.4 +/*
    38.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    38.6 + *
    38.7 + * Copyright 2008-2010 Oracle and/or its affiliates. All rights reserved.
    38.8 + *
    38.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   38.10 + * Other names may be trademarks of their respective owners.
   38.11 + *
   38.12 + * The contents of this file are subject to the terms of either the GNU
   38.13 + * General Public License Version 2 only ("GPL") or the Common
   38.14 + * Development and Distribution License("CDDL") (collectively, the
   38.15 + * "License"). You may not use this file except in compliance with the
   38.16 + * License. You can obtain a copy of the License at
   38.17 + * http://www.netbeans.org/cddl-gplv2.html
   38.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   38.19 + * specific language governing permissions and limitations under the
   38.20 + * License.  When distributing the software, include this License Header
   38.21 + * Notice in each file and include the License file at
   38.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   38.23 + * particular file as subject to the "Classpath" exception as provided
   38.24 + * by Oracle in the GPL Version 2 section of the License file that
   38.25 + * accompanied this code. If applicable, add the following below the
   38.26 + * License Header, with the fields enclosed by brackets [] replaced by
   38.27 + * your own identifying information:
   38.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   38.29 + *
   38.30 + * If you wish your version of this file to be governed by only the CDDL
   38.31 + * or only the GPL Version 2, indicate your decision by adding
   38.32 + * "[Contributor] elects to include this software in this distribution
   38.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   38.34 + * single choice of license, a recipient has the option to distribute
   38.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   38.36 + * to extend the choice of license to its licensees as provided above.
   38.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   38.38 + * Version 2 license, then the option applies only if the new code is
   38.39 + * made subject to such option by the copyright holder.
   38.40 + *
   38.41 + * Contributor(s):
   38.42 + *
   38.43 + * Portions Copyrighted 2008-2009 Sun Microsystems, Inc.
   38.44 + */
   38.45 +
   38.46 +package org.netbeans.modules.java.hints.spiimpl;
   38.47 +
   38.48 +import com.sun.source.util.TreePath;
   38.49 +import java.util.ArrayList;
   38.50 +import java.util.Collection;
   38.51 +import java.util.Collections;
   38.52 +import java.util.HashMap;
   38.53 +import java.util.IdentityHashMap;
   38.54 +import java.util.List;
   38.55 +import java.util.Map;
   38.56 +import java.util.Set;
   38.57 +import javax.lang.model.type.TypeMirror;
   38.58 +import org.netbeans.api.java.source.CompilationInfo;
   38.59 +import org.netbeans.api.java.source.JavaSource;
   38.60 +import org.netbeans.api.java.source.JavaSource.Phase;
   38.61 +import org.netbeans.api.java.source.ModificationResult.Difference;
   38.62 +import org.netbeans.api.java.source.Task;
   38.63 +import org.netbeans.api.java.source.WorkingCopy;
   38.64 +import org.netbeans.api.project.Project;
   38.65 +import org.netbeans.modules.java.hints.spiimpl.batch.BatchUtilities;
   38.66 +import org.netbeans.modules.java.source.JavaSourceAccessor;
   38.67 +import org.netbeans.modules.refactoring.spi.RefactoringElementImplementation;
   38.68 +import org.netbeans.spi.editor.hints.ChangeInfo;
   38.69 +import org.netbeans.spi.editor.hints.Fix;
   38.70 +import org.netbeans.spi.java.hints.HintContext;
   38.71 +import org.netbeans.spi.java.hints.JavaFix;
   38.72 +import org.openide.filesystems.FileObject;
   38.73 +import org.openide.util.Exceptions;
   38.74 +
   38.75 +/**TODO: move to better package
   38.76 + *
   38.77 + * @author Jan Lahoda
   38.78 + */
   38.79 +public final class JavaFixImpl implements Fix {
   38.80 +
   38.81 +    public final JavaFix jf;
   38.82 +
   38.83 +    public JavaFixImpl(JavaFix jf) {
   38.84 +        this.jf = jf;
   38.85 +    }
   38.86 +
   38.87 +    public String getText() {
   38.88 +        return Accessor.INSTANCE.getText(jf);
   38.89 +    }
   38.90 +
   38.91 +    public ChangeInfo implement() throws Exception {
   38.92 +        FileObject file = Accessor.INSTANCE.getFile(jf);
   38.93 +        
   38.94 +        BatchUtilities.fixDependencies(file, Collections.singletonList(jf), new IdentityHashMap<Project, Set<String>>());
   38.95 +
   38.96 +        JavaSource js = JavaSource.forFileObject(file);
   38.97 +
   38.98 +        js.runModificationTask(new Task<WorkingCopy>() {
   38.99 +            public void run(WorkingCopy wc) throws Exception {
  38.100 +                if (wc.toPhase(Phase.RESOLVED).compareTo(Phase.RESOLVED) < 0) {
  38.101 +                    return;
  38.102 +                }
  38.103 +
  38.104 +                Map<FileObject, byte[]> resourceContentChanges = new HashMap<FileObject, byte[]>();
  38.105 +                Accessor.INSTANCE.process(jf, wc, true, resourceContentChanges, /*Ignored in editor:*/new ArrayList<RefactoringElementImplementation>());
  38.106 +                Map<FileObject, List<Difference>> resourceContentDiffs = new HashMap<FileObject, List<Difference>>();
  38.107 +                BatchUtilities.addResourceContentChanges(resourceContentChanges, resourceContentDiffs);
  38.108 +                JavaSourceAccessor.getINSTANCE().createModificationResult(resourceContentDiffs, Collections.<Object, int[]>emptyMap()).commit();
  38.109 +            }
  38.110 +        }).commit();
  38.111 +
  38.112 +        return null;
  38.113 +    }
  38.114 +
  38.115 +    @Override
  38.116 +    public boolean equals(Object obj) {
  38.117 +        if (obj instanceof JavaFixImpl) {
  38.118 +            return jf.equals(((JavaFixImpl)obj).jf);
  38.119 +        }
  38.120 +        return super.equals(obj);
  38.121 +    }
  38.122 +
  38.123 +    @Override
  38.124 +    public int hashCode() {
  38.125 +        return jf.hashCode();
  38.126 +    }
  38.127 +
  38.128 +    public static abstract class Accessor {
  38.129 +
  38.130 +        static {
  38.131 +            try {
  38.132 +                Class.forName(JavaFix.class.getCanonicalName(), true, JavaFix.class.getClassLoader());
  38.133 +            } catch (ClassNotFoundException ex) {
  38.134 +                Exceptions.printStackTrace(ex);
  38.135 +            }
  38.136 +        }
  38.137 +        
  38.138 +        public static Accessor INSTANCE;
  38.139 +
  38.140 +        public abstract String getText(JavaFix jf);
  38.141 +        public abstract ChangeInfo process(JavaFix jf, WorkingCopy wc, boolean canShowUI, Map<FileObject, byte[]> resourceContent, Collection<? super RefactoringElementImplementation> fileChanges) throws Exception;
  38.142 +        public abstract FileObject getFile(JavaFix jf);
  38.143 +        public abstract Map<String, String> getOptions(JavaFix jf);
  38.144 +        public abstract Fix rewriteFix(CompilationInfo info, String displayName, TreePath what, final String to, Map<String, TreePath> parameters, Map<String, Collection<? extends TreePath>> parametersMulti, final Map<String, String> parameterNames, Map<String, TypeMirror> constraints, Map<String, String> options, String... imports);
  38.145 +        public abstract Fix createSuppressWarningsFix(CompilationInfo compilationInfo, TreePath treePath, String... keys);
  38.146 +        public abstract List<Fix> createSuppressWarnings(CompilationInfo compilationInfo, TreePath treePath, String... keys);
  38.147 +        public abstract List<Fix> resolveDefaultFixes(HintContext ctx, Fix... provided);
  38.148 +    }
  38.149 +}
    39.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    39.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/JavaHintsPositionRefresher.java	Wed May 08 21:47:42 2013 +0200
    39.3 @@ -0,0 +1,157 @@
    39.4 +/*
    39.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    39.6 + *
    39.7 + * Copyright 2009-2010 Oracle and/or its affiliates. All rights reserved.
    39.8 + *
    39.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   39.10 + * Other names may be trademarks of their respective owners.
   39.11 + *
   39.12 + * The contents of this file are subject to the terms of either the GNU
   39.13 + * General Public License Version 2 only ("GPL") or the Common
   39.14 + * Development and Distribution License("CDDL") (collectively, the
   39.15 + * "License"). You may not use this file except in compliance with the
   39.16 + * License. You can obtain a copy of the License at
   39.17 + * http://www.netbeans.org/cddl-gplv2.html
   39.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   39.19 + * specific language governing permissions and limitations under the
   39.20 + * License.  When distributing the software, include this License Header
   39.21 + * Notice in each file and include the License file at
   39.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   39.23 + * particular file as subject to the "Classpath" exception as provided
   39.24 + * by Oracle in the GPL Version 2 section of the License file that
   39.25 + * accompanied this code. If applicable, add the following below the
   39.26 + * License Header, with the fields enclosed by brackets [] replaced by
   39.27 + * your own identifying information:
   39.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   39.29 + *
   39.30 + * If you wish your version of this file to be governed by only the CDDL
   39.31 + * or only the GPL Version 2, indicate your decision by adding
   39.32 + * "[Contributor] elects to include this software in this distribution
   39.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   39.34 + * single choice of license, a recipient has the option to distribute
   39.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   39.36 + * to extend the choice of license to its licensees as provided above.
   39.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   39.38 + * Version 2 license, then the option applies only if the new code is
   39.39 + * made subject to such option by the copyright holder.
   39.40 + *
   39.41 + * Contributor(s):
   39.42 + *
   39.43 + * Portions Copyrighted 2009-2010 Sun Microsystems, Inc.
   39.44 + */
   39.45 +
   39.46 +package org.netbeans.modules.java.hints.spiimpl;
   39.47 +
   39.48 +import java.io.IOException;
   39.49 +import java.util.ArrayList;
   39.50 +import java.util.Collections;
   39.51 +import java.util.HashMap;
   39.52 +import java.util.Iterator;
   39.53 +import java.util.List;
   39.54 +import java.util.Map;
   39.55 +import java.util.logging.Level;
   39.56 +import java.util.logging.Logger;
   39.57 +import javax.swing.text.Document;
   39.58 +import org.netbeans.api.editor.mimelookup.MimeLookup;
   39.59 +import org.netbeans.api.editor.mimelookup.MimeRegistration;
   39.60 +import org.netbeans.api.java.source.CompilationController;
   39.61 +import org.netbeans.api.java.source.JavaSource;
   39.62 +import org.netbeans.api.java.source.JavaSource.Phase;
   39.63 +import org.netbeans.api.java.source.Task;
   39.64 +import org.netbeans.api.progress.ProgressUtils;
   39.65 +import org.netbeans.spi.editor.hints.Context;
   39.66 +import org.netbeans.spi.editor.hints.ErrorDescription;
   39.67 +import org.netbeans.spi.editor.hints.PositionRefresher;
   39.68 +import org.netbeans.modules.java.hints.providers.spi.PositionRefresherHelper;
   39.69 +import org.openide.util.Exceptions;
   39.70 +import org.openide.util.NbBundle;
   39.71 +
   39.72 +/**
   39.73 + * Refreshes all Java Hints on current line upon Alt-Enter or mouseclick
   39.74 + * @author Max Sauer
   39.75 + */
   39.76 +@MimeRegistration(mimeType="text/x-java", service=PositionRefresher.class)
   39.77 +public class JavaHintsPositionRefresher implements PositionRefresher {
   39.78 +
   39.79 +    private static final Logger LOG = Logger.getLogger(JavaHintsPositionRefresher.class.getName());
   39.80 +
   39.81 +    @Override
   39.82 +    public Map<String, List<ErrorDescription>> getErrorDescriptionsAt(final Context context, final Document doc) {
   39.83 +        final List<PositionRefresherHelper> refreshers = new ArrayList<PositionRefresherHelper>(MimeLookup.getLookup("text/x-java").lookupAll(PositionRefresherHelper.class));
   39.84 +
   39.85 +        for (Iterator<PositionRefresherHelper> it = refreshers.iterator(); it.hasNext();) {
   39.86 +            PositionRefresherHelper h = it.next();
   39.87 +
   39.88 +            if (h.upToDateCheck(context, doc)) {
   39.89 +                LOG.log(Level.FINE, "Not computing warnings for {0}, results are up-to-date.", h.getKey());
   39.90 +                it.remove();
   39.91 +            } else {
   39.92 +                LOG.log(Level.FINE, "Will compute warnings for {0}, results not up-to-date.", h.getKey());
   39.93 +            }
   39.94 +        }
   39.95 +
   39.96 +        if (refreshers.isEmpty()) return Collections.emptyMap();
   39.97 +        
   39.98 +        final JavaSource js = JavaSource.forDocument(doc);
   39.99 +
  39.100 +        if (js == null) {
  39.101 +            LOG.log(Level.FINE, "No JavaSource associated to: {0}", new Object[] {doc, doc.getProperty(Document.StreamDescriptionProperty)});
  39.102 +            return Collections.emptyMap();
  39.103 +        }
  39.104 +
  39.105 +        final Map<String, List<ErrorDescription>> eds = new HashMap<String, List<ErrorDescription>>();
  39.106 +
  39.107 +        Runnable r = new Runnable() {
  39.108 +
  39.109 +            public void run() {
  39.110 +                try {
  39.111 +                    js.runUserActionTask(new RefreshTask(eds, refreshers, context, doc), true);
  39.112 +                } catch (IOException ex) {
  39.113 +                    Exceptions.printStackTrace(ex);
  39.114 +                }
  39.115 +            }
  39.116 +        };
  39.117 +        
  39.118 +        ProgressUtils.runOffEventDispatchThread(r, NbBundle.getMessage(JavaHintsPositionRefresher.class, "Refresh_hints"), context.getCancel(), false); // NOI18N
  39.119 +
  39.120 +        return eds;
  39.121 +    }
  39.122 +
  39.123 +
  39.124 +    private class RefreshTask implements Task<CompilationController> {
  39.125 +
  39.126 +        private final Map<String, List<ErrorDescription>> eds;
  39.127 +        private final List<PositionRefresherHelper> refreshers;
  39.128 +        private final Context ctx;
  39.129 +        private final Document doc;
  39.130 +
  39.131 +        public RefreshTask(Map<String, List<ErrorDescription>> eds, List<PositionRefresherHelper> refreshers, Context ctx, Document doc) {
  39.132 +            this.eds = eds;
  39.133 +            this.refreshers = refreshers;
  39.134 +            this.ctx = ctx;
  39.135 +            this.doc = doc;
  39.136 +        }
  39.137 +
  39.138 +        public void run(CompilationController controller) throws Exception {
  39.139 +            if (controller.toPhase(JavaSource.Phase.RESOLVED).compareTo(Phase.RESOLVED) < 0) {
  39.140 +                return ;
  39.141 +            }
  39.142 +
  39.143 +            Document doc = controller.getDocument();
  39.144 +
  39.145 +            if (doc == null) {
  39.146 +                return;
  39.147 +            }
  39.148 +
  39.149 +            for (PositionRefresherHelper h : refreshers) {
  39.150 +                if (ctx.isCanceled()) {
  39.151 +                    return;
  39.152 +                }
  39.153 +                
  39.154 +                eds.put(h.getKey(), h.getErrorDescriptionsAt(controller, ctx, doc));
  39.155 +            }
  39.156 +        }
  39.157 +        
  39.158 +    }
  39.159 +
  39.160 +}
    40.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/MessageImpl.java	Wed May 08 21:47:42 2013 +0200
    40.3 @@ -0,0 +1,61 @@
    40.4 +/*
    40.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    40.6 + *
    40.7 + * Copyright 2010 Oracle and/or its affiliates. All rights reserved.
    40.8 + *
    40.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   40.10 + * Other names may be trademarks of their respective owners.
   40.11 + *
   40.12 + * The contents of this file are subject to the terms of either the GNU
   40.13 + * General Public License Version 2 only ("GPL") or the Common
   40.14 + * Development and Distribution License("CDDL") (collectively, the
   40.15 + * "License"). You may not use this file except in compliance with the
   40.16 + * License. You can obtain a copy of the License at
   40.17 + * http://www.netbeans.org/cddl-gplv2.html
   40.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   40.19 + * specific language governing permissions and limitations under the
   40.20 + * License.  When distributing the software, include this License Header
   40.21 + * Notice in each file and include the License file at
   40.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   40.23 + * particular file as subject to the "Classpath" exception as provided
   40.24 + * by Oracle in the GPL Version 2 section of the License file that
   40.25 + * accompanied this code. If applicable, add the following below the
   40.26 + * License Header, with the fields enclosed by brackets [] replaced by
   40.27 + * your own identifying information:
   40.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   40.29 + *
   40.30 + * If you wish your version of this file to be governed by only the CDDL
   40.31 + * or only the GPL Version 2, indicate your decision by adding
   40.32 + * "[Contributor] elects to include this software in this distribution
   40.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   40.34 + * single choice of license, a recipient has the option to distribute
   40.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   40.36 + * to extend the choice of license to its licensees as provided above.
   40.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   40.38 + * Version 2 license, then the option applies only if the new code is
   40.39 + * made subject to such option by the copyright holder.
   40.40 + *
   40.41 + * Contributor(s):
   40.42 + *
   40.43 + * Portions Copyrighted 2009 Sun Microsystems, Inc.
   40.44 + */
   40.45 +
   40.46 +package org.netbeans.modules.java.hints.spiimpl;
   40.47 +
   40.48 +import org.netbeans.spi.java.hints.HintContext.MessageKind;
   40.49 +
   40.50 +/**
   40.51 + *
   40.52 + * @author lahvacc
   40.53 + */
   40.54 +public class MessageImpl {
   40.55 +
   40.56 +    public final MessageKind kind;
   40.57 +    public final String text;
   40.58 +
   40.59 +    public MessageImpl(MessageKind kind, String text) {
   40.60 +        this.kind = kind;
   40.61 +        this.text = text;
   40.62 +    }
   40.63 +
   40.64 +}
    41.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    41.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/RulesManager.java	Wed May 08 21:47:42 2013 +0200
    41.3 @@ -0,0 +1,68 @@
    41.4 +/*
    41.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    41.6 + *
    41.7 + * Copyright 2008-2010 Oracle and/or its affiliates. All rights reserved.
    41.8 + *
    41.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   41.10 + * Other names may be trademarks of their respective owners.
   41.11 + *
   41.12 + * The contents of this file are subject to the terms of either the GNU
   41.13 + * General Public License Version 2 only ("GPL") or the Common
   41.14 + * Development and Distribution License("CDDL") (collectively, the
   41.15 + * "License"). You may not use this file except in compliance with the
   41.16 + * License. You can obtain a copy of the License at
   41.17 + * http://www.netbeans.org/cddl-gplv2.html
   41.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   41.19 + * specific language governing permissions and limitations under the
   41.20 + * License.  When distributing the software, include this License Header
   41.21 + * Notice in each file and include the License file at
   41.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   41.23 + * particular file as subject to the "Classpath" exception as provided
   41.24 + * by Oracle in the GPL Version 2 section of the License file that
   41.25 + * accompanied this code. If applicable, add the following below the
   41.26 + * License Header, with the fields enclosed by brackets [] replaced by
   41.27 + * your own identifying information:
   41.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   41.29 + *
   41.30 + * If you wish your version of this file to be governed by only the CDDL
   41.31 + * or only the GPL Version 2, indicate your decision by adding
   41.32 + * "[Contributor] elects to include this software in this distribution
   41.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   41.34 + * single choice of license, a recipient has the option to distribute
   41.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   41.36 + * to extend the choice of license to its licensees as provided above.
   41.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   41.38 + * Version 2 license, then the option applies only if the new code is
   41.39 + * made subject to such option by the copyright holder.
   41.40 + *
   41.41 + * Contributor(s):
   41.42 + *
   41.43 + * Portions Copyrighted 2008-2010 Sun Microsystems, Inc.
   41.44 + */
   41.45 +
   41.46 +package org.netbeans.modules.java.hints.spiimpl;
   41.47 +
   41.48 +import java.util.Collection;
   41.49 +import java.util.Map;
   41.50 +import java.util.concurrent.atomic.AtomicBoolean;
   41.51 +import org.netbeans.api.annotations.common.NullAllowed;
   41.52 +import org.netbeans.api.java.classpath.ClassPath;
   41.53 +import org.netbeans.api.java.source.CompilationInfo;
   41.54 +import org.netbeans.modules.java.hints.providers.spi.HintDescription;
   41.55 +import org.netbeans.modules.java.hints.providers.spi.HintMetadata;
   41.56 +import org.openide.util.Lookup;
   41.57 +
   41.58 +/**
   41.59 + *
   41.60 + * @author lahvac
   41.61 + */
   41.62 +public abstract class RulesManager {
   41.63 +
   41.64 +    public static RulesManager getInstance() {
   41.65 +        return Lookup.getDefault().lookup(RulesManager.class);
   41.66 +    }
   41.67 +
   41.68 +    public abstract Map<HintMetadata, ? extends Collection<? extends HintDescription>> readHints(@NullAllowed CompilationInfo info, @NullAllowed Collection<? extends ClassPath> from, @NullAllowed AtomicBoolean cancel);
   41.69 +    public abstract void reload(); //XXX
   41.70 +    
   41.71 +}
    42.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    42.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/RulesManagerImpl.java	Wed May 08 21:47:42 2013 +0200
    42.3 @@ -0,0 +1,140 @@
    42.4 +/*
    42.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    42.6 + *
    42.7 + * Copyright 2008-2010 Oracle and/or its affiliates. All rights reserved.
    42.8 + *
    42.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   42.10 + * Other names may be trademarks of their respective owners.
   42.11 + *
   42.12 + * The contents of this file are subject to the terms of either the GNU
   42.13 + * General Public License Version 2 only ("GPL") or the Common
   42.14 + * Development and Distribution License("CDDL") (collectively, the
   42.15 + * "License"). You may not use this file except in compliance with the
   42.16 + * License. You can obtain a copy of the License at
   42.17 + * http://www.netbeans.org/cddl-gplv2.html
   42.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   42.19 + * specific language governing permissions and limitations under the
   42.20 + * License.  When distributing the software, include this License Header
   42.21 + * Notice in each file and include the License file at
   42.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   42.23 + * particular file as subject to the "Classpath" exception as provided
   42.24 + * by Oracle in the GPL Version 2 section of the License file that
   42.25 + * accompanied this code. If applicable, add the following below the
   42.26 + * License Header, with the fields enclosed by brackets [] replaced by
   42.27 + * your own identifying information:
   42.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   42.29 + *
   42.30 + * If you wish your version of this file to be governed by only the CDDL
   42.31 + * or only the GPL Version 2, indicate your decision by adding
   42.32 + * "[Contributor] elects to include this software in this distribution
   42.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   42.34 + * single choice of license, a recipient has the option to distribute
   42.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   42.36 + * to extend the choice of license to its licensees as provided above.
   42.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   42.38 + * Version 2 license, then the option applies only if the new code is
   42.39 + * made subject to such option by the copyright holder.
   42.40 + *
   42.41 + * Contributor(s):
   42.42 + *
   42.43 + * Portions Copyrighted 2008-2010 Sun Microsystems, Inc.
   42.44 + */
   42.45 +
   42.46 +package org.netbeans.modules.java.hints.spiimpl;
   42.47 +
   42.48 +import java.util.ArrayList;
   42.49 +import java.util.Collection;
   42.50 +import java.util.Collections;
   42.51 +import java.util.HashMap;
   42.52 +import java.util.LinkedList;
   42.53 +import java.util.Map;
   42.54 +import java.util.Map.Entry;
   42.55 +import java.util.concurrent.atomic.AtomicBoolean;
   42.56 +import org.netbeans.api.java.classpath.ClassPath;
   42.57 +import org.netbeans.api.java.source.ClasspathInfo;
   42.58 +import org.netbeans.api.java.source.ClasspathInfo.PathKind;
   42.59 +import org.netbeans.api.java.source.CompilationInfo;
   42.60 +import org.netbeans.modules.java.hints.providers.spi.HintDescription;
   42.61 +import org.netbeans.modules.java.hints.providers.spi.HintMetadata;
   42.62 +import org.netbeans.modules.java.hints.providers.spi.ClassPathBasedHintProvider;
   42.63 +import org.netbeans.modules.java.hints.providers.spi.ElementBasedHintProvider;
   42.64 +import org.netbeans.modules.java.hints.providers.spi.HintProvider;
   42.65 +import org.netbeans.spi.java.classpath.support.ClassPathSupport;
   42.66 +import org.openide.util.Lookup;
   42.67 +import org.openide.util.lookup.ServiceProvider;
   42.68 +
   42.69 +/**
   42.70 + *
   42.71 + * @author lahvac
   42.72 + */
   42.73 +@ServiceProvider(service=RulesManager.class)
   42.74 +public class RulesManagerImpl extends RulesManager {
   42.75 +
   42.76 +    private final Map<HintMetadata, Collection<HintDescription>> globalHints = new HashMap<HintMetadata, Collection<HintDescription>>();
   42.77 +
   42.78 +    public RulesManagerImpl() {
   42.79 +        reload();
   42.80 +    }
   42.81 +    
   42.82 +    @Override
   42.83 +    public void reload() {
   42.84 +        globalHints.clear();
   42.85 +
   42.86 +        for (HintProvider p : Lookup.getDefault().lookupAll(HintProvider.class)) {
   42.87 +            Map<HintMetadata, ? extends Collection<? extends HintDescription>> pHints = p.computeHints();
   42.88 +
   42.89 +            if (pHints != null) {
   42.90 +                for (Entry<HintMetadata, ? extends Collection<? extends HintDescription>> e : pHints.entrySet()) {
   42.91 +                    globalHints.put(e.getKey(), new ArrayList<HintDescription>(e.getValue()));
   42.92 +                }
   42.93 +            }
   42.94 +        }
   42.95 +    }
   42.96 +
   42.97 +    @Override
   42.98 +    public Map<HintMetadata, ? extends Collection<? extends HintDescription>> readHints(CompilationInfo info, Collection<? extends ClassPath> from, AtomicBoolean cancel) {
   42.99 +        Map<HintMetadata, Collection<HintDescription>> result = new HashMap<HintMetadata, Collection<HintDescription>>(globalHints);
  42.100 +
  42.101 +        if (info != null) {
  42.102 +            for (ElementBasedHintProvider provider : Lookup.getDefault().lookupAll(ElementBasedHintProvider.class)) {
  42.103 +                sortByMetadata(provider.computeHints(info), result);
  42.104 +            }
  42.105 +        }
  42.106 +
  42.107 +        if (from == null) {
  42.108 +            if (info != null) {
  42.109 +                ClasspathInfo cpInfo = info.getClasspathInfo();
  42.110 +                LinkedList<ClassPath> cps = new LinkedList<ClassPath>();
  42.111 +
  42.112 +                cps.add(cpInfo.getClassPath(PathKind.BOOT));
  42.113 +                cps.add(cpInfo.getClassPath(PathKind.COMPILE));
  42.114 +                cps.add(cpInfo.getClassPath(PathKind.SOURCE));
  42.115 +
  42.116 +                from = cps;
  42.117 +            } else {
  42.118 +                from = Collections.emptyList();
  42.119 +            }
  42.120 +        }
  42.121 +
  42.122 +        ClassPath compound = ClassPathSupport.createProxyClassPath(from.toArray(new ClassPath[0]));
  42.123 +
  42.124 +        for (ClassPathBasedHintProvider p : Lookup.getDefault().lookupAll(ClassPathBasedHintProvider.class)) {
  42.125 +            sortByMetadata(p.computeHints(compound), result);
  42.126 +        }
  42.127 +
  42.128 +        return result;
  42.129 +    }
  42.130 +
  42.131 +    public static void sortByMetadata(Collection<? extends HintDescription> listedHints, Map<HintMetadata, Collection<HintDescription>> into) {
  42.132 +        for (HintDescription hd : listedHints) {
  42.133 +            Collection<HintDescription> h = into.get(hd.getMetadata());
  42.134 +
  42.135 +            if (h == null) {
  42.136 +                into.put(hd.getMetadata(), h = new ArrayList<HintDescription>());
  42.137 +            }
  42.138 +
  42.139 +            h.add(hd);
  42.140 +        }
  42.141 +    }
  42.142 +
  42.143 +}
    43.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    43.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/SPIAccessor.java	Wed May 08 21:47:42 2013 +0200
    43.3 @@ -0,0 +1,85 @@
    43.4 +/*
    43.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    43.6 + *
    43.7 + * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
    43.8 + *
    43.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   43.10 + * Other names may be trademarks of their respective owners.
   43.11 + *
   43.12 + * The contents of this file are subject to the terms of either the GNU
   43.13 + * General Public License Version 2 only ("GPL") or the Common
   43.14 + * Development and Distribution License("CDDL") (collectively, the
   43.15 + * "License"). You may not use this file except in compliance with the
   43.16 + * License. You can obtain a copy of the License at
   43.17 + * http://www.netbeans.org/cddl-gplv2.html
   43.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   43.19 + * specific language governing permissions and limitations under the
   43.20 + * License.  When distributing the software, include this License Header
   43.21 + * Notice in each file and include the License file at
   43.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   43.23 + * particular file as subject to the "Classpath" exception as provided
   43.24 + * by Oracle in the GPL Version 2 section of the License file that
   43.25 + * accompanied this code. If applicable, add the following below the
   43.26 + * License Header, with the fields enclosed by brackets [] replaced by
   43.27 + * your own identifying information:
   43.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   43.29 + *
   43.30 + * If you wish your version of this file to be governed by only the CDDL
   43.31 + * or only the GPL Version 2, indicate your decision by adding
   43.32 + * "[Contributor] elects to include this software in this distribution
   43.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   43.34 + * single choice of license, a recipient has the option to distribute
   43.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   43.36 + * to extend the choice of license to its licensees as provided above.
   43.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   43.38 + * Version 2 license, then the option applies only if the new code is
   43.39 + * made subject to such option by the copyright holder.
   43.40 + *
   43.41 + * Contributor(s):
   43.42 + *
   43.43 + * Portions Copyrighted 2012 Sun Microsystems, Inc.
   43.44 + */
   43.45 +package org.netbeans.modules.java.hints.spiimpl;
   43.46 +
   43.47 +import com.sun.source.util.TreePath;
   43.48 +import java.util.Collection;
   43.49 +import java.util.Map;
   43.50 +import java.util.concurrent.atomic.AtomicBoolean;
   43.51 +import javax.lang.model.type.TypeMirror;
   43.52 +import org.netbeans.api.java.source.CompilationInfo;
   43.53 +import org.netbeans.modules.java.hints.providers.spi.HintMetadata;
   43.54 +import org.netbeans.modules.java.hints.spiimpl.options.HintsSettings;
   43.55 +import org.netbeans.spi.java.hints.HintContext;
   43.56 +import org.openide.util.Exceptions;
   43.57 +
   43.58 +/**
   43.59 + *
   43.60 + * @author lahvac
   43.61 + */
   43.62 +public abstract class SPIAccessor {
   43.63 +
   43.64 +    private static volatile SPIAccessor accessor;
   43.65 +
   43.66 +    public static synchronized SPIAccessor getINSTANCE() {
   43.67 +        if (accessor == null) {
   43.68 +            try {
   43.69 +                Class.forName(HintContext.class.getName(), true, HintContext.class.getClassLoader());
   43.70 +                assert accessor != null;
   43.71 +            } catch (ClassNotFoundException e) {
   43.72 +                Exceptions.printStackTrace(e);
   43.73 +            }
   43.74 +        }
   43.75 +        return accessor;
   43.76 +    }
   43.77 +
   43.78 +    public static void setINSTANCE(SPIAccessor instance) {
   43.79 +        assert instance != null;
   43.80 +        accessor = instance;
   43.81 +    }
   43.82 +
   43.83 +    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);
   43.84 +    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);
   43.85 +    public abstract HintMetadata getHintMetadata(HintContext ctx);
   43.86 +    public abstract HintsSettings getHintSettings(HintContext ctx);
   43.87 +
   43.88 +}
    44.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    44.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/SyntheticFix.java	Wed May 08 21:47:42 2013 +0200
    44.3 @@ -0,0 +1,46 @@
    44.4 +/*
    44.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    44.6 + *
    44.7 + * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
    44.8 + *
    44.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   44.10 + * Other names may be trademarks of their respective owners.
   44.11 + *
   44.12 + * The contents of this file are subject to the terms of either the GNU
   44.13 + * General Public License Version 2 only ("GPL") or the Common Development and
   44.14 + * Distribution License("CDDL") (collectively, the "License"). You may not use
   44.15 + * this file except in compliance with the License. You can obtain a copy of
   44.16 + * the License at http://www.netbeans.org/cddl-gplv2.html or
   44.17 + * nbbuild/licenses/CDDL-GPL-2-CP. See the License for the specific language
   44.18 + * governing permissions and limitations under the License. When distributing
   44.19 + * the software, include this License Header Notice in each file and include
   44.20 + * the License file at nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
   44.21 + * particular file as subject to the "Classpath" exception as provided by
   44.22 + * Oracle in the GPL Version 2 section of the License file that accompanied
   44.23 + * this code. If applicable, add the following below the License Header, with
   44.24 + * the fields enclosed by brackets [] replaced by your own identifying
   44.25 + * information: "Portions Copyrighted [year] [name of copyright owner]"
   44.26 + *
   44.27 + * If you wish your version of this file to be governed by only the CDDL or
   44.28 + * only the GPL Version 2, indicate your decision by adding "[Contributor]
   44.29 + * elects to include this software in this distribution under the [CDDL or GPL
   44.30 + * Version 2] license." If you do not indicate a single choice of license, a
   44.31 + * recipient has the option to distribute your version of this file under
   44.32 + * either the CDDL, the GPL Version 2 or to extend the choice of license to its
   44.33 + * licensees as provided above. However, if you add GPL Version 2 code and
   44.34 + * therefore, elected the GPL Version 2 license, then the option applies only
   44.35 + * if the new code is made subject to such option by the copyright holder.
   44.36 + *
   44.37 + * Contributor(s):
   44.38 + *
   44.39 + * Portions Copyrighted 2011 Sun Microsystems, Inc.
   44.40 + */
   44.41 +package org.netbeans.modules.java.hints.spiimpl;
   44.42 +
   44.43 +/**
   44.44 + *
   44.45 + * @author lahvac
   44.46 + */
   44.47 +public interface SyntheticFix {
   44.48 +
   44.49 +}
    45.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    45.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/Utilities.java	Wed May 08 21:47:42 2013 +0200
    45.3 @@ -0,0 +1,1538 @@
    45.4 +/*
    45.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    45.6 + *
    45.7 + * Copyright 2008-2010 Sun Microsystems, Inc. All rights reserved.
    45.8 + *
    45.9 + * The contents of this file are subject to the terms of either the GNU
   45.10 + * General Public License Version 2 only ("GPL") or the Common
   45.11 + * Development and Distribution License("CDDL") (collectively, the
   45.12 + * "License"). You may not use this file except in compliance with the
   45.13 + * License. You can obtain a copy of the License at
   45.14 + * http://www.netbeans.org/cddl-gplv2.html
   45.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   45.16 + * specific language governing permissions and limitations under the
   45.17 + * License.  When distributing the software, include this License Header
   45.18 + * Notice in each file and include the License file at
   45.19 + * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
   45.20 + * particular file as subject to the "Classpath" exception as provided
   45.21 + * by Sun in the GPL Version 2 section of the License file that
   45.22 + * accompanied this code. If applicable, add the following below the
   45.23 + * License Header, with the fields enclosed by brackets [] replaced by
   45.24 + * your own identifying information:
   45.25 + * "Portions Copyrighted [year] [name of copyright owner]"
   45.26 + *
   45.27 + * If you wish your version of this file to be governed by only the CDDL
   45.28 + * or only the GPL Version 2, indicate your decision by adding
   45.29 + * "[Contributor] elects to include this software in this distribution
   45.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   45.31 + * single choice of license, a recipient has the option to distribute
   45.32 + * your version of this file under either the CDDL, the GPL Version 2 or
   45.33 + * to extend the choice of license to its licensees as provided above.
   45.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   45.35 + * Version 2 license, then the option applies only if the new code is
   45.36 + * made subject to such option by the copyright holder.
   45.37 + *
   45.38 + * Contributor(s):
   45.39 + *
   45.40 + * Portions Copyrighted 2008-2010 Sun Microsystems, Inc.
   45.41 + */
   45.42 +
   45.43 +package org.netbeans.modules.java.hints.spiimpl;
   45.44 +
   45.45 +import com.sun.source.tree.AnnotationTree;
   45.46 +import com.sun.source.tree.AssignmentTree;
   45.47 +import com.sun.source.tree.BlockTree;
   45.48 +import com.sun.source.tree.ClassTree;
   45.49 +import com.sun.source.tree.CompilationUnitTree;
   45.50 +import com.sun.source.tree.ExpressionStatementTree;
   45.51 +import com.sun.source.tree.ExpressionTree;
   45.52 +import com.sun.source.tree.IdentifierTree;
   45.53 +import com.sun.source.tree.ImportTree;
   45.54 +import com.sun.source.tree.LiteralTree;
   45.55 +import com.sun.source.tree.MemberSelectTree;
   45.56 +import com.sun.source.tree.MethodInvocationTree;
   45.57 +import com.sun.source.tree.MethodTree;
   45.58 +import com.sun.source.tree.ModifiersTree;
   45.59 +import com.sun.source.tree.NewArrayTree;
   45.60 +import com.sun.source.tree.NewClassTree;
   45.61 +import com.sun.source.tree.Scope;
   45.62 +import com.sun.source.tree.StatementTree;
   45.63 +import com.sun.source.tree.SwitchTree;
   45.64 +import com.sun.source.tree.Tree;
   45.65 +import com.sun.source.tree.Tree.Kind;
   45.66 +import com.sun.source.tree.TypeParameterTree;
   45.67 +import com.sun.source.tree.VariableTree;
   45.68 +import com.sun.source.util.SourcePositions;
   45.69 +import com.sun.source.util.TreePath;
   45.70 +import com.sun.source.util.TreePathScanner;
   45.71 +import com.sun.source.util.TreeScanner;
   45.72 +import com.sun.source.util.Trees;
   45.73 +import com.sun.tools.javac.api.JavacScope;
   45.74 +import com.sun.tools.javac.api.JavacTaskImpl;
   45.75 +import com.sun.tools.javac.api.JavacTrees;
   45.76 +import com.sun.tools.javac.code.Flags;
   45.77 +import com.sun.tools.javac.code.Symtab;
   45.78 +import com.sun.tools.javac.code.Type;
   45.79 +import com.sun.tools.javac.comp.Attr;
   45.80 +import com.sun.tools.javac.comp.AttrContext;
   45.81 +import com.sun.tools.javac.comp.Env;
   45.82 +import com.sun.tools.javac.comp.Todo;
   45.83 +import com.sun.tools.javac.main.JavaCompiler;
   45.84 +import com.sun.tools.javac.parser.JavacParser;
   45.85 +import com.sun.tools.javac.parser.Lexer;
   45.86 +import com.sun.tools.javac.parser.Parser;
   45.87 +import com.sun.tools.javac.parser.ParserFactory;
   45.88 +import com.sun.tools.javac.parser.Scanner;
   45.89 +import com.sun.tools.javac.parser.ScannerFactory;
   45.90 +import com.sun.tools.javac.parser.Tokens.Token;
   45.91 +import com.sun.tools.javac.parser.Tokens.TokenKind;
   45.92 +import com.sun.tools.javac.tree.JCTree;
   45.93 +import com.sun.tools.javac.tree.JCTree.JCCase;
   45.94 +import com.sun.tools.javac.tree.JCTree.JCCatch;
   45.95 +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
   45.96 +import com.sun.tools.javac.tree.JCTree.JCExpression;
   45.97 +import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
   45.98 +import com.sun.tools.javac.tree.JCTree.JCIdent;
   45.99 +import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
  45.100 +import com.sun.tools.javac.tree.JCTree.JCModifiers;
  45.101 +import com.sun.tools.javac.tree.JCTree.JCStatement;
  45.102 +import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
  45.103 +import com.sun.tools.javac.util.Context;
  45.104 +import com.sun.tools.javac.util.JCDiagnostic;
  45.105 +import com.sun.tools.javac.util.ListBuffer;
  45.106 +import com.sun.tools.javac.util.Log;
  45.107 +import com.sun.tools.javac.util.Names;
  45.108 +import com.sun.tools.javadoc.Messager;
  45.109 +import java.io.File;
  45.110 +import java.io.IOException;
  45.111 +import java.net.URI;
  45.112 +import java.nio.CharBuffer;
  45.113 +import java.util.Arrays;
  45.114 +import java.util.Collection;
  45.115 +import java.util.Collections;
  45.116 +import java.util.EnumSet;
  45.117 +import java.util.HashMap;
  45.118 +import java.util.HashSet;
  45.119 +import java.util.Iterator;
  45.120 +import java.util.LinkedList;
  45.121 +import java.util.List;
  45.122 +import java.util.Locale;
  45.123 +import java.util.Map;
  45.124 +import java.util.Map.Entry;
  45.125 +import java.util.Set;
  45.126 +import java.util.concurrent.atomic.AtomicBoolean;
  45.127 +import javax.lang.model.element.AnnotationMirror;
  45.128 +import javax.lang.model.element.AnnotationValue;
  45.129 +import javax.lang.model.element.AnnotationValueVisitor;
  45.130 +import javax.lang.model.element.Element;
  45.131 +import javax.lang.model.element.ElementKind;
  45.132 +import javax.lang.model.element.ExecutableElement;
  45.133 +import javax.lang.model.element.Modifier;
  45.134 +import javax.lang.model.element.Name;
  45.135 +import javax.lang.model.element.TypeElement;
  45.136 +import javax.lang.model.element.VariableElement;
  45.137 +import javax.lang.model.type.TypeKind;
  45.138 +import javax.lang.model.type.TypeMirror;
  45.139 +import javax.lang.model.util.Elements;
  45.140 +import javax.tools.Diagnostic;
  45.141 +import javax.tools.JavaCompiler.CompilationTask;
  45.142 +import javax.tools.JavaFileObject;
  45.143 +import javax.tools.SimpleJavaFileObject;
  45.144 +import org.netbeans.api.annotations.common.CheckForNull;
  45.145 +import org.netbeans.api.annotations.common.NonNull;
  45.146 +import org.netbeans.api.java.classpath.ClassPath;
  45.147 +import org.netbeans.api.java.platform.JavaPlatform;
  45.148 +import org.netbeans.api.java.platform.JavaPlatformManager;
  45.149 +import org.netbeans.api.java.queries.SourceForBinaryQuery;
  45.150 +import org.netbeans.api.java.queries.SourceForBinaryQuery.Result2;
  45.151 +import org.netbeans.api.java.source.ClasspathInfo;
  45.152 +import org.netbeans.api.java.source.CompilationInfo;
  45.153 +import org.netbeans.api.java.source.CompilationInfo.CacheClearPolicy;
  45.154 +import org.netbeans.api.java.source.SourceUtils;
  45.155 +import org.netbeans.api.java.source.TreeMaker;
  45.156 +import org.netbeans.modules.java.hints.providers.spi.ClassPathBasedHintProvider;
  45.157 +import org.netbeans.modules.java.hints.providers.spi.HintDescription;
  45.158 +import org.netbeans.modules.java.hints.providers.spi.Trigger.PatternDescription;
  45.159 +import org.netbeans.modules.java.hints.spiimpl.JackpotTrees.CatchWildcard;
  45.160 +import org.netbeans.modules.java.hints.spiimpl.JackpotTrees.VariableWildcard;
  45.161 +import org.netbeans.modules.java.source.JavaSourceAccessor;
  45.162 +import org.netbeans.modules.java.source.builder.TreeFactory;
  45.163 +import org.netbeans.lib.nbjavac.services.CancelService;
  45.164 +import org.netbeans.lib.nbjavac.services.NBParserFactory.NBJavacParser;
  45.165 +import org.netbeans.lib.nbjavac.services.NBParserFactory;
  45.166 +import org.netbeans.modules.java.hints.spiimpl.JackpotTrees.AnnotationWildcard;
  45.167 +import org.netbeans.modules.java.hints.spiimpl.JackpotTrees.FakeBlock;
  45.168 +import org.netbeans.modules.java.source.parsing.FileObjects;
  45.169 +import org.netbeans.modules.java.source.pretty.ImportAnalysis2;
  45.170 +import org.netbeans.modules.java.source.transform.ImmutableTreeTranslator;
  45.171 +import org.netbeans.spi.editor.hints.Severity;
  45.172 +import org.netbeans.spi.java.classpath.support.ClassPathSupport;
  45.173 +import org.openide.filesystems.FileObject;
  45.174 +import org.openide.filesystems.FileUtil;
  45.175 +import org.openide.util.Lookup;
  45.176 +import org.openide.util.NbCollections;
  45.177 +import org.openide.util.lookup.ServiceProvider;
  45.178 +
  45.179 +/**
  45.180 + *
  45.181 + * @author Jan Lahoda
  45.182 + */
  45.183 +public class Utilities {
  45.184 +
  45.185 +    private Utilities() {}
  45.186 +    
  45.187 +    public static Set<Severity> disableErrors(FileObject file) {
  45.188 +        if (file.getAttribute(DISABLE_ERRORS) != null) {
  45.189 +            return EnumSet.allOf(Severity.class);
  45.190 +        }
  45.191 +        if (!file.canWrite() && FileUtil.getArchiveFile(file) != null) {
  45.192 +            return EnumSet.allOf(Severity.class);
  45.193 +        }
  45.194 +
  45.195 +        return EnumSet.noneOf(Severity.class);
  45.196 +    }
  45.197 +
  45.198 +    private static final String DISABLE_ERRORS = "disable-java-errors";
  45.199 +    
  45.200 +
  45.201 +    public static <E> Iterable<E> checkedIterableByFilter(final Iterable raw, final Class<E> type, final boolean strict) {
  45.202 +        return new Iterable<E>() {
  45.203 +            public Iterator<E> iterator() {
  45.204 +                return NbCollections.checkedIteratorByFilter(raw.iterator(), type, strict);
  45.205 +            }
  45.206 +        };
  45.207 +    }
  45.208 +    
  45.209 +//    public static AnnotationTree constructConstraint(WorkingCopy wc, String name, TypeMirror tm) {
  45.210 +//        TreeMaker make = wc.getTreeMaker();
  45.211 +//        ExpressionTree variable = prepareAssignment(make, "variable", make.Literal(name));
  45.212 +//        ExpressionTree type     = prepareAssignment(make, "type", make.MemberSelect((ExpressionTree) make.Type(wc.getTypes().erasure(tm)), "class"));
  45.213 +//        TypeElement constraint  = wc.getElements().getTypeElement(Annotations.CONSTRAINT.toFQN());
  45.214 +//
  45.215 +//        return make.Annotation(make.QualIdent(constraint), Arrays.asList(variable, type));
  45.216 +//    }
  45.217 +
  45.218 +    public static ExpressionTree prepareAssignment(TreeMaker make, String name, ExpressionTree value) {
  45.219 +        return make.Assignment(make.Identifier(name), value);
  45.220 +    }
  45.221 +
  45.222 +    public static ExpressionTree findValue(AnnotationTree m, String name) {
  45.223 +        for (ExpressionTree et : m.getArguments()) {
  45.224 +            if (et.getKind() == Kind.ASSIGNMENT) {
  45.225 +                AssignmentTree at = (AssignmentTree) et;
  45.226 +                String varName = ((IdentifierTree) at.getVariable()).getName().toString();
  45.227 +
  45.228 +                if (varName.equals(name)) {
  45.229 +                    return at.getExpression();
  45.230 +                }
  45.231 +            }
  45.232 +
  45.233 +            if (et instanceof LiteralTree/*XXX*/ && "value".equals(name)) {
  45.234 +                return et;
  45.235 +            }
  45.236 +        }
  45.237 +
  45.238 +        return null;
  45.239 +    }
  45.240 +
  45.241 +    public static List<AnnotationTree> findArrayValue(AnnotationTree at, String name) {
  45.242 +        ExpressionTree fixesArray = findValue(at, name);
  45.243 +        List<AnnotationTree> fixes = new LinkedList<AnnotationTree>();
  45.244 +
  45.245 +        if (fixesArray != null && fixesArray.getKind() == Kind.NEW_ARRAY) {
  45.246 +            NewArrayTree trees = (NewArrayTree) fixesArray;
  45.247 +
  45.248 +            for (ExpressionTree fix : trees.getInitializers()) {
  45.249 +                if (fix.getKind() == Kind.ANNOTATION) {
  45.250 +                    fixes.add((AnnotationTree) fix);
  45.251 +                }
  45.252 +            }
  45.253 +        }
  45.254 +
  45.255 +        if (fixesArray != null && fixesArray.getKind() == Kind.ANNOTATION) {
  45.256 +            fixes.add((AnnotationTree) fixesArray);
  45.257 +        }
  45.258 +        
  45.259 +        return fixes;
  45.260 +    }
  45.261 +
  45.262 +    public static boolean isPureMemberSelect(Tree mst, boolean allowVariables) {
  45.263 +        switch (mst.getKind()) {
  45.264 +            case IDENTIFIER: return allowVariables || ((IdentifierTree) mst).getName().charAt(0) != '$';
  45.265 +            case MEMBER_SELECT: return isPureMemberSelect(((MemberSelectTree) mst).getExpression(), allowVariables);
  45.266 +            default: return false;
  45.267 +        }
  45.268 +    }
  45.269 +
  45.270 +    public static Map<String, Collection<HintDescription>> sortOutHints(Iterable<? extends HintDescription> hints, Map<String, Collection<HintDescription>> output) {
  45.271 +        for (HintDescription d : hints) {
  45.272 +            Collection<HintDescription> h = output.get(d.getMetadata().displayName);
  45.273 +
  45.274 +            if (h == null) {
  45.275 +                output.put(d.getMetadata().displayName, h = new LinkedList<HintDescription>());
  45.276 +            }
  45.277 +
  45.278 +            h.add(d);
  45.279 +        }
  45.280 +
  45.281 +        return output;
  45.282 +    }
  45.283 +
  45.284 +    public static List<HintDescription> listAllHints(Set<ClassPath> cps) {
  45.285 +        List<HintDescription> result = new LinkedList<HintDescription>();
  45.286 +
  45.287 +        for (Collection<? extends HintDescription> hints : RulesManager.getInstance().readHints(null, cps, new AtomicBoolean()).values()) {
  45.288 +            for (HintDescription hd : hints) {
  45.289 +                if (!(hd.getTrigger() instanceof PatternDescription)) continue; //TODO: only pattern based hints are currently supported
  45.290 +                result.add(hd);
  45.291 +            }
  45.292 +        }
  45.293 +
  45.294 +        result.addAll(listClassPathHints(Collections.<ClassPath>emptySet(), cps));
  45.295 +
  45.296 +        return result;
  45.297 +    }
  45.298 +
  45.299 +    public static List<HintDescription> listClassPathHints(Set<ClassPath> sourceCPs, Set<ClassPath> binaryCPs) {
  45.300 +        List<HintDescription> result = new LinkedList<HintDescription>();
  45.301 +        Set<FileObject> roots = new HashSet<FileObject>();
  45.302 +
  45.303 +        for (ClassPath cp : binaryCPs) {
  45.304 +            for (FileObject r : cp.getRoots()) {
  45.305 +                Result2 src = SourceForBinaryQuery.findSourceRoots2(r.toURL());
  45.306 +
  45.307 +                if (src != null && src.preferSources()) {
  45.308 +                    roots.addAll(Arrays.asList(src.getRoots()));
  45.309 +                } else {
  45.310 +                    roots.add(r);
  45.311 +                }
  45.312 +            }
  45.313 +        }
  45.314 +
  45.315 +        Set<ClassPath> cps = new HashSet<ClassPath>(sourceCPs);
  45.316 +
  45.317 +        cps.add(ClassPathSupport.createClassPath(roots.toArray(new FileObject[0])));
  45.318 +
  45.319 +        ClassPath cp = ClassPathSupport.createProxyClassPath(cps.toArray(new ClassPath[0]));
  45.320 +
  45.321 +        for (ClassPathBasedHintProvider p : Lookup.getDefault().lookupAll(ClassPathBasedHintProvider.class)) {
  45.322 +            result.addAll(p.computeHints(cp));
  45.323 +        }
  45.324 +
  45.325 +        return result;
  45.326 +    }
  45.327 +    
  45.328 +    public static Tree parseAndAttribute(CompilationInfo info, String pattern, Scope scope) {
  45.329 +        return parseAndAttribute(info, pattern, scope, null);
  45.330 +    }
  45.331 +
  45.332 +    public static Tree parseAndAttribute(CompilationInfo info, String pattern, Scope scope, Collection<Diagnostic<? extends JavaFileObject>> errors) {
  45.333 +        return parseAndAttribute(info, JavaSourceAccessor.getINSTANCE().getJavacTask(info), pattern, scope, errors);
  45.334 +    }
  45.335 +
  45.336 +    public static Tree parseAndAttribute(CompilationInfo info, String pattern, Scope scope, SourcePositions[] sourcePositions, Collection<Diagnostic<? extends JavaFileObject>> errors) {
  45.337 +        return parseAndAttribute(info, JavaSourceAccessor.getINSTANCE().getJavacTask(info), pattern, scope, sourcePositions, errors);
  45.338 +    }
  45.339 +
  45.340 +    public static Tree parseAndAttribute(JavacTaskImpl jti, String pattern) {
  45.341 +        return parseAndAttribute(jti, pattern, null);
  45.342 +    }
  45.343 +
  45.344 +    public static Tree parseAndAttribute(JavacTaskImpl jti, String pattern, Collection<Diagnostic<? extends JavaFileObject>> errors) {
  45.345 +        return parseAndAttribute(null, jti, pattern, null, errors);
  45.346 +    }
  45.347 +
  45.348 +    public static Tree parseAndAttribute(JavacTaskImpl jti, String pattern, SourcePositions[] sourcePositions, Collection<Diagnostic<? extends JavaFileObject>> errors) {
  45.349 +        return parseAndAttribute(null, jti, pattern, null, sourcePositions, errors);
  45.350 +    }
  45.351 +
  45.352 +    private static Tree parseAndAttribute(CompilationInfo info, JavacTaskImpl jti, String pattern, Scope scope, Collection<Diagnostic<? extends JavaFileObject>> errors) {
  45.353 +        return parseAndAttribute(info, jti, pattern, scope, new SourcePositions[1], errors);
  45.354 +    }
  45.355 +
  45.356 +    private static Tree parseAndAttribute(CompilationInfo info, JavacTaskImpl jti, String pattern, Scope scope, SourcePositions[] sourcePositions, Collection<Diagnostic<? extends JavaFileObject>> errors) {
  45.357 +        Context c = jti.getContext();
  45.358 +        TreeFactory make = TreeFactory.instance(c);
  45.359 +        List<Diagnostic<? extends JavaFileObject>> patternTreeErrors = new LinkedList<Diagnostic<? extends JavaFileObject>>();
  45.360 +        Tree patternTree = !isStatement(pattern) ? parseExpression(c, pattern, true, sourcePositions, patternTreeErrors) : null;
  45.361 +        int offset = 0;
  45.362 +        boolean expression = true;
  45.363 +        boolean classMember = false;
  45.364 +
  45.365 +        if (pattern.startsWith("case ")) {//XXX: should be a lexer token
  45.366 +            List<Diagnostic<? extends JavaFileObject>> currentPatternTreeErrors = new LinkedList<Diagnostic<? extends JavaFileObject>>();
  45.367 +            Tree switchTree = parseStatement(c, "switch ($$foo) {" + pattern + "}", sourcePositions, currentPatternTreeErrors);
  45.368 +
  45.369 +            offset = "switch ($$foo) {".length();
  45.370 +            patternTreeErrors = currentPatternTreeErrors;
  45.371 +            patternTree = ((SwitchTree) switchTree).getCases().get(0);
  45.372 +        }
  45.373 +
  45.374 +        if (patternTree == null || isErrorTree(patternTree)) {
  45.375 +            SourcePositions[] currentPatternTreePositions = new SourcePositions[1];
  45.376 +            List<Diagnostic<? extends JavaFileObject>> currentPatternTreeErrors = new LinkedList<Diagnostic<? extends JavaFileObject>>();
  45.377 +            Tree currentPatternTree = parseStatement(c, "{" + pattern + "}", currentPatternTreePositions, currentPatternTreeErrors);
  45.378 +
  45.379 +            assert currentPatternTree.getKind() == Kind.BLOCK : currentPatternTree.getKind();
  45.380 +
  45.381 +            List<? extends StatementTree> statements = ((BlockTree) currentPatternTree).getStatements();
  45.382 +
  45.383 +            if (statements.size() == 1) {
  45.384 +                currentPatternTree = statements.get(0);
  45.385 +            } else {
  45.386 +                com.sun.tools.javac.util.List<JCStatement> newStatements = com.sun.tools.javac.util.List.<JCStatement>nil();
  45.387 +
  45.388 +                if (!statements.isEmpty() && !Utilities.isMultistatementWildcardTree(statements.get(0)))
  45.389 +                    newStatements = newStatements.append((JCStatement) make.ExpressionStatement(make.Identifier("$$1$")));
  45.390 +                for (StatementTree st : statements) {
  45.391 +                    newStatements = newStatements.append((JCStatement) st);
  45.392 +                }
  45.393 +                if (!statements.isEmpty() && !Utilities.isMultistatementWildcardTree(statements.get(statements.size() - 1)))
  45.394 +                    newStatements = newStatements.append((JCStatement) make.ExpressionStatement(make.Identifier("$$2$")));
  45.395 +
  45.396 +                currentPatternTree = new FakeBlock(0L, newStatements);
  45.397 +            }
  45.398 +
  45.399 +            if (!currentPatternTreeErrors.isEmpty() || containsError(currentPatternTree)) {
  45.400 +                //maybe a class member?
  45.401 +                SourcePositions[] classPatternTreePositions = new SourcePositions[1];
  45.402 +                List<Diagnostic<? extends JavaFileObject>> classPatternTreeErrors = new LinkedList<Diagnostic<? extends JavaFileObject>>();
  45.403 +                Tree classPatternTree = parseExpression(c, "new Object() {" + pattern + "}", false, classPatternTreePositions, classPatternTreeErrors);
  45.404 +
  45.405 +                if (!containsError(classPatternTree)) {
  45.406 +                    sourcePositions[0] = classPatternTreePositions[0];
  45.407 +                    offset = "new Object() {".length();
  45.408 +                    patternTreeErrors = classPatternTreeErrors;
  45.409 +                    patternTree = classPatternTree;
  45.410 +                    classMember = true;
  45.411 +                } else {
  45.412 +                    sourcePositions[0] = currentPatternTreePositions[0];
  45.413 +                    offset = 1;
  45.414 +                    patternTreeErrors = currentPatternTreeErrors;
  45.415 +                    patternTree = currentPatternTree;
  45.416 +                }
  45.417 +            } else {
  45.418 +                sourcePositions[0] = currentPatternTreePositions[0];
  45.419 +                offset = 1;
  45.420 +                patternTreeErrors = currentPatternTreeErrors;
  45.421 +                patternTree = currentPatternTree;
  45.422 +            }
  45.423 +
  45.424 +            expression = false;
  45.425 +        }
  45.426 +
  45.427 +        if (scope != null) {
  45.428 +            TypeMirror type = attributeTree(jti, patternTree, scope, patternTreeErrors);
  45.429 +
  45.430 +            if (isError(type) && expression) {
  45.431 +                //maybe type?
  45.432 +                if (Utilities.isPureMemberSelect(patternTree, false)) {
  45.433 +                    SourcePositions[] varPositions = new SourcePositions[1];
  45.434 +                    List<Diagnostic<? extends JavaFileObject>> varErrors = new LinkedList<Diagnostic<? extends JavaFileObject>>();
  45.435 +                    Tree var = parseExpression(c, pattern + ".Class.class;", false, varPositions, varErrors);
  45.436 +
  45.437 +                    attributeTree(jti, var, scope, varErrors);
  45.438 +
  45.439 +                    ExpressionTree typeTree = ((MemberSelectTree) ((MemberSelectTree) var).getExpression()).getExpression();
  45.440 +                    final Symtab symtab = Symtab.instance(c);
  45.441 +                    final Elements el = jti.getElements();
  45.442 +                    final Trees trees = JavacTrees.instance(c);
  45.443 +                    CompilationUnitTree cut = ((JavacScope) scope).getEnv().toplevel;
  45.444 +                    final boolean[] found = new boolean[1];
  45.445 +
  45.446 +                    new TreePathScanner<Void, Void>() {
  45.447 +                        @Override public Void visitMemberSelect(MemberSelectTree node, Void p) {
  45.448 +                            Element currentElement = trees.getElement(getCurrentPath());
  45.449 +
  45.450 +                            if (!isError(currentElement)) {
  45.451 +                                if (currentElement.getKind() == ElementKind.PACKAGE && el.getPackageElement(node.toString()) == null) {
  45.452 +                                    ((JCFieldAccess) node).sym = symtab.errSymbol;
  45.453 +                                    ((JCFieldAccess) node).type = symtab.errType;
  45.454 +                                } else {
  45.455 +                                    found[0] = true;
  45.456 +                                    return null;
  45.457 +                                }
  45.458 +                            }
  45.459 +
  45.460 +                            return super.visitMemberSelect(node, p);
  45.461 +                        }
  45.462 +                        @Override public Void visitIdentifier(IdentifierTree node, Void p) {
  45.463 +                            Element currentElement = trees.getElement(getCurrentPath());
  45.464 +
  45.465 +                            if (!isError(currentElement)) {
  45.466 +                                if (currentElement.getKind() == ElementKind.PACKAGE && el.getPackageElement(node.toString()) == null) {
  45.467 +                                    ((JCIdent) node).sym = symtab.errSymbol;
  45.468 +                                    ((JCIdent) node).type = symtab.errType;
  45.469 +                                } else {
  45.470 +                                    found[0] = true;
  45.471 +                                    return null;
  45.472 +                                }
  45.473 +                            }
  45.474 +                            return super.visitIdentifier(node, p);
  45.475 +                        }
  45.476 +
  45.477 +                    }.scan(new TreePath(new TreePath(cut), typeTree), null);
  45.478 +
  45.479 +                    if (found[0]) {
  45.480 +                        sourcePositions[0] = varPositions[0];
  45.481 +                        offset = 0;
  45.482 +                        patternTreeErrors = varErrors;
  45.483 +                        patternTree = typeTree;
  45.484 +                    }
  45.485 +                }
  45.486 +            }
  45.487 +        }
  45.488 +
  45.489 +        if (classMember) {
  45.490 +            List<? extends Tree> members = ((NewClassTree) patternTree).getClassBody().getMembers();
  45.491 +            
  45.492 +            int syntheticOffset = !members.isEmpty() && members.get(0).getKind() == Kind.METHOD && (((JCMethodDecl) members.get(0)).mods.flags & Flags.GENERATEDCONSTR) != 0 ? 1 : 0;
  45.493 +
  45.494 +            if (members.size() > 1 + syntheticOffset) {
  45.495 +                ModifiersTree mt = make.Modifiers(EnumSet.noneOf(Modifier.class));
  45.496 +                List<Tree> newMembers = new LinkedList<Tree>();
  45.497 +
  45.498 +                newMembers.add(make.ExpressionStatement(make.Identifier("$$1$")));
  45.499 +                newMembers.addAll(members.subList(syntheticOffset, members.size()));
  45.500 +
  45.501 +                patternTree = make.Class(mt, "$", Collections.<TypeParameterTree>emptyList(), null, Collections.<Tree>emptyList(), newMembers);
  45.502 +            } else {
  45.503 +                patternTree = members.get(0 + syntheticOffset);
  45.504 +            }
  45.505 +        }
  45.506 +
  45.507 +        if (errors != null) {
  45.508 +            for (Diagnostic<? extends JavaFileObject> d : patternTreeErrors) {
  45.509 +                errors.add(new OffsetDiagnostic<JavaFileObject>(d, -offset));
  45.510 +            }
  45.511 +        }
  45.512 +
  45.513 +        sourcePositions[0] = new OffsetSourcePositions(sourcePositions[0], -offset);
  45.514 +        
  45.515 +        return patternTree;
  45.516 +    }
  45.517 +
  45.518 +    static boolean isError(Element el) {
  45.519 +        return (el == null || (el.getKind() == ElementKind.CLASS) && isError(((TypeElement) el).asType()));
  45.520 +    }
  45.521 +
  45.522 +    private static boolean isError(TypeMirror type) {
  45.523 +        return type == null || type.getKind() == TypeKind.ERROR;
  45.524 +    }
  45.525 +
  45.526 +    private static boolean isStatement(String pattern) {
  45.527 +        return pattern.trim().endsWith(";");
  45.528 +    }
  45.529 +
  45.530 +    private static boolean isErrorTree(Tree t) {
  45.531 +        return t.getKind() == Kind.ERRONEOUS || (t.getKind() == Kind.IDENTIFIER && ((IdentifierTree) t).getName().contentEquals("<error>")); //TODO: <error>...
  45.532 +    }
  45.533 +    
  45.534 +    private static boolean containsError(Tree t) {
  45.535 +        return new TreeScanner<Boolean, Void>() {
  45.536 +            @Override
  45.537 +            public Boolean scan(Tree node, Void p) {
  45.538 +                if (node != null && isErrorTree(node)) {
  45.539 +                    return true;
  45.540 +                }
  45.541 +                return super.scan(node, p) ==Boolean.TRUE;
  45.542 +            }
  45.543 +            @Override
  45.544 +            public Boolean reduce(Boolean r1, Boolean r2) {
  45.545 +                return r1 == Boolean.TRUE || r2 == Boolean.TRUE;
  45.546 +            }
  45.547 +        }.scan(t, null);
  45.548 +    }
  45.549 +
  45.550 +    private static JCStatement parseStatement(Context context, CharSequence stmt, SourcePositions[] pos, final List<Diagnostic<? extends JavaFileObject>> errors) {
  45.551 +        if (stmt == null || (pos != null && pos.length != 1))
  45.552 +            throw new IllegalArgumentException();
  45.553 +        JavaCompiler compiler = JavaCompiler.instance(context);
  45.554 +        JavaFileObject prev = compiler.log.useSource(new DummyJFO());
  45.555 +        Log.DiagnosticHandler discardHandler = new Log.DiscardDiagnosticHandler(compiler.log) {
  45.556 +            @Override
  45.557 +            public void report(JCDiagnostic diag) {
  45.558 +                errors.add(diag);
  45.559 +            }            
  45.560 +        };
  45.561 +        try {
  45.562 +            CharBuffer buf = CharBuffer.wrap((stmt+"\u0000").toCharArray(), 0, stmt.length());
  45.563 +            ParserFactory factory = ParserFactory.instance(context);
  45.564 +            ScannerFactory scannerFactory = ScannerFactory.instance(context);
  45.565 +            Names names = Names.instance(context);
  45.566 +            Parser parser = new JackpotJavacParser(context, (NBParserFactory) factory, scannerFactory.newScanner(buf, false), false, false, CancelService.instance(context), names);
  45.567 +            if (parser instanceof JavacParser) {
  45.568 +                if (pos != null)
  45.569 +                    pos[0] = new ParserSourcePositions((JavacParser)parser);
  45.570 +                return parser.parseStatement();
  45.571 +            }
  45.572 +            return null;
  45.573 +        } finally {
  45.574 +            compiler.log.useSource(prev);
  45.575 +            compiler.log.popDiagnosticHandler(discardHandler);
  45.576 +        }
  45.577 +    }
  45.578 +
  45.579 +    private static JCExpression parseExpression(Context context, CharSequence expr, boolean onlyFullInput, SourcePositions[] pos, final List<Diagnostic<? extends JavaFileObject>> errors) {
  45.580 +        if (expr == null || (pos != null && pos.length != 1))
  45.581 +            throw new IllegalArgumentException();
  45.582 +        JavaCompiler compiler = JavaCompiler.instance(context);
  45.583 +        JavaFileObject prev = compiler.log.useSource(new DummyJFO());
  45.584 +        Log.DiagnosticHandler discardHandler = new Log.DiscardDiagnosticHandler(compiler.log) {
  45.585 +            @Override
  45.586 +            public void report(JCDiagnostic diag) {
  45.587 +                errors.add(diag);
  45.588 +            }            
  45.589 +        };
  45.590 +        try {
  45.591 +            CharBuffer buf = CharBuffer.wrap((expr+"\u0000").toCharArray(), 0, expr.length());
  45.592 +            ParserFactory factory = ParserFactory.instance(context);
  45.593 +            ScannerFactory scannerFactory = ScannerFactory.instance(context);
  45.594 +            Names names = Names.instance(context);
  45.595 +            Scanner scanner = scannerFactory.newScanner(buf, false);
  45.596 +            Parser parser = new JackpotJavacParser(context, (NBParserFactory) factory, scanner, false, false, CancelService.instance(context), names);
  45.597 +            if (parser instanceof JavacParser) {
  45.598 +                if (pos != null)
  45.599 +                    pos[0] = new ParserSourcePositions((JavacParser)parser);
  45.600 +                JCExpression result = parser.parseExpression();
  45.601 +
  45.602 +                if (!onlyFullInput || scanner.token().kind == TokenKind.EOF) {
  45.603 +                    return result;
  45.604 +                }
  45.605 +            }
  45.606 +            return null;
  45.607 +        } finally {
  45.608 +            compiler.log.useSource(prev);
  45.609 +            compiler.log.popDiagnosticHandler(discardHandler);
  45.610 +        }
  45.611 +    }
  45.612 +
  45.613 +    private static TypeMirror attributeTree(JavacTaskImpl jti, Tree tree, Scope scope, final List<Diagnostic<? extends JavaFileObject>> errors) {
  45.614 +        Log log = Log.instance(jti.getContext());
  45.615 +        JavaFileObject prev = log.useSource(new DummyJFO());
  45.616 +        Log.DiagnosticHandler discardHandler = new Log.DiscardDiagnosticHandler(log) {
  45.617 +            @Override
  45.618 +            public void report(JCDiagnostic diag) {
  45.619 +                errors.add(diag);
  45.620 +            }            
  45.621 +        };
  45.622 +        try {
  45.623 +            Attr attr = Attr.instance(jti.getContext());
  45.624 +            Env<AttrContext> env = ((JavacScope) scope).getEnv();
  45.625 +            if (tree instanceof JCExpression)
  45.626 +                return attr.attribExpr((JCTree) tree,env, Type.noType);
  45.627 +            return attr.attribStat((JCTree) tree,env);
  45.628 +        } finally {
  45.629 +            log.useSource(prev);
  45.630 +            log.popDiagnosticHandler(discardHandler);
  45.631 +        }
  45.632 +    }
  45.633 +
  45.634 +    public static @CheckForNull CharSequence getWildcardTreeName(@NonNull Tree t) {
  45.635 +        if (t.getKind() == Kind.EXPRESSION_STATEMENT && ((ExpressionStatementTree) t).getExpression().getKind() == Kind.IDENTIFIER) {
  45.636 +            IdentifierTree identTree = (IdentifierTree) ((ExpressionStatementTree) t).getExpression();
  45.637 +            
  45.638 +            return identTree.getName().toString();
  45.639 +        }
  45.640 +
  45.641 +        if (t.getKind() == Kind.IDENTIFIER) {
  45.642 +            IdentifierTree identTree = (IdentifierTree) t;
  45.643 +            String name = identTree.getName().toString();
  45.644 +
  45.645 +            if (name.startsWith("$")) {
  45.646 +                return name;
  45.647 +            }
  45.648 +        }
  45.649 +        
  45.650 +        if (t.getKind() == Kind.TYPE_PARAMETER) {
  45.651 +            String name = ((TypeParameterTree) t).getName().toString();
  45.652 +
  45.653 +            if (name.startsWith("$")) {
  45.654 +                return name;
  45.655 +            }
  45.656 +        }
  45.657 +
  45.658 +        return null;
  45.659 +    }
  45.660 +
  45.661 +    public static boolean isMultistatementWildcard(@NonNull CharSequence name) {
  45.662 +        return name.charAt(name.length() - 1) == '$';
  45.663 +    }
  45.664 +
  45.665 +    public static boolean isMultistatementWildcardTree(Tree tree) {
  45.666 +        CharSequence name = Utilities.getWildcardTreeName(tree);
  45.667 +
  45.668 +        return name != null && Utilities.isMultistatementWildcard(name);
  45.669 +    }
  45.670 +
  45.671 +    private static long inc;
  45.672 +
  45.673 +    public static Scope constructScope(CompilationInfo info, Map<String, TypeMirror> constraints) {
  45.674 +        return constructScope(info, constraints, Collections.<String>emptyList());
  45.675 +    }
  45.676 +
  45.677 +    public static Scope constructScope(CompilationInfo info, Map<String, TypeMirror> constraints, Iterable<? extends String> auxiliaryImports) {
  45.678 +        ScopeDescription desc = new ScopeDescription(constraints, auxiliaryImports);
  45.679 +        Scope result = (Scope) info.getCachedValue(desc);
  45.680 +
  45.681 +        if (result != null) return result;
  45.682 +        
  45.683 +        StringBuilder clazz = new StringBuilder();
  45.684 +
  45.685 +        clazz.append("package $;");
  45.686 +
  45.687 +        for (String i : auxiliaryImports) {
  45.688 +            clazz.append(i);
  45.689 +        }
  45.690 +
  45.691 +        long count = inc++;
  45.692 +
  45.693 +        clazz.append("public class $" + count + "{");
  45.694 +
  45.695 +        for (Entry<String, TypeMirror> e : constraints.entrySet()) {
  45.696 +            if (e.getValue() != null) {
  45.697 +                clazz.append("private ");
  45.698 +                clazz.append(e.getValue().toString()); //XXX
  45.699 +                clazz.append(" ");
  45.700 +                clazz.append(e.getKey());
  45.701 +                clazz.append(";\n");
  45.702 +            }
  45.703 +        }
  45.704 +
  45.705 +        clazz.append("private void test() {\n");
  45.706 +        clazz.append("}\n");
  45.707 +        clazz.append("}\n");
  45.708 +
  45.709 +        JavacTaskImpl jti = JavaSourceAccessor.getINSTANCE().getJavacTask(info);
  45.710 +        Context context = jti.getContext();
  45.711 +        JavaCompiler compiler = JavaCompiler.instance(context);
  45.712 +        Log log = Log.instance(context);
  45.713 +        Log.DiagnosticHandler discardHandler = new Log.DiscardDiagnosticHandler(compiler.log);
  45.714 +
  45.715 +        JavaFileObject jfo = FileObjects.memoryFileObject("$", "$", new File("/tmp/$" + count + ".java").toURI(), System.currentTimeMillis(), clazz.toString());
  45.716 +
  45.717 +        boolean oldSkipAPs = compiler.skipAnnotationProcessing;
  45.718 +
  45.719 +        try {
  45.720 +            compiler.skipAnnotationProcessing = true;
  45.721 +            
  45.722 +            JCCompilationUnit cut = compiler.parse(jfo);
  45.723 +
  45.724 +            compiler.enterTrees(com.sun.tools.javac.util.List.of(cut));
  45.725 +
  45.726 +            Todo todo = compiler.todo;
  45.727 +            ListBuffer<Env<AttrContext>> defer = ListBuffer.<Env<AttrContext>>lb();
  45.728 +            
  45.729 +            while (todo.peek() != null) {
  45.730 +                Env<AttrContext> env = todo.remove();
  45.731 +
  45.732 +                if (env.toplevel == cut)
  45.733 +                    compiler.attribute(env);
  45.734 +                else
  45.735 +                    defer = defer.append(env);
  45.736 +            }
  45.737 +
  45.738 +            todo.addAll(defer);
  45.739 +
  45.740 +            Scope res = new ScannerImpl().scan(cut, info);
  45.741 +
  45.742 +            info.putCachedValue(desc, res, CacheClearPolicy.ON_SIGNATURE_CHANGE);
  45.743 +
  45.744 +            return res;
  45.745 +        } finally {
  45.746 +            log.popDiagnosticHandler(discardHandler);
  45.747 +            compiler.skipAnnotationProcessing = oldSkipAPs;
  45.748 +        }
  45.749 +    }
  45.750 +
  45.751 +    private static final class ScannerImpl extends TreePathScanner<Scope, CompilationInfo> {
  45.752 +
  45.753 +        @Override
  45.754 +        public Scope visitBlock(BlockTree node, CompilationInfo p) {
  45.755 +            return p.getTrees().getScope(getCurrentPath());
  45.756 +        }
  45.757 +
  45.758 +        @Override
  45.759 +        public Scope visitMethod(MethodTree node, CompilationInfo p) {
  45.760 +            if (node.getReturnType() == null) {
  45.761 +                return null;
  45.762 +            }
  45.763 +            return super.visitMethod(node, p);
  45.764 +        }
  45.765 +
  45.766 +        @Override
  45.767 +        public Scope reduce(Scope r1, Scope r2) {
  45.768 +            return r1 != null ? r1 : r2;
  45.769 +        }
  45.770 +
  45.771 +    }
  45.772 +
  45.773 +    private static final class ScopeDescription {
  45.774 +        private final Map<String, TypeMirror> constraints;
  45.775 +        private final Iterable<? extends String> auxiliaryImports;
  45.776 +
  45.777 +        public ScopeDescription(Map<String, TypeMirror> constraints, Iterable<? extends String> auxiliaryImports) {
  45.778 +            this.constraints = constraints;
  45.779 +            this.auxiliaryImports = auxiliaryImports;
  45.780 +        }
  45.781 +
  45.782 +        @Override
  45.783 +        public boolean equals(Object obj) {
  45.784 +            if (obj == null) {
  45.785 +                return false;
  45.786 +            }
  45.787 +            if (getClass() != obj.getClass()) {
  45.788 +                return false;
  45.789 +            }
  45.790 +            final ScopeDescription other = (ScopeDescription) obj;
  45.791 +            if (this.constraints != other.constraints && (this.constraints == null || !this.constraints.equals(other.constraints))) {
  45.792 +                return false;
  45.793 +            }
  45.794 +            if (this.auxiliaryImports != other.auxiliaryImports && (this.auxiliaryImports == null || !this.auxiliaryImports.equals(other.auxiliaryImports))) {
  45.795 +                return false;
  45.796 +            }
  45.797 +            return true;
  45.798 +        }
  45.799 +
  45.800 +        @Override
  45.801 +        public int hashCode() {
  45.802 +            int hash = 7;
  45.803 +            hash = 47 * hash + (this.constraints != null ? this.constraints.hashCode() : 0);
  45.804 +            hash = 47 * hash + (this.auxiliaryImports != null ? this.auxiliaryImports.hashCode() : 0);
  45.805 +            return hash;
  45.806 +        }
  45.807 +
  45.808 +    }
  45.809 +
  45.810 +//    private static Scope constructScope2(CompilationInfo info, Map<String, TypeMirror> constraints) {
  45.811 +//        JavacScope s = (JavacScope) info.getTrees().getScope(new TreePath(info.getCompilationUnit()));
  45.812 +//        Env<AttrContext> env = s.getEnv();
  45.813 +//
  45.814 +//        env = env.dup(env.tree);
  45.815 +//
  45.816 +//        env.info.
  45.817 +//    }
  45.818 +
  45.819 +    public static String toHumanReadableTime(double d) {
  45.820 +        StringBuilder result = new StringBuilder();
  45.821 +        long inSeconds = (long) (d / 1000);
  45.822 +        int seconds = (int) (inSeconds % 60);
  45.823 +        long inMinutes = inSeconds / 60;
  45.824 +        int minutes = (int) (inMinutes % 60);
  45.825 +        long inHours = inMinutes / 60;
  45.826 +
  45.827 +        if (inHours > 0) {
  45.828 +            result.append(inHours);
  45.829 +            result.append("h");
  45.830 +        }
  45.831 +
  45.832 +        if (minutes > 0) {
  45.833 +            result.append(minutes);
  45.834 +            result.append("m");
  45.835 +        }
  45.836 +        
  45.837 +        result.append(seconds);
  45.838 +        result.append("s");
  45.839 +
  45.840 +        return result.toString();
  45.841 +    }
  45.842 +
  45.843 +    public static ClasspathInfo createUniversalCPInfo() {
  45.844 +        return Lookup.getDefault().lookup(SPI.class).createUniversalCPInfo();
  45.845 +    }
  45.846 +
  45.847 +    @SuppressWarnings("deprecation")
  45.848 +    public static void waitScanFinished() throws InterruptedException {
  45.849 +        SourceUtils.waitScanFinished();
  45.850 +    }
  45.851 +
  45.852 +    public static Set<? extends String> findSuppressedWarnings(CompilationInfo info, TreePath path) {
  45.853 +        //TODO: cache?
  45.854 +        Set<String> keys = new HashSet<String>();
  45.855 +
  45.856 +        while (path != null) {
  45.857 +            Tree leaf = path.getLeaf();
  45.858 +
  45.859 +            switch (leaf.getKind()) {
  45.860 +                case METHOD:
  45.861 +                    handleSuppressWarnings(info, path, ((MethodTree) leaf).getModifiers(), keys);
  45.862 +                    break;
  45.863 +                case CLASS:
  45.864 +                    handleSuppressWarnings(info, path, ((ClassTree) leaf).getModifiers(), keys);
  45.865 +                    break;
  45.866 +                case VARIABLE:
  45.867 +                    handleSuppressWarnings(info, path, ((VariableTree) leaf).getModifiers(), keys);
  45.868 +                    break;
  45.869 +            }
  45.870 +
  45.871 +            path = path.getParentPath();
  45.872 +        }
  45.873 +
  45.874 +        return Collections.unmodifiableSet(keys);
  45.875 +    }
  45.876 +
  45.877 +    private static void handleSuppressWarnings(CompilationInfo info, TreePath path, ModifiersTree modifiers, final Set<String> keys) {
  45.878 +        Element el = info.getTrees().getElement(path);
  45.879 +
  45.880 +        if (el == null) {
  45.881 +            return ;
  45.882 +        }
  45.883 +
  45.884 +        for (AnnotationMirror am : el.getAnnotationMirrors()) {
  45.885 +            Name fqn = ((TypeElement) am.getAnnotationType().asElement()).getQualifiedName();
  45.886 +            
  45.887 +            if (!fqn.contentEquals("java.lang.SuppressWarnings")) {
  45.888 +                continue;
  45.889 +            }
  45.890 +
  45.891 +            for (Entry<? extends ExecutableElement, ? extends AnnotationValue> e : am.getElementValues().entrySet()) {
  45.892 +                if (!e.getKey().getSimpleName().contentEquals("value"))
  45.893 +                    continue;
  45.894 +
  45.895 +                e.getValue().accept(new AnnotationValueVisitor<Void, Void>() {
  45.896 +                    public Void visit(AnnotationValue av, Void p) {
  45.897 +                        av.accept(this, p);
  45.898 +                        return null;
  45.899 +                    }
  45.900 +                    public Void visit(AnnotationValue av) {
  45.901 +                        av.accept(this, null);
  45.902 +                        return null;
  45.903 +                    }
  45.904 +                    public Void visitBoolean(boolean b, Void p) {
  45.905 +                        return null;
  45.906 +                    }
  45.907 +                    public Void visitByte(byte b, Void p) {
  45.908 +                        return null;
  45.909 +                    }
  45.910 +                    public Void visitChar(char c, Void p) {
  45.911 +                        return null;
  45.912 +                    }
  45.913 +                    public Void visitDouble(double d, Void p) {
  45.914 +                        return null;
  45.915 +                    }
  45.916 +                    public Void visitFloat(float f, Void p) {
  45.917 +                        return null;
  45.918 +                    }
  45.919 +                    public Void visitInt(int i, Void p) {
  45.920 +                        return null;
  45.921 +                    }
  45.922 +                    public Void visitLong(long i, Void p) {
  45.923 +                        return null;
  45.924 +                    }
  45.925 +                    public Void visitShort(short s, Void p) {
  45.926 +                        return null;
  45.927 +                    }
  45.928 +                    public Void visitString(String s, Void p) {
  45.929 +                        keys.add(s);
  45.930 +                        return null;
  45.931 +                    }
  45.932 +                    public Void visitType(TypeMirror t, Void p) {
  45.933 +                        return null;
  45.934 +                    }
  45.935 +                    public Void visitEnumConstant(VariableElement c, Void p) {
  45.936 +                        return null;
  45.937 +                    }
  45.938 +                    public Void visitAnnotation(AnnotationMirror a, Void p) {
  45.939 +                        return null;
  45.940 +                    }
  45.941 +                    public Void visitArray(List<? extends AnnotationValue> vals, Void p) {
  45.942 +                        for (AnnotationValue av : vals) {
  45.943 +                            av.accept(this, p);
  45.944 +                        }
  45.945 +                        return null;
  45.946 +                    }
  45.947 +                    public Void visitUnknown(AnnotationValue av, Void p) {
  45.948 +                        return null;
  45.949 +                    }
  45.950 +                }, null);
  45.951 +            }
  45.952 +        }
  45.953 +    }
  45.954 +
  45.955 +    public static Tree generalizePattern(CompilationInfo info, TreePath original) {
  45.956 +        return generalizePattern(JavaSourceAccessor.getINSTANCE().getJavacTask(info), original);
  45.957 +    }
  45.958 +
  45.959 +    public static Tree generalizePattern(CompilationTask task, TreePath original) {
  45.960 +        JavacTaskImpl jti = (JavacTaskImpl) task;
  45.961 +        com.sun.tools.javac.util.Context c = jti.getContext();
  45.962 +        TreeFactory make = TreeFactory.instance(c);
  45.963 +        Trees javacTrees = Trees.instance(task);
  45.964 +        GeneralizePattern gp = new GeneralizePattern(javacTrees, make);
  45.965 +
  45.966 +        gp.scan(original, null);
  45.967 +
  45.968 +        GeneralizePatternITT itt = new GeneralizePatternITT(gp.tree2Variable);
  45.969 +
  45.970 +        itt.attach(c, new NoImports(c), null);
  45.971 +
  45.972 +        return itt.translate(original.getLeaf());
  45.973 +    }
  45.974 +
  45.975 +    public static Tree generalizePattern(CompilationInfo info, TreePath original, int firstStatement, int lastStatement) {
  45.976 +        JavacTaskImpl jti = JavaSourceAccessor.getINSTANCE().getJavacTask(info);
  45.977 +        com.sun.tools.javac.util.Context c = jti.getContext();
  45.978 +        TreeFactory make = TreeFactory.instance(c);
  45.979 +        Tree translated = Utilities.generalizePattern(jti, original);
  45.980 +
  45.981 +        assert translated.getKind() == Kind.BLOCK;
  45.982 +
  45.983 +        List<StatementTree> newStatements = new LinkedList<StatementTree>();
  45.984 +        BlockTree block = (BlockTree) translated;
  45.985 +
  45.986 +        if (firstStatement != lastStatement) {
  45.987 +            newStatements.add(make.ExpressionStatement(make.Identifier("$s0$")));
  45.988 +            newStatements.addAll(block.getStatements().subList(firstStatement, lastStatement + 1));
  45.989 +            newStatements.add(make.ExpressionStatement(make.Identifier("$s1$")));
  45.990 +
  45.991 +            translated = make.Block(newStatements, block.isStatic());
  45.992 +        } else {
  45.993 +            translated = block.getStatements().get(firstStatement);
  45.994 +        }
  45.995 +
  45.996 +        return translated;
  45.997 +    }
  45.998 +
  45.999 +    public interface SPI {
 45.1000 +        public ClasspathInfo createUniversalCPInfo();
 45.1001 +    }
 45.1002 +
 45.1003 +    @ServiceProvider(service=SPI.class)
 45.1004 +    public static final class NbSPIImpl implements SPI {
 45.1005 +
 45.1006 +        public ClasspathInfo createUniversalCPInfo() {
 45.1007 +            JavaPlatform select = JavaPlatform.getDefault();
 45.1008 +
 45.1009 +            if (select.getSpecification().getVersion() != null) {
 45.1010 +                for (JavaPlatform p : JavaPlatformManager.getDefault().getInstalledPlatforms()) {
 45.1011 +                    if (!"j2se".equals(p.getSpecification().getName()) || p.getSpecification().getVersion() == null) continue;
 45.1012 +                    if (p.getSpecification().getVersion().compareTo(select.getSpecification().getVersion()) > 0) {
 45.1013 +                        select = p;
 45.1014 +                    }
 45.1015 +                }
 45.1016 +            }
 45.1017 +
 45.1018 +            return ClasspathInfo.create(select.getBootstrapLibraries(), ClassPath.EMPTY, ClassPath.EMPTY);
 45.1019 +        }
 45.1020 +
 45.1021 +    }
 45.1022 +    
 45.1023 +    private static final class GeneralizePattern extends TreePathScanner<Void, Void> {
 45.1024 +
 45.1025 +        public final Map<Tree, Tree> tree2Variable = new HashMap<Tree, Tree>();
 45.1026 +        private final Map<Element, String> element2Variable = new HashMap<Element, String>();
 45.1027 +        private final Trees javacTrees;
 45.1028 +        private final TreeFactory make;
 45.1029 +
 45.1030 +        private int currentVariableIndex = 0;
 45.1031 +
 45.1032 +        public GeneralizePattern(Trees javacTrees, TreeFactory make) {
 45.1033 +            this.javacTrees = javacTrees;
 45.1034 +            this.make = make;
 45.1035 +        }
 45.1036 +
 45.1037 +        private @NonNull String getVariable(@NonNull Element el) {
 45.1038 +            String var = element2Variable.get(el);
 45.1039 +
 45.1040 +            if (var == null) {
 45.1041 +                element2Variable.put(el, var = "$" + currentVariableIndex++);
 45.1042 +            }
 45.1043 +
 45.1044 +            return var;
 45.1045 +        }
 45.1046 +
 45.1047 +        private boolean shouldBeGeneralized(@NonNull Element el) {
 45.1048 +            if (el.getModifiers().contains(Modifier.PRIVATE)) {
 45.1049 +                return true;
 45.1050 +            }
 45.1051 +
 45.1052 +            switch (el.getKind()) {
 45.1053 +                case LOCAL_VARIABLE:
 45.1054 +                case EXCEPTION_PARAMETER:
 45.1055 +                case PARAMETER:
 45.1056 +                    return true;
 45.1057 +            }
 45.1058 +
 45.1059 +            return false;
 45.1060 +        }
 45.1061 +
 45.1062 +        @Override
 45.1063 +        public Void visitIdentifier(IdentifierTree node, Void p) {
 45.1064 +            Element e = javacTrees.getElement(getCurrentPath());
 45.1065 +
 45.1066 +            if (e != null && shouldBeGeneralized(e)) {
 45.1067 +                tree2Variable.put(node, make.Identifier(getVariable(e)));
 45.1068 +            }
 45.1069 +
 45.1070 +            return super.visitIdentifier(node, p);
 45.1071 +        }
 45.1072 +
 45.1073 +        @Override
 45.1074 +        public Void visitVariable(VariableTree node, Void p) {
 45.1075 +            Element e = javacTrees.getElement(getCurrentPath());
 45.1076 +
 45.1077 +            if (e != null && shouldBeGeneralized(e)) {
 45.1078 +                VariableTree nue = make.Variable(node.getModifiers(), getVariable(e), node.getType(), node.getInitializer());
 45.1079 +
 45.1080 +                tree2Variable.put(node, nue);
 45.1081 +            }
 45.1082 +
 45.1083 +            return super.visitVariable(node, p);
 45.1084 +        }
 45.1085 +
 45.1086 +        @Override
 45.1087 +        public Void visitNewClass(NewClassTree node, Void p) {
 45.1088 +            //XXX:
 45.1089 +            if (node.getEnclosingExpression() != null) {
 45.1090 +                tree2Variable.put(node, make.Identifier("$" + currentVariableIndex++));
 45.1091 +                return null;
 45.1092 +            }
 45.1093 +
 45.1094 +            NewClassTree nue = make.NewClass(node.getEnclosingExpression(), Collections.<ExpressionTree>singletonList(make.Identifier("$" + currentVariableIndex++ + "$")), make.Identifier("$" + currentVariableIndex++), Collections.<ExpressionTree>singletonList(make.Identifier("$" + currentVariableIndex++ + "$")), null);
 45.1095 +
 45.1096 +            tree2Variable.put(node, nue);
 45.1097 +
 45.1098 +            return null;
 45.1099 +        }
 45.1100 +
 45.1101 +    }
 45.1102 +
 45.1103 +    private static final class GeneralizePatternITT extends ImmutableTreeTranslator {
 45.1104 +
 45.1105 +        private final Map<Tree, Tree> tree2Variable;
 45.1106 +
 45.1107 +        public GeneralizePatternITT(Map<Tree, Tree> tree2Variable) {
 45.1108 +            super(null);
 45.1109 +            this.tree2Variable = tree2Variable;
 45.1110 +        }
 45.1111 +
 45.1112 +        @Override
 45.1113 +        public Tree translate(Tree tree) {
 45.1114 +            Tree var = tree2Variable.remove(tree);
 45.1115 +
 45.1116 +            if (var != null) {
 45.1117 +                return super.translate(var);
 45.1118 +            }
 45.1119 +
 45.1120 +            return super.translate(tree);
 45.1121 +        }
 45.1122 +
 45.1123 +    }
 45.1124 +
 45.1125 +    private static final class NoImports extends ImportAnalysis2 {
 45.1126 +
 45.1127 +        public NoImports(Context env) {
 45.1128 +            super(env);
 45.1129 +        }
 45.1130 +
 45.1131 +        @Override
 45.1132 +        public void classEntered(ClassTree clazz) {}
 45.1133 +
 45.1134 +        @Override
 45.1135 +        public void enterVisibleThroughClasses(ClassTree clazz) {}
 45.1136 +
 45.1137 +        @Override
 45.1138 +        public void classLeft() {}
 45.1139 +
 45.1140 +        @Override
 45.1141 +        public ExpressionTree resolveImport(MemberSelectTree orig, Element element) {
 45.1142 +            return orig;
 45.1143 +        }
 45.1144 +
 45.1145 +        @Override
 45.1146 +        public void setCompilationUnit(CompilationUnitTree cut) {}
 45.1147 +
 45.1148 +        @Override
 45.1149 +        public void setImports(List<? extends ImportTree> importsToAdd) {}
 45.1150 +
 45.1151 +        @Override
 45.1152 +        public Set<? extends Element> getImports() {
 45.1153 +            return Collections.emptySet();
 45.1154 +        }
 45.1155 +
 45.1156 +        @Override
 45.1157 +        public void setPackage(ExpressionTree packageNameTree) {}
 45.1158 +
 45.1159 +    }
 45.1160 +
 45.1161 +    public static long patternValue(Tree pattern) {
 45.1162 +        class VisitorImpl extends TreeScanner<Void, Void> {
 45.1163 +            private int value;
 45.1164 +            @Override
 45.1165 +            public Void scan(Tree node, Void p) {
 45.1166 +                if (node != null) value++;
 45.1167 +                return super.scan(node, p);
 45.1168 +            }
 45.1169 +            @Override
 45.1170 +            public Void visitIdentifier(IdentifierTree node, Void p) {
 45.1171 +                if (node.getName().toString().startsWith("$")) value--;
 45.1172 +                
 45.1173 +                return super.visitIdentifier(node, p);
 45.1174 +            }
 45.1175 +            @Override
 45.1176 +            public Void visitNewClass(NewClassTree node, Void p) {
 45.1177 +                return null;
 45.1178 +            }
 45.1179 +        }
 45.1180 +
 45.1181 +        VisitorImpl vi = new VisitorImpl();
 45.1182 +
 45.1183 +        vi.scan(pattern, null);
 45.1184 +
 45.1185 +        return vi.value;
 45.1186 +    }
 45.1187 +
 45.1188 +    public static boolean containsMultistatementTrees(List<? extends Tree> statements) {
 45.1189 +        for (Tree t : statements) {
 45.1190 +            if (Utilities.isMultistatementWildcardTree(t)) {
 45.1191 +                return true;
 45.1192 +            }
 45.1193 +        }
 45.1194 +
 45.1195 +        return false;
 45.1196 +    }
 45.1197 +
 45.1198 +    public static boolean isJavadocSupported(CompilationInfo info) {
 45.1199 +        Context c = JavaSourceAccessor.getINSTANCE().getJavacTask(info).getContext();
 45.1200 +
 45.1201 +        try {
 45.1202 +        return c.get(Log.logKey) instanceof Messager;
 45.1203 +        } catch (NoClassDefFoundError e) {
 45.1204 +            return false;
 45.1205 +        }
 45.1206 +    }
 45.1207 +
 45.1208 +    private static class JackpotJavacParser extends NBJavacParser {
 45.1209 +
 45.1210 +        private final Context ctx;
 45.1211 +        private final com.sun.tools.javac.util.Name dollar;
 45.1212 +        public JackpotJavacParser(Context ctx, NBParserFactory fac,
 45.1213 +                         Lexer S,
 45.1214 +                         boolean keepDocComments,
 45.1215 +                         boolean keepLineMap,
 45.1216 +                         CancelService cancelService,
 45.1217 +                         Names names) {
 45.1218 +            super(fac, S, keepDocComments, keepLineMap, true, cancelService);
 45.1219 +            this.ctx = ctx;
 45.1220 +            this.dollar = names.fromString("$");
 45.1221 +        }
 45.1222 +
 45.1223 +        @Override
 45.1224 +        protected JCModifiers modifiersOpt(JCModifiers partial) {
 45.1225 +            if (token.kind == TokenKind.IDENTIFIER) {
 45.1226 +                String ident = token.name().toString();
 45.1227 +
 45.1228 +                if (Utilities.isMultistatementWildcard(ident)) {
 45.1229 +                    com.sun.tools.javac.util.Name name = token.name();
 45.1230 +
 45.1231 +                    nextToken();
 45.1232 +                    
 45.1233 +                    JCModifiers result = super.modifiersOpt(partial);
 45.1234 +                    
 45.1235 +                    result.annotations = result.annotations.prepend(new AnnotationWildcard(name, F.Ident(name)));
 45.1236 +
 45.1237 +                    return result;
 45.1238 +                }
 45.1239 +            }
 45.1240 +
 45.1241 +            return super.modifiersOpt(partial);
 45.1242 +        }
 45.1243 +
 45.1244 +        @Override
 45.1245 +        public JCVariableDecl formalParameter(boolean lambdaParam) {
 45.1246 +            if (token.kind == TokenKind.IDENTIFIER) {
 45.1247 +                if (token.name().startsWith(dollar)) {
 45.1248 +                    com.sun.tools.javac.util.Name name = token.name();
 45.1249 +
 45.1250 +                    Token peeked = S.token(1);
 45.1251 +
 45.1252 +                    if (peeked.kind == TokenKind.COMMA || peeked.kind == TokenKind.RPAREN) {
 45.1253 +                        nextToken();
 45.1254 +                        return new VariableWildcard(ctx, name, F.Ident(name));
 45.1255 +                    }
 45.1256 +                }
 45.1257 +            }
 45.1258 +
 45.1259 +            return super.formalParameter(lambdaParam);
 45.1260 +        }
 45.1261 +
 45.1262 +        @Override
 45.1263 +        protected JCVariableDecl implicitParameter() {
 45.1264 +            if (token.kind == TokenKind.IDENTIFIER) {
 45.1265 +                if (token.name().startsWith(dollar)) {
 45.1266 +                    com.sun.tools.javac.util.Name name = token.name();
 45.1267 +
 45.1268 +                    Token peeked = S.token(1);
 45.1269 +
 45.1270 +                    if (peeked.kind == TokenKind.COMMA || peeked.kind == TokenKind.RPAREN) {
 45.1271 +                        nextToken();
 45.1272 +                        return new VariableWildcard(ctx, name, F.Ident(name));
 45.1273 +                    }
 45.1274 +                }
 45.1275 +            }
 45.1276 +
 45.1277 +            return super.implicitParameter();
 45.1278 +        }
 45.1279 +        
 45.1280 +        @Override
 45.1281 +        protected JCCatch catchClause() {
 45.1282 +            if (token.kind == TokenKind.CATCH) {
 45.1283 +                Token peeked = S.token(1);
 45.1284 +                
 45.1285 +                if (   peeked.kind == TokenKind.IDENTIFIER
 45.1286 +                    && Utilities.isMultistatementWildcard(peeked.name().toString())) {
 45.1287 +                    accept(TokenKind.CATCH);
 45.1288 +                    
 45.1289 +                    com.sun.tools.javac.util.Name name = token.name();
 45.1290 +
 45.1291 +                    accept(TokenKind.IDENTIFIER);
 45.1292 +
 45.1293 +                    return new CatchWildcard(ctx, name, F.Ident(name));
 45.1294 +                } else {
 45.1295 +                    nextToken();
 45.1296 +                }
 45.1297 +            }
 45.1298 +            return super.catchClause();
 45.1299 +        }
 45.1300 +
 45.1301 +        @Override
 45.1302 +        public com.sun.tools.javac.util.List<JCTree> classOrInterfaceBodyDeclaration(com.sun.tools.javac.util.Name className, boolean isInterface) {
 45.1303 +            if (token.kind == TokenKind.IDENTIFIER) {
 45.1304 +                if (token.name().startsWith(dollar)) {
 45.1305 +                    com.sun.tools.javac.util.Name name = token.name();
 45.1306 +
 45.1307 +                    Token peeked = S.token(1);
 45.1308 +
 45.1309 +                    if (peeked.kind == TokenKind.SEMI) {
 45.1310 +                        nextToken();
 45.1311 +                        nextToken();
 45.1312 +                        
 45.1313 +                        return com.sun.tools.javac.util.List.<JCTree>of(F.Ident(name));
 45.1314 +                    }
 45.1315 +                }
 45.1316 +            }
 45.1317 +            return super.classOrInterfaceBodyDeclaration(className, isInterface);
 45.1318 +        }
 45.1319 +        
 45.1320 +        @Override
 45.1321 +        protected JCExpression checkExprStat(JCExpression t) {
 45.1322 +            if (t.getTag() == JCTree.Tag.IDENT) {
 45.1323 +                if (((IdentifierTree) t).getName().toString().startsWith("$")) {
 45.1324 +                    return t;
 45.1325 +                }
 45.1326 +            }
 45.1327 +            return super.checkExprStat(t);
 45.1328 +        }
 45.1329 +
 45.1330 +        @Override
 45.1331 +        protected JCCase switchBlockStatementGroup() {
 45.1332 +            if (token.kind == TokenKind.CASE) {
 45.1333 +                Token peeked = S.token(1);
 45.1334 +
 45.1335 +                if (peeked.kind == TokenKind.IDENTIFIER) {
 45.1336 +                    String ident = peeked.name().toString();
 45.1337 +
 45.1338 +                    if (ident.startsWith("$") && ident.endsWith("$")) {
 45.1339 +                        nextToken();
 45.1340 +                        
 45.1341 +                        int pos = token.pos;
 45.1342 +                        com.sun.tools.javac.util.Name name = token.name();
 45.1343 +
 45.1344 +                        nextToken();
 45.1345 +
 45.1346 +                        if (token.kind == TokenKind.SEMI) {
 45.1347 +                            nextToken();
 45.1348 +                        }
 45.1349 +
 45.1350 +                        return new JackpotTrees.CaseWildcard(ctx, name, F.at(pos).Ident(name));
 45.1351 +                    }
 45.1352 +                }
 45.1353 +            }
 45.1354 +
 45.1355 +            return super.switchBlockStatementGroup();
 45.1356 +        }
 45.1357 +
 45.1358 +
 45.1359 +        @Override
 45.1360 +        protected JCTree resource() {
 45.1361 +            if (token.kind == TokenKind.IDENTIFIER && token.name().startsWith(dollar)) {
 45.1362 +                Token peeked = S.token(1);
 45.1363 +
 45.1364 +                if (peeked.kind == TokenKind.SEMI || peeked.kind == TokenKind.RPAREN) {
 45.1365 +                    int pos = token.pos;
 45.1366 +                    com.sun.tools.javac.util.Name name = token.name();
 45.1367 +
 45.1368 +                    nextToken();
 45.1369 +
 45.1370 +                    return F.at(pos).Ident(name);
 45.1371 +                }
 45.1372 +            }
 45.1373 +            return super.resource();
 45.1374 +        }
 45.1375 +
 45.1376 +    }
 45.1377 +
 45.1378 +    private static final class DummyJFO extends SimpleJavaFileObject {
 45.1379 +        private DummyJFO() {
 45.1380 +            super(URI.create("dummy.java"), JavaFileObject.Kind.SOURCE);
 45.1381 +        }
 45.1382 +        @Override
 45.1383 +        public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
 45.1384 +            return "";
 45.1385 +        }
 45.1386 +    };
 45.1387 +
 45.1388 +    /**
 45.1389 +     * Only for members (i.e. generated constructor):
 45.1390 +     */
 45.1391 +    public static List<? extends Tree> filterHidden(TreePath basePath, Iterable<? extends Tree> members) {
 45.1392 +        List<Tree> result = new LinkedList<Tree>();
 45.1393 +
 45.1394 +        for (Tree t : members) {
 45.1395 +            if (!isSynthetic(basePath != null ? basePath.getCompilationUnit() : null, t)) {
 45.1396 +                result.add(t);
 45.1397 +            }
 45.1398 +        }
 45.1399 +
 45.1400 +        return result;
 45.1401 +    }
 45.1402 +
 45.1403 +    private static boolean isSynthetic(CompilationUnitTree cut, Tree leaf) throws NullPointerException {
 45.1404 +        JCTree tree = (JCTree) leaf;
 45.1405 +
 45.1406 +        if (tree.pos == (-1))
 45.1407 +            return true;
 45.1408 +
 45.1409 +        if (leaf.getKind() == Kind.METHOD) {
 45.1410 +            //check for synthetic constructor:
 45.1411 +            return (((JCMethodDecl)leaf).mods.flags & Flags.GENERATEDCONSTR) != 0L;
 45.1412 +        }
 45.1413 +
 45.1414 +        //check for synthetic superconstructor call:
 45.1415 +        if (cut != null && leaf.getKind() == Kind.EXPRESSION_STATEMENT) {
 45.1416 +            ExpressionStatementTree est = (ExpressionStatementTree) leaf;
 45.1417 +
 45.1418 +            if (est.getExpression().getKind() == Kind.METHOD_INVOCATION) {
 45.1419 +                MethodInvocationTree mit = (MethodInvocationTree) est.getExpression();
 45.1420 +
 45.1421 +                if (mit.getMethodSelect().getKind() == Kind.IDENTIFIER) {
 45.1422 +                    IdentifierTree it = (IdentifierTree) mit.getMethodSelect();
 45.1423 +
 45.1424 +                    if ("super".equals(it.getName().toString())) {
 45.1425 +                        return ((JCCompilationUnit) cut).endPositions.getEndPos(tree) == (-1);
 45.1426 +                    }
 45.1427 +                }
 45.1428 +            }
 45.1429 +        }
 45.1430 +
 45.1431 +        return false;
 45.1432 +    }
 45.1433 +
 45.1434 +    public static boolean isFakeBlock(Tree t) {
 45.1435 +        return t instanceof FakeBlock;
 45.1436 +    }
 45.1437 +
 45.1438 +    public static boolean isFakeClass(Tree t) {
 45.1439 +        if (!(t instanceof ClassTree)) {
 45.1440 +            return false;
 45.1441 +        }
 45.1442 +
 45.1443 +        ClassTree ct = (ClassTree) t;
 45.1444 +
 45.1445 +        if (ct.getMembers().isEmpty()) {
 45.1446 +            return false;
 45.1447 +        }
 45.1448 +
 45.1449 +        CharSequence wildcardTreeName = Utilities.getWildcardTreeName(ct.getMembers().get(0));
 45.1450 +
 45.1451 +        if (wildcardTreeName == null) {
 45.1452 +            return false;
 45.1453 +        }
 45.1454 +
 45.1455 +        return wildcardTreeName.toString().startsWith("$$");
 45.1456 +    }
 45.1457 +
 45.1458 +    private static final class OffsetSourcePositions implements SourcePositions {
 45.1459 +
 45.1460 +        private final SourcePositions delegate;
 45.1461 +        private final long offset;
 45.1462 +
 45.1463 +        public OffsetSourcePositions(SourcePositions delegate, long offset) {
 45.1464 +            this.delegate = delegate;
 45.1465 +            this.offset = offset;
 45.1466 +        }
 45.1467 +
 45.1468 +        public long getStartPosition(CompilationUnitTree cut, Tree tree) {
 45.1469 +            return delegate.getStartPosition(cut, tree) + offset;
 45.1470 +        }
 45.1471 +
 45.1472 +        public long getEndPosition(CompilationUnitTree cut, Tree tree) {
 45.1473 +            return delegate.getEndPosition(cut, tree) + offset;
 45.1474 +        }
 45.1475 +
 45.1476 +    }
 45.1477 +
 45.1478 +    private static final class OffsetDiagnostic<S> implements Diagnostic<S> {
 45.1479 +        private final Diagnostic<? extends S> delegate;
 45.1480 +        private final long offset;
 45.1481 +
 45.1482 +        public OffsetDiagnostic(Diagnostic<? extends S> delegate, long offset) {
 45.1483 +            this.delegate = delegate;
 45.1484 +            this.offset = offset;
 45.1485 +        }
 45.1486 +
 45.1487 +        public Diagnostic.Kind getKind() {
 45.1488 +            return delegate.getKind();
 45.1489 +        }
 45.1490 +
 45.1491 +        public S getSource() {
 45.1492 +            return delegate.getSource();
 45.1493 +        }
 45.1494 +
 45.1495 +        public long getPosition() {
 45.1496 +            return delegate.getPosition() + offset;
 45.1497 +        }
 45.1498 +
 45.1499 +        public long getStartPosition() {
 45.1500 +            return delegate.getStartPosition() + offset;
 45.1501 +        }
 45.1502 +
 45.1503 +        public long getEndPosition() {
 45.1504 +            return delegate.getEndPosition() + offset;
 45.1505 +        }
 45.1506 +
 45.1507 +        public long getLineNumber() {
 45.1508 +            throw new UnsupportedOperationException("Not supported yet.");
 45.1509 +        }
 45.1510 +
 45.1511 +        public long getColumnNumber() {
 45.1512 +            throw new UnsupportedOperationException("Not supported yet.");
 45.1513 +        }
 45.1514 +
 45.1515 +        public String getCode() {
 45.1516 +            return delegate.getCode();
 45.1517 +        }
 45.1518 +
 45.1519 +        public String getMessage(Locale locale) {
 45.1520 +            return delegate.getMessage(locale);
 45.1521 +        }
 45.1522 +
 45.1523 +    }
 45.1524 +
 45.1525 +    private static class ParserSourcePositions implements SourcePositions {
 45.1526 +
 45.1527 +        private JavacParser parser;
 45.1528 +
 45.1529 +        private ParserSourcePositions(JavacParser parser) {
 45.1530 +            this.parser = parser;
 45.1531 +        }
 45.1532 +
 45.1533 +        public long getStartPosition(CompilationUnitTree file, Tree tree) {
 45.1534 +            return parser.getStartPos((JCTree)tree);
 45.1535 +        }
 45.1536 +
 45.1537 +        public long getEndPosition(CompilationUnitTree file, Tree tree) {
 45.1538 +            return parser.getEndPos((JCTree)tree);
 45.1539 +        }
 45.1540 +    }
 45.1541 +}
    46.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    46.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/batch/BatchSearch.java	Wed May 08 21:47:42 2013 +0200
    46.3 @@ -0,0 +1,643 @@
    46.4 +/*
    46.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    46.6 + *
    46.7 + * Copyright 2009-2011 Oracle and/or its affiliates. All rights reserved.
    46.8 + *
    46.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   46.10 + * Other names may be trademarks of their respective owners.
   46.11 + *
   46.12 + * The contents of this file are subject to the terms of either the GNU
   46.13 + * General Public License Version 2 only ("GPL") or the Common
   46.14 + * Development and Distribution License("CDDL") (collectively, the
   46.15 + * "License"). You may not use this file except in compliance with the
   46.16 + * License. You can obtain a copy of the License at
   46.17 + * http://www.netbeans.org/cddl-gplv2.html
   46.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   46.19 + * specific language governing permissions and limitations under the
   46.20 + * License.  When distributing the software, include this License Header
   46.21 + * Notice in each file and include the License file at
   46.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   46.23 + * particular file as subject to the "Classpath" exception as provided
   46.24 + * by Oracle in the GPL Version 2 section of the License file that
   46.25 + * accompanied this code. If applicable, add the following below the
   46.26 + * License Header, with the fields enclosed by brackets [] replaced by
   46.27 + * your own identifying information:
   46.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   46.29 + *
   46.30 + * If you wish your version of this file to be governed by only the CDDL
   46.31 + * or only the GPL Version 2, indicate your decision by adding
   46.32 + * "[Contributor] elects to include this software in this distribution
   46.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   46.34 + * single choice of license, a recipient has the option to distribute
   46.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   46.36 + * to extend the choice of license to its licensees as provided above.
   46.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   46.38 + * Version 2 license, then the option applies only if the new code is
   46.39 + * made subject to such option by the copyright holder.
   46.40 + *
   46.41 + * Contributor(s):
   46.42 + *
   46.43 + * Portions Copyrighted 2009-2011 Sun Microsystems, Inc.
   46.44 + */
   46.45 +package org.netbeans.modules.java.hints.spiimpl.batch;
   46.46 +
   46.47 +import org.netbeans.spi.java.hints.HintContext.MessageKind;
   46.48 +import org.netbeans.modules.java.hints.providers.spi.HintDescription;
   46.49 +import com.sun.source.tree.Tree;
   46.50 +import com.sun.source.util.TreePath;
   46.51 +import java.io.IOException;
   46.52 +import java.io.OutputStreamWriter;
   46.53 +import java.io.Writer;
   46.54 +import java.nio.ByteBuffer;
   46.55 +import java.util.ArrayList;
   46.56 +import java.util.Collection;
   46.57 +import java.util.HashMap;
   46.58 +import java.util.HashSet;
   46.59 +import java.util.LinkedList;
   46.60 +import java.util.List;
   46.61 +import java.util.Map;
   46.62 +import java.util.Map.Entry;
   46.63 +import java.util.Set;
   46.64 +import java.util.concurrent.Callable;
   46.65 +import java.util.concurrent.atomic.AtomicBoolean;
   46.66 +import java.util.concurrent.atomic.AtomicInteger;
   46.67 +import java.util.concurrent.atomic.AtomicReference;
   46.68 +import java.util.logging.Level;
   46.69 +import java.util.logging.Logger;
   46.70 +import org.netbeans.api.annotations.common.NonNull;
   46.71 +import org.netbeans.api.annotations.common.NullAllowed;
   46.72 +import org.netbeans.api.fileinfo.NonRecursiveFolder;
   46.73 +import org.netbeans.api.java.classpath.ClassPath;
   46.74 +import org.netbeans.api.java.classpath.GlobalPathRegistry;
   46.75 +import org.netbeans.api.java.source.ClasspathInfo;
   46.76 +import org.netbeans.api.java.source.ClasspathInfo.PathKind;
   46.77 +import org.netbeans.api.java.source.CompilationController;
   46.78 +import org.netbeans.api.java.source.CompilationInfo;
   46.79 +import org.netbeans.api.java.source.JavaSource;
   46.80 +import org.netbeans.api.java.source.JavaSource.Phase;
   46.81 +import org.netbeans.api.java.source.Task;
   46.82 +import org.netbeans.api.queries.FileEncodingQuery;
   46.83 +import org.netbeans.modules.java.hints.spiimpl.MessageImpl;
   46.84 +import org.netbeans.modules.java.hints.spiimpl.Utilities;
   46.85 +import org.netbeans.modules.java.hints.spiimpl.hints.HintsInvoker;
   46.86 +import org.netbeans.modules.java.hints.spiimpl.pm.BulkSearch;
   46.87 +import org.netbeans.modules.java.hints.spiimpl.pm.BulkSearch.BulkPattern;
   46.88 +import org.netbeans.modules.java.hints.providers.spi.HintDescription.AdditionalQueryConstraints;
   46.89 +import org.netbeans.modules.java.hints.providers.spi.Trigger.PatternDescription;
   46.90 +import org.netbeans.spi.editor.hints.ErrorDescription;
   46.91 +import org.netbeans.api.java.source.matching.Matcher;
   46.92 +import org.netbeans.api.java.source.matching.Pattern;
   46.93 +import org.netbeans.modules.java.hints.spiimpl.options.HintsSettings;
   46.94 +import org.openide.filesystems.FileObject;
   46.95 +import org.openide.filesystems.FileUtil;
   46.96 +import org.openide.util.Exceptions;
   46.97 +
   46.98 +/**
   46.99 + *
  46.100 + * @author lahvac
  46.101 + */
  46.102 +public class BatchSearch {
  46.103 +
  46.104 +    private static final Logger LOG = Logger.getLogger(BatchSearch.class.getName());
  46.105 +
  46.106 +    public static BatchResult findOccurrences(Iterable<? extends HintDescription> patterns, Scope scope) {
  46.107 +        return findOccurrences(patterns, scope, new ProgressHandleWrapper(null), HintsSettings.getGlobalSettings());
  46.108 +    }
  46.109 +
  46.110 +    public static BatchResult findOccurrences(final Iterable<? extends HintDescription> patterns, final Scope scope, final ProgressHandleWrapper progress, @NullAllowed HintsSettings settingsProvider) {
  46.111 +        return findOccurrencesLocal(patterns, scope.getIndexMapper(patterns), scope.getTodo(), progress, settingsProvider);
  46.112 +    }
  46.113 +
  46.114 +    private static BatchResult findOccurrencesLocal(final Iterable<? extends HintDescription> patterns, final MapIndices indexMapper, final Collection<? extends Folder> todo, final ProgressHandleWrapper progress, final @NullAllowed HintsSettings settingsProvider) {
  46.115 +        final BatchResult[] result = new BatchResult[1];
  46.116 +
  46.117 +        try {
  46.118 +            JavaSource.create(Utilities.createUniversalCPInfo()).runUserActionTask(new Task<CompilationController>() {
  46.119 +                public void run(CompilationController parameter) throws Exception {
  46.120 +                    result[0] = findOccurrencesLocalImpl(parameter, patterns, indexMapper, todo, progress, settingsProvider);
  46.121 +                }
  46.122 +            }, true);
  46.123 +        } catch (IOException ex) {
  46.124 +            throw new IllegalStateException(ex);
  46.125 +        }
  46.126 +
  46.127 +        return result[0];
  46.128 +    }
  46.129 +    
  46.130 +    private static BatchResult findOccurrencesLocalImpl(final CompilationInfo info, final Iterable<? extends HintDescription> patterns, MapIndices indexMapper, Collection<? extends Folder> todo, ProgressHandleWrapper progress, HintsSettings settingsProvider) {
  46.131 +        boolean hasKindPatterns = false;
  46.132 +
  46.133 +        for (HintDescription pattern : patterns) {
  46.134 +            if (!(pattern.getTrigger() instanceof PatternDescription)) {
  46.135 +                hasKindPatterns = true;
  46.136 +                break;
  46.137 +            }
  46.138 +        }
  46.139 +
  46.140 +        final Callable<BulkPattern> bulkPattern = hasKindPatterns ? null : new Callable<BulkPattern>() {
  46.141 +            private final AtomicReference<BulkPattern> pattern = new AtomicReference<BulkPattern>();
  46.142 +            public BulkPattern call() {
  46.143 +                if (pattern.get() == null) {
  46.144 +                    pattern.set(preparePattern(patterns, info));
  46.145 +                }
  46.146 +
  46.147 +                return pattern.get();
  46.148 +            }
  46.149 +        };
  46.150 +        final Map<IndexEnquirer, Collection<? extends Resource>> result = new HashMap<IndexEnquirer, Collection<? extends Resource>>();
  46.151 +        final Collection<MessageImpl> problems = new LinkedList<MessageImpl>();
  46.152 +        ProgressHandleWrapper innerForAll = progress.startNextPartWithEmbedding(ProgressHandleWrapper.prepareParts(2 * todo.size()));
  46.153 +        
  46.154 +        for (final Folder src : todo) {
  46.155 +            LOG.log(Level.FINE, "Processing: {0}", FileUtil.getFileDisplayName(src.getFileObject()));
  46.156 +            
  46.157 +            IndexEnquirer indexEnquirer;// = indexMapper.findIndex(src.getFileObject(), innerForAll, src.isRecursive());
  46.158 +
  46.159 +//            if (indexEnquirer == null) {
  46.160 +                indexEnquirer = new FileSystemBasedIndexEnquirer(src.getFileObject(), src.isRecursive());
  46.161 +//            }
  46.162 +
  46.163 +            Collection<? extends Resource> occurrences = indexEnquirer.findResources(patterns, innerForAll, bulkPattern, problems, settingsProvider);
  46.164 +
  46.165 +            if (!occurrences.isEmpty()) {
  46.166 +                result.put(indexEnquirer, occurrences);
  46.167 +            }
  46.168 +
  46.169 +            innerForAll.tick();
  46.170 +        }
  46.171 +
  46.172 +        return new BatchResult(result, problems);
  46.173 +    }
  46.174 +
  46.175 +    private static BulkPattern preparePattern(final Iterable<? extends HintDescription> patterns, CompilationInfo info) {
  46.176 +        Collection<String> code = new LinkedList<String>();
  46.177 +        Collection<Tree> trees = new LinkedList<Tree>();
  46.178 +        Collection<AdditionalQueryConstraints> additionalConstraints = new LinkedList<AdditionalQueryConstraints>();
  46.179 +
  46.180 +        for (HintDescription pattern : patterns) {
  46.181 +            String textPattern = ((PatternDescription) pattern.getTrigger()).getPattern();
  46.182 +
  46.183 +            code.add(textPattern);
  46.184 +            trees.add(Utilities.parseAndAttribute(info, textPattern, null));
  46.185 +            additionalConstraints.add(pattern.getAdditionalConstraints());
  46.186 +        }
  46.187 +
  46.188 +        return BulkSearch.getDefault().create(code, trees, additionalConstraints, new AtomicBoolean());
  46.189 +    }
  46.190 +
  46.191 +    public static void getVerifiedSpans(BatchResult candidates, @NonNull ProgressHandleWrapper progress, final VerifiedSpansCallBack callback, final Collection<? super MessageImpl> problems, AtomicBoolean cancel) {
  46.192 +        getVerifiedSpans(candidates, progress, callback, false, problems, cancel);
  46.193 +    }
  46.194 +
  46.195 +    public static void getVerifiedSpans(BatchResult candidates, @NonNull ProgressHandleWrapper progress, final VerifiedSpansCallBack callback, boolean doNotRegisterClassPath, final Collection<? super MessageImpl> problems, AtomicBoolean cancel) {
  46.196 +        int[] parts = new int[candidates.projectId2Resources.size()];
  46.197 +        int   index = 0;
  46.198 +
  46.199 +        for (Entry<? extends IndexEnquirer, ? extends Collection<? extends Resource>> e : candidates.projectId2Resources.entrySet()) {
  46.200 +            parts[index++] = e.getValue().size();
  46.201 +        }
  46.202 +
  46.203 +        ProgressHandleWrapper inner = progress.startNextPartWithEmbedding(parts);
  46.204 +
  46.205 +        for (Entry<? extends IndexEnquirer, ? extends Collection<? extends Resource>> e : candidates.projectId2Resources.entrySet()) {
  46.206 +            if (cancel.get()) 
  46.207 +                return;
  46.208 +            inner.startNextPart(e.getValue().size());
  46.209 +
  46.210 +            e.getKey().validateResource(e.getValue(), inner, callback, doNotRegisterClassPath, problems, cancel);
  46.211 +        }
  46.212 +    }
  46.213 +
  46.214 +    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) {
  46.215 +        Collection<FileObject> files = new LinkedList<FileObject>();
  46.216 +        final Map<FileObject, Resource> file2Resource = new HashMap<FileObject, Resource>();
  46.217 +
  46.218 +        for (Resource r : resources) {
  46.219 +            FileObject file = r.getResolvedFile();
  46.220 +
  46.221 +            if (file != null) {
  46.222 +                files.add(file);
  46.223 +                file2Resource.put(file, r);
  46.224 +            } else {
  46.225 +                callback.cannotVerifySpan(r);
  46.226 +                progress.tick();
  46.227 +            }
  46.228 +        }
  46.229 +
  46.230 +        Map<ClasspathInfo, Collection<FileObject>> cp2Files = BatchUtilities.sortFiles(files);
  46.231 +        ClassPath[] toRegister = null;
  46.232 +
  46.233 +        if (!doNotRegisterClassPath) {
  46.234 +            Set<ClassPath> toRegisterSet = new HashSet<ClassPath>();
  46.235 +
  46.236 +            for (ClasspathInfo cpInfo : cp2Files.keySet()) {
  46.237 +                toRegisterSet.add(cpInfo.getClassPath(PathKind.SOURCE));
  46.238 +            }
  46.239 +
  46.240 +            toRegister = !toRegisterSet.isEmpty() ? toRegisterSet.toArray(new ClassPath[0]) : null;
  46.241 +
  46.242 +            if (toRegister != null) {
  46.243 +                GlobalPathRegistry.getDefault().register(ClassPath.SOURCE, toRegister);
  46.244 +                try {
  46.245 +                    Utilities.waitScanFinished();
  46.246 +                } catch (InterruptedException ex) {
  46.247 +                    Exceptions.printStackTrace(ex);
  46.248 +                }
  46.249 +            }
  46.250 +        }
  46.251 +
  46.252 +        try {
  46.253 +            for (Entry<ClasspathInfo, Collection<FileObject>> e : cp2Files.entrySet()) {
  46.254 +                try {
  46.255 +                    List<FileObject> toProcess = new ArrayList<FileObject>(e.getValue());
  46.256 +                    final AtomicInteger currentPointer = new AtomicInteger();
  46.257 +                    callback.groupStarted();
  46.258 +
  46.259 +//                    for (FileObject f : toProcess) {
  46.260 +                    while (currentPointer.get() < toProcess.size()) {
  46.261 +                        if (cancel.get())
  46.262 +                            return;
  46.263 +                        final AtomicBoolean stop = new AtomicBoolean();
  46.264 +//                        JavaSource js = JavaSource.create(e.getKey(), f);
  46.265 +                        JavaSource js = JavaSource.create(e.getKey(), toProcess.subList(currentPointer.get(), toProcess.size()));
  46.266 +
  46.267 +                        js.runUserActionTask(new Task<CompilationController>() {
  46.268 +                            public void run(CompilationController parameter) throws Exception {
  46.269 +                                if (stop.get()) return;
  46.270 +                                if (cancel.get()) return;
  46.271 +
  46.272 +                                boolean cont = true;
  46.273 +
  46.274 +                                try {
  46.275 +                                    if (parameter.toPhase(Phase.RESOLVED).compareTo(Phase.RESOLVED) < 0)
  46.276 +                                        return ;
  46.277 +
  46.278 +                                    progress.setMessage("processing: " + FileUtil.getFileDisplayName(parameter.getFileObject()));
  46.279 +                                    Resource r = file2Resource.get(parameter.getFileObject());
  46.280 +
  46.281 +                                    HintsSettings settings = r.settings;
  46.282 +                                    Iterable<? extends HintDescription> enabledHints;
  46.283 +                                    
  46.284 +                                    if (settings == null) {
  46.285 +                                        settings = HintsSettings.getSettingsFor(parameter.getFileObject());
  46.286 +                                        List<HintDescription> hintsCopy = new ArrayList<>();
  46.287 +                                        for (HintDescription hd : r.hints) {
  46.288 +                                            if (settings.isEnabled(hd.getMetadata())) {
  46.289 +                                                hintsCopy.add(hd);
  46.290 +                                            }
  46.291 +                                        }
  46.292 +                                        enabledHints = hintsCopy;
  46.293 +                                    } else {
  46.294 +                                        enabledHints = r.hints;
  46.295 +                                    }
  46.296 +                                    
  46.297 +                                    List<ErrorDescription> hints = new HintsInvoker(settings, true, new AtomicBoolean()).computeHints(parameter, enabledHints, problems);
  46.298 +
  46.299 +                                    assert hints != null;
  46.300 +                                    
  46.301 +                                    cont = callback.spansVerified(parameter, r, hints);
  46.302 +                                } catch (ThreadDeath td) {
  46.303 +                                    throw td;
  46.304 +                                } catch (Throwable t) {
  46.305 +                                    LOG.log(Level.INFO, "Exception while performing batch processing in " + FileUtil.getFileDisplayName(parameter.getFileObject()), t);
  46.306 +                                    problems.add(new MessageImpl(MessageKind.WARNING, "An exception occurred while processing file: " + FileUtil.getFileDisplayName(parameter.getFileObject()) + " (" + t.getLocalizedMessage() + ")."));
  46.307 +                                }
  46.308 +                                
  46.309 +                                if (cont) {
  46.310 +                                    progress.tick();
  46.311 +                                    currentPointer.incrementAndGet();
  46.312 +                                } else {
  46.313 +                                    stop.set(true);
  46.314 +                                }
  46.315 +                            }
  46.316 +                        }, true);
  46.317 +                    }
  46.318 +
  46.319 +                    callback.groupFinished();
  46.320 +                } catch (IOException ex) {
  46.321 +                    Exceptions.printStackTrace(ex);
  46.322 +                }
  46.323 +            }
  46.324 +        } finally {
  46.325 +            if (toRegister != null) {
  46.326 +                GlobalPathRegistry.getDefault().unregister(ClassPath.SOURCE, toRegister);
  46.327 +            }
  46.328 +            progress.finish();
  46.329 +        }
  46.330 +    }
  46.331 +
  46.332 +    public interface VerifiedSpansCallBack {
  46.333 +        public void groupStarted();
  46.334 +        public boolean spansVerified(CompilationController wc, Resource r, Collection<? extends ErrorDescription> hints) throws Exception;
  46.335 +        public void groupFinished();
  46.336 +        public void cannotVerifySpan(Resource r);
  46.337 +    }
  46.338 +
  46.339 +    
  46.340 +    public static class Folder {
  46.341 +
  46.342 +        private FileObject file;
  46.343 +        private NonRecursiveFolder folder;
  46.344 +        
  46.345 +        public Folder(FileObject file) {
  46.346 +            this.file = file;
  46.347 +        }
  46.348 +        
  46.349 +        public Folder(NonRecursiveFolder folder) {
  46.350 +            this.folder = folder;
  46.351 +        }
  46.352 +        
  46.353 +        public FileObject getFileObject() {
  46.354 +            if (file!=null) {
  46.355 +                return file;
  46.356 +            }
  46.357 +            return folder.getFolder();
  46.358 +            
  46.359 +        }
  46.360 +        
  46.361 +        private boolean isRecursive() {
  46.362 +            if (file!=null) {
  46.363 +                return file.isFolder();
  46.364 +            }
  46.365 +            return false;
  46.366 +        }
  46.367 +
  46.368 +        public static Folder[] convert(FileObject... files) {
  46.369 +            Folder[] result = new Folder[files.length];
  46.370 +            for (int i=0;i<files.length;i++) {
  46.371 +                result[i] = new Folder(files[i]);
  46.372 +            }
  46.373 +            return result;
  46.374 +        }
  46.375 +
  46.376 +        public static Folder[] convert(Collection list) {
  46.377 +            Folder[] result = new Folder[list.size()];
  46.378 +            int i=0;
  46.379 +            for (Object item:list) {
  46.380 +                if (item instanceof FileObject)
  46.381 +                    result[i] = new Folder((FileObject) item);
  46.382 +                else 
  46.383 +                    result[i] = new Folder((NonRecursiveFolder) item);
  46.384 +                i++;
  46.385 +            }
  46.386 +            return result;
  46.387 +        }
  46.388 +
  46.389 +        @Override
  46.390 +        public String toString() {
  46.391 +            return !isRecursive()?"Non":"" + "Recursive file " + getFileObject().getPath();
  46.392 +        }
  46.393 +        
  46.394 +        
  46.395 +    }
  46.396 +    
  46.397 +    public abstract static class Scope {
  46.398 +
  46.399 +        public abstract String getDisplayName();
  46.400 +        public abstract Collection<? extends Folder> getTodo();
  46.401 +        public abstract MapIndices getIndexMapper(Iterable<? extends HintDescription> hints);
  46.402 +        
  46.403 +    }
  46.404 +    
  46.405 +    public static final class BatchResult {
  46.406 +        
  46.407 +        private final Map<? extends IndexEnquirer, ? extends Collection<? extends Resource>> projectId2Resources;
  46.408 +        public final Collection<? extends MessageImpl> problems;
  46.409 +        
  46.410 +        public BatchResult(Map<? extends IndexEnquirer, ? extends Collection<? extends Resource>> projectId2Resources, Collection<? extends MessageImpl> problems) {
  46.411 +            this.projectId2Resources = projectId2Resources;
  46.412 +            this.problems = problems;
  46.413 +        }
  46.414 +
  46.415 +        public Collection<? extends Collection<? extends Resource>> getResources() {
  46.416 +            return projectId2Resources.values();
  46.417 +        }
  46.418 +
  46.419 +        public Map<FileObject, Collection<? extends Resource>> getResourcesWithRoots() {
  46.420 +            Map<FileObject, Collection<? extends Resource>> result = new HashMap<FileObject, Collection<? extends Resource>>();
  46.421 +
  46.422 +            for (Entry<? extends IndexEnquirer, ? extends Collection<? extends Resource>> e : projectId2Resources.entrySet()) {
  46.423 +                result.put(e.getKey().src, e.getValue());
  46.424 +            }
  46.425 +
  46.426 +            return result;
  46.427 +        }
  46.428 +    }
  46.429 +
  46.430 +    public static final class Resource {
  46.431 +        private final IndexEnquirer indexEnquirer;
  46.432 +        private final String relativePath;
  46.433 +        final Iterable<? extends HintDescription> hints;
  46.434 +        private final BulkPattern pattern;
  46.435 +        final HintsSettings settings;
  46.436 +
  46.437 +        public Resource(IndexEnquirer indexEnquirer, String relativePath, Iterable<? extends HintDescription> hints, BulkPattern pattern, HintsSettings settings) {
  46.438 +            this.indexEnquirer = indexEnquirer;
  46.439 +            this.relativePath = relativePath;
  46.440 +            this.hints = hints;
  46.441 +            this.pattern = pattern;
  46.442 +            this.settings = settings;
  46.443 +        }
  46.444 +
  46.445 +        public String getRelativePath() {
  46.446 +            return relativePath;
  46.447 +        }
  46.448 +        
  46.449 +        public Iterable<int[]> getCandidateSpans() {
  46.450 +            FileObject file = getResolvedFile();
  46.451 +            JavaSource js;
  46.452 +
  46.453 +            if (file != null) {
  46.454 +                js = JavaSource.forFileObject(file);
  46.455 +            } else {
  46.456 +                CharSequence text = getSourceCode();
  46.457 +
  46.458 +                if (text == null) {
  46.459 +                    return null;
  46.460 +                }
  46.461 +
  46.462 +                Writer out = null;
  46.463 +
  46.464 +                try {
  46.465 +                    file = FileUtil.createData(FileUtil.createMemoryFileSystem().getRoot(), relativePath);
  46.466 +                    out = new OutputStreamWriter(file.getOutputStream());
  46.467 +
  46.468 +                    out.write(text.toString());
  46.469 +                } catch (IOException ex) {
  46.470 +                    Exceptions.printStackTrace(ex);
  46.471 +                    return null;
  46.472 +                } finally {
  46.473 +                    if (out != null) {
  46.474 +                        try {
  46.475 +                            out.close();
  46.476 +                        } catch (IOException ex) {
  46.477 +                            Exceptions.printStackTrace(ex);
  46.478 +                        }
  46.479 +                    }
  46.480 +                }
  46.481 +
  46.482 +                js = JavaSource.create(Utilities.createUniversalCPInfo(), file);
  46.483 +            }
  46.484 +
  46.485 +            final List<int[]> span = new LinkedList<int[]>();
  46.486 +
  46.487 +            try {
  46.488 +                js.runUserActionTask(new Task<CompilationController>() {
  46.489 +                    public void run(CompilationController cc) throws Exception {
  46.490 +                        cc.toPhase(Phase.PARSED);
  46.491 +
  46.492 +                        span.addAll(doComputeSpans(cc));
  46.493 +                    }
  46.494 +                }, true);
  46.495 +            } catch (IOException ex) {
  46.496 +                Exceptions.printStackTrace(ex);
  46.497 +            }
  46.498 +
  46.499 +            return span;
  46.500 +        }
  46.501 +
  46.502 +        private Collection<int[]> doComputeSpans(CompilationInfo ci) {
  46.503 +            Collection<int[]> result = new LinkedList<int[]>();
  46.504 +            Map<String, Collection<TreePath>> found = BulkSearch.getDefault().match(ci, new AtomicBoolean(), new TreePath(ci.getCompilationUnit()), pattern);
  46.505 +            
  46.506 +            for (Entry<String, Collection<TreePath>> e : found.entrySet()) {
  46.507 +                Tree treePattern = Utilities.parseAndAttribute(ci, e.getKey(), null);
  46.508 +                
  46.509 +                for (TreePath tp : e.getValue()) {
  46.510 +                    //XXX: this pass will not be performed on the web!!!
  46.511 +                    if (   BulkSearch.getDefault().requiresLightweightVerification()
  46.512 +                        && !Matcher.create(ci).setCancel(new AtomicBoolean()).setSearchRoot(tp).setTreeTopSearch().setUntypedMatching().match(Pattern.createSimplePattern(new TreePath(new TreePath(ci.getCompilationUnit()), treePattern))).iterator().hasNext()) {
  46.513 +                        continue;
  46.514 +                    }
  46.515 +                    int[] span = new int[] {
  46.516 +                        (int) ci.getTrees().getSourcePositions().getStartPosition(ci.getCompilationUnit(), tp.getLeaf()),
  46.517 +                        (int) ci.getTrees().getSourcePositions().getEndPosition(ci.getCompilationUnit(), tp.getLeaf())
  46.518 +                    };
  46.519 +
  46.520 +                    result.add(span);
  46.521 +                }
  46.522 +            }
  46.523 +
  46.524 +            return result;
  46.525 +        }
  46.526 +        
  46.527 +        public FileObject getResolvedFile() {
  46.528 +            return indexEnquirer.src.getFileObject(relativePath);
  46.529 +        }
  46.530 +
  46.531 +        public String getDisplayName() {
  46.532 +            FileObject file = getResolvedFile();
  46.533 +
  46.534 +            if (file != null) {
  46.535 +                return FileUtil.getFileDisplayName(file);
  46.536 +            } else {
  46.537 +                return relativePath; //TODO:+container
  46.538 +            }
  46.539 +        }
  46.540 +        
  46.541 +        public CharSequence getSourceCode() {
  46.542 +            try {
  46.543 +                FileObject file = getResolvedFile();
  46.544 +                ByteBuffer bb = ByteBuffer.wrap(file.asBytes());
  46.545 +
  46.546 +                return FileEncodingQuery.getEncoding(file).decode(bb);
  46.547 +            } catch (IOException ex) {
  46.548 +                Exceptions.printStackTrace(ex);
  46.549 +                return null;
  46.550 +            }
  46.551 +        }
  46.552 +
  46.553 +        public FileObject getRoot() {
  46.554 +            return indexEnquirer.src;
  46.555 +        }
  46.556 +    }
  46.557 +
  46.558 +    public static interface MapIndices {
  46.559 +        public IndexEnquirer findIndex(FileObject root, ProgressHandleWrapper progress, boolean recursive);
  46.560 +    }
  46.561 +
  46.562 +    public static abstract class IndexEnquirer {
  46.563 +        final FileObject src;
  46.564 +        public IndexEnquirer(FileObject src) {
  46.565 +            this.src = src;
  46.566 +        }
  46.567 +        public abstract Collection<? extends Resource> findResources(Iterable<? extends HintDescription> hints, ProgressHandleWrapper progress, @NullAllowed Callable<BulkPattern> bulkPattern, Collection<? super MessageImpl> problems, HintsSettings settingsProvider);
  46.568 +        public abstract void validateResource(Collection<? extends Resource> resources, ProgressHandleWrapper progress, VerifiedSpansCallBack callback, boolean doNotRegisterClassPath, Collection<? super MessageImpl> problems, AtomicBoolean cancel);
  46.569 +//        public int[] getEstimatedSpan(Resource r);
  46.570 +    }
  46.571 +
  46.572 +    public static abstract class LocalIndexEnquirer extends IndexEnquirer {
  46.573 +        public LocalIndexEnquirer(FileObject src) {
  46.574 +            super(src);
  46.575 +        }
  46.576 +        public void validateResource(Collection<? extends Resource> resources, ProgressHandleWrapper progress, VerifiedSpansCallBack callback, boolean doNotRegisterClassPath, Collection<? super MessageImpl> problems, AtomicBoolean cancel) {
  46.577 +            getLocalVerifiedSpans(resources, progress, callback, doNotRegisterClassPath, problems, cancel);
  46.578 +        }
  46.579 +    }
  46.580 +
  46.581 +    public static final class FileSystemBasedIndexEnquirer extends LocalIndexEnquirer {
  46.582 +        private boolean recursive;
  46.583 +        public FileSystemBasedIndexEnquirer(FileObject src, boolean recursive) {
  46.584 +            super(src);
  46.585 +            this.recursive = recursive;
  46.586 +        }
  46.587 +        public Collection<? extends Resource> findResources(final Iterable<? extends HintDescription> hints, ProgressHandleWrapper progress, final @NullAllowed Callable<BulkPattern> bulkPattern, final Collection<? super MessageImpl> problems, final HintsSettings settingsProvider) {
  46.588 +            Collection<FileObject> files = new LinkedList<FileObject>();
  46.589 +
  46.590 +            final ProgressHandleWrapper innerProgress = progress.startNextPartWithEmbedding(30, 70);
  46.591 +
  46.592 +            BatchUtilities.recursive(src, src, files, innerProgress, 0, null, null, recursive);
  46.593 +
  46.594 +            LOG.log(Level.FINE, "files: {0}", files);
  46.595 +
  46.596 +            innerProgress.startNextPart(files.size());
  46.597 +
  46.598 +            final Collection<Resource> result = new ArrayList<Resource>();
  46.599 +
  46.600 +            if (!files.isEmpty()) {
  46.601 +                try {
  46.602 +                    if (bulkPattern != null) {
  46.603 +                        long start = System.currentTimeMillis();
  46.604 +
  46.605 +                        JavaSource.create(Utilities.createUniversalCPInfo(), files).runUserActionTask(new Task<CompilationController>() {
  46.606 +                            public void run(CompilationController cc) throws Exception {
  46.607 +                                if (cc.toPhase(Phase.PARSED).compareTo(Phase.PARSED) <0) {
  46.608 +                                    return ;
  46.609 +                                }
  46.610 +
  46.611 +                                try {
  46.612 +                                    boolean matches = BulkSearch.getDefault().matches(cc, new AtomicBoolean(), new TreePath(cc.getCompilationUnit()), bulkPattern.call());
  46.613 +
  46.614 +                                    if (matches) {
  46.615 +                                        result.add(new Resource(FileSystemBasedIndexEnquirer.this, FileUtil.getRelativePath(src, cc.getFileObject()), hints, bulkPattern.call(), settingsProvider));
  46.616 +                                    }
  46.617 +                                } catch (ThreadDeath td) {
  46.618 +                                    throw td;
  46.619 +                                } catch (Throwable t) {
  46.620 +                                    LOG.log(Level.INFO, "Exception while performing batch search in " + FileUtil.getFileDisplayName(cc.getFileObject()), t);
  46.621 +                                    problems.add(new MessageImpl(MessageKind.WARNING, "An exception occurred while testing file: " + FileUtil.getFileDisplayName(cc.getFileObject()) + " (" + t.getLocalizedMessage() + ")."));
  46.622 +                                }
  46.623 +
  46.624 +                                innerProgress.tick();
  46.625 +                            }
  46.626 +                        }, true);
  46.627 +
  46.628 +                        long end = System.currentTimeMillis();
  46.629 +
  46.630 +                        LOG.log(Level.FINE, "took: {0}, per file: {1}", new Object[]{end - start, (end - start) / files.size()});
  46.631 +                    } else {
  46.632 +                        for (FileObject file : files) {
  46.633 +                            result.add(new Resource(this, FileUtil.getRelativePath(src, file), hints, null, settingsProvider));
  46.634 +                        }
  46.635 +                    }
  46.636 +                } catch (IOException ex) {
  46.637 +                    Exceptions.printStackTrace(ex);
  46.638 +                }
  46.639 +            }
  46.640 +
  46.641 +            return result;
  46.642 +        }
  46.643 +
  46.644 +    }
  46.645 +
  46.646 +}
    47.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    47.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/batch/BatchUtilities.java	Wed May 08 21:47:42 2013 +0200
    47.3 @@ -0,0 +1,548 @@
    47.4 +/*
    47.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    47.6 + *
    47.7 + * Copyright 2009-2011 Oracle and/or its affiliates. All rights reserved.
    47.8 + *
    47.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   47.10 + * Other names may be trademarks of their respective owners.
   47.11 + *
   47.12 + * The contents of this file are subject to the terms of either the GNU
   47.13 + * General Public License Version 2 only ("GPL") or the Common
   47.14 + * Development and Distribution License("CDDL") (collectively, the
   47.15 + * "License"). You may not use this file except in compliance with the
   47.16 + * License. You can obtain a copy of the License at
   47.17 + * http://www.netbeans.org/cddl-gplv2.html
   47.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   47.19 + * specific language governing permissions and limitations under the
   47.20 + * License.  When distributing the software, include this License Header
   47.21 + * Notice in each file and include the License file at
   47.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   47.23 + * particular file as subject to the "Classpath" exception as provided
   47.24 + * by Oracle in the GPL Version 2 section of the License file that
   47.25 + * accompanied this code. If applicable, add the following below the
   47.26 + * License Header, with the fields enclosed by brackets [] replaced by
   47.27 + * your own identifying information:
   47.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   47.29 + *
   47.30 + * If you wish your version of this file to be governed by only the CDDL
   47.31 + * or only the GPL Version 2, indicate your decision by adding
   47.32 + * "[Contributor] elects to include this software in this distribution
   47.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   47.34 + * single choice of license, a recipient has the option to distribute
   47.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   47.36 + * to extend the choice of license to its licensees as provided above.
   47.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   47.38 + * Version 2 license, then the option applies only if the new code is
   47.39 + * made subject to such option by the copyright holder.
   47.40 + *
   47.41 + * Contributor(s):
   47.42 + *
   47.43 + * Portions Copyrighted 2009-2011 Sun Microsystems, Inc.
   47.44 + */
   47.45 +package org.netbeans.modules.java.hints.spiimpl.batch;
   47.46 +
   47.47 +import com.sun.tools.javac.api.JavacTaskImpl;
   47.48 +import com.sun.tools.javac.util.Log;
   47.49 +import java.io.IOException;
   47.50 +import java.lang.reflect.Constructor;
   47.51 +import java.lang.reflect.Method;
   47.52 +import java.nio.ByteBuffer;
   47.53 +import java.nio.charset.Charset;
   47.54 +import java.util.ArrayList;
   47.55 +import java.util.Collection;
   47.56 +import java.util.Collections;
   47.57 +import java.util.HashMap;
   47.58 +import java.util.HashSet;
   47.59 +import java.util.IdentityHashMap;
   47.60 +import java.util.Iterator;
   47.61 +import java.util.LinkedHashMap;
   47.62 +import java.util.LinkedHashSet;
   47.63 +import java.util.LinkedList;
   47.64 +import java.util.List;
   47.65 +import java.util.Map;
   47.66 +import java.util.Map.Entry;
   47.67 +import java.util.Properties;
   47.68 +import java.util.Set;
   47.69 +import java.util.concurrent.atomic.AtomicBoolean;
   47.70 +import java.util.logging.Level;
   47.71 +import java.util.logging.Logger;
   47.72 +import javax.swing.text.BadLocationException;
   47.73 +import org.netbeans.api.annotations.common.NonNull;
   47.74 +import org.netbeans.api.java.classpath.ClassPath;
   47.75 +import org.netbeans.api.java.classpath.ClassPath.PathConversionMode;
   47.76 +import org.netbeans.api.java.platform.JavaPlatformManager;
   47.77 +import org.netbeans.api.java.source.ClasspathInfo;
   47.78 +import org.netbeans.api.java.source.CompilationController;
   47.79 +import org.netbeans.api.java.source.CompilationInfo;
   47.80 +import org.netbeans.api.java.source.JavaSource;
   47.81 +import org.netbeans.api.java.source.JavaSource.Phase;
   47.82 +import org.netbeans.api.java.source.ModificationResult;
   47.83 +import org.netbeans.api.java.source.ModificationResult.Difference;
   47.84 +import org.netbeans.api.java.source.Task;
   47.85 +import org.netbeans.api.java.source.WorkingCopy;
   47.86 +import org.netbeans.api.project.FileOwnerQuery;
   47.87 +import org.netbeans.api.project.Project;
   47.88 +import org.netbeans.api.project.ProjectUtils;
   47.89 +import org.netbeans.api.project.SourceGroup;
   47.90 +import org.netbeans.api.project.Sources;
   47.91 +import org.netbeans.api.queries.FileEncodingQuery;
   47.92 +import org.netbeans.api.queries.VisibilityQuery;
   47.93 +//import org.netbeans.modules.java.editor.semantic.SemanticHighlighter;
   47.94 +import org.netbeans.modules.java.hints.spiimpl.JavaFixImpl;
   47.95 +import org.netbeans.modules.java.hints.spiimpl.JavaFixImpl.Accessor;
   47.96 +import org.netbeans.modules.java.hints.spiimpl.MessageImpl;
   47.97 +import org.netbeans.modules.java.hints.spiimpl.SyntheticFix;
   47.98 +import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.BatchResult;
   47.99 +import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.Resource;
  47.100 +import org.netbeans.modules.java.hints.spiimpl.ipi.upgrade.ProjectDependencyUpgrader;
  47.101 +import org.netbeans.modules.java.source.JavaSourceAccessor;
  47.102 +import org.netbeans.modules.java.source.parsing.CompilationInfoImpl;
  47.103 +import org.netbeans.modules.java.source.save.DiffUtilities;
  47.104 +import org.netbeans.modules.java.source.save.ElementOverlay;
  47.105 +import org.netbeans.modules.refactoring.spi.RefactoringElementImplementation;
  47.106 +import org.netbeans.spi.editor.hints.ErrorDescription;
  47.107 +import org.netbeans.spi.editor.hints.Fix;
  47.108 +import org.netbeans.spi.java.hints.HintContext.MessageKind;
  47.109 +import org.netbeans.spi.java.hints.JavaFix;
  47.110 +import org.openide.filesystems.FileObject;
  47.111 +import org.openide.filesystems.FileUtil;
  47.112 +import org.openide.util.Exceptions;
  47.113 +import org.openide.util.Lookup;
  47.114 +
  47.115 +/**
  47.116 + *
  47.117 + * @author Jan Lahoda
  47.118 + */
  47.119 +public class BatchUtilities {
  47.120 +
  47.121 +    private static final Logger LOG = Logger.getLogger(BatchUtilities.class.getName());
  47.122 +    
  47.123 +    public static Collection<ModificationResult> applyFixes(BatchResult candidates, @NonNull final ProgressHandleWrapper progress, AtomicBoolean cancel, final Collection<? super MessageImpl> problems) {
  47.124 +        return applyFixes(candidates, progress, cancel, new ArrayList<RefactoringElementImplementation>(), problems);
  47.125 +    }
  47.126 +    
  47.127 +    public static Collection<ModificationResult> applyFixes(BatchResult candidates, @NonNull final ProgressHandleWrapper progress, AtomicBoolean cancel, final Collection<? super RefactoringElementImplementation> fileChanges, final Collection<? super MessageImpl> problems) {
  47.128 +        return applyFixes(candidates, progress, cancel, fileChanges, null, problems);
  47.129 +    }
  47.130 +    
  47.131 +    public static Collection<ModificationResult> applyFixes(BatchResult candidates, @NonNull final ProgressHandleWrapper progress, AtomicBoolean cancel, final Collection<? super RefactoringElementImplementation> fileChanges, final Map<JavaFix, ModificationResult> changesPerFix, final Collection<? super MessageImpl> problems) {
  47.132 +        return applyFixes(candidates, progress, cancel, fileChanges, changesPerFix, false, problems);
  47.133 +    }
  47.134 +    
  47.135 +    public static Collection<ModificationResult> applyFixes(BatchResult candidates, @NonNull final ProgressHandleWrapper progress, AtomicBoolean cancel, final Collection<? super RefactoringElementImplementation> fileChanges, final Map<JavaFix, ModificationResult> changesPerFix, boolean doNotRegisterClassPath, final Collection<? super MessageImpl> problems) {
  47.136 +        final Map<Project, Set<String>> processedDependencyChanges = new IdentityHashMap<Project, Set<String>>();
  47.137 +        final Map<FileObject, List<ModificationResult.Difference>> result = new LinkedHashMap<FileObject, List<ModificationResult.Difference>>();
  47.138 +        final Map<FileObject, byte[]> resourceContentChanges = new HashMap<FileObject, byte[]>();
  47.139 +
  47.140 +        BatchSearch.VerifiedSpansCallBack callback = new BatchSearch.VerifiedSpansCallBack() {
  47.141 +            private ElementOverlay overlay;
  47.142 +            public void groupStarted() {
  47.143 +                overlay = ElementOverlay.getOrCreateOverlay();
  47.144 +            }
  47.145 +            public boolean spansVerified(CompilationController wc, Resource r, Collection<? extends ErrorDescription> hints) throws Exception {
  47.146 +                if (hints.isEmpty()) return true;
  47.147 +                
  47.148 +                Constructor<WorkingCopy> wcConstr = WorkingCopy.class.getDeclaredConstructor(CompilationInfoImpl.class, ElementOverlay.class);
  47.149 +                wcConstr.setAccessible(true);
  47.150 +
  47.151 +//                final WorkingCopy copy = new WorkingCopy(JavaSourceAccessor.getINSTANCE().getCompilationInfoImpl(parameter), overlay);
  47.152 +                WorkingCopy copy = wcConstr.newInstance(JavaSourceAccessor.getINSTANCE().getCompilationInfoImpl(wc), overlay);
  47.153 +                Method setJavaSource = CompilationInfo.class.getDeclaredMethod("setJavaSource", JavaSource.class);
  47.154 +                setJavaSource.setAccessible(true);
  47.155 +
  47.156 +//                copy.setJavaSource(JavaSource.this);
  47.157 +                setJavaSource.invoke(copy, wc.getJavaSource());
  47.158 +
  47.159 +                copy.toPhase(Phase.RESOLVED);
  47.160 +                progress.tick();
  47.161 +                
  47.162 +                if (applyFixes(copy, processedDependencyChanges, hints, resourceContentChanges, fileChanges, changesPerFix, problems)) {
  47.163 +                    return false;
  47.164 +                }
  47.165 +
  47.166 +                final JavacTaskImpl jt = JavaSourceAccessor.getINSTANCE().getJavacTask(copy);
  47.167 +                Log.instance(jt.getContext()).nerrors = 0;
  47.168 +                Method getChanges = WorkingCopy.class.getDeclaredMethod("getChanges", Map.class);
  47.169 +                getChanges.setAccessible(true);
  47.170 +
  47.171 +                result.put(copy.getFileObject(), (List<ModificationResult.Difference>) getChanges.invoke(copy, new HashMap<Object, int[]>()));
  47.172 +
  47.173 +                if (LOG.isLoggable(Level.FINE)) {
  47.174 +                    LOG.log(Level.FINE, "fixes applied to: {0}", FileUtil.getFileDisplayName(wc.getFileObject()));
  47.175 +                }
  47.176 +
  47.177 +                return true;
  47.178 +            }
  47.179 +
  47.180 +            public void groupFinished() {
  47.181 +                overlay = null;
  47.182 +            }
  47.183 +
  47.184 +            public void cannotVerifySpan(Resource r) {
  47.185 +                problems.add(new MessageImpl(MessageKind.WARNING, "Cannot parse: " + r.getRelativePath()));
  47.186 +            }
  47.187 +        };
  47.188 +
  47.189 +        BatchSearch.getVerifiedSpans(candidates, progress, callback, doNotRegisterClassPath, problems, cancel);
  47.190 +        
  47.191 +        addResourceContentChanges(resourceContentChanges, result);
  47.192 +
  47.193 +        return Collections.singletonList(JavaSourceAccessor.getINSTANCE().createModificationResult(result, Collections.<Object, int[]>emptyMap()));
  47.194 +    }
  47.195 +
  47.196 +    public static void addResourceContentChanges(final Map<FileObject, byte[]> resourceContentChanges, final Map<FileObject, List<Difference>> result) {
  47.197 +        for (Entry<FileObject, byte[]> e : resourceContentChanges.entrySet()) {
  47.198 +            try {
  47.199 +                byte[] origBytes = e.getKey().asBytes();
  47.200 +                Charset encoding = FileEncodingQuery.getEncoding(e.getKey());
  47.201 +                String origContent = encoding.newDecoder().decode(ByteBuffer.wrap(origBytes)).toString();
  47.202 +                String newContent  = encoding.newDecoder().decode(ByteBuffer.wrap(e.getValue())).toString();
  47.203 +
  47.204 +                result.put(e.getKey(), DiffUtilities.diff2ModificationResultDifference(e.getKey(), null, Collections.<Integer, String>emptyMap(), origContent, newContent));
  47.205 +            } catch (BadLocationException ex) {
  47.206 +                Exceptions.printStackTrace(ex);
  47.207 +            } catch (IOException ex) {
  47.208 +                Exceptions.printStackTrace(ex);
  47.209 +            }
  47.210 +        }
  47.211 +    }
  47.212 +
  47.213 +    private static String positionToString(ErrorDescription ed) {
  47.214 +        try {
  47.215 +            return ed.getFile().getNameExt() + ":" + ed.getRange().getBegin().getLine();
  47.216 +        } catch (IOException ex) {
  47.217 +            LOG.log(Level.FINE, null, ex);
  47.218 +            return ed.getFile().getNameExt();
  47.219 +        }
  47.220 +    }
  47.221 +
  47.222 +//    public static void removeUnusedImports(Collection<? extends FileObject> files) throws IOException {
  47.223 +//        Map<ClasspathInfo, Collection<FileObject>> sortedFastFiles = sortFiles(files);
  47.224 +//
  47.225 +//        for (Entry<ClasspathInfo, Collection<FileObject>> e : sortedFastFiles.entrySet()) {
  47.226 +//            JavaSource.create(e.getKey(), e.getValue()).runModificationTask(new RemoveUnusedImports()).commit();
  47.227 +//        }
  47.228 +//    }
  47.229 +//
  47.230 +//    private static final class RemoveUnusedImports implements Task<WorkingCopy> {
  47.231 +//        public void run(WorkingCopy wc) throws IOException {
  47.232 +//            Document doc = wc.getSnapshot().getSource().getDocument(true);
  47.233 +//            
  47.234 +//            if (wc.toPhase(Phase.RESOLVED).compareTo(Phase.RESOLVED) < 0) {
  47.235 +//                return;
  47.236 +//            }
  47.237 +//
  47.238 +//            //compute imports to remove:
  47.239 +//            List<TreePathHandle> unusedImports = SemanticHighlighter.computeUnusedImports(wc);
  47.240 +//            CompilationUnitTree cut = wc.getCompilationUnit();
  47.241 +//            // make the changes to the source
  47.242 +//            for (TreePathHandle handle : unusedImports) {
  47.243 +//                TreePath path = handle.resolve(wc);
  47.244 +//                assert path != null;
  47.245 +//                cut = wc.getTreeMaker().removeCompUnitImport(cut,
  47.246 +//                        (ImportTree) path.getLeaf());
  47.247 +//            }
  47.248 +//
  47.249 +//            if (!unusedImports.isEmpty()) {
  47.250 +//                wc.rewrite(wc.getCompilationUnit(), cut);
  47.251 +//            }
  47.252 +//        }
  47.253 +//    }
  47.254 +
  47.255 +    public static boolean applyFixes(WorkingCopy copy, Map<Project, Set<String>> processedDependencyChanges, Collection<? extends ErrorDescription> hints, Map<FileObject, byte[]> resourceContentChanges, Collection<? super RefactoringElementImplementation> fileChanges, Collection<? super MessageImpl> problems) throws IllegalStateException, Exception {
  47.256 +        return applyFixes(copy, processedDependencyChanges, hints, resourceContentChanges, fileChanges, null, problems);
  47.257 +    }
  47.258 +    
  47.259 +    public static boolean applyFixes(WorkingCopy copy, Map<Project, Set<String>> processedDependencyChanges, Collection<? extends ErrorDescription> hints, Map<FileObject, byte[]> resourceContentChanges, Collection<? super RefactoringElementImplementation> fileChanges, Map<JavaFix, ModificationResult> changesPerFix, Collection<? super MessageImpl> problems) throws IllegalStateException, Exception {
  47.260 +        Set<JavaFix> fixes = new LinkedHashSet<JavaFix>();
  47.261 +        for (ErrorDescription ed : hints) {
  47.262 +            if (!ed.getFixes().isComputed()) {
  47.263 +                throw new IllegalStateException();//TODO: should be problem
  47.264 +            }
  47.265 +
  47.266 +            Fix toApply = null;
  47.267 +
  47.268 +            for (Fix f : ed.getFixes().getFixes()) {
  47.269 +                if (f instanceof SyntheticFix) continue;
  47.270 +                if (toApply == null) toApply = f;
  47.271 +                else problems.add(new MessageImpl(MessageKind.WARNING, "More than one fix for: " + ed.getDescription() + " at " + positionToString(ed) + ", only the first one will be used."));
  47.272 +            }
  47.273 +
  47.274 +            if (toApply == null) {
  47.275 +                //TODO: currently giving a warning so that the hints can be augmented with "Options.QUERY", but that should be removed
  47.276 +                //if a non-query hint cannot produce any fix, it is likely Ok - if not, the hint should produce a warning itself
  47.277 +                boolean doWarning = false;
  47.278 +                assert doWarning = true;
  47.279 +                if (doWarning) {
  47.280 +                    problems.add(new MessageImpl(MessageKind.WARNING, "No fix for: " + ed.getDescription() + " at " + positionToString(ed) + "."));
  47.281 +                }
  47.282 +                continue;
  47.283 +            }
  47.284 +
  47.285 +            if (!(toApply instanceof JavaFixImpl)) {
  47.286 +                throw new IllegalStateException(toApply.getClass().getName());//XXX: hints need to provide JavaFixes
  47.287 +            }
  47.288 +
  47.289 +
  47.290 +            fixes.add(((JavaFixImpl) toApply).jf);
  47.291 +        }
  47.292 +        if (fixDependencies(copy.getFileObject(), fixes, processedDependencyChanges)) {
  47.293 +            return true;
  47.294 +        }
  47.295 +        for (JavaFix f : fixes) {
  47.296 +//                    if (cancel.get()) return ;
  47.297 +
  47.298 +            JavaFixImpl.Accessor.INSTANCE.process(f, copy, false, resourceContentChanges, fileChanges);
  47.299 +            
  47.300 +            if (changesPerFix != null) {
  47.301 +                ElementOverlay overlay = ElementOverlay.getOrCreateOverlay(); //XXX: will use the incorrect overlay?
  47.302 +                Constructor<WorkingCopy> wcConstr = WorkingCopy.class.getDeclaredConstructor(CompilationInfoImpl.class, ElementOverlay.class);
  47.303 +                wcConstr.setAccessible(true);
  47.304 +
  47.305 +//                final WorkingCopy copy = new WorkingCopy(JavaSourceAccessor.getINSTANCE().getCompilationInfoImpl(parameter), overlay);
  47.306 +                WorkingCopy perFixCopy = wcConstr.newInstance(JavaSourceAccessor.getINSTANCE().getCompilationInfoImpl(copy), overlay);
  47.307 +                Method setJavaSource = CompilationInfo.class.getDeclaredMethod("setJavaSource", JavaSource.class);
  47.308 +                setJavaSource.setAccessible(true);
  47.309 +
  47.310 +//                copy.setJavaSource(JavaSource.this);
  47.311 +                setJavaSource.invoke(perFixCopy, copy.getJavaSource());
  47.312 +
  47.313 +                perFixCopy.toPhase(Phase.RESOLVED);
  47.314 +                
  47.315 +                final Map<FileObject, byte[]> perFixResourceContentChanges = new HashMap<FileObject, byte[]>();
  47.316 +        
  47.317 +                JavaFixImpl.Accessor.INSTANCE.process(f, perFixCopy, false, perFixResourceContentChanges, new ArrayList<RefactoringElementImplementation>());
  47.318 +                
  47.319 +                final JavacTaskImpl jt = JavaSourceAccessor.getINSTANCE().getJavacTask(perFixCopy);
  47.320 +                Log.instance(jt.getContext()).nerrors = 0;
  47.321 +                Method getChanges = WorkingCopy.class.getDeclaredMethod("getChanges", Map.class);
  47.322 +                getChanges.setAccessible(true);
  47.323 +                
  47.324 +                Map<FileObject, List<Difference>> changes = new HashMap<FileObject, List<Difference>>();
  47.325 +                
  47.326 +                changes.put(perFixCopy.getFileObject(), (List<ModificationResult.Difference>) getChanges.invoke(perFixCopy, new HashMap<Object, int[]>()));
  47.327 +                
  47.328 +                addResourceContentChanges(resourceContentChanges, changes);
  47.329 +                
  47.330 +                for (Iterator<Entry<FileObject, List<Difference>>> it = changes.entrySet().iterator(); it.hasNext();) {
  47.331 +                    if (it.next().getValue().isEmpty()) it.remove();
  47.332 +                }
  47.333 +
  47.334 +                if (!changes.isEmpty()) {
  47.335 +                    ModificationResult perFixResult = JavaSourceAccessor.getINSTANCE().createModificationResult(changes, Collections.<Object, int[]>emptyMap());
  47.336 +
  47.337 +                    changesPerFix.put(f, perFixResult);
  47.338 +                }
  47.339 +            }
  47.340 +        }
  47.341 +        return false;
  47.342 +    }
  47.343 +    
  47.344 +    public static Collection<ModificationResult> applyFixes(final Map<FileObject, Collection<JavaFix>> toRun) {
  47.345 +        final Map<FileObject, List<ModificationResult.Difference>> result = new LinkedHashMap<FileObject, List<ModificationResult.Difference>>();
  47.346 +        final Map<FileObject, byte[]> resourceContentChanges = new HashMap<FileObject, byte[]>();
  47.347 +        Map<ClasspathInfo, Collection<FileObject>> cp2Files = BatchUtilities.sortFiles(toRun.keySet());
  47.348 +
  47.349 +        for (Entry<ClasspathInfo, Collection<FileObject>> e : cp2Files.entrySet()) {
  47.350 +            try {
  47.351 +                ModificationResult mr = JavaSource.create(e.getKey(), e.getValue()).runModificationTask(new Task<WorkingCopy>() {
  47.352 +                    @Override
  47.353 +                    public void run(WorkingCopy parameter) throws Exception {
  47.354 +                        if (parameter.toPhase(Phase.RESOLVED).compareTo(Phase.RESOLVED) < 0) return ;
  47.355 +
  47.356 +                        for (JavaFix jf : toRun.get(parameter.getFileObject())) {
  47.357 +                            JavaFixImpl.Accessor.INSTANCE.process(jf, parameter, false, resourceContentChanges, new ArrayList<RefactoringElementImplementation>());
  47.358 +                        }
  47.359 +                    }
  47.360 +                });
  47.361 +                
  47.362 +                result.putAll(JavaSourceAccessor.getINSTANCE().getDiffsFromModificationResult(mr));
  47.363 +            } catch (IOException ex) {
  47.364 +                Exceptions.printStackTrace(ex);
  47.365 +            }
  47.366 +        }
  47.367 +        
  47.368 +        addResourceContentChanges(resourceContentChanges, result);
  47.369 +        
  47.370 +        return Collections.singletonList(JavaSourceAccessor.getINSTANCE().createModificationResult(result, Collections.<Object, int[]>emptyMap()));
  47.371 +    }
  47.372 +
  47.373 +    public static Collection<FileObject> getSourceGroups(Iterable<? extends Project> prjs) {
  47.374 +        List<FileObject> result = new LinkedList<FileObject>();
  47.375 +        
  47.376 +        for (Project p : prjs) {
  47.377 +            Sources s = ProjectUtils.getSources(p);
  47.378 +
  47.379 +            for (SourceGroup sg : s.getSourceGroups("java")) {
  47.380 +                result.add(sg.getRootFolder());
  47.381 +            }
  47.382 +        }
  47.383 +
  47.384 +        return result;
  47.385 +    }
  47.386 +
  47.387 +    public static Map<ClasspathInfo, Collection<FileObject>> sortFiles(Collection<? extends FileObject> from) {
  47.388 +        Map<CPCategorizer, Collection<FileObject>> m = new HashMap<CPCategorizer, Collection<FileObject>>();
  47.389 +
  47.390 +        for (FileObject f : from) {
  47.391 +            CPCategorizer cpCategorizer = new CPCategorizer(f);
  47.392 +
  47.393 +            Collection<FileObject> files = m.get(cpCategorizer);
  47.394 +
  47.395 +            if (files == null) {
  47.396 +                m.put(cpCategorizer, files = new LinkedList<FileObject>());
  47.397 +            }
  47.398 +
  47.399 +            files.add(f);
  47.400 +        }
  47.401 +        
  47.402 +        Map<ClasspathInfo, Collection<FileObject>> result = new IdentityHashMap<ClasspathInfo, Collection<FileObject>>();
  47.403 +
  47.404 +        for (Entry<CPCategorizer, Collection<FileObject>> e : m.entrySet()) {
  47.405 +            result.put(ClasspathInfo.create(e.getKey().boot, e.getKey().compile, e.getKey().source), e.getValue());
  47.406 +        }
  47.407 +        
  47.408 +        return result;
  47.409 +    }
  47.410 +    
  47.411 +    private static final ClassPath getClassPath(FileObject forFO, String id) {
  47.412 +        ClassPath result = ClassPath.getClassPath(forFO, id);
  47.413 +        
  47.414 +        if (result == null) {
  47.415 +            if (ClassPath.BOOT.equals(id)) {
  47.416 +                result = JavaPlatformManager.getDefault().getDefaultPlatform().getBootstrapLibraries();
  47.417 +            } else {
  47.418 +                result = ClassPath.EMPTY;
  47.419 +            }
  47.420 +        }
  47.421 +        
  47.422 +        return result;
  47.423 +    }
  47.424 +    
  47.425 +    private static final class CPCategorizer {
  47.426 +        private final String cps;
  47.427 +        private final ClassPath boot;
  47.428 +        private final ClassPath compile;
  47.429 +        private final ClassPath source;
  47.430 +        private final FileObject sourceRoot;
  47.431 +
  47.432 +        public CPCategorizer(FileObject file) {
  47.433 +            this.boot = getClassPath(file, ClassPath.BOOT);
  47.434 +            this.compile = getClassPath(file, ClassPath.COMPILE);
  47.435 +            this.source = getClassPath(file, ClassPath.SOURCE);
  47.436 +            this.sourceRoot = source != null ? source.findOwnerRoot(file) : null;
  47.437 +            
  47.438 +            StringBuilder cps = new StringBuilder();
  47.439 +            
  47.440 +            if (boot != null) cps.append(boot.toString(PathConversionMode.PRINT));
  47.441 +            if (compile != null) cps.append(compile.toString(PathConversionMode.PRINT));
  47.442 +            if (source != null) cps.append(source.toString(PathConversionMode.PRINT));
  47.443 +            
  47.444 +            this.cps = cps.toString();
  47.445 +        }
  47.446 +
  47.447 +        @Override
  47.448 +        public int hashCode() {
  47.449 +            int hash = 5;
  47.450 +            hash = 53 * hash + this.cps.hashCode();
  47.451 +            hash = 53 * hash + (this.sourceRoot != null ? this.sourceRoot.hashCode() : 0);
  47.452 +            return hash;
  47.453 +        }
  47.454 +
  47.455 +        @Override
  47.456 +        public boolean equals(Object obj) {
  47.457 +            if (obj == null) {
  47.458 +                return false;
  47.459 +            }
  47.460 +            if (getClass() != obj.getClass()) {
  47.461 +                return false;
  47.462 +            }
  47.463 +            final CPCategorizer other = (CPCategorizer) obj;
  47.464 +            if (!this.cps.equals(other.cps)) {
  47.465 +                return false;
  47.466 +            }
  47.467 +            if (this.sourceRoot != other.sourceRoot && (this.sourceRoot == null || !this.sourceRoot.equals(other.sourceRoot))) {
  47.468 +                return false;
  47.469 +            }
  47.470 +            return true;
  47.471 +        }
  47.472 +        
  47.473 +    }
  47.474 +
  47.475 +    public static final String ENSURE_DEPENDENCY = "ensure-dependency";
  47.476 +
  47.477 +    public static boolean fixDependencies(FileObject file, Iterable<? extends JavaFix> toProcess, Map<Project, Set<String>> alreadyProcessed) {
  47.478 +        boolean modified = false;
  47.479 +//        for (FileObject file : toProcess.keySet()) {
  47.480 +            for (JavaFix fix : toProcess) {
  47.481 +                String updateTo = Accessor.INSTANCE.getOptions(fix).get(ENSURE_DEPENDENCY);
  47.482 +
  47.483 +                if (updateTo != null) {
  47.484 +                    Project p = FileOwnerQuery.getOwner(file);
  47.485 +
  47.486 +                    if (p != null) {
  47.487 +                        Set<String> seen = alreadyProcessed.get(p);
  47.488 +
  47.489 +                        if (seen == null) {
  47.490 +                            alreadyProcessed.put(p, seen = new HashSet<String>());
  47.491 +                        }
  47.492 +
  47.493 +                        if (seen.add(updateTo)) {
  47.494 +                            for (ProjectDependencyUpgrader up : Lookup.getDefault().lookupAll(ProjectDependencyUpgrader.class)) {
  47.495 +                                if (up.ensureDependency(p, updateTo, false)) { //XXX: should check whether the given project was actually modified
  47.496 +                                    modified = true;
  47.497 +                                    break;
  47.498 +                                }
  47.499 +                            }
  47.500 +                            //TODO: fail if cannot update the dependency?
  47.501 +                        }
  47.502 +                    }
  47.503 +                }
  47.504 +            }
  47.505 +
  47.506 +            return modified;
  47.507 +//        }
  47.508 +    }
  47.509 +
  47.510 +    public static void recursive(FileObject root, FileObject file, Collection<FileObject> collected, ProgressHandleWrapper progress, int depth, Properties timeStamps, Set<String> removedFiles, boolean recursive) {
  47.511 +        if (!VisibilityQuery.getDefault().isVisible(file)) return;
  47.512 +
  47.513 +        if (file.isData()) {
  47.514 +            if (timeStamps != null) {
  47.515 +                String relativePath = FileUtil.getRelativePath(root, file);
  47.516 +                String lastModified = Long.toHexString(file.lastModified().getTime());
  47.517 +
  47.518 +                removedFiles.remove(relativePath);
  47.519 +
  47.520 +                if (lastModified.equals(timeStamps.getProperty(relativePath))) {
  47.521 +                    return;
  47.522 +                }
  47.523 +
  47.524 +                timeStamps.setProperty(relativePath, lastModified);
  47.525 +            }
  47.526 +
  47.527 +            if (/*???:*/"java".equals(file.getExt()) || "text/x-java".equals(FileUtil.getMIMEType(file, "text/x-java"))) {
  47.528 +                collected.add(file);
  47.529 +            }
  47.530 +        } else {
  47.531 +            FileObject[] children = file.getChildren();
  47.532 +
  47.533 +            if (children.length == 0) return;
  47.534 +
  47.535 +            ProgressHandleWrapper inner = depth < 2 ? progress.startNextPartWithEmbedding(ProgressHandleWrapper.prepareParts(children.length)) : null;
  47.536 +
  47.537 +            if (inner == null && progress != null) {
  47.538 +                progress.startNextPart(children.length);
  47.539 +            } else {
  47.540 +                progress = null;
  47.541 +            }
  47.542 +
  47.543 +            for (FileObject c : children) {
  47.544 +                if (recursive || c.isData())
  47.545 +                    recursive(root, c, collected, inner, depth + 1, timeStamps, removedFiles, recursive);
  47.546 +
  47.547 +                if (progress != null) progress.tick();
  47.548 +            }
  47.549 +        }
  47.550 +    }    
  47.551 +}
    48.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    48.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/batch/ProgressHandleWrapper.java	Wed May 08 21:47:42 2013 +0200
    48.3 @@ -0,0 +1,293 @@
    48.4 +/*
    48.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    48.6 + *
    48.7 + * Copyright 2009-2011 Oracle and/or its affiliates. All rights reserved.
    48.8 + *
    48.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   48.10 + * Other names may be trademarks of their respective owners.
   48.11 + *
   48.12 + * The contents of this file are subject to the terms of either the GNU
   48.13 + * General Public License Version 2 only ("GPL") or the Common
   48.14 + * Development and Distribution License("CDDL") (collectively, the
   48.15 + * "License"). You may not use this file except in compliance with the
   48.16 + * License. You can obtain a copy of the License at
   48.17 + * http://www.netbeans.org/cddl-gplv2.html
   48.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   48.19 + * specific language governing permissions and limitations under the
   48.20 + * License.  When distributing the software, include this License Header
   48.21 + * Notice in each file and include the License file at
   48.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   48.23 + * particular file as subject to the "Classpath" exception as provided
   48.24 + * by Oracle in the GPL Version 2 section of the License file that
   48.25 + * accompanied this code. If applicable, add the following below the
   48.26 + * License Header, with the fields enclosed by brackets [] replaced by
   48.27 + * your own identifying information:
   48.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   48.29 + *
   48.30 + * If you wish your version of this file to be governed by only the CDDL
   48.31 + * or only the GPL Version 2, indicate your decision by adding
   48.32 + * "[Contributor] elects to include this software in this distribution
   48.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   48.34 + * single choice of license, a recipient has the option to distribute
   48.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   48.36 + * to extend the choice of license to its licensees as provided above.
   48.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   48.38 + * Version 2 license, then the option applies only if the new code is
   48.39 + * made subject to such option by the copyright holder.
   48.40 + *
   48.41 + * Contributor(s):
   48.42 + *
   48.43 + * Portions Copyrighted 2009-2011 Sun Microsystems, Inc.
   48.44 + */
   48.45 +package org.netbeans.modules.java.hints.spiimpl.batch;
   48.46 +
   48.47 +import java.util.Arrays;
   48.48 +import java.util.logging.Level;
   48.49 +import java.util.logging.Logger;
   48.50 +import org.netbeans.api.progress.ProgressHandle;
   48.51 +import org.netbeans.modules.analysis.spi.Analyzer.Context;
   48.52 +import org.netbeans.modules.java.hints.spiimpl.Utilities;
   48.53 +
   48.54 +public final class ProgressHandleWrapper {
   48.55 +
   48.56 +    private static final int TOTAL = 1000;
   48.57 +    private final ProgressHandleAbstraction handle;
   48.58 +    private final int[] parts;
   48.59 +    private int currentPart = -1;
   48.60 +    private int currentPartTotalWork;
   48.61 +    private int currentPartWorkDone;
   48.62 +    private long currentPartStartTime;
   48.63 +    private int currentOffset;
   48.64 +    private final long[] spentTime;
   48.65 +    private boolean debug;
   48.66 +
   48.67 +    public ProgressHandleWrapper(int... parts) {
   48.68 +        this((ProgressHandleAbstraction) null, parts);
   48.69 +    }
   48.70 +
   48.71 +    public ProgressHandleWrapper(ProgressHandle handle, int... parts) {
   48.72 +        this(new ProgressHandleBasedProgressHandleAbstraction(handle), parts);
   48.73 +    }
   48.74 +
   48.75 +    public ProgressHandleWrapper(Context handle, int... parts) {
   48.76 +        this(new AnalysisContextBasedProgressHandleAbstraction(handle), parts);
   48.77 +    }
   48.78 +
   48.79 +    public ProgressHandleWrapper(ProgressHandleAbstraction handle, int... parts) {
   48.80 +        this.handle = handle;
   48.81 +        if (handle == null) {
   48.82 +            this.parts = null;
   48.83 +            this.spentTime = null;
   48.84 +        } else {
   48.85 +            int total = 0;
   48.86 +            for (int i : parts) {
   48.87 +                total += i;
   48.88 +            }
   48.89 +            this.parts = new int[parts.length];
   48.90 +            for (int cntr = 0; cntr < parts.length; cntr++) {
   48.91 +                this.parts[cntr] = (TOTAL * parts[cntr]) / total;
   48.92 +            }
   48.93 +            this.spentTime = new long[parts.length];
   48.94 +        }
   48.95 +    }
   48.96 +
   48.97 +    public void setDebug(boolean debug) {
   48.98 +        this.debug = debug;
   48.99 +    }
  48.100 +
  48.101 +    public void startNextPart(int totalWork) {
  48.102 +        if (handle == null) {
  48.103 +            return;
  48.104 +        }
  48.105 +        if (currentPart == (-1)) {
  48.106 +            handle.start(TOTAL);
  48.107 +        } else {
  48.108 +            currentOffset += parts[currentPart];
  48.109 +            spentTime[currentPart] = System.currentTimeMillis() - currentPartStartTime;
  48.110 +        }
  48.111 +        currentPart++;
  48.112 +        currentPartTotalWork = totalWork;
  48.113 +        currentPartWorkDone = 0;
  48.114 +        currentPartStartTime = System.currentTimeMillis();
  48.115 +        currentPartWorkDoneUpdated();
  48.116 +    }
  48.117 +
  48.118 +    public ProgressHandleWrapper startNextPartWithEmbedding(int... embeddedParts) {
  48.119 +//        startNextPart(TOTAL);
  48.120 +        return new ProgressHandleWrapper(new ProgressHandleWrapperBasedProgressHandleAbstraction(this), embeddedParts);
  48.121 +    }
  48.122 +
  48.123 +    public void tick() {
  48.124 +        if (handle == null) {
  48.125 +            return;
  48.126 +        }
  48.127 +        currentPartWorkDone++;
  48.128 +        currentPartWorkDoneUpdated();
  48.129 +    }
  48.130 +
  48.131 +    private void setCurrentPartWorkDone(int done) {
  48.132 +        if (handle == null) {
  48.133 +            return;
  48.134 +        }
  48.135 +        currentPartWorkDone = done;
  48.136 +        currentPartWorkDoneUpdated();
  48.137 +    }
  48.138 +
  48.139 +    private void currentPartWorkDoneUpdated() {
  48.140 +        if (currentPartTotalWork > 0) {
  48.141 +            int parentProgress = currentOffset + (parts[currentPart] * currentPartWorkDone) / currentPartTotalWork;
  48.142 +            if (debug) {
  48.143 +                System.err.println("currentOffset=" + currentOffset);
  48.144 +                System.err.println("currentPart=" + currentPart);
  48.145 +                System.err.println("parts[currentPart]= " +parts[currentPart]);
  48.146 +                System.err.println("currentPartWorkDone=" + currentPartWorkDone);
  48.147 +                System.err.println("currentPartTotalWork= " +currentPartTotalWork);
  48.148 +                System.err.println("parentProgress=" + parentProgress);
  48.149 +            }
  48.150 +            handle.progress(parentProgress);
  48.151 +        } else {
  48.152 +            handle.progress(currentOffset + parts[currentPart]);
  48.153 +        }
  48.154 +        setAutomatedMessage();
  48.155 +    }
  48.156 +
  48.157 +    public void setMessage(String message) {
  48.158 +        if (handle == null) {
  48.159 +            return;
  48.160 +        }
  48.161 +        handle.progress(message);
  48.162 +    }
  48.163 +
  48.164 +    private void setAutomatedMessage() {
  48.165 +        if (handle == null || currentPart == (-1)) {
  48.166 +            return;
  48.167 +        }
  48.168 +        long spentTime = System.currentTimeMillis() - currentPartStartTime;
  48.169 +        double timePerUnit = ((double) spentTime) / currentPartWorkDone;
  48.170 +        String timeString;
  48.171 +        if (spentTime > 0) {
  48.172 +            double totalTime = currentPartTotalWork * timePerUnit;
  48.173 +            timeString = Utilities.toHumanReadableTime(spentTime) + "/" + Utilities.toHumanReadableTime(totalTime);
  48.174 +        } else {
  48.175 +            timeString = "No estimate";
  48.176 +        }
  48.177 +        handle.progress("Part " + (currentPart + 1) + "/" + parts.length + ", " + currentPartWorkDone + "/" + currentPartTotalWork + ", " + timeString);
  48.178 +    }
  48.179 +
  48.180 +    public void finish() {
  48.181 +        if (handle == null) {
  48.182 +            return ;
  48.183 +        }
  48.184 +
  48.185 +        handle.finish();
  48.186 +
  48.187 +        if (currentPart < 0) return ;
  48.188 +        
  48.189 +        spentTime[currentPart] = System.currentTimeMillis() - currentPartStartTime;
  48.190 +
  48.191 +        double total = 0.0;
  48.192 +
  48.193 +        for (long t : spentTime) {
  48.194 +            total += t;
  48.195 +        }
  48.196 +
  48.197 +        double[] actualSplit = new double[spentTime.length];
  48.198 +        int i = 0;
  48.199 +
  48.200 +        for (long t : spentTime) {
  48.201 +            actualSplit[i++] = TOTAL * (t / total);
  48.202 +        }
  48.203 +
  48.204 +        Logger.getLogger(ProgressHandleWrapper.class.getName()).log(Level.FINE, "Progress handle with split: {0}, actual times: {1}, actual split: {2}", new Object[] {Arrays.toString(parts), Arrays.toString(spentTime), Arrays.toString(actualSplit)});
  48.205 +    }
  48.206 +
  48.207 +    public static int[] prepareParts(int count) {
  48.208 +        int[] result = new int[count];
  48.209 +
  48.210 +        for (int cntr = 0; cntr < count; cntr++) {
  48.211 +            result[cntr] = 1;
  48.212 +        }
  48.213 +
  48.214 +        return result;
  48.215 +    }
  48.216 +
  48.217 +    public static interface ProgressHandleAbstraction {
  48.218 +
  48.219 +        public void start(int totalWork);
  48.220 +
  48.221 +        public void progress(int currentWorkDone);
  48.222 +
  48.223 +        public void progress(String message);
  48.224 +
  48.225 +        public void finish();
  48.226 +
  48.227 +    }
  48.228 +
  48.229 +    private static final class ProgressHandleBasedProgressHandleAbstraction implements ProgressHandleAbstraction {
  48.230 +        private final ProgressHandle delegate;
  48.231 +        public ProgressHandleBasedProgressHandleAbstraction(ProgressHandle delegate) {
  48.232 +            this.delegate = delegate;
  48.233 +        }
  48.234 +
  48.235 +        public void start(int totalWork) {
  48.236 +            delegate.start(totalWork);
  48.237 +        }
  48.238 +
  48.239 +        public void progress(int currentWorkDone) {
  48.240 +            delegate.progress(currentWorkDone);
  48.241 +        }
  48.242 +
  48.243 +        public void progress(String message) {
  48.244 +            delegate.progress(message);
  48.245 +        }
  48.246 +
  48.247 +        public void finish() {
  48.248 +            delegate.finish();
  48.249 +        }
  48.250 +    }
  48.251 +
  48.252 +    private static final class AnalysisContextBasedProgressHandleAbstraction implements ProgressHandleAbstraction {
  48.253 +        private final Context delegate;
  48.254 +        AnalysisContextBasedProgressHandleAbstraction(Context delegate) {
  48.255 +            this.delegate = delegate;
  48.256 +        }
  48.257 +
  48.258 +        public void start(int totalWork) {
  48.259 +            delegate.start(totalWork);
  48.260 +        }
  48.261 +
  48.262 +        public void progress(int currentWorkDone) {
  48.263 +            delegate.progress(currentWorkDone);
  48.264 +        }
  48.265 +
  48.266 +        public void progress(String message) {
  48.267 +            delegate.progress(message);
  48.268 +        }
  48.269 +
  48.270 +        public void finish() {
  48.271 +            delegate.finish();
  48.272 +        }
  48.273 +    }
  48.274 +
  48.275 +    private static final class ProgressHandleWrapperBasedProgressHandleAbstraction implements ProgressHandleAbstraction {
  48.276 +        private final ProgressHandleWrapper delegate;
  48.277 +        public ProgressHandleWrapperBasedProgressHandleAbstraction(ProgressHandleWrapper delegate) {
  48.278 +            this.delegate = delegate;
  48.279 +        }
  48.280 +
  48.281 +        public void start(int totalWork) {
  48.282 +            delegate.startNextPart(totalWork);
  48.283 +        }
  48.284 +
  48.285 +        public void progress(int currentWorkDone) {
  48.286 +            delegate.setCurrentPartWorkDone(currentWorkDone);
  48.287 +        }
  48.288 +
  48.289 +        public void progress(String message) {
  48.290 +            delegate.setMessage(message);
  48.291 +        }
  48.292 +
  48.293 +        public void finish() {}
  48.294 +    }
  48.295 +
  48.296 +}
    49.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    49.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/batch/Scopes.java	Wed May 08 21:47:42 2013 +0200
    49.3 @@ -0,0 +1,141 @@
    49.4 +/*
    49.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    49.6 + *
    49.7 + * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
    49.8 + *
    49.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   49.10 + * Other names may be trademarks of their respective owners.
   49.11 + *
   49.12 + * The contents of this file are subject to the terms of either the GNU
   49.13 + * General Public License Version 2 only ("GPL") or the Common
   49.14 + * Development and Distribution License("CDDL") (collectively, the
   49.15 + * "License"). You may not use this file except in compliance with the
   49.16 + * License. You can obtain a copy of the License at
   49.17 + * http://www.netbeans.org/cddl-gplv2.html
   49.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   49.19 + * specific language governing permissions and limitations under the
   49.20 + * License.  When distributing the software, include this License Header
   49.21 + * Notice in each file and include the License file at
   49.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   49.23 + * particular file as subject to the "Classpath" exception as provided
   49.24 + * by Oracle in the GPL Version 2 section of the License file that
   49.25 + * accompanied this code. If applicable, add the following below the
   49.26 + * License Header, with the fields enclosed by brackets [] replaced by
   49.27 + * your own identifying information:
   49.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   49.29 + *
   49.30 + * If you wish your version of this file to be governed by only the CDDL
   49.31 + * or only the GPL Version 2, indicate your decision by adding
   49.32 + * "[Contributor] elects to include this software in this distribution
   49.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   49.34 + * single choice of license, a recipient has the option to distribute
   49.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   49.36 + * to extend the choice of license to its licensees as provided above.
   49.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   49.38 + * Version 2 license, then the option applies only if the new code is
   49.39 + * made subject to such option by the copyright holder.
   49.40 + *
   49.41 + * Contributor(s):
   49.42 + *
   49.43 + * Portions Copyrighted 2011 Sun Microsystems, Inc.
   49.44 + */
   49.45 +package org.netbeans.modules.java.hints.spiimpl.batch;
   49.46 +
   49.47 +import java.util.Arrays;
   49.48 +import java.util.Collection;
   49.49 +import java.util.HashSet;
   49.50 +import java.util.Set;
   49.51 +import org.netbeans.api.java.classpath.ClassPath;
   49.52 +import org.netbeans.api.java.classpath.GlobalPathRegistry;
   49.53 +import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.Folder;
   49.54 +import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.IndexEnquirer;
   49.55 +import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.MapIndices;
   49.56 +import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.Scope;
   49.57 +import org.netbeans.modules.java.hints.providers.spi.HintDescription;
   49.58 +import org.openide.filesystems.FileObject;
   49.59 +import org.openide.util.Lookup;
   49.60 +
   49.61 +/**
   49.62 + *
   49.63 + * @author lahvac
   49.64 + */
   49.65 +public class Scopes {
   49.66 +
   49.67 +    public static Scope allOpenedProjectsScope() {
   49.68 +        return new AllOpenedProjectsScope();
   49.69 +    }
   49.70 +
   49.71 +    private static final class AllOpenedProjectsScope extends Scope {
   49.72 +
   49.73 +        @Override
   49.74 +        public String getDisplayName() {
   49.75 +            return "All Opened Projects";
   49.76 +        }
   49.77 +
   49.78 +        @Override
   49.79 +        public Collection<? extends Folder> getTodo() {
   49.80 +            Set<Folder> todo = new HashSet<Folder>();
   49.81 +
   49.82 +            for (ClassPath source : GlobalPathRegistry.getDefault().getPaths(ClassPath.SOURCE)) {
   49.83 +                todo.addAll(Arrays.asList(Folder.convert(source.getRoots())));
   49.84 +            }
   49.85 +
   49.86 +            return todo;
   49.87 +        }
   49.88 +
   49.89 +        @Override
   49.90 +        public MapIndices getIndexMapper(Iterable<? extends HintDescription> hints) {
   49.91 +            return getDefaultIndicesMapper();
   49.92 +        }
   49.93 +    }
   49.94 +
   49.95 +    public static Scope specifiedFoldersScope(Folder... roots) {
   49.96 +        return new SpecificFoldersScope(roots);
   49.97 +    }
   49.98 +    
   49.99 +    private static final class SpecificFoldersScope extends Scope {
  49.100 +
  49.101 +        private final Collection<? extends Folder> roots;
  49.102 +
  49.103 +        public SpecificFoldersScope(Folder... roots) {
  49.104 +            this.roots = Arrays.asList(roots);
  49.105 +        }
  49.106 +
  49.107 +        @Override
  49.108 +        public String getDisplayName() {
  49.109 +            return "Specified Root";
  49.110 +        }
  49.111 +
  49.112 +        @Override
  49.113 +        public Collection<? extends Folder> getTodo() {
  49.114 +            return roots;
  49.115 +        }
  49.116 +
  49.117 +        @Override
  49.118 +        public MapIndices getIndexMapper(Iterable<? extends HintDescription> hints) {
  49.119 +            return getDefaultIndicesMapper();
  49.120 +        }
  49.121 +    }
  49.122 +
  49.123 +    public static MapIndices getDefaultIndicesMapper() {
  49.124 +        return new MapIndices() {
  49.125 +            @Override
  49.126 +            public IndexEnquirer findIndex(FileObject root, ProgressHandleWrapper progress, boolean recursive) {
  49.127 +                IndexEnquirer e = findIndexEnquirer(root, progress, recursive);
  49.128 +
  49.129 +                if (e != null) return e;
  49.130 +                else return new BatchSearch.FileSystemBasedIndexEnquirer(root, recursive);
  49.131 +            }
  49.132 +        };
  49.133 +    }
  49.134 +    
  49.135 +    public static IndexEnquirer findIndexEnquirer(FileObject root, ProgressHandleWrapper progress, boolean recursive) {
  49.136 +        for (MapIndices mi : Lookup.getDefault().lookupAll(MapIndices.class)) {
  49.137 +            IndexEnquirer r = mi.findIndex(root, progress, recursive);
  49.138 +
  49.139 +            if (r != null) return r;
  49.140 +        }
  49.141 +
  49.142 +        return null;
  49.143 +    }
  49.144 +}
    50.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    50.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/hints/HintsInvoker.java	Wed May 08 21:47:42 2013 +0200
    50.3 @@ -0,0 +1,862 @@
    50.4 +/*
    50.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    50.6 + *
    50.7 + * Copyright 2008-2010 Oracle and/or its affiliates. All rights reserved.
    50.8 + *
    50.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   50.10 + * Other names may be trademarks of their respective owners.
   50.11 + *
   50.12 + * The contents of this file are subject to the terms of either the GNU
   50.13 + * General Public License Version 2 only ("GPL") or the Common
   50.14 + * Development and Distribution License("CDDL") (collectively, the
   50.15 + * "License"). You may not use this file except in compliance with the
   50.16 + * License. You can obtain a copy of the License at
   50.17 + * http://www.netbeans.org/cddl-gplv2.html
   50.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   50.19 + * specific language governing permissions and limitations under the
   50.20 + * License.  When distributing the software, include this License Header
   50.21 + * Notice in each file and include the License file at
   50.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   50.23 + * particular file as subject to the "Classpath" exception as provided
   50.24 + * by Oracle in the GPL Version 2 section of the License file that
   50.25 + * accompanied this code. If applicable, add the following below the
   50.26 + * License Header, with the fields enclosed by brackets [] replaced by
   50.27 + * your own identifying information:
   50.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   50.29 + *
   50.30 + * If you wish your version of this file to be governed by only the CDDL
   50.31 + * or only the GPL Version 2, indicate your decision by adding
   50.32 + * "[Contributor] elects to include this software in this distribution
   50.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   50.34 + * single choice of license, a recipient has the option to distribute
   50.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   50.36 + * to extend the choice of license to its licensees as provided above.
   50.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   50.38 + * Version 2 license, then the option applies only if the new code is
   50.39 + * made subject to such option by the copyright holder.
   50.40 + *
   50.41 + * Contributor(s):
   50.42 + *
   50.43 + * Portions Copyrighted 2008-2010 Sun Microsystems, Inc.
   50.44 + */
   50.45 +
   50.46 +package org.netbeans.modules.java.hints.spiimpl.hints;
   50.47 +
   50.48 +import com.sun.source.tree.Tree;
   50.49 +import java.util.Stack;
   50.50 +import java.util.concurrent.atomic.AtomicBoolean;
   50.51 +import javax.lang.model.element.AnnotationMirror;
   50.52 +import javax.lang.model.element.AnnotationValue;
   50.53 +import javax.lang.model.element.Element;
   50.54 +import javax.lang.model.element.ExecutableElement;
   50.55 +import javax.lang.model.element.TypeElement;
   50.56 +import javax.swing.text.Document;
   50.57 +import org.netbeans.api.java.source.support.CancellableTreePathScanner;
   50.58 +import org.netbeans.editor.GuardedDocument;
   50.59 +import org.netbeans.editor.MarkBlock;
   50.60 +import org.netbeans.editor.MarkBlockChain;
   50.61 +import org.openide.filesystems.FileObject;
   50.62 +
   50.63 +import com.sun.source.tree.Tree.Kind;
   50.64 +import com.sun.source.util.TreePath;
   50.65 +import com.sun.source.util.Trees;
   50.66 +import java.io.IOException;
   50.67 +import java.util.ArrayList;
   50.68 +import java.util.Arrays;
   50.69 +import java.util.Collection;
   50.70 +import java.util.Collections;
   50.71 +import java.util.Comparator;
   50.72 +import java.util.EnumMap;
   50.73 +import java.util.HashMap;
   50.74 +import java.util.HashSet;
   50.75 +import java.util.Iterator;
   50.76 +import java.util.LinkedList;
   50.77 +import java.util.List;
   50.78 +import java.util.Map;
   50.79 +import java.util.Map.Entry;
   50.80 +import java.util.Set;
   50.81 +import java.util.prefs.Preferences;
   50.82 +import javax.annotation.processing.ProcessingEnvironment;
   50.83 +import javax.lang.model.type.TypeKind;
   50.84 +import javax.lang.model.type.TypeMirror;
   50.85 +import org.netbeans.api.annotations.common.CheckForNull;
   50.86 +import org.netbeans.api.java.source.CompilationInfo;
   50.87 +import org.netbeans.modules.java.hints.spiimpl.Hacks;
   50.88 +import org.netbeans.spi.java.hints.HintContext;
   50.89 +import org.netbeans.modules.java.hints.providers.spi.HintDescription;
   50.90 +import org.netbeans.modules.java.hints.providers.spi.HintMetadata;
   50.91 +import org.netbeans.modules.java.hints.providers.spi.Trigger;
   50.92 +import org.netbeans.modules.java.hints.providers.spi.Trigger.Kinds;
   50.93 +import org.netbeans.modules.java.hints.providers.spi.Trigger.PatternDescription;
   50.94 +import org.netbeans.modules.java.hints.spiimpl.options.HintsSettings;
   50.95 +import org.netbeans.modules.java.hints.spiimpl.MessageImpl;
   50.96 +import org.netbeans.modules.java.hints.spiimpl.RulesManager;
   50.97 +import org.netbeans.modules.java.hints.spiimpl.SPIAccessor;
   50.98 +import org.netbeans.modules.java.hints.spiimpl.Utilities;
   50.99 +import org.netbeans.modules.java.hints.spiimpl.pm.BulkSearch;
  50.100 +import org.netbeans.modules.java.hints.spiimpl.pm.BulkSearch.BulkPattern;
  50.101 +import org.netbeans.modules.java.hints.spiimpl.pm.PatternCompiler;
  50.102 +import org.netbeans.spi.editor.hints.ErrorDescription;
  50.103 +import org.netbeans.spi.editor.hints.Severity;
  50.104 +import org.netbeans.spi.java.hints.Hint;
  50.105 +import org.netbeans.api.java.source.matching.Matcher;
  50.106 +import org.netbeans.api.java.source.matching.Occurrence;
  50.107 +import org.netbeans.api.java.source.matching.Pattern;
  50.108 +import org.openide.util.Exceptions;
  50.109 +
  50.110 +/**
  50.111 + *
  50.112 + * @author lahvac
  50.113 + */
  50.114 +public class HintsInvoker {
  50.115 +
  50.116 +    private final Map<String, Long> timeLog = new HashMap<String, Long>();
  50.117 +
  50.118 +    private final HintsSettings settings;
  50.119 +    private final int caret;
  50.120 +    private final int from;
  50.121 +    private final int to;
  50.122 +    private final boolean bulkMode;
  50.123 +    private final AtomicBoolean cancel;
  50.124 +
  50.125 +    public HintsInvoker(HintsSettings settings, AtomicBoolean cancel) {
  50.126 +        this(settings, false, cancel);
  50.127 +    }
  50.128 +
  50.129 +    public HintsInvoker(HintsSettings settings, boolean bulkMode, AtomicBoolean cancel) {
  50.130 +        this(settings, -1, -1, -1, bulkMode, cancel);
  50.131 +    }
  50.132 +
  50.133 +    public HintsInvoker(HintsSettings settings, int caret, AtomicBoolean cancel) {
  50.134 +        this(settings, caret, -1, -1, false, cancel);
  50.135 +    }
  50.136 +
  50.137 +    public HintsInvoker(HintsSettings settings, int from, int to, AtomicBoolean cancel) {
  50.138 +        this(settings, -1, from, to, false, cancel);
  50.139 +    }
  50.140 +
  50.141 +    private HintsInvoker(HintsSettings settings, int caret, int from, int to, boolean bulkMode, AtomicBoolean cancel) {
  50.142 +        this.settings = settings;
  50.143 +        this.caret = caret;
  50.144 +        this.from = from;
  50.145 +        this.to = to;
  50.146 +        this.bulkMode = bulkMode;
  50.147 +        this.cancel = cancel;
  50.148 +    }
  50.149 +
  50.150 +    @CheckForNull
  50.151 +    public List<ErrorDescription> computeHints(CompilationInfo info) {
  50.152 +        return computeHints(info, new TreePath(info.getCompilationUnit()));
  50.153 +    }
  50.154 +
  50.155 +    private List<ErrorDescription> computeHints(CompilationInfo info, TreePath startAt) {
  50.156 +        List<HintDescription> descs = new LinkedList<HintDescription>();
  50.157 +        Map<HintMetadata, ? extends Collection<? extends HintDescription>> allHints = RulesManager.getInstance().readHints(info, null, cancel);
  50.158 +
  50.159 +        for (Entry<HintMetadata, ? extends Collection<? extends HintDescription>> e : allHints.entrySet()) {
  50.160 +            HintMetadata m = e.getKey();
  50.161 +
  50.162 +            if (!settings.isEnabled(m)) {
  50.163 +                continue;
  50.164 +            }
  50.165 +
  50.166 +            if (caret != -1) {
  50.167 +                if (m.kind == Hint.Kind.ACTION) {
  50.168 +                    descs.addAll(e.getValue());
  50.169 +                } else {
  50.170 +                    if (settings.getSeverity(m) == Severity.HINT) {
  50.171 +                        descs.addAll(e.getValue());
  50.172 +                    }
  50.173 +                }
  50.174 +            } else {
  50.175 +                if (m.kind == Hint.Kind.INSPECTION) {
  50.176 +                    if (settings.getSeverity(m) != Severity.HINT) {
  50.177 +                        descs.addAll(e.getValue());
  50.178 +                    }
  50.179 +                }
  50.180 +            }
  50.181 +        }
  50.182 +
  50.183 +        List<ErrorDescription> errors = join(computeHints(info, startAt, descs, new LinkedList<MessageImpl>()));
  50.184 +
  50.185 +        dumpTimeSpentInHints();
  50.186 +        
  50.187 +        return errors;
  50.188 +    }
  50.189 +
  50.190 +    @CheckForNull
  50.191 +    public List<ErrorDescription> computeHints(CompilationInfo info,
  50.192 +                                               Iterable<? extends HintDescription> hints) {
  50.193 +        return computeHints(info, hints, new LinkedList<MessageImpl>());
  50.194 +    }
  50.195 +
  50.196 +    @CheckForNull
  50.197 +    public List<ErrorDescription> computeHints(CompilationInfo info,
  50.198 +                                               Iterable<? extends HintDescription> hints,
  50.199 +                                               Collection<? super MessageImpl> problems) {
  50.200 +        return join(computeHints(info, new TreePath(info.getCompilationUnit()), hints, problems));
  50.201 +    }
  50.202 +
  50.203 +    private static final Iterable<? extends Class<? extends Trigger>> TRIGGER_KINDS = Arrays.asList(Kinds.class, PatternDescription.class);
  50.204 +    
  50.205 +    @CheckForNull
  50.206 +    public Map<HintDescription, List<ErrorDescription>> computeHints(CompilationInfo info,
  50.207 +                                        TreePath startAt,
  50.208 +                                        Iterable<? extends HintDescription> hints,
  50.209 +                                        Collection<? super MessageImpl> problems) {
  50.210 +        return computeHints(info, startAt, true, hints, problems);
  50.211 +    }
  50.212 +    
  50.213 +    @CheckForNull
  50.214 +    public Map<HintDescription, List<ErrorDescription>> computeHints(CompilationInfo info,
  50.215 +                                        TreePath startAt,
  50.216 +                                        boolean recursive,
  50.217 +                                        Iterable<? extends HintDescription> hints,
  50.218 +                                        Collection<? super MessageImpl> problems) {
  50.219 +        Map<Class, List<HintDescription>> triggerKind2Hints = new HashMap<Class, List<HintDescription>>();
  50.220 +
  50.221 +        for (Class<? extends Trigger> c : TRIGGER_KINDS) {
  50.222 +            triggerKind2Hints.put(c, new ArrayList<HintDescription>());
  50.223 +        }
  50.224 +
  50.225 +        for (HintDescription hd : hints) {
  50.226 +            List<HintDescription> sorted = triggerKind2Hints.get(hd.getTrigger().getClass());
  50.227 +
  50.228 +            sorted.add(hd);
  50.229 +        }
  50.230 +
  50.231 +        if (caret != -1) {
  50.232 +            TreePath tp = info.getTreeUtilities().pathFor(caret);
  50.233 +            return computeSuggestions(info, tp, true, triggerKind2Hints, problems);
  50.234 +        } else {
  50.235 +            if (from != (-1) && to != (-1)) {
  50.236 +                return computeHintsInSpan(info, triggerKind2Hints, problems);
  50.237 +            } else if (!recursive) {
  50.238 +                return computeSuggestions(info, startAt, false, triggerKind2Hints, problems);
  50.239 +            } else {
  50.240 +                return computeHintsImpl(info, startAt, triggerKind2Hints, problems);
  50.241 +            }
  50.242 +        }
  50.243 +    }
  50.244 +
  50.245 +    private Map<HintDescription, List<ErrorDescription>> computeHintsImpl(CompilationInfo info,
  50.246 +                                        TreePath startAt,
  50.247 +                                        Map<Class, List<HintDescription>> triggerKind2Hints,
  50.248 +                                        Collection<? super MessageImpl> problems) {
  50.249 +        Map<HintDescription, List<ErrorDescription>> errors = new HashMap<HintDescription, List<ErrorDescription>>();
  50.250 +        List<HintDescription> kindBasedHints = triggerKind2Hints.get(Kinds.class);
  50.251 +
  50.252 +        timeLog.put("[C] Kind Based Hints", (long) kindBasedHints.size());
  50.253 +
  50.254 +        if (!kindBasedHints.isEmpty()) {
  50.255 +            long kindStart = System.currentTimeMillis();
  50.256 +
  50.257 +            new ScannerImpl(info, cancel, sortByKinds(kindBasedHints), problems).scan(startAt, errors);
  50.258 +
  50.259 +            long kindEnd = System.currentTimeMillis();
  50.260 +
  50.261 +            timeLog.put("Kind Based Hints", kindEnd - kindStart);
  50.262 +        }
  50.263 +
  50.264 +        if (cancel.get()) return null;
  50.265 +        
  50.266 +        List<HintDescription> patternBasedHints = triggerKind2Hints.get(PatternDescription.class);
  50.267 +
  50.268 +        timeLog.put("[C] Pattern Based Hints", (long) patternBasedHints.size());
  50.269 +
  50.270 +        long patternStart = System.currentTimeMillis();
  50.271 +
  50.272 +        Map<PatternDescription, List<HintDescription>> patternHints = sortByPatterns(patternBasedHints);
  50.273 +        Map<String, List<PatternDescription>> patternTests = computePatternTests(patternHints);
  50.274 +
  50.275 +        long bulkPatternStart = System.currentTimeMillis();
  50.276 +
  50.277 +        BulkPattern bulkPattern = BulkSearch.getDefault().create(info, cancel, patternTests.keySet());
  50.278 +
  50.279 +        if (bulkPattern == null || cancel.get()) return null;
  50.280 +        
  50.281 +        long bulkPatternEnd = System.currentTimeMillis();
  50.282 +
  50.283 +        timeLog.put("Bulk Pattern preparation", bulkPatternEnd - bulkPatternStart);
  50.284 +
  50.285 +        long bulkStart = System.currentTimeMillis();
  50.286 +
  50.287 +        Map<String, Collection<TreePath>> occurringPatterns = BulkSearch.getDefault().match(info, cancel, startAt, bulkPattern, timeLog);
  50.288 +        
  50.289 +        if (occurringPatterns == null || cancel.get()) return null;
  50.290 +
  50.291 +        long bulkEnd = System.currentTimeMillis();
  50.292 +
  50.293 +        timeLog.put("Bulk Search", bulkEnd - bulkStart);
  50.294 +        
  50.295 +        Map<HintDescription, List<ErrorDescription>> computedHints = doComputeHints(info, occurringPatterns, patternTests, patternHints, problems);
  50.296 +
  50.297 +        if (computedHints == null || cancel.get()) return null;
  50.298 +        
  50.299 +        mergeAll(errors, computedHints);
  50.300 +
  50.301 +        long patternEnd = System.currentTimeMillis();
  50.302 +
  50.303 +        timeLog.put("Pattern Based Hints", patternEnd - patternStart);
  50.304 +
  50.305 +        return errors;
  50.306 +    }
  50.307 +
  50.308 +    private Map<HintDescription, List<ErrorDescription>> computeHintsInSpan(CompilationInfo info,
  50.309 +                                        Map<Class, List<HintDescription>> triggerKind2Hints,
  50.310 +                                        Collection<? super MessageImpl> problems) {
  50.311 +
  50.312 +        TreePath path = info.getTreeUtilities().pathFor((from + to) / 2);
  50.313 +
  50.314 +        while (path.getLeaf().getKind() != Kind.COMPILATION_UNIT) {
  50.315 +            int start = (int) info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), path.getLeaf());
  50.316 +            int end = (int) info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), path.getLeaf());
  50.317 +
  50.318 +            if (start <= from && end >= to) {
  50.319 +                break;
  50.320 +            }
  50.321 +
  50.322 +            path = path.getParentPath();
  50.323 +        }
  50.324 +
  50.325 +        Map<HintDescription, List<ErrorDescription>> errors = new HashMap<HintDescription, List<ErrorDescription>>();
  50.326 +        List<HintDescription> kindBasedHints = triggerKind2Hints.get(Kinds.class);
  50.327 +
  50.328 +        if (!kindBasedHints.isEmpty()) {
  50.329 +            long kindStart = System.currentTimeMillis();
  50.330 +
  50.331 +            new ScannerImpl(info, cancel, sortByKinds(kindBasedHints), problems).scan(path, errors);
  50.332 +
  50.333 +            long kindEnd = System.currentTimeMillis();
  50.334 +
  50.335 +            timeLog.put("Kind Based Hints", kindEnd - kindStart);
  50.336 +        }
  50.337 +
  50.338 +        List<HintDescription> patternBasedHints = triggerKind2Hints.get(PatternDescription.class);
  50.339 +
  50.340 +        if (!patternBasedHints.isEmpty()) {
  50.341 +            long patternStart = System.currentTimeMillis();
  50.342 +
  50.343 +            Map<PatternDescription, List<HintDescription>> patternHints = sortByPatterns(patternBasedHints);
  50.344 +            Map<String, List<PatternDescription>> patternTests = computePatternTests(patternHints);
  50.345 +
  50.346 +            long bulkStart = System.currentTimeMillis();
  50.347 +
  50.348 +            BulkPattern bulkPattern = BulkSearch.getDefault().create(info, cancel, patternTests.keySet());
  50.349 +            
  50.350 +            if (bulkPattern == null || cancel.get()) return null;
  50.351 +            
  50.352 +            Map<String, Collection<TreePath>> occurringPatterns = BulkSearch.getDefault().match(info, cancel, path, bulkPattern, timeLog);
  50.353 +
  50.354 +            long bulkEnd = System.currentTimeMillis();
  50.355 +
  50.356 +            timeLog.put("Bulk Search", bulkEnd - bulkStart);
  50.357 +            
  50.358 +            Map<HintDescription, List<ErrorDescription>> computedHints = doComputeHints(info, occurringPatterns, patternTests, patternHints, problems);
  50.359 +
  50.360 +            if (computedHints == null || cancel.get()) return null;
  50.361 +            
  50.362 +            mergeAll(errors, computedHints);
  50.363 +
  50.364 +            long patternEnd = System.currentTimeMillis();
  50.365 +
  50.366 +            timeLog.put("Pattern Based Hints", patternEnd - patternStart);
  50.367 +        }
  50.368 +
  50.369 +        if (path != null) {
  50.370 +            Map<HintDescription, List<ErrorDescription>> suggestions = computeSuggestions(info, path, true, triggerKind2Hints, problems);
  50.371 +            
  50.372 +            if (suggestions == null || cancel.get()) return null;
  50.373 +            
  50.374 +            mergeAll(errors, suggestions);
  50.375 +        }
  50.376 +
  50.377 +        return errors;
  50.378 +    }
  50.379 +
  50.380 +    private Map<HintDescription, List<ErrorDescription>> computeSuggestions(CompilationInfo info,
  50.381 +                                        TreePath workOn,
  50.382 +                                        boolean up,
  50.383 +                                        Map<Class, List<HintDescription>> triggerKind2Hints,
  50.384 +                                        Collection<? super MessageImpl> problems) {
  50.385 +        Map<HintDescription, List<ErrorDescription>> errors = new HashMap<HintDescription, List<ErrorDescription>>();
  50.386 +        List<HintDescription> kindBasedHints = triggerKind2Hints.get(Kinds.class);
  50.387 +
  50.388 +        if (!kindBasedHints.isEmpty()) {
  50.389 +            long kindStart = System.currentTimeMillis();
  50.390 +            
  50.391 +            Map<Kind, List<HintDescription>> hints = sortByKinds(kindBasedHints);
  50.392 +            TreePath proc = workOn;
  50.393 +
  50.394 +            while (proc != null) {
  50.395 +                new ScannerImpl(info, cancel, hints, problems).scanDoNotGoDeeper(proc, errors);
  50.396 +                if (!up) break;
  50.397 +                proc = proc.getParentPath();
  50.398 +            }
  50.399 +
  50.400 +            long kindEnd = System.currentTimeMillis();
  50.401 +
  50.402 +            timeLog.put("Kind Based Suggestions", kindEnd - kindStart);
  50.403 +        }
  50.404 +        
  50.405 +        if (cancel.get()) return null;
  50.406 +
  50.407 +        List<HintDescription> patternBasedHints = triggerKind2Hints.get(PatternDescription.class);
  50.408 +
  50.409 +        if (!patternBasedHints.isEmpty()) {
  50.410 +            long patternStart = System.currentTimeMillis();
  50.411 +
  50.412 +            Map<PatternDescription, List<HintDescription>> patternHints = sortByPatterns(patternBasedHints);
  50.413 +            Map<String, List<PatternDescription>> patternTests = computePatternTests(patternHints);
  50.414 +
  50.415 +            //pretend that all the patterns occur on all treepaths from the current path
  50.416 +            //up (probably faster than using BulkSearch over whole file)
  50.417 +            //TODO: what about machint trees under the current path?
  50.418 +            Set<TreePath> paths = new HashSet<TreePath>();
  50.419 +
  50.420 +            TreePath tp = workOn;
  50.421 +
  50.422 +            while (tp != null) {
  50.423 +                paths.add(tp);
  50.424 +                if (!up) break;
  50.425 +                tp = tp.getParentPath();
  50.426 +            }
  50.427 +
  50.428 +            Map<String, Collection<TreePath>> occurringPatterns = new HashMap<String, Collection<TreePath>>();
  50.429 +
  50.430 +            for (String p : patternTests.keySet()) {
  50.431 +                occurringPatterns.put(p, paths);
  50.432 +            }
  50.433 +
  50.434 +//            long bulkStart = System.currentTimeMillis();
  50.435 +//
  50.436 +//            BulkPattern bulkPattern = BulkSearch.getDefault().create(info, patternTests.keySet());
  50.437 +//            Map<String, Collection<TreePath>> occurringPatterns = BulkSearch.getDefault().match(info, new TreePath(info.getCompilationUnit()), bulkPattern, timeLog);
  50.438 +//
  50.439 +//            long bulkEnd = System.currentTimeMillis();
  50.440 +//
  50.441 +//            Set<Tree> acceptedLeafs = new HashSet<Tree>();
  50.442 +//
  50.443 +//            TreePath tp = workOn;
  50.444 +//
  50.445 +//            while (tp != null) {
  50.446 +//                acceptedLeafs.add(tp.getLeaf());
  50.447 +//                tp = tp.getParentPath();
  50.448 +//            }
  50.449 +//
  50.450 +//            for (Entry<String, Collection<TreePath>> e : occurringPatterns.entrySet()) {
  50.451 +//                for (Iterator<TreePath> it = e.getValue().iterator(); it.hasNext(); ) {
  50.452 +//                    if (!acceptedLeafs.contains(it.next().getLeaf())) {
  50.453 +//                        it.remove();
  50.454 +//                    }
  50.455 +//                }
  50.456 +//            }
  50.457 +//
  50.458 +//            timeLog.put("Bulk Search", bulkEnd - bulkStart);
  50.459 +
  50.460 +            Map<HintDescription, List<ErrorDescription>> computed = doComputeHints(info, occurringPatterns, patternTests, patternHints, problems);
  50.461 +            
  50.462 +            if (computed == null || cancel.get()) return null;
  50.463 +            
  50.464 +            mergeAll(errors, computed);
  50.465 +
  50.466 +            long patternEnd = System.currentTimeMillis();
  50.467 +
  50.468 +            timeLog.put("Pattern Based Hints", patternEnd - patternStart);
  50.469 +        }
  50.470 +
  50.471 +        return errors;
  50.472 +    }
  50.473 +
  50.474 +    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 {
  50.475 +        return doComputeHints(info, occurringPatterns, patterns, patternHints, new LinkedList<MessageImpl>());
  50.476 +    }
  50.477 +
  50.478 +    private static Map<Kind, List<HintDescription>> sortByKinds(List<HintDescription> kindBasedHints) {
  50.479 +        Map<Kind, List<HintDescription>> result = new EnumMap<Kind, List<HintDescription>>(Kind.class);
  50.480 +
  50.481 +        for (HintDescription hd : kindBasedHints) {
  50.482 +            for (Kind k : ((Kinds) hd.getTrigger()).getKinds()) {
  50.483 +                List<HintDescription> hints = result.get(k);
  50.484 +
  50.485 +                if (hints == null) {
  50.486 +                    result.put(k, hints = new ArrayList<HintDescription>());
  50.487 +                }
  50.488 +
  50.489 +                hints.add(hd);
  50.490 +            }
  50.491 +        }
  50.492 +
  50.493 +        return result;
  50.494 +    }
  50.495 +
  50.496 +    private static Map<PatternDescription, List<HintDescription>> sortByPatterns(List<HintDescription> kindBasedHints) {
  50.497 +        Map<PatternDescription, List<HintDescription>> result = new HashMap<PatternDescription, List<HintDescription>>();
  50.498 +
  50.499 +        for (HintDescription hd : kindBasedHints) {
  50.500 +            List<HintDescription> hints = result.get((PatternDescription) hd.getTrigger());
  50.501 +
  50.502 +            if (hints == null) {
  50.503 +                result.put((PatternDescription) hd.getTrigger(), hints = new ArrayList<HintDescription>());
  50.504 +            }
  50.505 +
  50.506 +            hints.add(hd);
  50.507 +        }
  50.508 +
  50.509 +        return result;
  50.510 +    }
  50.511 +
  50.512 +    public static Map<String, List<PatternDescription>> computePatternTests(Map<PatternDescription, List<HintDescription>> patternHints) {
  50.513 +        Map<String, List<PatternDescription>> patternTests = new HashMap<String, List<PatternDescription>>();
  50.514 +        for (Entry<PatternDescription, List<HintDescription>> e : patternHints.entrySet()) {
  50.515 +            String p = e.getKey().getPattern();
  50.516 +            List<PatternDescription> descs = patternTests.get(p);
  50.517 +            if (descs == null) {
  50.518 +                patternTests.put(p, descs = new LinkedList<PatternDescription>());
  50.519 +            }
  50.520 +            descs.add(e.getKey());
  50.521 +        }
  50.522 +        return patternTests;
  50.523 +    }
  50.524 +
  50.525 +    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 {
  50.526 +        Map<HintDescription, List<ErrorDescription>> errors = new HashMap<HintDescription, List<ErrorDescription>>();
  50.527 +
  50.528 +        for (Entry<String, Collection<TreePath>> occ : occurringPatterns.entrySet()) {
  50.529 +            PATTERN_LOOP: for (PatternDescription d : patterns.get(occ.getKey())) {
  50.530 +                if (cancel.get()) return null;
  50.531 +                
  50.532 +                Map<String, TypeMirror> constraints = new HashMap<String, TypeMirror>();
  50.533 +
  50.534 +                for (Entry<String, String> e : d.getConstraints().entrySet()) {
  50.535 +                    TypeMirror designedType = Hacks.parseFQNType(info, e.getValue());
  50.536 +
  50.537 +                    if (designedType == null || designedType.getKind() == TypeKind.ERROR) {
  50.538 +                        //will not bind to anything anyway (#190449), skip pattern:
  50.539 +                        continue PATTERN_LOOP;
  50.540 +                    }
  50.541 +
  50.542 +                    constraints.put(e.getKey(), designedType);
  50.543 +                }
  50.544 +
  50.545 +                Pattern pattern = PatternCompiler.compile(info, occ.getKey(), constraints, d.getImports());
  50.546 +
  50.547 +                for (TreePath candidate : occ.getValue()) {
  50.548 +                    if (cancel.get()) return null;
  50.549 +                
  50.550 +                    Iterator<? extends Occurrence> verified = Matcher.create(info).setCancel(cancel).setSearchRoot(candidate).setTreeTopSearch().match(pattern).iterator();
  50.551 +
  50.552 +                    if (!verified.hasNext()) {
  50.553 +                        continue;
  50.554 +                    }
  50.555 +
  50.556 +                    Set<String> suppressedWarnings = new HashSet<String>(Utilities.findSuppressedWarnings(info, candidate));
  50.557 +                    Occurrence verifiedVariables = verified.next();
  50.558 +
  50.559 +                    for (HintDescription hd : patternHints.get(d)) {
  50.560 +                        HintMetadata hm = hd.getMetadata();
  50.561 +                        HintContext c = SPIAccessor.getINSTANCE().createHintContext(info, settings, hm, candidate, verifiedVariables.getVariables(), verifiedVariables.getMultiVariables(), verifiedVariables.getVariables2Names(), constraints, problems, bulkMode, cancel, caret);
  50.562 +
  50.563 +                        if (!Collections.disjoint(suppressedWarnings, hm.suppressWarnings))
  50.564 +                            continue;
  50.565 +
  50.566 +                        Collection<? extends ErrorDescription> workerErrors = runHint(hd, c);
  50.567 +
  50.568 +                        if (workerErrors != null) {
  50.569 +                            merge(errors, hd, workerErrors);
  50.570 +                        }
  50.571 +                    }
  50.572 +                }
  50.573 +            }
  50.574 +        }
  50.575 +
  50.576 +        return errors;
  50.577 +    }
  50.578 +
  50.579 +//    public static void computeHints(URI file, ProcessingEnvironment env, CompilationUnitTree cut, RulesManager m) {
  50.580 +//        Map<Kind, HintDescription> hints = m.getKindBasedHints();
  50.581 +//
  50.582 +//        if (hints.isEmpty()) {
  50.583 +//            return ;
  50.584 +//        }
  50.585 +//
  50.586 +//        List<ErrorDescription> errors = new  LinkedList<ErrorDescription>();
  50.587 +//
  50.588 +//        File af = new File(file.getPath());
  50.589 +//        FileObject f = FileUtil.toFileObject(af);
  50.590 +//
  50.591 +//        new ScannerImpl(f, env, hints).scan(cut, errors);
  50.592 +//
  50.593 +//        for (ErrorDescription ed : errors) {
  50.594 +//            Diagnostic.Kind k;
  50.595 +//
  50.596 +//            switch (ed.getSeverity()) {
  50.597 +//                case ERROR:
  50.598 +//                    k = Diagnostic.Kind.ERROR;
  50.599 +//                    break;
  50.600 +//                default:
  50.601 +//                    k = Diagnostic.Kind.WARNING;
  50.602 +//                    break;
  50.603 +//            }
  50.604 +//
  50.605 +//            env.getMessager().printMessage(k, ed.getDescription());
  50.606 +//        }
  50.607 +//    }
  50.608 +
  50.609 +    public Map<String, Long> getTimeLog() {
  50.610 +        return timeLog;
  50.611 +    }
  50.612 +
  50.613 +    private final class ScannerImpl extends CancellableTreePathScanner<Void, Map<HintDescription, List<ErrorDescription>>> {
  50.614 +
  50.615 +        private final Stack<Set<String>> suppresWarnings = new Stack<Set<String>>();
  50.616 +        private final CompilationInfo info;
  50.617 +        private final FileObject file;
  50.618 +        private final ProcessingEnvironment env;
  50.619 +        private final Map<Kind, List<HintDescription>> hints;
  50.620 +        private final Collection<? super MessageImpl> problems;
  50.621 +        
  50.622 +        public ScannerImpl(CompilationInfo info, AtomicBoolean cancel, Map<Kind, List<HintDescription>> hints, Collection<? super MessageImpl> problems) {
  50.623 +            super(cancel);
  50.624 +            this.info = info;
  50.625 +            this.file = null;
  50.626 +            this.env  = null;
  50.627 +            this.hints = hints;
  50.628 +            this.problems = problems;
  50.629 +        }
  50.630 +
  50.631 +        public ScannerImpl(FileObject file, ProcessingEnvironment env, Map<Kind, List<HintDescription>> hints, Collection<? super MessageImpl> problems) {
  50.632 +            super(new AtomicBoolean());
  50.633 +            this.info = null;
  50.634 +            this.file = file;
  50.635 +            this.env = env;
  50.636 +            this.hints = hints;
  50.637 +            this.problems = problems;
  50.638 +        }
  50.639 +
  50.640 +        private void runAndAdd(TreePath path, List<HintDescription> rules, Map<HintDescription, List<ErrorDescription>> d) {
  50.641 +            if (rules != null && !isInGuarded(info, path)) {
  50.642 +                OUTER: for (HintDescription hd : rules) {
  50.643 +                    if (isCanceled()) {
  50.644 +                        return ;
  50.645 +                    }
  50.646 +
  50.647 +                    HintMetadata hm = hd.getMetadata();
  50.648 +
  50.649 +                    for (String wname : hm.suppressWarnings) {
  50.650 +                        if( !suppresWarnings.empty() && suppresWarnings.peek().contains(wname)) {
  50.651 +                            continue OUTER;
  50.652 +                        }
  50.653 +                    }
  50.654 +
  50.655 +                    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);
  50.656 +                    Collection<? extends ErrorDescription> errors = runHint(hd, c);
  50.657 +
  50.658 +                    if (errors != null) {
  50.659 +                        merge(d, hd, errors);
  50.660 +                    }
  50.661 +                }
  50.662 +            }
  50.663 +        }
  50.664 +
  50.665 +        @Override
  50.666 +        public Void scan(Tree tree, Map<HintDescription, List<ErrorDescription>> p) {
  50.667 +            if (tree == null)
  50.668 +                return null;
  50.669 +
  50.670 +            TreePath tp = new TreePath(getCurrentPath(), tree);
  50.671 +            Kind k = tree.getKind();
  50.672 +
  50.673 +            boolean b = pushSuppressWarrnings(tp);
  50.674 +            try {
  50.675 +                runAndAdd(tp, hints.get(k), p);
  50.676 +
  50.677 +                if (isCanceled()) {
  50.678 +                    return null;
  50.679 +                }
  50.680 +
  50.681 +                return super.scan(tree, p);
  50.682 +            } finally {
  50.683 +                if (b) {
  50.684 +                    suppresWarnings.pop();
  50.685 +                }
  50.686 +            }
  50.687 +        }
  50.688 +
  50.689 +        @Override
  50.690 +        public Void scan(TreePath path, Map<HintDescription, List<ErrorDescription>> p) {
  50.691 +            Kind k = path.getLeaf().getKind();
  50.692 +            boolean b = pushSuppressWarrnings(path);
  50.693 +            try {
  50.694 +                runAndAdd(path, hints.get(k), p);
  50.695 +
  50.696 +                if (isCanceled()) {
  50.697 +                    return null;
  50.698 +                }
  50.699 +
  50.700 +                return super.scan(path, p);
  50.701 +            } finally {
  50.702 +                if (b) {
  50.703 +                    suppresWarnings.pop();
  50.704 +                }
  50.705 +            }
  50.706 +        }
  50.707 +
  50.708 +        public void scanDoNotGoDeeper(TreePath path, Map<HintDescription, List<ErrorDescription>> p) {
  50.709 +            Kind k = path.getLeaf().getKind();
  50.710 +            runAndAdd(path, hints.get(k), p);
  50.711 +        }
  50.712 +
  50.713 +        private boolean pushSuppressWarrnings(TreePath path) {
  50.714 +            switch(path.getLeaf().getKind()) {
  50.715 +                case ANNOTATION_TYPE:
  50.716 +                case CLASS:
  50.717 +                case ENUM:
  50.718 +                case INTERFACE:
  50.719 +                case METHOD:
  50.720 +                case VARIABLE:
  50.721 +                    Set<String> current = suppresWarnings.size() == 0 ? null : suppresWarnings.peek();
  50.722 +                    Set<String> nju = current == null ? new HashSet<String>() : new HashSet<String>(current);
  50.723 +
  50.724 +                    Element e = getTrees().getElement(path);
  50.725 +
  50.726 +                    if ( e != null) {
  50.727 +                        for (AnnotationMirror am : e.getAnnotationMirrors()) {
  50.728 +                            String name = ((TypeElement)am.getAnnotationType().asElement()).getQualifiedName().toString();
  50.729 +                            if ( "java.lang.SuppressWarnings".equals(name) ) { // NOI18N
  50.730 +                                Map<? extends ExecutableElement, ? extends AnnotationValue> elementValues = am.getElementValues();
  50.731 +                                for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : elementValues.entrySet()) {
  50.732 +                                    if( "value".equals(entry.getKey().getSimpleName().toString()) ) { // NOI18N
  50.733 +                                        Object value = entry.getValue().getValue();
  50.734 +                                        if ( value instanceof List) {
  50.735 +                                            for (Object av : (List)value) {
  50.736 +                                                if( av instanceof AnnotationValue ) {
  50.737 +                                                    Object wname = ((AnnotationValue)av).getValue();
  50.738 +                                                    if ( wname instanceof String ) {
  50.739 +                                                        nju.add((String)wname);
  50.740 +                                                    }
  50.741 +                                                }
  50.742 +                                            }
  50.743 +                                        }
  50.744 +                                    }
  50.745 +                                }
  50.746 +                            }
  50.747 +                        }
  50.748 +                    }
  50.749 +
  50.750 +                    suppresWarnings.push(nju);
  50.751 +                    return true;
  50.752 +            }
  50.753 +            return false;
  50.754 +        }
  50.755 +
  50.756 +        private Trees getTrees() {
  50.757 +            return info != null ? info.getTrees() : Trees.instance(env);
  50.758 +        }
  50.759 +    }
  50.760 +
  50.761 +    static boolean isInGuarded(CompilationInfo info, TreePath tree) {
  50.762 +        if (info == null) {
  50.763 +            return false;
  50.764 +        }
  50.765 +
  50.766 +        try {
  50.767 +            Document doc = info.getDocument();
  50.768 +
  50.769 +            if (doc instanceof GuardedDocument) {
  50.770 +                int start = (int) info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), tree.getLeaf());
  50.771 +                int end = (int) info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), tree.getLeaf());
  50.772 +                GuardedDocument gdoc = (GuardedDocument) doc;
  50.773 +                MarkBlockChain guardedBlockChain = gdoc.getGuardedBlockChain();
  50.774 +                if (guardedBlockChain.compareBlock(start, end) == MarkBlock.INNER) {
  50.775 +                    return true;
  50.776 +                }
  50.777 +            }
  50.778 +        } catch (IOException ex) {
  50.779 +            Exceptions.printStackTrace(ex);
  50.780 +        }
  50.781 +
  50.782 +        return false;
  50.783 +    }
  50.784 +
  50.785 +    private Collection<? extends ErrorDescription> runHint(HintDescription hd, HintContext ctx) {
  50.786 +        long start = System.nanoTime();
  50.787 +
  50.788 +        try {
  50.789 +            return hd.getWorker().createErrors(ctx);
  50.790 +        } finally {
  50.791 +            long end = System.nanoTime();
  50.792 +            reportSpentTime(hd.getMetadata().id, end - start);
  50.793 +        }
  50.794 +    }
  50.795 +
  50.796 +    public static <K, V> Map<K, List<V>> merge(Map<K, List<V>> to, K key, Collection<? extends V> value) {
  50.797 +        List<V> toColl = to.get(key);
  50.798 +
  50.799 +        if (toColl == null) {
  50.800 +            to.put(key, toColl = new LinkedList<V>());
  50.801 +        }
  50.802 +
  50.803 +        toColl.addAll(value);
  50.804 +
  50.805 +        return to;
  50.806 +    }
  50.807 +
  50.808 +    public static <K, V> Map<K, List<V>> mergeAll(Map<K, List<V>> to, Map<? extends K, ? extends Collection<? extends V>> what) {
  50.809 +        for (Entry<? extends K, ? extends Collection<? extends V>> e : what.entrySet()) {
  50.810 +            List<V> toColl = to.get(e.getKey());
  50.811 +
  50.812 +            if (toColl == null) {
  50.813 +                to.put(e.getKey(), toColl = new LinkedList<V>());
  50.814 +            }
  50.815 +
  50.816 +            toColl.addAll(e.getValue());
  50.817 +        }
  50.818 +
  50.819 +        return to;
  50.820 +    }
  50.821 +
  50.822 +    public static List<ErrorDescription> join(Map<?, ? extends List<? extends ErrorDescription>> errors) {
  50.823 +        if (errors == null) return null;
  50.824 +        
  50.825 +        List<ErrorDescription> result = new LinkedList<ErrorDescription>();
  50.826 +
  50.827 +        for (Entry<?, ? extends Collection<? extends ErrorDescription>> e : errors.entrySet()) {
  50.828 +            result.addAll(e.getValue());
  50.829 +        }
  50.830 +
  50.831 +        return result;
  50.832 +    }
  50.833 +
  50.834 +    private static final boolean logTimeSpentInHints = Boolean.getBoolean("java.HintsInvoker.time.in.hints");
  50.835 +    private final Map<String, Long> hint2SpentTime = new HashMap<String, Long>();
  50.836 +
  50.837 +    private void reportSpentTime(String id, long nanoTime) {
  50.838 +        if (!logTimeSpentInHints) return;
  50.839 +        
  50.840 +        Long prev = hint2SpentTime.get(id);
  50.841 +
  50.842 +        if (prev == null) {
  50.843 +            prev = (long) 0;
  50.844 +        }
  50.845 +
  50.846 +        hint2SpentTime.put(id, prev + nanoTime);
  50.847 +    }
  50.848 +
  50.849 +    private void dumpTimeSpentInHints() {
  50.850 +        if (!logTimeSpentInHints) return;
  50.851 +
  50.852 +        List<Entry<String, Long>> l = new ArrayList<Entry<String, Long>>(hint2SpentTime.entrySet());
  50.853 +
  50.854 +        Collections.sort(l, new Comparator<Entry<String, Long>>() {
  50.855 +            @Override
  50.856 +            public int compare(Entry<String, Long> o1, Entry<String, Long> o2) {
  50.857 +                return (int) Math.signum(o1.getValue() - o2.getValue());
  50.858 +            }
  50.859 +        });
  50.860 +
  50.861 +        for (Entry<String, Long> e : l) {
  50.862 +            System.err.println(e.getKey() + "=" + String.format("%3.2f", e.getValue() / 1000000.0));
  50.863 +        }
  50.864 +    }
  50.865 +}
    51.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    51.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/hints/HintsTask.java	Wed May 08 21:47:42 2013 +0200
    51.3 @@ -0,0 +1,254 @@
    51.4 +/*
    51.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    51.6 + *
    51.7 + * Copyright 2008-2010 Oracle and/or its affiliates. All rights reserved.
    51.8 + *
    51.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   51.10 + * Other names may be trademarks of their respective owners.
   51.11 + *
   51.12 + * The contents of this file are subject to the terms of either the GNU
   51.13 + * General Public License Version 2 only ("GPL") or the Common
   51.14 + * Development and Distribution License("CDDL") (collectively, the
   51.15 + * "License"). You may not use this file except in compliance with the
   51.16 + * License. You can obtain a copy of the License at
   51.17 + * http://www.netbeans.org/cddl-gplv2.html
   51.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   51.19 + * specific language governing permissions and limitations under the
   51.20 + * License.  When distributing the software, include this License Header
   51.21 + * Notice in each file and include the License file at
   51.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   51.23 + * particular file as subject to the "Classpath" exception as provided
   51.24 + * by Oracle in the GPL Version 2 section of the License file that
   51.25 + * accompanied this code. If applicable, add the following below the
   51.26 + * License Header, with the fields enclosed by brackets [] replaced by
   51.27 + * your own identifying information:
   51.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   51.29 + *
   51.30 + * If you wish your version of this file to be governed by only the CDDL
   51.31 + * or only the GPL Version 2, indicate your decision by adding
   51.32 + * "[Contributor] elects to include this software in this distribution
   51.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   51.34 + * single choice of license, a recipient has the option to distribute
   51.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   51.36 + * to extend the choice of license to its licensees as provided above.
   51.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   51.38 + * Version 2 license, then the option applies only if the new code is
   51.39 + * made subject to such option by the copyright holder.
   51.40 + *
   51.41 + * Contributor(s):
   51.42 + *
   51.43 + * Portions Copyrighted 2008-2010 Sun Microsystems, Inc.
   51.44 + */
   51.45 +
   51.46 +package org.netbeans.modules.java.hints.spiimpl.hints;
   51.47 +
   51.48 +import java.util.List;
   51.49 +import java.util.Map.Entry;
   51.50 +import java.util.concurrent.atomic.AtomicBoolean;
   51.51 +import java.util.logging.Level;
   51.52 +import java.util.logging.Logger;
   51.53 +import javax.swing.event.ChangeEvent;
   51.54 +import javax.swing.event.ChangeListener;
   51.55 +import javax.swing.text.BadLocationException;
   51.56 +import javax.swing.text.Document;
   51.57 +import org.netbeans.api.editor.mimelookup.MimeLookup;
   51.58 +import org.netbeans.api.editor.mimelookup.MimeRegistration;
   51.59 +import org.netbeans.api.java.source.CancellableTask;
   51.60 +import org.netbeans.api.java.source.CompilationInfo;
   51.61 +import org.netbeans.api.java.source.JavaSource.Phase;
   51.62 +import org.netbeans.api.java.source.JavaSource.Priority;
   51.63 +import org.netbeans.api.java.source.JavaSourceTaskFactory;
   51.64 +import org.netbeans.api.java.source.support.CaretAwareJavaSourceTaskFactory;
   51.65 +import org.netbeans.api.java.source.support.EditorAwareJavaSourceTaskFactory;
   51.66 +import org.netbeans.editor.BaseDocument;
   51.67 +import org.netbeans.editor.Utilities;
   51.68 +import org.netbeans.lib.editor.util.swing.DocumentUtilities;
   51.69 +import org.netbeans.modules.java.hints.providers.spi.PositionRefresherHelper;
   51.70 +import org.netbeans.modules.java.hints.providers.spi.PositionRefresherHelper.DocumentVersion;
   51.71 +import org.netbeans.modules.java.hints.spiimpl.options.HintsSettings;
   51.72 +import org.netbeans.modules.parsing.spi.TaskIndexingMode;
   51.73 +import org.netbeans.spi.editor.hints.Context;
   51.74 +import org.netbeans.spi.editor.hints.ErrorDescription;
   51.75 +import org.netbeans.spi.editor.hints.HintsController;
   51.76 +import org.netbeans.spi.editor.hints.Severity;
   51.77 +import org.netbeans.spi.editor.hints.settings.FileHintPreferences;
   51.78 +import org.openide.filesystems.FileObject;
   51.79 +import org.openide.util.WeakListeners;
   51.80 +import org.openide.util.lookup.ServiceProvider;
   51.81 +
   51.82 +/**
   51.83 + *
   51.84 + * @author lahvac
   51.85 + */
   51.86 +public class HintsTask implements CancellableTask<CompilationInfo> {
   51.87 +
   51.88 +    public static final String KEY_HINTS = HintsInvoker.class.getName() + "-hints";
   51.89 +    public static final String KEY_SUGGESTIONS = HintsInvoker.class.getName() + "-suggestions";
   51.90 +
   51.91 +    private static final Logger TIMER = Logger.getLogger("TIMER");
   51.92 +    private static final Logger TIMER_EDITOR = Logger.getLogger("TIMER.editor");
   51.93 +    private static final Logger TIMER_CARET = Logger.getLogger("TIMER.caret");
   51.94 +
   51.95 +    private final AtomicBoolean cancel = new AtomicBoolean();
   51.96 +
   51.97 +    private final boolean caretAware;
   51.98 +
   51.99 +    public HintsTask(boolean caretAware) {
  51.100 +        this.caretAware = caretAware;
  51.101 +    }
  51.102 +    
  51.103 +    public void run(CompilationInfo info) {
  51.104 +        cancel.set(false);
  51.105 +
  51.106 +        if (org.netbeans.modules.java.hints.spiimpl.Utilities.disableErrors(info.getFileObject()).contains(Severity.VERIFIER)) {
  51.107 +            return;
  51.108 +        }
  51.109 +
  51.110 +        Document doc = info.getSnapshot().getSource().getDocument(false);
  51.111 +        long version = doc != null ? DocumentUtilities.getDocumentVersion(doc) : 0;
  51.112 +        long startTime = System.currentTimeMillis();
  51.113 +
  51.114 +        int caret = CaretAwareJavaSourceTaskFactory.getLastPosition(info.getFileObject());
  51.115 +        HintsSettings settings = HintsSettings.getSettingsFor(info.getFileObject());
  51.116 +        HintsInvoker inv = caretAware ? new HintsInvoker(settings, caret, cancel) : new HintsInvoker(settings, cancel);
  51.117 +        List<ErrorDescription> result = inv.computeHints(info);
  51.118 +
  51.119 +        if (result == null || cancel.get()) {
  51.120 +            return;
  51.121 +        }
  51.122 +
  51.123 +        HintsController.setErrors(info.getFileObject(), caretAware ? KEY_SUGGESTIONS : KEY_HINTS, result);
  51.124 +
  51.125 +        if (caretAware) {
  51.126 +            SuggestionsPositionRefresherHelper.setVersion(doc, caret);
  51.127 +        } else {
  51.128 +            HintPositionRefresherHelper.setVersion(doc);
  51.129 +        }
  51.130 +
  51.131 +        long endTime = System.currentTimeMillis();
  51.132 +        
  51.133 +        TIMER.log(Level.FINE, "Jackpot 3.0 Hints Task" + (caretAware ? " - Caret Aware" : ""), new Object[] {info.getFileObject(), endTime - startTime});
  51.134 +
  51.135 +        Logger l = caretAware ? TIMER_CARET : TIMER_EDITOR;
  51.136 +
  51.137 +        for (Entry<String, Long> e : inv.getTimeLog().entrySet()) {
  51.138 +            l.log(Level.FINE, e.getKey(), new Object[] {info.getFileObject(), e.getValue()});
  51.139 +        }
  51.140 +    }
  51.141 +
  51.142 +    public void cancel() {
  51.143 +        cancel.set(true);
  51.144 +    }
  51.145 +
  51.146 +
  51.147 +    @ServiceProvider(service=JavaSourceTaskFactory.class)
  51.148 +    public static final class FactoryImpl extends EditorAwareJavaSourceTaskFactory implements ChangeListener {
  51.149 +
  51.150 +        public FactoryImpl() {
  51.151 +            super(Phase.RESOLVED, Priority.LOW, TaskIndexingMode.ALLOWED_DURING_SCAN);
  51.152 +            FileHintPreferences.addChangeListener(WeakListeners.change(this, HintsSettings.class));
  51.153 +        }
  51.154 +
  51.155 +        @Override
  51.156 +        protected CancellableTask<CompilationInfo> createTask(FileObject file) {
  51.157 +            return new HintsTask(false);
  51.158 +        }
  51.159 +
  51.160 +	@Override
  51.161 +	public void stateChanged(ChangeEvent e) {
  51.162 +	    for (FileObject file : getFileObjects()) {
  51.163 +		reschedule(file);
  51.164 +	    }
  51.165 +	}
  51.166 +        
  51.167 +    }
  51.168 +
  51.169 +    @ServiceProvider(service=JavaSourceTaskFactory.class)
  51.170 +    public static final class CaretFactoryImpl extends CaretAwareJavaSourceTaskFactory implements ChangeListener {
  51.171 +
  51.172 +        public CaretFactoryImpl() {
  51.173 +            super(Phase.RESOLVED, Priority.LOW);
  51.174 +            FileHintPreferences.addChangeListener(WeakListeners.change(this, HintsSettings.class));
  51.175 +        }
  51.176 +
  51.177 +        @Override
  51.178 +        protected CancellableTask<CompilationInfo> createTask(FileObject file) {
  51.179 +            return new HintsTask(true);
  51.180 +        }
  51.181 +
  51.182 +	@Override
  51.183 +	public void stateChanged(ChangeEvent e) {
  51.184 +	    for (FileObject file : getFileObjects()) {
  51.185 +		reschedule(file);
  51.186 +	    }
  51.187 +	}
  51.188 +
  51.189 +    }
  51.190 +
  51.191 +    @MimeRegistration(mimeType="text/x-java", service=PositionRefresherHelper.class)
  51.192 +    public static final class HintPositionRefresherHelper extends PositionRefresherHelper<DocumentVersion> {
  51.193 +
  51.194 +        public HintPositionRefresherHelper() {
  51.195 +            super(KEY_HINTS);
  51.196 +        }
  51.197 +
  51.198 +        @Override
  51.199 +        protected boolean isUpToDate(Context context, Document doc, DocumentVersion oldVersion) {
  51.200 +            return true;
  51.201 +        }
  51.202 +
  51.203 +        @Override
  51.204 +        public List<ErrorDescription> getErrorDescriptionsAt(CompilationInfo info, Context context, Document doc) throws BadLocationException {
  51.205 +            int rowStart = Utilities.getRowStart((BaseDocument) doc, context.getPosition());
  51.206 +            int rowEnd = Utilities.getRowEnd((BaseDocument) doc, context.getPosition());
  51.207 +
  51.208 +            return new HintsInvoker(HintsSettings.getSettingsFor(info.getFileObject()), rowStart, rowEnd, context.getCancel()).computeHints(info);
  51.209 +        }
  51.210 +
  51.211 +        private static void setVersion(Document doc) {
  51.212 +            for (PositionRefresherHelper h : MimeLookup.getLookup("text/x-java").lookupAll(PositionRefresherHelper.class)) {
  51.213 +                if (h instanceof HintPositionRefresherHelper) {
  51.214 +                    ((HintPositionRefresherHelper) h).setVersion(doc, new DocumentVersion(doc));
  51.215 +                }
  51.216 +            }
  51.217 +        }
  51.218 +
  51.219 +    }
  51.220 +
  51.221 +    @MimeRegistration(mimeType="text/x-java", service=PositionRefresherHelper.class)
  51.222 +    public static final class SuggestionsPositionRefresherHelper extends PositionRefresherHelper<SuggestionsDocumentVersion> {
  51.223 +
  51.224 +        public SuggestionsPositionRefresherHelper() {
  51.225 +            super(KEY_SUGGESTIONS);
  51.226 +        }
  51.227 +
  51.228 +        @Override
  51.229 +        protected boolean isUpToDate(Context context, Document doc, SuggestionsDocumentVersion oldVersion) {
  51.230 +            return oldVersion.suggestionsCaret == context.getPosition();
  51.231 +        }
  51.232 +
  51.233 +        @Override
  51.234 +        public List<ErrorDescription> getErrorDescriptionsAt(CompilationInfo info, Context context, Document doc) throws BadLocationException {
  51.235 +            return new HintsInvoker(HintsSettings.getSettingsFor(info.getFileObject()), context.getPosition(), context.getCancel()).computeHints(info);
  51.236 +        }
  51.237 +
  51.238 +        private static void setVersion(Document doc, int caret) {
  51.239 +            for (PositionRefresherHelper h : MimeLookup.getLookup("text/x-java").lookupAll(PositionRefresherHelper.class)) {
  51.240 +                if (h instanceof SuggestionsPositionRefresherHelper) {
  51.241 +                    ((SuggestionsPositionRefresherHelper) h).setVersion(doc, new SuggestionsDocumentVersion(doc, caret));
  51.242 +                }
  51.243 +            }
  51.244 +        }
  51.245 +    }
  51.246 +
  51.247 +    private static class SuggestionsDocumentVersion extends DocumentVersion {
  51.248 +
  51.249 +        private final int suggestionsCaret;
  51.250 +        
  51.251 +        public SuggestionsDocumentVersion(Document doc, int suggestionsCaret) {
  51.252 +            super(doc);
  51.253 +            this.suggestionsCaret = suggestionsCaret;
  51.254 +        }
  51.255 +    }
  51.256 +
  51.257 +}
    52.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    52.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/ipi/upgrade/ProjectDependencyUpgrader.java	Wed May 08 21:47:42 2013 +0200
    52.3 @@ -0,0 +1,64 @@
    52.4 +/*
    52.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    52.6 + *
    52.7 + * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
    52.8 + *
    52.9 + * The contents of this file are subject to the terms of either the GNU
   52.10 + * General Public License Version 2 only ("GPL") or the Common
   52.11 + * Development and Distribution License("CDDL") (collectively, the
   52.12 + * "License"). You may not use this file except in compliance with the
   52.13 + * License. You can obtain a copy of the License at
   52.14 + * http://www.netbeans.org/cddl-gplv2.html
   52.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   52.16 + * specific language governing permissions and limitations under the
   52.17 + * License.  When distributing the software, include this License Header
   52.18 + * Notice in each file and include the License file at
   52.19 + * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
   52.20 + * particular file as subject to the "Classpath" exception as provided
   52.21 + * by Sun in the GPL Version 2 section of the License file that
   52.22 + * accompanied this code. If applicable, add the following below the
   52.23 + * License Header, with the fields enclosed by brackets [] replaced by
   52.24 + * your own identifying information:
   52.25 + * "Portions Copyrighted [year] [name of copyright owner]"
   52.26 + *
   52.27 + * If you wish your version of this file to be governed by only the CDDL
   52.28 + * or only the GPL Version 2, indicate your decision by adding
   52.29 + * "[Contributor] elects to include this software in this distribution
   52.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   52.31 + * single choice of license, a recipient has the option to distribute
   52.32 + * your version of this file under either the CDDL, the GPL Version 2 or
   52.33 + * to extend the choice of license to its licensees as provided above.
   52.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   52.35 + * Version 2 license, then the option applies only if the new code is
   52.36 + * made subject to such option by the copyright holder.
   52.37 + *
   52.38 + * Contributor(s):
   52.39 + *
   52.40 + * Portions Copyrighted 2010 Sun Microsystems, Inc.
   52.41 + */
   52.42 +package org.netbeans.modules.java.hints.spiimpl.ipi.upgrade;
   52.43 +
   52.44 +import org.netbeans.api.project.Project;
   52.45 +import org.openide.DialogDisplayer;
   52.46 +import org.openide.NotifyDescriptor;
   52.47 +import org.openide.filesystems.FileObject;
   52.48 +import org.openide.modules.SpecificationVersion;
   52.49 +
   52.50 +/**
   52.51 + *
   52.52 + * @author lahvac
   52.53 + */
   52.54 +public abstract class ProjectDependencyUpgrader {
   52.55 +
   52.56 +    public abstract boolean ensureDependency(Project p, FileObject dep, SpecificationVersion spec, boolean canShowUI);
   52.57 +    public abstract boolean ensureDependency(Project p, String specification, boolean b);
   52.58 +
   52.59 +    protected final boolean showDependencyUpgradeDialog(Project p, String dep, SpecificationVersion currentDependency, SpecificationVersion spec, boolean newDepenency, boolean canShowUI) {
   52.60 +        if (!canShowUI) return true;
   52.61 +        
   52.62 +        NotifyDescriptor nd = new NotifyDescriptor.Confirmation("New version: " + spec, "Update spec version.", NotifyDescriptor.YES_NO_OPTION);
   52.63 +
   52.64 +        return DialogDisplayer.getDefault().notify(nd) == NotifyDescriptor.YES_OPTION;
   52.65 +    }
   52.66 +
   52.67 +}
    53.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    53.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/options/HintsSettings.java	Wed May 08 21:47:42 2013 +0200
    53.3 @@ -0,0 +1,149 @@
    53.4 +/*
    53.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    53.6 + *
    53.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    53.8 + *
    53.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   53.10 + * Other names may be trademarks of their respective owners.
   53.11 + *
   53.12 + * The contents of this file are subject to the terms of either the GNU
   53.13 + * General Public License Version 2 only ("GPL") or the Common
   53.14 + * Development and Distribution License("CDDL") (collectively, the
   53.15 + * "License"). You may not use this file except in compliance with the
   53.16 + * License. You can obtain a copy of the License at
   53.17 + * http://www.netbeans.org/cddl-gplv2.html
   53.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   53.19 + * specific language governing permissions and limitations under the
   53.20 + * License.  When distributing the software, include this License Header
   53.21 + * Notice in each file and include the License file at
   53.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   53.23 + * particular file as subject to the "Classpath" exception as provided
   53.24 + * by Oracle in the GPL Version 2 section of the License file that
   53.25 + * accompanied this code. If applicable, add the following below the
   53.26 + * License Header, with the fields enclosed by brackets [] replaced by
   53.27 + * your own identifying information:
   53.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   53.29 + *
   53.30 + * Contributor(s):
   53.31 + *
   53.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   53.33 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2010 Sun
   53.34 + * Microsystems, Inc. All Rights Reserved.
   53.35 + *
   53.36 + * If you wish your version of this file to be governed by only the CDDL
   53.37 + * or only the GPL Version 2, indicate your decision by adding
   53.38 + * "[Contributor] elects to include this software in this distribution
   53.39 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   53.40 + * single choice of license, a recipient has the option to distribute
   53.41 + * your version of this file under either the CDDL, the GPL Version 2 or
   53.42 + * to extend the choice of license to its licensees as provided above.
   53.43 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   53.44 + * Version 2 license, then the option applies only if the new code is
   53.45 + * made subject to such option by the copyright holder.
   53.46 + */
   53.47 +package org.netbeans.modules.java.hints.spiimpl.options;
   53.48 +
   53.49 +import java.util.prefs.Preferences;
   53.50 +import org.netbeans.api.editor.mimelookup.MimeRegistration;
   53.51 +import org.netbeans.modules.java.hints.providers.spi.HintMetadata;
   53.52 +import org.netbeans.spi.editor.hints.Severity;
   53.53 +import org.netbeans.spi.editor.hints.settings.FileHintPreferences;
   53.54 +import org.netbeans.spi.editor.hints.settings.FileHintPreferences.GlobalHintPreferencesProvider;
   53.55 +import org.openide.filesystems.FileObject;
   53.56 +import org.openide.util.NbPreferences;
   53.57 +
   53.58 +/**
   53.59 + *
   53.60 + * @author Petr Hrebejk
   53.61 + * @author Jan Lahoda
   53.62 + */
   53.63 +public abstract class HintsSettings {
   53.64 +
   53.65 +    private static final String ENABLED_KEY = "enabled";         // NOI18N
   53.66 +    private static final String OLD_SEVERITY_KEY = "severity";       // NOI18N
   53.67 +    private static final String NEW_SEVERITY_KEY = "hintSeverity";       // NOI18N
   53.68 +//    protected static final String IN_TASK_LIST_KEY = "inTaskList"; // NOI18N
   53.69 +
   53.70 +    public abstract boolean isEnabled(HintMetadata hint);
   53.71 +    public abstract void setEnabled(HintMetadata hint, boolean value);
   53.72 +    public abstract Preferences getHintPreferences(HintMetadata hint);
   53.73 +    public abstract Severity getSeverity(HintMetadata hint);
   53.74 +    public abstract void setSeverity(HintMetadata hint, Severity severity);
   53.75 +//    public abstract Iterable<? extends HintDescription> getEnabledHints();
   53.76 +    
   53.77 +    private static final class PreferencesBasedHintsSettings extends HintsSettings {
   53.78 +
   53.79 +        private final Preferences preferences;
   53.80 +        private final boolean useDefaultEnabled;
   53.81 +        private final Severity overrideSeverity;
   53.82 +
   53.83 +        public PreferencesBasedHintsSettings(Preferences preferences, boolean useDefaultEnabled, Severity overrideSeverity) {
   53.84 +            this.preferences = preferences;
   53.85 +            this.useDefaultEnabled = useDefaultEnabled;
   53.86 +            this.overrideSeverity = overrideSeverity;
   53.87 +        }
   53.88 +
   53.89 +        @Override
   53.90 +        public boolean isEnabled(HintMetadata hint) {
   53.91 +            return getHintPreferences(hint).getBoolean(ENABLED_KEY, useDefaultEnabled && hint.enabled);
   53.92 +        }
   53.93 +
   53.94 +        @Override
   53.95 +        public void setEnabled(HintMetadata hint, boolean value) {
   53.96 +            getHintPreferences(hint).putBoolean(ENABLED_KEY, value);
   53.97 +        }
   53.98 +
   53.99 +        @Override
  53.100 +        public Preferences getHintPreferences(HintMetadata hint) {
  53.101 +            return preferences.node(hint.id);
  53.102 +        }
  53.103 +
  53.104 +        @Override
  53.105 +        public Severity getSeverity(HintMetadata hint) {
  53.106 +            Preferences prefs = getHintPreferences(hint);
  53.107 +            String s = prefs.get(NEW_SEVERITY_KEY, null);
  53.108 +            if (s != null) return Severity.valueOf(s);
  53.109 +
  53.110 +            s = prefs.get(OLD_SEVERITY_KEY, null);
  53.111 +
  53.112 +            if (s == null) return overrideSeverity != null ? overrideSeverity : hint != null ? hint.severity : null;
  53.113 +
  53.114 +            if ("ERROR".equals(s)) return Severity.ERROR;
  53.115 +            else if ("WARNING".equals(s)) return Severity.VERIFIER;
  53.116 +            else if ("CURRENT_LINE_WARNING".equals(s)) return Severity.HINT;
  53.117 +
  53.118 +            return overrideSeverity != null ? overrideSeverity : hint != null ? hint.severity : null;
  53.119 +        }
  53.120 +        
  53.121 +        @Override
  53.122 +        public void setSeverity(HintMetadata hint, Severity severity) {
  53.123 +            getHintPreferences(hint).put(NEW_SEVERITY_KEY, severity.name());
  53.124 +        }
  53.125 +    }
  53.126 +    
  53.127 +    public static HintsSettings createPreferencesBasedHintsSettings(Preferences preferences, boolean useDefaultEnabled, Severity overrideSeverity) {
  53.128 +        return new PreferencesBasedHintsSettings(preferences, useDefaultEnabled, overrideSeverity);
  53.129 +    }
  53.130 +    
  53.131 +    public static HintsSettings getSettingsFor(FileObject file) {
  53.132 +        return createPreferencesBasedHintsSettings(FileHintPreferences.getFilePreferences(file, "text/x-java"), true, null);
  53.133 +    }
  53.134 +    
  53.135 +    public static HintsSettings getGlobalSettings() {
  53.136 +        return GLOBAL_SETTINGS;
  53.137 +    }
  53.138 +    
  53.139 +    private static final String DEFAULT_PROFILE = "default"; // NOI18N
  53.140 +    private static final String PREFERENCES_LOCATION = "org/netbeans/modules/java/hints";
  53.141 +    private static final HintsSettings GLOBAL_SETTINGS = createPreferencesBasedHintsSettings(NbPreferences.root().node(PREFERENCES_LOCATION).node(DEFAULT_PROFILE), true, null);
  53.142 +    
  53.143 +    @MimeRegistration(mimeType="text/x-java", service=GlobalHintPreferencesProvider.class)
  53.144 +    public static class GlobalSettingsProvider implements GlobalHintPreferencesProvider {
  53.145 +
  53.146 +        @Override
  53.147 +        public Preferences getGlobalPreferences() {
  53.148 +            return NbPreferences.root().node(PREFERENCES_LOCATION).node(DEFAULT_PROFILE);
  53.149 +        }
  53.150 +        
  53.151 +    }
  53.152 +}
    54.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    54.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/pm/BulkSearch.java	Wed May 08 21:47:42 2013 +0200
    54.3 @@ -0,0 +1,190 @@
    54.4 +/*
    54.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    54.6 + *
    54.7 + * Copyright 2010 Oracle and/or its affiliates. All rights reserved.
    54.8 + *
    54.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   54.10 + * Other names may be trademarks of their respective owners.
   54.11 + *
   54.12 + * The contents of this file are subject to the terms of either the GNU
   54.13 + * General Public License Version 2 only ("GPL") or the Common
   54.14 + * Development and Distribution License("CDDL") (collectively, the
   54.15 + * "License"). You may not use this file except in compliance with the
   54.16 + * License. You can obtain a copy of the License at
   54.17 + * http://www.netbeans.org/cddl-gplv2.html
   54.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   54.19 + * specific language governing permissions and limitations under the
   54.20 + * License.  When distributing the software, include this License Header
   54.21 + * Notice in each file and include the License file at
   54.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   54.23 + * particular file as subject to the "Classpath" exception as provided
   54.24 + * by Oracle in the GPL Version 2 section of the License file that
   54.25 + * accompanied this code. If applicable, add the following below the
   54.26 + * License Header, with the fields enclosed by brackets [] replaced by
   54.27 + * your own identifying information:
   54.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   54.29 + *
   54.30 + * If you wish your version of this file to be governed by only the CDDL
   54.31 + * or only the GPL Version 2, indicate your decision by adding
   54.32 + * "[Contributor] elects to include this software in this distribution
   54.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   54.34 + * single choice of license, a recipient has the option to distribute
   54.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   54.36 + * to extend the choice of license to its licensees as provided above.
   54.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   54.38 + * Version 2 license, then the option applies only if the new code is
   54.39 + * made subject to such option by the copyright holder.
   54.40 + *
   54.41 + * Contributor(s):
   54.42 + *
   54.43 + * Portions Copyrighted 2009 Sun Microsystems, Inc.
   54.44 + */
   54.45 +
   54.46 +package org.netbeans.modules.java.hints.spiimpl.pm;
   54.47 +
   54.48 +import com.sun.source.tree.Tree;
   54.49 +import com.sun.source.util.TreePath;
   54.50 +import java.io.InputStream;
   54.51 +import java.io.OutputStream;
   54.52 +import java.util.Arrays;
   54.53 +import java.util.Collection;
   54.54 +import java.util.LinkedList;
   54.55 +import java.util.List;
   54.56 +import java.util.Map;
   54.57 +import java.util.Set;
   54.58 +import java.util.concurrent.atomic.AtomicBoolean;
   54.59 +import org.netbeans.api.annotations.common.CheckForNull;
   54.60 +import org.netbeans.api.java.source.CompilationInfo;
   54.61 +import org.netbeans.modules.java.hints.spiimpl.Utilities;
   54.62 +import org.netbeans.modules.java.hints.providers.spi.HintDescription.AdditionalQueryConstraints;
   54.63 +
   54.64 +/**
   54.65 + *
   54.66 + * @author lahvac
   54.67 + */
   54.68 +public abstract class BulkSearch {
   54.69 +
   54.70 +    private static final BulkSearch INSTANCE = new NFABasedBulkSearch();
   54.71 +//    private static final BulkSearch INSTANCE = new REBasedBulkSearch();
   54.72 +
   54.73 +    public static BulkSearch getDefault() {
   54.74 +        return INSTANCE;
   54.75 +    }
   54.76 +    
   54.77 +    private final boolean requiresLightweightVerification;
   54.78 +    
   54.79 +    protected BulkSearch(boolean requiresLightweightVerification) {
   54.80 +        this.requiresLightweightVerification = requiresLightweightVerification;
   54.81 +    }
   54.82 +    
   54.83 +    public final Map<String, Collection<TreePath>> match(CompilationInfo info, AtomicBoolean cancel, TreePath toSearch, BulkPattern pattern) {
   54.84 +        return match(info, cancel, toSearch, pattern, null);
   54.85 +    }
   54.86 +
   54.87 +    public final boolean requiresLightweightVerification() {
   54.88 +        return requiresLightweightVerification;
   54.89 +    }
   54.90 +
   54.91 +    @CheckForNull
   54.92 +    public abstract Map<String, Collection<TreePath>> match(CompilationInfo info, AtomicBoolean cancel, TreePath toSearch, BulkPattern pattern, Map<String, Long> timeLog);
   54.93 +
   54.94 +    public abstract boolean matches(InputStream encoded, AtomicBoolean cancel, BulkPattern pattern);
   54.95 +    
   54.96 +    @CheckForNull
   54.97 +    public abstract Map<String, Integer> matchesWithFrequencies(InputStream encoded, BulkPattern pattern, AtomicBoolean cancel);
   54.98 +    
   54.99 +    public abstract boolean matches(CompilationInfo info, AtomicBoolean cancel, TreePath toSearch, BulkPattern pattern);
  54.100 +
  54.101 +    public abstract void encode(Tree tree, EncodingContext ctx, AtomicBoolean cancel);
  54.102 +    
  54.103 +    @CheckForNull
  54.104 +    public final BulkPattern create(CompilationInfo info, AtomicBoolean cancel, String... code) {
  54.105 +        return create(info, cancel, Arrays.asList(code));
  54.106 +    }
  54.107 +
  54.108 +    @CheckForNull
  54.109 +    public final BulkPattern create(CompilationInfo info, AtomicBoolean cancel, Collection<? extends String> code) {
  54.110 +        List<Tree> patterns = new LinkedList<Tree>();
  54.111 +        List<AdditionalQueryConstraints> additionalConstraints = new LinkedList<AdditionalQueryConstraints>();
  54.112 +
  54.113 +        for (String c : code) {
  54.114 +            patterns.add(Utilities.parseAndAttribute(info, c, null));
  54.115 +            additionalConstraints.add(AdditionalQueryConstraints.empty());
  54.116 +        }
  54.117 +
  54.118 +        return create(code, patterns, additionalConstraints, cancel);
  54.119 +    }
  54.120 +    
  54.121 +    @CheckForNull
  54.122 +    public abstract BulkPattern create(Collection<? extends String> code, Collection<? extends Tree> patterns, Collection<? extends AdditionalQueryConstraints> additionalConstraints, AtomicBoolean cancel);
  54.123 +
  54.124 +    public static abstract class BulkPattern {
  54.125 +
  54.126 +        private final List<? extends String> patterns;
  54.127 +        private final List<? extends Set<? extends String>> identifiers;
  54.128 +        private final List<List<List<String>>> requiredContent;
  54.129 +        private final List<AdditionalQueryConstraints> additionalConstraints;
  54.130 +
  54.131 +        public BulkPattern(List<? extends String> patterns, List<? extends Set<? extends String>> identifiers, List<List<List<String>>> requiredContent, List<AdditionalQueryConstraints> additionalConstraints) {
  54.132 +            this.patterns = patterns;
  54.133 +            this.identifiers = identifiers;//TODO: immutable, maybe clone
  54.134 +            this.requiredContent = requiredContent;
  54.135 +            this.additionalConstraints = additionalConstraints;
  54.136 +        }
  54.137 +
  54.138 +        public List<? extends String> getPatterns() {
  54.139 +            return patterns;
  54.140 +        }
  54.141 +
  54.142 +        public List<? extends Set<? extends String>> getIdentifiers() {
  54.143 +            return identifiers;
  54.144 +        }
  54.145 +
  54.146 +        public List<List<List<String>>> getRequiredContent() {
  54.147 +            return requiredContent;
  54.148 +        }
  54.149 +
  54.150 +        public List<AdditionalQueryConstraints> getAdditionalConstraints() {
  54.151 +            return additionalConstraints;
  54.152 +        }
  54.153 +
  54.154 +    }
  54.155 +
  54.156 +    public static final class EncodingContext {
  54.157 +
  54.158 +        private final OutputStream out;
  54.159 +        private final boolean forDuplicates;
  54.160 +        private Set<? extends String> identifiers;
  54.161 +        private List<String> content;
  54.162 +
  54.163 +        public EncodingContext(OutputStream out, boolean forDuplicates) {
  54.164 +            this.out = out;
  54.165 +            this.forDuplicates = forDuplicates;
  54.166 +        }
  54.167 +
  54.168 +        public Set<? extends String> getIdentifiers() {
  54.169 +            return identifiers;
  54.170 +        }
  54.171 +
  54.172 +        public OutputStream getOut() {
  54.173 +            return out;
  54.174 +        }
  54.175 +
  54.176 +        public boolean isForDuplicates() {
  54.177 +            return forDuplicates;
  54.178 +        }
  54.179 +
  54.180 +        public void setIdentifiers(Set<? extends String> identifiers) {
  54.181 +            this.identifiers = identifiers;
  54.182 +        }
  54.183 +
  54.184 +        public void setContent(List<String> content) {
  54.185 +            this.content = content;
  54.186 +        }
  54.187 +
  54.188 +        public List<String> getContent() {
  54.189 +            return content;
  54.190 +        }
  54.191 +
  54.192 +    }
  54.193 +}
    55.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    55.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/pm/CopyFinderBasedBulkSearch.java	Wed May 08 21:47:42 2013 +0200
    55.3 @@ -0,0 +1,141 @@
    55.4 +/*
    55.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    55.6 + *
    55.7 + * Copyright 2010 Oracle and/or its affiliates. All rights reserved.
    55.8 + *
    55.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   55.10 + * Other names may be trademarks of their respective owners.
   55.11 + *
   55.12 + * The contents of this file are subject to the terms of either the GNU
   55.13 + * General Public License Version 2 only ("GPL") or the Common
   55.14 + * Development and Distribution License("CDDL") (collectively, the
   55.15 + * "License"). You may not use this file except in compliance with the
   55.16 + * License. You can obtain a copy of the License at
   55.17 + * http://www.netbeans.org/cddl-gplv2.html
   55.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   55.19 + * specific language governing permissions and limitations under the
   55.20 + * License.  When distributing the software, include this License Header
   55.21 + * Notice in each file and include the License file at
   55.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   55.23 + * particular file as subject to the "Classpath" exception as provided
   55.24 + * by Oracle in the GPL Version 2 section of the License file that
   55.25 + * accompanied this code. If applicable, add the following below the
   55.26 + * License Header, with the fields enclosed by brackets [] replaced by
   55.27 + * your own identifying information:
   55.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   55.29 + *
   55.30 + * If you wish your version of this file to be governed by only the CDDL
   55.31 + * or only the GPL Version 2, indicate your decision by adding
   55.32 + * "[Contributor] elects to include this software in this distribution
   55.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   55.34 + * single choice of license, a recipient has the option to distribute
   55.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   55.36 + * to extend the choice of license to its licensees as provided above.
   55.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   55.38 + * Version 2 license, then the option applies only if the new code is
   55.39 + * made subject to such option by the copyright holder.
   55.40 + *
   55.41 + * Contributor(s):
   55.42 + *
   55.43 + * Portions Copyrighted 2009 Sun Microsystems, Inc.
   55.44 + */
   55.45 +
   55.46 +package org.netbeans.modules.java.hints.spiimpl.pm;
   55.47 +
   55.48 +import com.sun.source.tree.Tree;
   55.49 +import com.sun.source.util.TreePath;
   55.50 +import java.io.InputStream;
   55.51 +import java.util.Collection;
   55.52 +import java.util.Collections;
   55.53 +import java.util.HashMap;
   55.54 +import java.util.Iterator;
   55.55 +import java.util.LinkedList;
   55.56 +import java.util.Map;
   55.57 +import java.util.Map.Entry;
   55.58 +import java.util.concurrent.atomic.AtomicBoolean;
   55.59 +import javax.lang.model.type.TypeMirror;
   55.60 +import org.netbeans.api.java.source.CompilationInfo;
   55.61 +import org.netbeans.modules.java.hints.providers.spi.HintDescription.AdditionalQueryConstraints;
   55.62 +import org.netbeans.api.java.source.matching.Matcher;
   55.63 +import org.netbeans.api.java.source.matching.Occurrence;
   55.64 +import org.netbeans.api.java.source.matching.Pattern;
   55.65 +import org.openide.util.Parameters;
   55.66 +
   55.67 +/**
   55.68 + *
   55.69 + * @author lahvac
   55.70 + */
   55.71 +public class CopyFinderBasedBulkSearch extends BulkSearch {
   55.72 +
   55.73 +    public CopyFinderBasedBulkSearch() {
   55.74 +        super(false);
   55.75 +    }
   55.76 +
   55.77 +    @Override
   55.78 +    public Map<String, Collection<TreePath>> match(CompilationInfo info, AtomicBoolean cancel, TreePath toSearch, BulkPattern pattern, Map<String, Long> timeLog) {
   55.79 +        Parameters.notNull("info", info);
   55.80 +        Map<String, Collection<TreePath>> result = new HashMap<String, Collection<TreePath>>();
   55.81 +        TreePath topLevel = new TreePath(info.getCompilationUnit());
   55.82 +        
   55.83 +        for (Entry<Tree, String> e : ((BulkPatternImpl) pattern).pattern2Code.entrySet()) {
   55.84 +            for (Occurrence od : Matcher.create(info).setCancel(new AtomicBoolean()).setUntypedMatching().setCancel(cancel).match(Pattern.createPatternWithFreeVariables(new TreePath(topLevel, e.getKey()), Collections.<String, TypeMirror>emptyMap()))) {
   55.85 +                Collection<TreePath> c = result.get(e.getValue());
   55.86 +
   55.87 +                if (c == null) {
   55.88 +                    result.put(e.getValue(), c = new LinkedList<TreePath>());
   55.89 +                }
   55.90 +
   55.91 +                c.add(od.getOccurrenceRoot());
   55.92 +            }
   55.93 +        }
   55.94 +
   55.95 +        return result;
   55.96 +    }
   55.97 +
   55.98 +    @Override
   55.99 +    public boolean matches(CompilationInfo info, AtomicBoolean cancel, TreePath toSearch, BulkPattern pattern) {
  55.100 +        //XXX: performance
  55.101 +        return !match(info, cancel, toSearch, pattern).isEmpty();
  55.102 +    }
  55.103 +
  55.104 +    @Override
  55.105 +    public BulkPattern create(Collection<? extends String> code, Collection<? extends Tree> patterns, Collection<? extends AdditionalQueryConstraints> additionalConstraints, AtomicBoolean cancel) {
  55.106 +        Map<Tree, String> pattern2Code = new HashMap<Tree, String>();
  55.107 +
  55.108 +        Iterator<? extends String> itCode = code.iterator();
  55.109 +        Iterator<? extends Tree>   itPatt = patterns.iterator();
  55.110 +
  55.111 +        while (itCode.hasNext() && itPatt.hasNext()) {
  55.112 +            pattern2Code.put(itPatt.next(), itCode.next());
  55.113 +        }
  55.114 +
  55.115 +        return new BulkPatternImpl(additionalConstraints, pattern2Code);
  55.116 +    }
  55.117 +
  55.118 +    @Override
  55.119 +    public boolean matches(InputStream encoded, AtomicBoolean cancel, BulkPattern pattern) {
  55.120 +        throw new UnsupportedOperationException("Not supported yet.");
  55.121 +    }
  55.122 +
  55.123 +    @Override
  55.124 +    public void encode(Tree tree, EncodingContext ctx, AtomicBoolean cancel) {
  55.125 +        throw new UnsupportedOperationException("Not supported yet.");
  55.126 +    }
  55.127 +
  55.128 +    @Override
  55.129 +    public Map<String, Integer> matchesWithFrequencies(InputStream encoded, BulkPattern pattern, AtomicBoolean cancel) {
  55.130 +        throw new UnsupportedOperationException("Not supported yet.");
  55.131 +    }
  55.132 +
  55.133 +    private static final class BulkPatternImpl extends BulkPattern {
  55.134 +
  55.135 +        private final Map<Tree, String> pattern2Code;
  55.136 +        
  55.137 +        public BulkPatternImpl(Collection<? extends AdditionalQueryConstraints> additionalConstraints, Map<Tree, String> pattern2Code) {
  55.138 +            super(new LinkedList<String>(pattern2Code.values()), null, null, new LinkedList<AdditionalQueryConstraints>(additionalConstraints));
  55.139 +            this.pattern2Code = pattern2Code;
  55.140 +        }
  55.141 +
  55.142 +    }
  55.143 +
  55.144 +}
    56.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    56.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/pm/NFA.java	Wed May 08 21:47:42 2013 +0200
    56.3 @@ -0,0 +1,216 @@
    56.4 +/*
    56.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    56.6 + *
    56.7 + * Copyright 2009-2010 Oracle and/or its affiliates. All rights reserved.
    56.8 + *
    56.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   56.10 + * Other names may be trademarks of their respective owners.
   56.11 + *
   56.12 + * The contents of this file are subject to the terms of either the GNU
   56.13 + * General Public License Version 2 only ("GPL") or the Common
   56.14 + * Development and Distribution License("CDDL") (collectively, the
   56.15 + * "License"). You may not use this file except in compliance with the
   56.16 + * License. You can obtain a copy of the License at
   56.17 + * http://www.netbeans.org/cddl-gplv2.html
   56.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   56.19 + * specific language governing permissions and limitations under the
   56.20 + * License.  When distributing the software, include this License Header
   56.21 + * Notice in each file and include the License file at
   56.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   56.23 + * particular file as subject to the "Classpath" exception as provided
   56.24 + * by Oracle in the GPL Version 2 section of the License file that
   56.25 + * accompanied this code. If applicable, add the following below the
   56.26 + * License Header, with the fields enclosed by brackets [] replaced by
   56.27 + * your own identifying information:
   56.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   56.29 + *
   56.30 + * If you wish your version of this file to be governed by only the CDDL
   56.31 + * or only the GPL Version 2, indicate your decision by adding
   56.32 + * "[Contributor] elects to include this software in this distribution
   56.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   56.34 + * single choice of license, a recipient has the option to distribute
   56.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   56.36 + * to extend the choice of license to its licensees as provided above.
   56.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   56.38 + * Version 2 license, then the option applies only if the new code is
   56.39 + * made subject to such option by the copyright holder.
   56.40 + *
   56.41 + * Contributor(s):
   56.42 + *
   56.43 + * Portions Copyrighted 2009 Sun Microsystems, Inc.
   56.44 + */
   56.45 +
   56.46 +package org.netbeans.modules.java.hints.spiimpl.pm;
   56.47 +
   56.48 +import java.util.BitSet;
   56.49 +import java.util.HashSet;
   56.50 +import java.util.Map;
   56.51 +import java.util.Set;
   56.52 +
   56.53 +/**
   56.54 + *
   56.55 + * @author lahvac
   56.56 + */
   56.57 +public class NFA<I, R> {
   56.58 +
   56.59 +    /*XXX: private*/ final int stateCount;
   56.60 +    private final int startingState;
   56.61 +    private final Set<I> inputs;
   56.62 +    private final Map<Key<I>, State> transitionTable;
   56.63 +    private final Map<Integer, R> finalStates;
   56.64 +
   56.65 +    private final State startingStateObject;
   56.66 +
   56.67 +    private NFA(int startingState, int stateCount, Set<I> inputs, Map<Key<I>, State> transitionTable, Map<Integer, R> finalStates) {
   56.68 +        this.startingState = startingState;
   56.69 +        this.stateCount = stateCount;
   56.70 +        this.inputs = inputs;
   56.71 +        this.transitionTable = transitionTable;
   56.72 +        this.finalStates = finalStates;
   56.73 +
   56.74 +        startingStateObject = State.create().mutableOr(startingState);
   56.75 +    }
   56.76 +
   56.77 +    public State getStartingState() {
   56.78 +        return startingStateObject;
   56.79 +    }
   56.80 +
   56.81 +    public State transition(final State active, final I input) {
   56.82 +        State result = null;
   56.83 +
   56.84 +//        for (int i : active) {
   56.85 +        for (int i = active.nextSetBit(0); i >= 0; i = active.nextSetBit(i+1)) {
   56.86 +             State target = transitionTable.get(Key.create(i, input));
   56.87 +
   56.88 +             if (target != null) {
   56.89 +                 if (result == null) {
   56.90 +                     result = State.create();
   56.91 +                 }
   56.92 +                 
   56.93 +                 result.mutableOr(target);
   56.94 +             }
   56.95 +        }
   56.96 +
   56.97 +        State r;
   56.98 +
   56.99 +        //XXX:
  56.100 +        if (result == null) {
  56.101 +            r = startingStateObject;
  56.102 +        } else {
  56.103 +            r = result.mutableOr(startingState);//???
  56.104 +        }
  56.105 +
  56.106 +        return r;
  56.107 +    }
  56.108 +
  56.109 +    public Set<R> getResults(State bs) {
  56.110 +        Set<R> result = new HashSet<R>();
  56.111 +
  56.112 +        for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) {
  56.113 +            if (finalStates.get(i) != null) {
  56.114 +                result.add(finalStates.get(i));
  56.115 +            }
  56.116 +        }
  56.117 +
  56.118 +        return result;
  56.119 +    }
  56.120 +
  56.121 +    public static <I, R> NFA<I, R> create(int startingState, int stateCount, Set<I> inputs, Map<Key<I>, State> transitionTable, Map<Integer, R> finalStates) {
  56.122 +        return new NFA<I, R>(startingState, stateCount, inputs, transitionTable, finalStates);
  56.123 +    }
  56.124 +
  56.125 +    public State join(State s1, State s2) {
  56.126 +        State bs = State.create();
  56.127 +
  56.128 +        bs.mutableOr(s1);
  56.129 +        bs.mutableOr(s2);
  56.130 +
  56.131 +        return bs;
  56.132 +    }
  56.133 +
  56.134 +    public static final class Key<I> {
  56.135 +        private final int state;
  56.136 +        private final I   input;
  56.137 +
  56.138 +        private Key(int state, I input) {
  56.139 +            this.state = state;
  56.140 +            this.input = input;
  56.141 +        }
  56.142 +
  56.143 +        public static <I> Key<I> create(int state, I input) {
  56.144 +            return new Key<I>(state, input);
  56.145 +        }
  56.146 +
  56.147 +        @Override
  56.148 +        public boolean equals(Object obj) {
  56.149 +            if (obj == null) {
  56.150 +                return false;
  56.151 +            }
  56.152 +            if (getClass() != obj.getClass()) {
  56.153 +                return false;
  56.154 +            }
  56.155 +            final Key<?> other = (Key<?>) obj;
  56.156 +            if (this.state != other.state) {
  56.157 +                return false;
  56.158 +            }
  56.159 +            if (this.input != other.input && (this.input == null || !this.input.equals(other.input))) {
  56.160 +                return false;
  56.161 +            }
  56.162 +            return true;
  56.163 +        }
  56.164 +
  56.165 +        @Override
  56.166 +        public int hashCode() {
  56.167 +            int hash = 3;
  56.168 +            hash = 83 * hash + this.state;
  56.169 +            hash = 83 * hash + (this.input != null ? this.input.hashCode() : 0);
  56.170 +            return hash;
  56.171 +        }
  56.172 +
  56.173 +        @Override
  56.174 +        public String toString() {
  56.175 +            return "[" + state + ", " + input + "]";
  56.176 +        }
  56.177 +
  56.178 +    }
  56.179 +
  56.180 +//    public static final class State extends HashSet<Integer> {
  56.181 +//        private State() {
  56.182 +//        }
  56.183 +//
  56.184 +//        public static State create() {
  56.185 +//            return new State();
  56.186 +//        }
  56.187 +//
  56.188 +//        public State mutableOr(int state) {
  56.189 +//            add(state);
  56.190 +//            return this;
  56.191 +//        }
  56.192 +//
  56.193 +//        public State mutableOr(State or) {
  56.194 +//            addAll(or);
  56.195 +//            return this;
  56.196 +//        }
  56.197 +//
  56.198 +//    }
  56.199 +
  56.200 +    public static final class State extends BitSet {
  56.201 +        private State() {}
  56.202 +
  56.203 +        public static State create() {
  56.204 +            return new State();
  56.205 +        }
  56.206 +
  56.207 +        public State mutableOr(int state) {
  56.208 +            set(state);
  56.209 +            return this;
  56.210 +        }
  56.211 +
  56.212 +        public State mutableOr(State or) {
  56.213 +            or(or);
  56.214 +            return this;
  56.215 +        }
  56.216 +
  56.217 +    }
  56.218 +
  56.219 +}
    57.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    57.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/pm/NFABasedBulkSearch.java	Wed May 08 21:47:42 2013 +0200
    57.3 @@ -0,0 +1,826 @@
    57.4 +/*
    57.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    57.6 + *
    57.7 + * Copyright 2009-2010 Oracle and/or its affiliates. All rights reserved.
    57.8 + *
    57.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   57.10 + * Other names may be trademarks of their respective owners.
   57.11 + *
   57.12 + * The contents of this file are subject to the terms of either the GNU
   57.13 + * General Public License Version 2 only ("GPL") or the Common
   57.14 + * Development and Distribution License("CDDL") (collectively, the
   57.15 + * "License"). You may not use this file except in compliance with the
   57.16 + * License. You can obtain a copy of the License at
   57.17 + * http://www.netbeans.org/cddl-gplv2.html
   57.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   57.19 + * specific language governing permissions and limitations under the
   57.20 + * License.  When distributing the software, include this License Header
   57.21 + * Notice in each file and include the License file at
   57.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   57.23 + * particular file as subject to the "Classpath" exception as provided
   57.24 + * by Oracle in the GPL Version 2 section of the License file that
   57.25 + * accompanied this code. If applicable, add the following below the
   57.26 + * License Header, with the fields enclosed by brackets [] replaced by
   57.27 + * your own identifying information:
   57.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   57.29 + *
   57.30 + * If you wish your version of this file to be governed by only the CDDL
   57.31 + * or only the GPL Version 2, indicate your decision by adding
   57.32 + * "[Contributor] elects to include this software in this distribution
   57.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   57.34 + * single choice of license, a recipient has the option to distribute
   57.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   57.36 + * to extend the choice of license to its licensees as provided above.
   57.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   57.38 + * Version 2 license, then the option applies only if the new code is
   57.39 + * made subject to such option by the copyright holder.
   57.40 + *
   57.41 + * Contributor(s):
   57.42 + *
   57.43 + * Portions Copyrighted 2009-2010 Sun Microsystems, Inc.
   57.44 + */
   57.45 +
   57.46 +package org.netbeans.modules.java.hints.spiimpl.pm;
   57.47 +
   57.48 +import com.sun.source.tree.AnnotationTree;
   57.49 +import com.sun.source.tree.BlockTree;
   57.50 +import com.sun.source.tree.ClassTree;
   57.51 +import com.sun.source.tree.IdentifierTree;
   57.52 +import com.sun.source.tree.LiteralTree;
   57.53 +import com.sun.source.tree.MemberSelectTree;
   57.54 +import com.sun.source.tree.MethodTree;
   57.55 +import com.sun.source.tree.ModifiersTree;
   57.56 +import com.sun.source.tree.StatementTree;
   57.57 +import com.sun.source.tree.Tree;
   57.58 +import com.sun.source.tree.Tree.Kind;
   57.59 +import com.sun.source.tree.VariableTree;
   57.60 +import com.sun.source.util.TreePath;
   57.61 +import com.sun.source.util.TreeScanner;
   57.62 +import java.io.ByteArrayOutputStream;
   57.63 +import java.io.IOException;
   57.64 +import java.io.InputStream;
   57.65 +import java.io.UnsupportedEncodingException;
   57.66 +import java.util.ArrayList;
   57.67 +import java.util.Collection;
   57.68 +import java.util.Collections;
   57.69 +import java.util.EnumMap;
   57.70 +import java.util.EnumSet;
   57.71 +import java.util.HashMap;
   57.72 +import java.util.HashSet;
   57.73 +import java.util.Iterator;
   57.74 +import java.util.LinkedHashMap;
   57.75 +import java.util.LinkedList;
   57.76 +import java.util.List;
   57.77 +import java.util.Map;
   57.78 +import java.util.Map.Entry;
   57.79 +import java.util.Set;
   57.80 +import java.util.Stack;
   57.81 +import java.util.concurrent.atomic.AtomicBoolean;
   57.82 +import javax.lang.model.element.Name;
   57.83 +import org.netbeans.api.java.source.CompilationInfo;
   57.84 +import org.netbeans.api.java.source.support.CancellableTreeScanner;
   57.85 +import org.netbeans.modules.java.hints.spiimpl.Utilities;
   57.86 +import org.netbeans.modules.java.hints.providers.spi.HintDescription.AdditionalQueryConstraints;
   57.87 +import org.openide.util.Exceptions;
   57.88 +
   57.89 +/**
   57.90 + *
   57.91 + * @author lahvac
   57.92 + */
   57.93 +public class NFABasedBulkSearch extends BulkSearch {
   57.94 +
   57.95 +    public NFABasedBulkSearch() {
   57.96 +        super(false);
   57.97 +    }
   57.98 +
   57.99 +    @Override
  57.100 +    public Map<String, Collection<TreePath>> match(CompilationInfo info, final AtomicBoolean cancel, TreePath tree, BulkPattern patternIn, Map<String, Long> timeLog) {
  57.101 +        BulkPatternImpl pattern = (BulkPatternImpl) patternIn;
  57.102 +        
  57.103 +        final Map<Res, Collection<TreePath>> occurringPatterns = new HashMap<Res, Collection<TreePath>>();
  57.104 +        final NFA<Input, Res> nfa = pattern.toNFA();
  57.105 +        final Set<String> identifiers = new HashSet<String>();
  57.106 +
  57.107 +        new CollectIdentifiers<Void, TreePath>(identifiers, cancel) {
  57.108 +            private NFA.State active = nfa.getStartingState();
  57.109 +            @Override
  57.110 +            public Void scan(Tree node, TreePath p) {
  57.111 +                if (node == null) {
  57.112 +                    return null;
  57.113 +                }
  57.114 +
  57.115 +                TreePath currentPath = new TreePath(p, node);
  57.116 +                boolean[] goDeeper = new boolean[1];
  57.117 +                final NFA.State newActiveAfterVariable = nfa.transition(active, new Input(Kind.IDENTIFIER, "$", false));
  57.118 +                Input normalizedInput = normalizeInput(node, goDeeper, null);
  57.119 +                boolean ignoreKind = normalizedInput.kind == Kind.IDENTIFIER || normalizedInput.kind == Kind.MEMBER_SELECT;
  57.120 +
  57.121 +                NFA.State newActiveBefore = nfa.transition(active, normalizedInput);
  57.122 +
  57.123 +                if (normalizedInput.name != null && !ignoreKind) {
  57.124 +                    newActiveBefore = nfa.join(newActiveBefore, nfa.transition(active, new Input(normalizedInput.kind, "$", false)));
  57.125 +                }
  57.126 +
  57.127 +                active = newActiveBefore;
  57.128 +
  57.129 +                if (goDeeper[0]) {
  57.130 +                    super.scan(node, currentPath);
  57.131 +                } else {
  57.132 +                    new CollectIdentifiers<Void, Void>(identifiers, cancel).scan(node, null);
  57.133 +                }
  57.134 +                
  57.135 +                if (cancel.get()) return null;
  57.136 +
  57.137 +                NFA.State newActiveAfter = nfa.transition(active, UP);
  57.138 +
  57.139 +                active = nfa.join(newActiveAfter, nfa.transition(newActiveAfterVariable, UP));
  57.140 +
  57.141 +                for (Res r : nfa.getResults(active)) {
  57.142 +                    addOccurrence(r, currentPath);
  57.143 +                }
  57.144 +
  57.145 +                return null;
  57.146 +            }
  57.147 +
  57.148 +            @Override
  57.149 +            public Void scan(Iterable<? extends Tree> nodes, TreePath p) {
  57.150 +                active = nfa.transition(active, new Input(Kind.IDENTIFIER, "(", false));
  57.151 +                try {
  57.152 +                    return super.scan(nodes, p);
  57.153 +                } finally {
  57.154 +                    active = nfa.transition(active, UP);
  57.155 +                }
  57.156 +            }
  57.157 +            
  57.158 +            private void addOccurrence(Res r, TreePath currentPath) {
  57.159 +                Collection<TreePath> occurrences = occurringPatterns.get(r);
  57.160 +                if (occurrences == null) {
  57.161 +                    occurringPatterns.put(r, occurrences = new LinkedList<TreePath>());
  57.162 +                }
  57.163 +                occurrences.add(currentPath);
  57.164 +            }
  57.165 +        }.scan(tree, tree.getParentPath());
  57.166 +
  57.167 +        if (cancel.get()) return null;
  57.168 +        
  57.169 +        Map<String, Collection<TreePath>> result = new HashMap<String, Collection<TreePath>>();
  57.170 +
  57.171 +        for (Entry<Res, Collection<TreePath>> e : occurringPatterns.entrySet()) {
  57.172 +            if (cancel.get()) return null;
  57.173 +            if (!identifiers.containsAll(pattern.getIdentifiers().get(e.getKey().patternIndex))) {
  57.174 +                continue;
  57.175 +            }
  57.176 +
  57.177 +            result.put(e.getKey().pattern, e.getValue());
  57.178 +        }
  57.179 +
  57.180 +        return result;
  57.181 +    }
  57.182 +
  57.183 +    @Override
  57.184 +    public BulkPattern create(Collection<? extends String> code, Collection<? extends Tree> patterns, Collection<? extends AdditionalQueryConstraints> additionalConstraints, final AtomicBoolean cancel) {
  57.185 +        int startState = 0;
  57.186 +        final int[] nextState = new int[] {1};
  57.187 +        final Map<NFA.Key<Input>, NFA.State> transitionTable = new LinkedHashMap<NFA.Key<Input>, NFA.State>();
  57.188 +        Map<Integer, Res> finalStates = new HashMap<Integer, Res>();
  57.189 +        List<Set<? extends String>> identifiers = new LinkedList<Set<? extends String>>();
  57.190 +        List<List<List<String>>> requiredContent = new ArrayList<List<List<String>>>();
  57.191 +        Iterator<? extends String> codeIt = code.iterator();
  57.192 +        int patternIndex = 0;
  57.193 +
  57.194 +        for (final Tree pattern : patterns) {
  57.195 +            final int[] currentState = new int[] {startState};
  57.196 +            final Set<String> patternIdentifiers = new HashSet<String>();
  57.197 +            final List<List<String>> content = new ArrayList<List<String>>();
  57.198 +
  57.199 +            identifiers.add(patternIdentifiers);
  57.200 +            requiredContent.add(content);
  57.201 +
  57.202 +            class Scanner extends CollectIdentifiers<Void, Void> {
  57.203 +                public Scanner() {
  57.204 +                    super(patternIdentifiers, cancel);
  57.205 +                }
  57.206 +                private boolean auxPath;
  57.207 +                private List<String> currentContent;
  57.208 +                {
  57.209 +                    content.add(currentContent = new ArrayList<String>());
  57.210 +                }
  57.211 +                @Override
  57.212 +                public Void scan(Tree t, Void v) {
  57.213 +                    if (t == null) {
  57.214 +                        return null;
  57.215 +                    }
  57.216 +
  57.217 +                    if (Utilities.isMultistatementWildcardTree(t) || multiModifiers(t)) {
  57.218 +                        int target = nextState[0]++;
  57.219 +
  57.220 +                        setBit(transitionTable, NFA.Key.create(currentState[0], new Input(Kind.IDENTIFIER, "$", false)), target);
  57.221 +                        setBit(transitionTable, NFA.Key.create(target, UP), currentState[0]);
  57.222 +
  57.223 +                        content.add(currentContent = new ArrayList<String>());
  57.224 +                        
  57.225 +                        return null;
  57.226 +                    }
  57.227 +
  57.228 +                    if (t.getKind() == Kind.BLOCK) {
  57.229 +                        StatementTree singletonStatement = null;
  57.230 +                        BlockTree bt = (BlockTree) t;
  57.231 +
  57.232 +                        if (!bt.isStatic()) {
  57.233 +                            switch (bt.getStatements().size()) {
  57.234 +                                case 1:
  57.235 +                                    singletonStatement = bt.getStatements().get(0);
  57.236 +                                    break;
  57.237 +                                case 2:
  57.238 +                                    if (Utilities.isMultistatementWildcardTree(bt.getStatements().get(0))) {
  57.239 +                                        singletonStatement = bt.getStatements().get(1);
  57.240 +                                    } else {
  57.241 +                                        if (Utilities.isMultistatementWildcardTree(bt.getStatements().get(1))) {
  57.242 +                                            singletonStatement = bt.getStatements().get(0);
  57.243 +                                        }
  57.244 +                                    }
  57.245 +                                    break;
  57.246 +                                case 3:
  57.247 +                                    if (Utilities.isMultistatementWildcardTree(bt.getStatements().get(0)) && Utilities.isMultistatementWildcardTree(bt.getStatements().get(2))) {
  57.248 +                                        singletonStatement = bt.getStatements().get(1);
  57.249 +                                    }
  57.250 +                                    break;
  57.251 +                            }
  57.252 +                        }
  57.253 +
  57.254 +                        if (singletonStatement != null) {
  57.255 +                            int backup = currentState[0];
  57.256 +
  57.257 +                            boolean oldAuxPath = auxPath;
  57.258 +
  57.259 +                            auxPath = true;
  57.260 +
  57.261 +                            scan(singletonStatement, null);
  57.262 +
  57.263 +                            auxPath = oldAuxPath;
  57.264 +
  57.265 +                            int target = currentState[0];
  57.266 +
  57.267 +                            setBit(transitionTable, NFA.Key.create(backup, new Input(Kind.BLOCK, null, false)), currentState[0] = nextState[0]++);
  57.268 +                            setBit(transitionTable, NFA.Key.create(currentState[0], new Input(Kind.IDENTIFIER, "(", false)), currentState[0] = nextState[0]++);
  57.269 +
  57.270 +                            for (StatementTree st : bt.getStatements()) {
  57.271 +                                scan(st, null);
  57.272 +                            }
  57.273 +
  57.274 +                            setBit(transitionTable, NFA.Key.create(currentState[0], UP), currentState[0] = nextState[0]++);
  57.275 +                            setBit(transitionTable, NFA.Key.create(currentState[0], UP), target);
  57.276 +                            currentState[0] = target;
  57.277 +
  57.278 +                            return null;
  57.279 +                        }
  57.280 +                    }
  57.281 +                    
  57.282 +                    boolean[] goDeeper = new boolean[1];
  57.283 +                    Input[] bypass = new Input[1];
  57.284 +                    Input i = normalizeInput(t, goDeeper, bypass);
  57.285 +
  57.286 +                    if (!TO_IGNORE.contains(i.kind) && !auxPath) {
  57.287 +                        currentContent.add(kind2EncodedString.get(i.kind));
  57.288 +                    }
  57.289 +
  57.290 +                    if (i.name != null && !auxPath) {
  57.291 +                        if (!"$".equals(i.name)) {
  57.292 +                            if (isIdentifierAcceptable(i.name)) {
  57.293 +                                currentContent.add(i.name);
  57.294 +                            }
  57.295 +                            if (Utilities.isPureMemberSelect(t, false)) {
  57.296 +                                content.add(currentContent = new ArrayList<String>());
  57.297 +                            }
  57.298 +                        } else {
  57.299 +                            content.add(currentContent = new ArrayList<String>());
  57.300 +                        }
  57.301 +                    }
  57.302 +
  57.303 +                    int backup = currentState[0];
  57.304 +
  57.305 +                    handleTree(i, goDeeper, t, bypass);
  57.306 +
  57.307 +                    boolean oldAuxPath = auxPath;
  57.308 +
  57.309 +                    auxPath = true;
  57.310 +
  57.311 +                    if (StatementTree.class.isAssignableFrom(t.getKind().asInterface()) && t != pattern) {
  57.312 +                        int target = currentState[0];
  57.313 +
  57.314 +                        setBit(transitionTable, NFA.Key.create(backup, new Input(Kind.BLOCK, null, false)), currentState[0] = nextState[0]++);
  57.315 +                        setBit(transitionTable, NFA.Key.create(currentState[0], new Input(Kind.IDENTIFIER, "(", false)), currentState[0] = nextState[0]++);
  57.316 +                        handleTree(i, goDeeper, t, bypass);
  57.317 +                        setBit(transitionTable, NFA.Key.create(currentState[0], UP), currentState[0] = nextState[0]++);
  57.318 +                        setBit(transitionTable, NFA.Key.create(currentState[0], UP), target);
  57.319 +                        currentState[0] = target;
  57.320 +                    }
  57.321 +
  57.322 +                    auxPath = oldAuxPath;
  57.323 +
  57.324 +                    return null;
  57.325 +                }
  57.326 +
  57.327 +                @Override
  57.328 +                public Void scan(Iterable<? extends Tree> nodes, Void p) {
  57.329 +                    setBit(transitionTable, NFA.Key.create(currentState[0], new Input(Kind.IDENTIFIER, "(", false)), currentState[0] = nextState[0]++);
  57.330 +                    try {
  57.331 +                        return super.scan(nodes, p);
  57.332 +                    } finally {
  57.333 +                        setBit(transitionTable, NFA.Key.create(currentState[0], UP), currentState[0] = nextState[0]++);
  57.334 +                    }
  57.335 +                }
  57.336 +
  57.337 +                private void handleTree(Input i, boolean[] goDeeper, Tree t, Input[] bypass) {
  57.338 +                    int backup = currentState[0];
  57.339 +                    int target = nextState[0]++;
  57.340 +
  57.341 +                    setBit(transitionTable, NFA.Key.create(backup, i), currentState[0] = nextState[0]++);
  57.342 +
  57.343 +                    if (goDeeper[0]) {
  57.344 +                        super.scan(t, null);
  57.345 +                    } else {
  57.346 +                        new CollectIdentifiers<Void, Void>(patternIdentifiers, cancel).scan(t, null);
  57.347 +                        int aux = nextState[0]++;
  57.348 +                        setBit(transitionTable, NFA.Key.create(backup, new Input(Kind.MEMBER_SELECT, i.name, false)), aux);
  57.349 +                        setBit(transitionTable, NFA.Key.create(aux, new Input(Kind.IDENTIFIER, "$", false)), aux = nextState[0]++);
  57.350 +                        setBit(transitionTable, NFA.Key.create(aux, UP), aux = nextState[0]++);
  57.351 +                        setBit(transitionTable, NFA.Key.create(aux, UP), target);
  57.352 +                    }
  57.353 +
  57.354 +                    setBit(transitionTable, NFA.Key.create(currentState[0], UP), target);
  57.355 +                    
  57.356 +                    if (bypass[0] != null) {
  57.357 +                        int intermediate = nextState[0]++;
  57.358 +                        
  57.359 +                        setBit(transitionTable, NFA.Key.create(backup, bypass[0]), intermediate);
  57.360 +                        setBit(transitionTable, NFA.Key.create(intermediate, UP), target);
  57.361 +                    }
  57.362 +                    
  57.363 +                    currentState[0] = target;
  57.364 +                }
  57.365 +            }
  57.366 +
  57.367 +            Scanner s = new Scanner();
  57.368 +
  57.369 +            s.scan(pattern, null);
  57.370 +
  57.371 +            finalStates.put(currentState[0], new Res(codeIt.next(), patternIndex++));
  57.372 +        }
  57.373 +
  57.374 +        if (cancel.get()) return null;
  57.375 +        
  57.376 +        NFA<Input, Res> nfa = NFA.<Input, Res>create(startState, nextState[0], null, transitionTable, finalStates);
  57.377 +
  57.378 +        return new BulkPatternImpl(new LinkedList<String>(code), identifiers, requiredContent, new LinkedList<AdditionalQueryConstraints>(additionalConstraints), nfa);
  57.379 +    }
  57.380 +
  57.381 +    private static void setBit(Map<NFA.Key<Input>, NFA.State> transitionTable, NFA.Key<Input> input, int state) {
  57.382 +        NFA.State target = transitionTable.get(input);
  57.383 +
  57.384 +        if (target == null) {
  57.385 +            transitionTable.put(input, target = NFA.State.create());
  57.386 +        }
  57.387 +
  57.388 +        target.mutableOr(state);
  57.389 +    }
  57.390 +
  57.391 +    private static Input normalizeInput(Tree t, boolean[] goDeeper, Input[] bypass) {
  57.392 +        if (t.getKind() == Kind.IDENTIFIER && ((IdentifierTree) t).getName().toString().startsWith("$")) {
  57.393 +            goDeeper[0] = false;
  57.394 +            return new Input(Kind.IDENTIFIER, "$", false);
  57.395 +        }
  57.396 +
  57.397 +        if (Utilities.getWildcardTreeName(t) != null) {
  57.398 +            goDeeper[0] = false;
  57.399 +            return new Input(Kind.IDENTIFIER, "$", false);
  57.400 +        }
  57.401 +        
  57.402 +        if (t.getKind() == Kind.IDENTIFIER) {
  57.403 +            goDeeper[0] = false;
  57.404 +            String name = ((IdentifierTree) t).getName().toString();
  57.405 +            return new Input(Kind.IDENTIFIER, name, false);
  57.406 +        }
  57.407 +
  57.408 +        if (t.getKind() == Kind.MEMBER_SELECT) {
  57.409 +            String name = ((MemberSelectTree) t).getIdentifier().toString();
  57.410 +            if (name.startsWith("$")) {
  57.411 +                goDeeper[0] = false;//???
  57.412 +                return new Input(Kind.IDENTIFIER, "$", false);
  57.413 +            }
  57.414 +            if (bypass != null && Utilities.isPureMemberSelect(t, true)) {
  57.415 +                bypass[0] = new Input(Kind.IDENTIFIER, name, false);
  57.416 +            }
  57.417 +            goDeeper[0] = true;
  57.418 +            return new Input(Kind.MEMBER_SELECT, name, false);
  57.419 +        }
  57.420 +
  57.421 +        goDeeper[0] = true;
  57.422 +
  57.423 +        String name;
  57.424 +
  57.425 +        switch (t.getKind()) {
  57.426 +            case CLASS: name = ((ClassTree)t).getSimpleName().toString(); break;
  57.427 +            case VARIABLE: name = ((VariableTree)t).getName().toString(); break;
  57.428 +            case METHOD: name = ((MethodTree)t).getName().toString(); break;
  57.429 +            case BOOLEAN_LITERAL: name = ((LiteralTree) t).getValue().toString(); break;
  57.430 +            default: name = null;
  57.431 +        }
  57.432 +
  57.433 +        if (name != null) {
  57.434 +            if (!name.isEmpty() && name.charAt(0) == '$') {
  57.435 +                name = "$";
  57.436 +            }
  57.437 +        }
  57.438 +        return new Input(t.getKind(), name, false);
  57.439 +    }
  57.440 +    
  57.441 +    private boolean multiModifiers(Tree t) {
  57.442 +        if (t.getKind() != Kind.MODIFIERS) return false;
  57.443 +        
  57.444 +        List<AnnotationTree> annotations = new ArrayList<AnnotationTree>(((ModifiersTree) t).getAnnotations());
  57.445 +
  57.446 +        return !annotations.isEmpty() && annotations.get(0).getAnnotationType().getKind() == Kind.IDENTIFIER;
  57.447 +    }
  57.448 +
  57.449 +    @Override
  57.450 +    public boolean matches(CompilationInfo info, AtomicBoolean cancel, TreePath tree, BulkPattern pattern) {
  57.451 +        //XXX: performance
  57.452 +        return !match(info, cancel, tree, pattern).isEmpty();
  57.453 +    }
  57.454 +
  57.455 +    private static final Set<Kind> TO_IGNORE = EnumSet.of(Kind.BLOCK, Kind.IDENTIFIER, Kind.MEMBER_SELECT);
  57.456 +
  57.457 +    @Override
  57.458 +    public void encode(Tree tree, final EncodingContext ctx, AtomicBoolean cancel) {
  57.459 +        final Set<String> identifiers = new HashSet<String>();
  57.460 +        final List<String> content = new ArrayList<String>();
  57.461 +        if (!ctx.isForDuplicates()) {
  57.462 +            new CollectIdentifiers<Void, Void>(identifiers, cancel).scan(tree, null);
  57.463 +            try {
  57.464 +                int size = identifiers.size();
  57.465 +                ctx.getOut().write((size >> 24) & 0xFF);
  57.466 +                ctx.getOut().write((size >> 16) & 0xFF);
  57.467 +                ctx.getOut().write((size >>  8) & 0xFF);
  57.468 +                ctx.getOut().write((size >>  0) & 0xFF);
  57.469 +                for (String ident : identifiers) {
  57.470 +                    ctx.getOut().write(ident.getBytes("UTF-8"));//XXX: might probably contain ';'
  57.471 +                    ctx.getOut().write(';');
  57.472 +                }
  57.473 +            } catch (IOException ex) {
  57.474 +                throw new IllegalStateException(ex);
  57.475 +            }
  57.476 +        }
  57.477 +        if (cancel.get());
  57.478 +        new CollectIdentifiers<Void, Void>(new HashSet<String>(), cancel) {
  57.479 +            private boolean encode = true;
  57.480 +            @Override
  57.481 +            public Void scan(Tree t, Void v) {
  57.482 +                if (t == null) return null;
  57.483 +
  57.484 +                if (t instanceof StatementTree && Utilities.isMultistatementWildcardTree((StatementTree) t)) {
  57.485 +                    return null;
  57.486 +                }
  57.487 +
  57.488 +                boolean[] goDeeper = new boolean[1];
  57.489 +
  57.490 +                Input i = normalizeInput(t, goDeeper, null);
  57.491 +                try {
  57.492 +                    ctx.getOut().write('(');
  57.493 +                    ctx.getOut().write(kind2Encoded.get(i.kind));
  57.494 +                    if (!TO_IGNORE.contains(i.kind)) {
  57.495 +                        content.add(kind2EncodedString.get(i.kind));
  57.496 +                    }
  57.497 +                    if (i.name != null) {
  57.498 +                        if (encode) {
  57.499 +                            ctx.getOut().write('$');
  57.500 +                            ctx.getOut().write(i.name.getBytes("UTF-8"));
  57.501 +                            ctx.getOut().write(';');
  57.502 +                        }
  57.503 +                        if (isIdentifierAcceptable(i.name)) content.add(i.name);
  57.504 +                    }
  57.505 +
  57.506 +                    boolean oldEncode = encode;
  57.507 +
  57.508 +                    encode &= goDeeper[0];
  57.509 +                    super.scan(t, v);
  57.510 +                    encode = oldEncode;
  57.511 +
  57.512 +                    ctx.getOut().write(')');
  57.513 +                } catch (IOException ex) {
  57.514 +                    //XXX
  57.515 +                    Exceptions.printStackTrace(ex);
  57.516 +                }
  57.517 +
  57.518 +                return null;
  57.519 +            }
  57.520 +            @Override
  57.521 +            public Void scan(Iterable<? extends Tree> nodes, Void p) {
  57.522 +                try {
  57.523 +                    ctx.getOut().write('(');
  57.524 +                    ctx.getOut().write(kind2Encoded.get(Kind.IDENTIFIER));
  57.525 +                    ctx.getOut().write('$');
  57.526 +                    ctx.getOut().write('(');
  57.527 +                    ctx.getOut().write(';');
  57.528 +                    super.scan(nodes, p);
  57.529 +                    ctx.getOut().write(')');
  57.530 +                } catch (IOException ex) {
  57.531 +                    //XXX
  57.532 +                    Exceptions.printStackTrace(ex);
  57.533 +                }
  57.534 +                return null;
  57.535 +            }
  57.536 +        }.scan(tree, null);
  57.537 +
  57.538 +        ctx.setIdentifiers(identifiers);
  57.539 +        ctx.setContent(content);
  57.540 +        if (cancel.get());
  57.541 +    }
  57.542 +
  57.543 +    @Override
  57.544 +    public boolean matches(InputStream encoded, AtomicBoolean cancel, BulkPattern patternIn) {
  57.545 +        try {
  57.546 +            return !matchesImpl(encoded, cancel, patternIn, false).isEmpty();
  57.547 +        } catch (IOException ex) {
  57.548 +            Exceptions.printStackTrace(ex);
  57.549 +            return false;
  57.550 +        }
  57.551 +    }
  57.552 +
  57.553 +    @Override
  57.554 +    public Map<String, Integer> matchesWithFrequencies(InputStream encoded, BulkPattern patternIn, AtomicBoolean cancel) {
  57.555 +        try {
  57.556 +            return matchesImpl(encoded, cancel, patternIn, true);
  57.557 +        } catch (IOException ex) {
  57.558 +            Exceptions.printStackTrace(ex);
  57.559 +            return Collections.emptyMap();
  57.560 +        }
  57.561 +    }
  57.562 +
  57.563 +    public Map<String, Integer> matchesImpl(InputStream encoded, AtomicBoolean cancel, BulkPattern patternIn, boolean withFrequencies) throws IOException {
  57.564 +        BulkPatternImpl pattern = (BulkPatternImpl) patternIn;
  57.565 +        final NFA<Input, Res> nfa = pattern.toNFA();
  57.566 +        Stack<NFA.State> skips = new Stack<NFA.State>();
  57.567 +        NFA.State active = nfa.getStartingState();
  57.568 +        int identSize = 0;
  57.569 +
  57.570 +        identSize = encoded.read();
  57.571 +        identSize = (identSize << 8) + encoded.read();
  57.572 +        identSize = (identSize << 8) + encoded.read();
  57.573 +        identSize = (identSize << 8) + encoded.read();
  57.574 +
  57.575 +        Set<String> identifiers = new HashSet<String>(2 * identSize);
  57.576 +
  57.577 +        while (identSize-- > 0) {
  57.578 +            if (cancel.get()) return null;
  57.579 +            int read = encoded.read();
  57.580 +
  57.581 +            ByteArrayOutputStream baos = new ByteArrayOutputStream();
  57.582 +
  57.583 +            //read name:
  57.584 +            while (read != ';') {
  57.585 +                baos.write(read);
  57.586 +                read = encoded.read();
  57.587 +            }
  57.588 +
  57.589 +            identifiers.add(new String(baos.toByteArray(), "UTF-8"));
  57.590 +        }
  57.591 +
  57.592 +        Map<String, Integer> patternsAndFrequencies = new HashMap<String, Integer>();
  57.593 +        int read = encoded.read();
  57.594 +        
  57.595 +        while (read != (-1)) {
  57.596 +            if (cancel.get()) return null;
  57.597 +            if (read == '(') {
  57.598 +                read = encoded.read(); //kind
  57.599 +
  57.600 +                Kind k = encoded2Kind.get((read << 8) + encoded.read());
  57.601 +
  57.602 +                read = encoded.read();
  57.603 +
  57.604 +                String name;
  57.605 +
  57.606 +                if (read == '$') {
  57.607 +                    //XXX:
  57.608 +                    read = encoded.read();
  57.609 +
  57.610 +                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
  57.611 +
  57.612 +                    //read name:
  57.613 +                    while (read != ';') {
  57.614 +                        baos.write(read);
  57.615 +                        read = encoded.read();
  57.616 +                    }
  57.617 +
  57.618 +                    read = encoded.read();
  57.619 +                    name = new String(baos.toByteArray(), "UTF-8");
  57.620 +                } else {
  57.621 +                    name = null;
  57.622 +                }
  57.623 +                
  57.624 +                final NFA.State newActiveAfterVariable = nfa.transition(active, new Input(Kind.IDENTIFIER, "$", false));
  57.625 +                Input normalizedInput = new Input(k, name, false);
  57.626 +                boolean ignoreKind = normalizedInput.kind == Kind.IDENTIFIER || normalizedInput.kind == Kind.MEMBER_SELECT;
  57.627 +
  57.628 +                NFA.State newActive = nfa.transition(active, normalizedInput);
  57.629 +
  57.630 +                if (normalizedInput.name != null && !ignoreKind) {
  57.631 +                    newActive = nfa.join(newActive, nfa.transition(active, new Input(k, "$", false)));
  57.632 +                }
  57.633 +
  57.634 +                active = newActive;
  57.635 +
  57.636 +                skips.push(newActiveAfterVariable);
  57.637 +            } else {
  57.638 +                NFA.State newActiveAfterVariable = skips.pop();
  57.639 +                NFA.State newActive = nfa.transition(active, UP);
  57.640 +                NFA.State s2 = nfa.transition(newActiveAfterVariable, UP);
  57.641 +
  57.642 +                active = nfa.join(newActive, s2);
  57.643 +                
  57.644 +                for (Res res : nfa.getResults(active)) {
  57.645 +                    if (identifiers.containsAll(pattern.getIdentifiers().get(res.patternIndex))) {
  57.646 +                        if (!withFrequencies) {
  57.647 +                            patternsAndFrequencies.put(res.pattern, 1);
  57.648 +                            return patternsAndFrequencies;
  57.649 +                        }
  57.650 +                        
  57.651 +                        Integer freqs = patternsAndFrequencies.get(res.pattern);
  57.652 +
  57.653 +                        if (freqs == null) freqs = 0;
  57.654 +
  57.655 +                        patternsAndFrequencies.put(res.pattern, freqs + 1);
  57.656 +                    }
  57.657 +                }
  57.658 +
  57.659 +                read = encoded.read();
  57.660 +            }
  57.661 +        }
  57.662 +
  57.663 +        return patternsAndFrequencies;
  57.664 +    }
  57.665 +
  57.666 +    private static final Map<Kind, byte[]> kind2Encoded;
  57.667 +    private static final Map<Kind, String> kind2EncodedString;
  57.668 +    private static final Map<Integer, Kind> encoded2Kind;
  57.669 +
  57.670 +    static {
  57.671 +        kind2Encoded = new EnumMap<Kind, byte[]>(Kind.class);
  57.672 +        kind2EncodedString = new EnumMap<Kind, String>(Kind.class);
  57.673 +        encoded2Kind = new HashMap<Integer, Kind>();
  57.674 +
  57.675 +        for (Kind k : Kind.values()) {
  57.676 +            String enc = Integer.toHexString(k.ordinal());
  57.677 +
  57.678 +            if (enc.length() < 2) {
  57.679 +                enc = "0" + enc;
  57.680 +            }
  57.681 +
  57.682 +            try {
  57.683 +                final byte[] bytes = enc.getBytes("UTF-8");
  57.684 +
  57.685 +                assert bytes.length == 2;
  57.686 +
  57.687 +                kind2Encoded.put(k, bytes);
  57.688 +                kind2EncodedString.put(k, enc);
  57.689 +
  57.690 +                encoded2Kind.put((bytes[0] << 8) + bytes[1], k);
  57.691 +            } catch (UnsupportedEncodingException ex) {
  57.692 +                throw new IllegalStateException(ex);
  57.693 +            }
  57.694 +        }
  57.695 +    }
  57.696 +
  57.697 +    public static class BulkPatternImpl extends BulkPattern {
  57.698 +
  57.699 +        private final NFA<Input, Res> nfa;
  57.700 +
  57.701 +        private BulkPatternImpl(List<? extends String> patterns, List<? extends Set<? extends String>> identifiers, List<List<List<String>>> requiredContent, List<AdditionalQueryConstraints> additionalConstraints, NFA<Input, Res> nfa) {
  57.702 +            super(patterns, identifiers, requiredContent, additionalConstraints);
  57.703 +            this.nfa = nfa;
  57.704 +        }
  57.705 +
  57.706 +        NFA<Input, Res> toNFA() {
  57.707 +            return nfa;
  57.708 +        }
  57.709 +        
  57.710 +    }
  57.711 +
  57.712 +    private static final class Res {
  57.713 +        private final String pattern;
  57.714 +        private final int patternIndex;
  57.715 +
  57.716 +        public Res(String pattern, int patternIndex) {
  57.717 +            this.pattern = pattern;
  57.718 +            this.patternIndex = patternIndex;
  57.719 +        }
  57.720 +
  57.721 +    }
  57.722 +
  57.723 +    private static final class Input {
  57.724 +        private final Kind kind;
  57.725 +        private final String name;
  57.726 +        private final boolean end;
  57.727 +
  57.728 +        private Input(Kind kind, String name, boolean end) {
  57.729 +            this.kind = kind;
  57.730 +            this.name = name;
  57.731 +            this.end = end;
  57.732 +        }
  57.733 +
  57.734 +        @Override
  57.735 +        public boolean equals(Object obj) {
  57.736 +            if (obj == null) {
  57.737 +                return false;
  57.738 +            }
  57.739 +            if (getClass() != obj.getClass()) {
  57.740 +                return false;
  57.741 +            }
  57.742 +            final Input other = (Input) obj;
  57.743 +            if (this.kind != other.kind) {
  57.744 +                return false;
  57.745 +            }
  57.746 +            if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
  57.747 +                return false;
  57.748 +            }
  57.749 +            if (this.end != other.end) {
  57.750 +                return false;
  57.751 +            }
  57.752 +            return true;
  57.753 +        }
  57.754 +
  57.755 +        @Override
  57.756 +        public int hashCode() {
  57.757 +            int hash = 7;
  57.758 +            hash = 47 * hash + (this.kind != null ? this.kind.hashCode() : 17);
  57.759 +            hash = 47 * hash + (this.name != null ? this.name.hashCode() : 0);
  57.760 +            hash = 47 * hash + (this.end ? 1 : 0);
  57.761 +            return hash;
  57.762 +        }
  57.763 +
  57.764 +        @Override
  57.765 +        public String toString() {
  57.766 +            return kind + ", " + name + ", " + end;
  57.767 +        }
  57.768 +
  57.769 +    }
  57.770 +
  57.771 +    private static final Input UP = new Input(null, null, true);
  57.772 +
  57.773 +    private static boolean isIdentifierAcceptable(CharSequence content) {
  57.774 +        if (content.length() == 0) return false;
  57.775 +        if (content.charAt(0) == '$' || content.charAt(0) == '<') return false;
  57.776 +        String stringValue = content.toString();
  57.777 +        if (stringValue.contentEquals("java") || "lang".equals(stringValue)) return false;
  57.778 +        return true;
  57.779 +    }
  57.780 +
  57.781 +    private static class CollectIdentifiers<R, P> extends CancellableTreeScanner<R, P> {
  57.782 +
  57.783 +        private final Set<String> identifiers;
  57.784 +
  57.785 +        public CollectIdentifiers(Set<String> identifiers, AtomicBoolean cancel) {
  57.786 +            super(cancel);
  57.787 +            this.identifiers = identifiers;
  57.788 +        }
  57.789 +
  57.790 +        private void addIdentifier(Name ident) {
  57.791 +            if (!isIdentifierAcceptable(ident)) return;
  57.792 +            identifiers.add(ident.toString());
  57.793 +        }
  57.794 +
  57.795 +        @Override
  57.796 +        public R visitMemberSelect(MemberSelectTree node, P p) {
  57.797 +            addIdentifier(node.getIdentifier());
  57.798 +            return super.visitMemberSelect(node, p);
  57.799 +        }
  57.800 +
  57.801 +        @Override
  57.802 +        public R visitIdentifier(IdentifierTree node, P p) {
  57.803 +            addIdentifier(node.getName());
  57.804 +            return super.visitIdentifier(node, p);
  57.805 +        }
  57.806 +
  57.807 +        @Override
  57.808 +        public R visitClass(ClassTree node, P p) {
  57.809 +            if (node.getSimpleName().length() == 0) {
  57.810 +                return scan(Utilities.filterHidden(null, node.getMembers()), p);
  57.811 +            }
  57.812 +            addIdentifier(node.getSimpleName());
  57.813 +            return super.visitClass(node, p);
  57.814 +        }
  57.815 +
  57.816 +        @Override
  57.817 +        public R visitMethod(MethodTree node, P p) {
  57.818 +            addIdentifier(node.getName());
  57.819 +            return super.visitMethod(node, p);
  57.820 +        }
  57.821 +
  57.822 +        @Override
  57.823 +        public R visitVariable(VariableTree node, P p) {
  57.824 +            addIdentifier(node.getName());
  57.825 +            return super.visitVariable(node, p);
  57.826 +        }
  57.827 +
  57.828 +    }
  57.829 +}
    58.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    58.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/pm/PatternCompiler.java	Wed May 08 21:47:42 2013 +0200
    58.3 @@ -0,0 +1,72 @@
    58.4 +/*
    58.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    58.6 + *
    58.7 + * Copyright 2008-2010 Oracle and/or its affiliates. All rights reserved.
    58.8 + *
    58.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   58.10 + * Other names may be trademarks of their respective owners.
   58.11 + *
   58.12 + * The contents of this file are subject to the terms of either the GNU
   58.13 + * General Public License Version 2 only ("GPL") or the Common
   58.14 + * Development and Distribution License("CDDL") (collectively, the
   58.15 + * "License"). You may not use this file except in compliance with the
   58.16 + * License. You can obtain a copy of the License at
   58.17 + * http://www.netbeans.org/cddl-gplv2.html
   58.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   58.19 + * specific language governing permissions and limitations under the
   58.20 + * License.  When distributing the software, include this License Header
   58.21 + * Notice in each file and include the License file at
   58.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   58.23 + * particular file as subject to the "Classpath" exception as provided
   58.24 + * by Oracle in the GPL Version 2 section of the License file that
   58.25 + * accompanied this code. If applicable, add the following below the
   58.26 + * License Header, with the fields enclosed by brackets [] replaced by
   58.27 + * your own identifying information:
   58.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   58.29 + *
   58.30 + * If you wish your version of this file to be governed by only the CDDL
   58.31 + * or only the GPL Version 2, indicate your decision by adding
   58.32 + * "[Contributor] elects to include this software in this distribution
   58.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   58.34 + * single choice of license, a recipient has the option to distribute
   58.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   58.36 + * to extend the choice of license to its licensees as provided above.
   58.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   58.38 + * Version 2 license, then the option applies only if the new code is
   58.39 + * made subject to such option by the copyright holder.
   58.40 + *
   58.41 + * Contributor(s):
   58.42 + *
   58.43 + * Portions Copyrighted 2008-2009 Sun Microsystems, Inc.
   58.44 + */
   58.45 +
   58.46 +package org.netbeans.modules.java.hints.spiimpl.pm;
   58.47 +
   58.48 +import com.sun.source.tree.Scope;
   58.49 +import com.sun.source.tree.Tree;
   58.50 +import com.sun.source.util.TreePath;
   58.51 +import java.util.Map;
   58.52 +import javax.lang.model.type.TypeMirror;
   58.53 +import org.netbeans.api.java.source.CompilationInfo;
   58.54 +import org.netbeans.modules.java.hints.spiimpl.Utilities;
   58.55 +import org.netbeans.api.java.source.matching.Pattern;
   58.56 +
   58.57 +/**XXX: cancelability!
   58.58 + *
   58.59 + * @author Jan Lahoda
   58.60 + */
   58.61 +public class PatternCompiler {
   58.62 +
   58.63 +    public static Pattern compile(CompilationInfo info, String pattern, Map<String, TypeMirror> constraints, Iterable<? extends String> imports) {
   58.64 +        Scope scope = Utilities.constructScope(info, constraints, imports);
   58.65 +
   58.66 +        if (scope == null) {
   58.67 +            return null; //TODO: can happen?
   58.68 +        }
   58.69 +
   58.70 +        Tree patternTree = Utilities.parseAndAttribute(info, pattern, scope);
   58.71 +
   58.72 +        return Pattern.createPatternWithFreeVariables(new TreePath(new TreePath(info.getCompilationUnit()), patternTree), constraints);
   58.73 +    }
   58.74 +
   58.75 +}
    59.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    59.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/processor/Bundle.properties	Wed May 08 21:47:42 2013 +0200
    59.3 @@ -0,0 +1,3 @@
    59.4 +OpenIDE-Module-Name=Java Hints Annotation Processor
    59.5 +OpenIDE-Module-Display-Category=Java
    59.6 +OpenIDE-Module-Short-Description=Java Hints Annotation Processor
    60.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    60.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/processor/JavaHintsAnnotationProcessor.java	Wed May 08 21:47:42 2013 +0200
    60.3 @@ -0,0 +1,635 @@
    60.4 +/*
    60.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    60.6 + *
    60.7 + * Copyright 2008-2010 Oracle and/or its affiliates. All rights reserved.
    60.8 + *
    60.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   60.10 + * Other names may be trademarks of their respective owners.
   60.11 + *
   60.12 + * The contents of this file are subject to the terms of either the GNU
   60.13 + * General Public License Version 2 only ("GPL") or the Common
   60.14 + * Development and Distribution License("CDDL") (collectively, the
   60.15 + * "License"). You may not use this file except in compliance with the
   60.16 + * License. You can obtain a copy of the License at
   60.17 + * http://www.netbeans.org/cddl-gplv2.html
   60.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   60.19 + * specific language governing permissions and limitations under the
   60.20 + * License.  When distributing the software, include this License Header
   60.21 + * Notice in each file and include the License file at
   60.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   60.23 + * particular file as subject to the "Classpath" exception as provided
   60.24 + * by Oracle in the GPL Version 2 section of the License file that
   60.25 + * accompanied this code. If applicable, add the following below the
   60.26 + * License Header, with the fields enclosed by brackets [] replaced by
   60.27 + * your own identifying information:
   60.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   60.29 + *
   60.30 + * If you wish your version of this file to be governed by only the CDDL
   60.31 + * or only the GPL Version 2, indicate your decision by adding
   60.32 + * "[Contributor] elects to include this software in this distribution
   60.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   60.34 + * single choice of license, a recipient has the option to distribute
   60.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   60.36 + * to extend the choice of license to its licensees as provided above.
   60.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   60.38 + * Version 2 license, then the option applies only if the new code is
   60.39 + * made subject to such option by the copyright holder.
   60.40 + *
   60.41 + * Contributor(s):
   60.42 + *
   60.43 + * Portions Copyrighted 2008-2010 Sun Microsystems, Inc.
   60.44 + */
   60.45 +
   60.46 +package org.netbeans.modules.java.hints.spiimpl.processor;
   60.47 +
   60.48 +import java.lang.reflect.Array;
   60.49 +import java.util.Map.Entry;
   60.50 +import java.util.*;
   60.51 +import java.util.AbstractMap.SimpleEntry;
   60.52 +import java.util.logging.Logger;
   60.53 +import java.util.regex.Matcher;
   60.54 +import java.util.regex.Pattern;
   60.55 +import javax.annotation.processing.Processor;
   60.56 +import javax.annotation.processing.RoundEnvironment;
   60.57 +import javax.annotation.processing.SupportedAnnotationTypes;
   60.58 +import javax.annotation.processing.SupportedSourceVersion;
   60.59 +import javax.lang.model.SourceVersion;
   60.60 +import javax.lang.model.element.*;
   60.61 +import javax.lang.model.type.DeclaredType;
   60.62 +import javax.lang.model.type.TypeMirror;
   60.63 +import javax.lang.model.util.AbstractAnnotationValueVisitor6;
   60.64 +import javax.lang.model.util.ElementFilter;
   60.65 +import javax.lang.model.util.ElementScanner6;
   60.66 +import javax.lang.model.util.Elements;
   60.67 +import javax.lang.model.util.Types;
   60.68 +import javax.tools.Diagnostic.Kind;
   60.69 +import org.openide.filesystems.annotations.LayerBuilder;
   60.70 +import org.openide.filesystems.annotations.LayerBuilder.File;
   60.71 +import org.openide.filesystems.annotations.LayerGeneratingProcessor;
   60.72 +import org.openide.filesystems.annotations.LayerGenerationException;
   60.73 +import org.openide.util.NbCollections;
   60.74 +import org.openide.util.lookup.ServiceProvider;
   60.75 +
   60.76 +/**Inspired by https://sezpoz.dev.java.net/.
   60.77 + *
   60.78 + * @author lahvac
   60.79 + */
   60.80 +@SupportedSourceVersion(SourceVersion.RELEASE_6)
   60.81 +@SupportedAnnotationTypes("org.netbeans.spi.java.hints.*")
   60.82 +@ServiceProvider(service=Processor.class, position=100)
   60.83 +public class JavaHintsAnnotationProcessor extends LayerGeneratingProcessor {
   60.84 +    
   60.85 +    private static final Logger LOG = Logger.getLogger(JavaHintsAnnotationProcessor.class.getName());
   60.86 +    
   60.87 +    @Override
   60.88 +    protected boolean handleProcess(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) throws LayerGenerationException {
   60.89 +        if (!roundEnv.processingOver()) {
   60.90 +            generateTypeList("org.netbeans.spi.java.hints.Hint", roundEnv);
   60.91 +        }
   60.92 +
   60.93 +        return false;
   60.94 +    }
   60.95 +
   60.96 +    private static final String[] TRIGGERS = new String[] {
   60.97 +        "org.netbeans.spi.java.hints.TriggerTreeKind",
   60.98 +        "org.netbeans.spi.java.hints.TriggerPattern",
   60.99 +        "org.netbeans.spi.java.hints.TriggerPatterns",
  60.100 +    };
  60.101 +
  60.102 +    private static final String[] OPTIONS = new String[] {
  60.103 +        "org.netbeans.spi.java.hints.BooleanOption"
  60.104 +    };
  60.105 +
  60.106 +    private void generateTypeList(String annotationName, RoundEnvironment roundEnv) throws LayerGenerationException {
  60.107 +        TypeElement hint = processingEnv.getElementUtils().getTypeElement(annotationName);
  60.108 +
  60.109 +        if (hint == null) return ;
  60.110 +        
  60.111 +        for (Element annotated : roundEnv.getElementsAnnotatedWith(hint)) {
  60.112 +            if (!verifyHintAnnotationAcceptable(annotated)) continue;
  60.113 +            if (!annotated.getKind().isClass() && !annotated.getKind().isInterface()) {
  60.114 +                if (annotated.getKind() != ElementKind.METHOD) {
  60.115 +                    //the compiler should have already warned about this
  60.116 +                    continue;
  60.117 +                }
  60.118 +
  60.119 +                annotated = annotated.getEnclosingElement();
  60.120 +            } else {
  60.121 +                if (!annotated.getKind().isClass()) {
  60.122 +                    //the compiler should have already warned about this
  60.123 +                    continue;
  60.124 +                }
  60.125 +            }
  60.126 +
  60.127 +            if (!annotated.getKind().isClass()) {
  60.128 +                processingEnv.getMessager().printMessage(Kind.ERROR, "Internal error - cannot find class containing the hint", annotated);
  60.129 +                continue;
  60.130 +            }
  60.131 +
  60.132 +            TypeElement clazz = (TypeElement) annotated;
  60.133 +            String classFolder = "org-netbeans-modules-java-hints/code-hints/" + getFQN(clazz).replace('.', '-') + ".class";
  60.134 +
  60.135 +            {
  60.136 +                LayerBuilder builder = layer(clazz);
  60.137 +                File clazzFolder = builder.folder(classFolder);
  60.138 +                
  60.139 +                for (AnnotationMirror am : clazz.getAnnotationMirrors()) {
  60.140 +                    dumpAnnotation(builder, clazzFolder, clazz, am, true);
  60.141 +                }
  60.142 +                
  60.143 +                clazzFolder.write();
  60.144 +            }
  60.145 +
  60.146 +            for (ExecutableElement ee : ElementFilter.methodsIn(clazz.getEnclosedElements())) {
  60.147 +                if (!ee.getAnnotationMirrors().isEmpty()) {
  60.148 +                    LayerBuilder builder = layer(ee);
  60.149 +                    File methodFolder = builder.folder(classFolder + "/" + ee.getSimpleName() + ".method");
  60.150 +
  60.151 +                    for (AnnotationMirror am : ee.getAnnotationMirrors()) {
  60.152 +                        dumpAnnotation(builder, methodFolder, ee, am, true);
  60.153 +                    }
  60.154 +
  60.155 +                    methodFolder.write();
  60.156 +                }
  60.157 +            }
  60.158 +
  60.159 +            for (VariableElement var : ElementFilter.fieldsIn(clazz.getEnclosedElements())) {
  60.160 +                if (!var.getAnnotationMirrors().isEmpty()) {
  60.161 +                    LayerBuilder builder = layer(var);
  60.162 +                    File fieldFolder = builder.folder(classFolder + "/" + var.getSimpleName() + ".field");
  60.163 +
  60.164 +                    for (AnnotationMirror am : var.getAnnotationMirrors()) {
  60.165 +                        dumpAnnotation(builder, fieldFolder, var, am, true);
  60.166 +                    }
  60.167 +
  60.168 +                    if (var.getConstantValue() instanceof String) {
  60.169 +                        fieldFolder.stringvalue("constantValue", (String) var.getConstantValue());
  60.170 +                    }
  60.171 +
  60.172 +                    fieldFolder.write();
  60.173 +                }
  60.174 +            }
  60.175 +            
  60.176 +            new ElementScanner6<Void, Void>() {
  60.177 +                @Override public Void scan(Element e, Void p) {
  60.178 +                    AnnotationMirror hintMirror = findAnnotation(e.getAnnotationMirrors(), "org.netbeans.spi.java.hints.Hint");
  60.179 +            
  60.180 +                    if (hintMirror != null) {
  60.181 +                        String qualifiedName;
  60.182 +                        switch (e.getKind()) {
  60.183 +                            case METHOD: case CONSTRUCTOR:
  60.184 +                                qualifiedName = e.getEnclosingElement().asType().toString() + "." + e.getSimpleName().toString() + e.asType().toString();
  60.185 +                                break;
  60.186 +                            case FIELD: case ENUM_CONSTANT:
  60.187 +                                qualifiedName = e.getEnclosingElement().asType().toString() + "." + e.getSimpleName().toString();
  60.188 +                                break;
  60.189 +                            case ANNOTATION_TYPE: case CLASS:
  60.190 +                            case ENUM: case INTERFACE:
  60.191 +                            default:
  60.192 +                                qualifiedName = e.asType().toString();
  60.193 +                                break;
  60.194 +                        }
  60.195 +                        
  60.196 +                        try {
  60.197 +                            File keywordsFile = layer(e)
  60.198 +                                               .file("OptionsDialog/Keywords/".concat(qualifiedName))
  60.199 +                                               .stringvalue("location", "Editor")
  60.200 +                                               .bundlevalue("tabTitle", "org.netbeans.modules.options.editor.Bundle", "CTL_Hints_DisplayName");
  60.201 +
  60.202 +                            String displayName = getAttributeValue(hintMirror, "displayName", String.class);
  60.203 +
  60.204 +                            if (displayName != null)
  60.205 +                                keywordsFile = keywordsFile.bundlevalue("keywords-1", displayName);
  60.206 +
  60.207 +                            String description = getAttributeValue(hintMirror, "description", String.class);
  60.208 +
  60.209 +                            if (description != null)
  60.210 +                                keywordsFile = keywordsFile.bundlevalue("keywords-2", description);
  60.211 +
  60.212 +                            int i = 3;
  60.213 +
  60.214 +                            for (String sw : getAttributeValue(hintMirror, "suppressWarnings", String[].class)) {
  60.215 +                                keywordsFile = keywordsFile.stringvalue("keywords-" + i++, sw);
  60.216 +                            }
  60.217 +
  60.218 +                            keywordsFile.write();
  60.219 +                        } catch (LayerGenerationException ex) {
  60.220 +                            JavaHintsAnnotationProcessor.<RuntimeException>rethrowAsRuntime(ex);
  60.221 +                        }
  60.222 +                    }
  60.223 +
  60.224 +                    return super.scan(e, p);
  60.225 +                }
  60.226 +            }.scan(annotated, null);
  60.227 +        }
  60.228 +
  60.229 +        for (String ann : TRIGGERS) {
  60.230 +            TypeElement annRes = processingEnv.getElementUtils().getTypeElement(ann);
  60.231 +
  60.232 +            if (annRes == null) continue;
  60.233 +
  60.234 +            for (ExecutableElement method : ElementFilter.methodsIn(roundEnv.getElementsAnnotatedWith(annRes))) {
  60.235 +                verifyHintMethod(method);
  60.236 +                verifyTriggerAnnotations(method);
  60.237 +            }
  60.238 +        }
  60.239 +
  60.240 +        for (String ann : OPTIONS) {
  60.241 +            TypeElement annRes = processingEnv.getElementUtils().getTypeElement(ann);
  60.242 +
  60.243 +            if (annRes == null) continue;
  60.244 +
  60.245 +            for (VariableElement var : ElementFilter.fieldsIn(roundEnv.getElementsAnnotatedWith(annRes))) {
  60.246 +                verifyOptionField(var);
  60.247 +            }
  60.248 +        }
  60.249 +
  60.250 +    }
  60.251 +
  60.252 +    private void dumpAnnotation(LayerBuilder builder, File folder, Element errElement, AnnotationMirror annotation, boolean topLevel) {
  60.253 +        String fqn = getFQN(((TypeElement) annotation.getAnnotationType().asElement())).replace('.', '-');
  60.254 +        if (topLevel && !fqn.startsWith("org-netbeans-spi-java-hints")) return ;
  60.255 +        final File   annotationFolder = builder.folder(folder.getPath() + "/" + fqn + ".annotation");
  60.256 +
  60.257 +        for (Entry<? extends ExecutableElement, ? extends AnnotationValue> e : annotation.getElementValues().entrySet()) {
  60.258 +            final String attrName = e.getKey().getSimpleName().toString();
  60.259 +            e.getValue().accept(new DumpAnnotationValue(builder, annotationFolder, attrName, errElement, annotation, e.getValue()), null);
  60.260 +        }
  60.261 +
  60.262 +        annotationFolder.write();
  60.263 +    }
  60.264 +
  60.265 +    private String getFQN(TypeElement clazz) {
  60.266 +        return processingEnv.getElementUtils().getBinaryName(clazz).toString();
  60.267 +    }
  60.268 +
  60.269 +    static final String ERR_RETURN_TYPE = "The return type must be either org.netbeans.spi.editor.hints.ErrorDescription or java.util.List<org.netbeans.spi.editor.hints.ErrorDescription>";
  60.270 +    static final String ERR_PARAMETERS = "The method must have exactly one parameter of type org.netbeans.spi.java.hints.HintContext";
  60.271 +    static final String ERR_MUST_BE_STATIC = "The method must be static";
  60.272 +    static final String ERR_OPTION_TYPE = "The option field must be of type java.lang.String";
  60.273 +    static final String ERR_OPTION_MUST_BE_STATIC_FINAL = "The option field must be static final";
  60.274 +    static final String WARN_BUNDLE_KEY_NOT_FOUND = "Bundle key %s not found";
  60.275 +
  60.276 +    private static AnnotationMirror findAnnotation(Iterable<? extends AnnotationMirror> annotations, String annotationFQN) {
  60.277 +        for (AnnotationMirror am : annotations) {
  60.278 +            if (((TypeElement) am.getAnnotationType().asElement()).getQualifiedName().contentEquals(annotationFQN)) {
  60.279 +                return am;
  60.280 +            }
  60.281 +        }
  60.282 +
  60.283 +        return null;
  60.284 +    }
  60.285 +
  60.286 +    private <T> T getAttributeValue(AnnotationMirror annotation, String attribute, Class<T> clazz) {
  60.287 +        if (clazz.isArray()) {
  60.288 +            Iterable<?> attributes = getAttributeValueInternal(annotation, attribute, Iterable.class);
  60.289 +            
  60.290 +            Collection<Object> coll = new ArrayList<Object>();
  60.291 +            Class<?> componentType = clazz.getComponentType();
  60.292 +
  60.293 +            for (Object attr : attributes) {
  60.294 +                if (attr instanceof AnnotationValue) {
  60.295 +                    attr = ((AnnotationValue) attr).getValue();
  60.296 +                }
  60.297 +                
  60.298 +                if (componentType.isAssignableFrom(attr.getClass())) {
  60.299 +                    coll.add(componentType.cast(attr));
  60.300 +                }
  60.301 +            }
  60.302 +
  60.303 +            return clazz.cast(coll.toArray((Object[]) Array.newInstance(clazz.getComponentType(), 0)));
  60.304 +        } else {
  60.305 +            return getAttributeValueInternal(annotation, attribute, clazz);
  60.306 +        }
  60.307 +    }
  60.308 +
  60.309 +    private <T> T getAttributeValueInternal(AnnotationMirror annotation, String attribute, Class<T> clazz) {
  60.310 +        for (Entry<? extends ExecutableElement, ? extends AnnotationValue> e : processingEnv.getElementUtils().getElementValuesWithDefaults(annotation).entrySet()) {
  60.311 +            if (e.getKey().getSimpleName().contentEquals(attribute)) {
  60.312 +                Object value = e.getValue().getValue();
  60.313 +
  60.314 +                if (clazz.isAssignableFrom(value.getClass())) {
  60.315 +                    return clazz.cast(value);
  60.316 +                }
  60.317 +
  60.318 +                return null;
  60.319 +            }
  60.320 +        }
  60.321 +        
  60.322 +        return null;
  60.323 +    }
  60.324 +
  60.325 +    private AnnotationValue getAttributeValueDescription(AnnotationMirror annotation, String attribute) {
  60.326 +        for (Entry<? extends ExecutableElement, ? extends AnnotationValue> e : processingEnv.getElementUtils().getElementValuesWithDefaults(annotation).entrySet()) {
  60.327 +            if (e.getKey().getSimpleName().contentEquals(attribute)) {
  60.328 +                return e.getValue();
  60.329 +            }
  60.330 +        }
  60.331 +
  60.332 +        return null;
  60.333 +    }
  60.334 +    
  60.335 +    private boolean verifyHintAnnotationAcceptable(Element hint) {
  60.336 +        AnnotationMirror hintMirror = findAnnotation(hint.getAnnotationMirrors(), "org.netbeans.spi.java.hints.Hint");
  60.337 +
  60.338 +        if (hintMirror == null) return false;
  60.339 +
  60.340 +        String id = getAttributeValue(hintMirror, "id", String.class);
  60.341 +
  60.342 +        if (id == null || id.isEmpty()) {
  60.343 +            switch (hint.getKind()) {
  60.344 +                case CLASS:
  60.345 +                case METHOD:
  60.346 +                    break; //OK
  60.347 +                default:
  60.348 +                    //compiler should have already warned about this
  60.349 +                    return false;
  60.350 +            }
  60.351 +        }
  60.352 +
  60.353 +        TypeMirror customizerProviderType = getAttributeValue(hintMirror, "customizerProvider", TypeMirror.class);
  60.354 +
  60.355 +        if (customizerProviderType != null) {
  60.356 +            Element customizerProvider = processingEnv.getTypeUtils().asElement(customizerProviderType);
  60.357 +
  60.358 +            if (customizerProvider != null) {
  60.359 +                if (customizerProvider.getKind() != ElementKind.CLASS) {
  60.360 +                    TypeElement customizerProviderInterface = processingEnv.getElementUtils().getTypeElement("org.netbeans.spi.java.hints.CustomizerProvider");
  60.361 +
  60.362 +                    if (customizerProviderInterface != null && !customizerProviderInterface.equals(customizerProvider)) {
  60.363 +                        processingEnv.getMessager().printMessage(Kind.ERROR, "Customizer provider must be a concrete class", hint, hintMirror, getAttributeValueDescription(hintMirror, "customizerProvider"));
  60.364 +                    }
  60.365 +                } else {
  60.366 +                    TypeElement customizerProviderClazz = (TypeElement) customizerProvider;
  60.367 +
  60.368 +                    if (!customizerProviderClazz.getModifiers().contains(Modifier.PUBLIC)) {
  60.369 +                        processingEnv.getMessager().printMessage(Kind.ERROR, "Customizer provider must be public", hint, hintMirror, getAttributeValueDescription(hintMirror, "customizerProvider"));
  60.370 +                    }
  60.371 +
  60.372 +                    if (   customizerProviderClazz.getEnclosingElement().getKind() != ElementKind.PACKAGE
  60.373 +                        && !customizerProviderClazz.getModifiers().contains(Modifier.STATIC)) {
  60.374 +                        processingEnv.getMessager().printMessage(Kind.ERROR, "Customizer provider must be non-static innerclass", hint, hintMirror, getAttributeValueDescription(hintMirror, "customizerProvider"));
  60.375 +                    }
  60.376 +
  60.377 +                    boolean foundDefaultConstructor = false;
  60.378 +
  60.379 +                    for (ExecutableElement ee : ElementFilter.constructorsIn(customizerProviderClazz.getEnclosedElements())) {
  60.380 +                        if (ee.getParameters().isEmpty()) {
  60.381 +                            foundDefaultConstructor = true;
  60.382 +                            if (!ee.getModifiers().contains(Modifier.PUBLIC)) {
  60.383 +                                processingEnv.getMessager().printMessage(Kind.ERROR, "Customizer provider must provide a public default constructor", hint, hintMirror, getAttributeValueDescription(hintMirror, "customizerProvider"));
  60.384 +                            }
  60.385 +                            break;
  60.386 +                        }
  60.387 +                    }
  60.388 +
  60.389 +                    if (!foundDefaultConstructor) {
  60.390 +                        processingEnv.getMessager().printMessage(Kind.ERROR, "Customizer provider must provide a public default constructor", hint, hintMirror, getAttributeValueDescription(hintMirror, "customizerProvider"));
  60.391 +                    }
  60.392 +                }
  60.393 +            }
  60.394 +        }
  60.395 +
  60.396 +        return true;
  60.397 +    }
  60.398 +
  60.399 +    private boolean verifyHintMethod(ExecutableElement method) {
  60.400 +        StringBuilder error = new StringBuilder();
  60.401 +        Elements elements = processingEnv.getElementUtils();
  60.402 +        TypeElement errDesc = elements.getTypeElement("org.netbeans.spi.editor.hints.ErrorDescription");
  60.403 +        TypeElement jlIterable = elements.getTypeElement("java.lang.Iterable");
  60.404 +        TypeElement hintCtx = elements.getTypeElement("org.netbeans.spi.java.hints.HintContext");
  60.405 +
  60.406 +        if (errDesc == null || jlIterable == null || hintCtx == null) {
  60.407 +            return true;
  60.408 +        }
  60.409 +
  60.410 +        Types types = processingEnv.getTypeUtils();
  60.411 +        TypeMirror errDescType = errDesc.asType(); //no type params, no need to erasure
  60.412 +        TypeMirror jlIterableErrDesc = types.getDeclaredType(jlIterable, errDescType);
  60.413 +        TypeMirror ret = method.getReturnType();
  60.414 +
  60.415 +        if (!types.isSameType(ret, errDescType) && !types.isAssignable(ret, jlIterableErrDesc)) {
  60.416 +            error.append(ERR_RETURN_TYPE);
  60.417 +            error.append("\n");
  60.418 +        }
  60.419 +
  60.420 +        if (method.getParameters().size() != 1 || !types.isSameType(method.getParameters().get(0).asType(), hintCtx.asType())) {
  60.421 +            error.append(ERR_PARAMETERS);
  60.422 +            error.append("\n");
  60.423 +        }
  60.424 +
  60.425 +        if (!method.getModifiers().contains(Modifier.STATIC)) {
  60.426 +            error.append(ERR_MUST_BE_STATIC);
  60.427 +            error.append("\n");
  60.428 +        }
  60.429 +
  60.430 +        if (error.length() == 0) {
  60.431 +            return true;
  60.432 +        }
  60.433 +
  60.434 +        if (error.charAt(error.length() - 1) == '\n') {
  60.435 +            error.delete(error.length() - 1, error.length());
  60.436 +        }
  60.437 +
  60.438 +        processingEnv.getMessager().printMessage(Kind.ERROR, error.toString(), method);
  60.439 +
  60.440 +        return false;
  60.441 +    }
  60.442 +
  60.443 +    private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\$[a-zA-Z0-9_]+");
  60.444 +    private boolean verifyTriggerAnnotations(ExecutableElement method) {
  60.445 +        List<AnnotationMirror> patternAnnotations = new ArrayList<AnnotationMirror>();
  60.446 +        AnnotationMirror am = findAnnotation(method.getAnnotationMirrors(), "org.netbeans.spi.java.hints.TriggerPattern");
  60.447 +
  60.448 +        if (am != null) {
  60.449 +            patternAnnotations.add(am);
  60.450 +        }
  60.451 +
  60.452 +        am = findAnnotation(method.getAnnotationMirrors(), "org.netbeans.spi.java.hints.TriggerPatterns");
  60.453 +
  60.454 +        if (am != null) {
  60.455 +            patternAnnotations.addAll(Arrays.asList(getAttributeValue(am, "value", AnnotationMirror[].class)));
  60.456 +        }
  60.457 +
  60.458 +        for (AnnotationMirror patternDescription : patternAnnotations) {
  60.459 +            String pattern = getAttributeValue(patternDescription, "value", String.class);
  60.460 +
  60.461 +            if (pattern == null) continue;
  60.462 +
  60.463 +            Set<String> variables = new HashSet<String>();
  60.464 +            Matcher m = VARIABLE_PATTERN.matcher(pattern);
  60.465 +
  60.466 +            while (m.find()) {
  60.467 +                variables.add(m.group(0));
  60.468 +            }
  60.469 +
  60.470 +            for (AnnotationMirror constraint : getAttributeValue(patternDescription, "constraints", AnnotationMirror[].class)) {
  60.471 +                String variable = getAttributeValue(constraint, "variable", String.class);
  60.472 +                String type = getAttributeValue(constraint, "type", String.class);
  60.473 +
  60.474 +                if (variable == null || type == null) continue;
  60.475 +
  60.476 +                if (!variables.contains(variable)) {
  60.477 +                    processingEnv.getMessager().printMessage(Kind.WARNING, "Variable " + variable + " not used in the pattern", method, constraint, getAttributeValueDescription(constraint, "variable"));
  60.478 +                }
  60.479 +            }
  60.480 +        }
  60.481 +
  60.482 +        return false;
  60.483 +    }
  60.484 +
  60.485 +    private boolean verifyOptionField(VariableElement field) {
  60.486 +        StringBuilder error = new StringBuilder();
  60.487 +        Elements elements = processingEnv.getElementUtils();
  60.488 +        TypeElement jlString = elements.getTypeElement("java.lang.String");
  60.489 +
  60.490 +        if (jlString == null) {
  60.491 +            return true;
  60.492 +        }
  60.493 +
  60.494 +        Types types = processingEnv.getTypeUtils();
  60.495 +        TypeMirror jlStringType = jlString.asType(); //no type params, no need to erasure
  60.496 +
  60.497 +        if (!types.isSameType(field.asType(), jlStringType)) {
  60.498 +            error.append(ERR_RETURN_TYPE);
  60.499 +            error.append("\n");
  60.500 +        }
  60.501 +
  60.502 +        if (!field.getModifiers().contains(Modifier.STATIC) || !field.getModifiers().contains(Modifier.FINAL)) {
  60.503 +            error.append(ERR_OPTION_MUST_BE_STATIC_FINAL);
  60.504 +            error.append("\n");
  60.505 +        }
  60.506 +
  60.507 +        Object key = field.getConstantValue();
  60.508 +
  60.509 +        if (key == null) {
  60.510 +            error.append("Option field not a compile-time constant");
  60.511 +            error.append("\n");
  60.512 +        }
  60.513 +
  60.514 +        if (error.length() == 0) {
  60.515 +            return true;
  60.516 +        }
  60.517 +
  60.518 +        if (error.charAt(error.length() - 1) == '\n') {
  60.519 +            error.delete(error.length() - 1, error.length());
  60.520 +        }
  60.521 +
  60.522 +        processingEnv.getMessager().printMessage(Kind.ERROR, error.toString(), field);
  60.523 +
  60.524 +        return false;
  60.525 +    }
  60.526 +
  60.527 +    private class DumpAnnotationValue extends AbstractAnnotationValueVisitor6<Void, Void> {
  60.528 +
  60.529 +        private final LayerBuilder builder;
  60.530 +        private final File annotationFolder;
  60.531 +        private final String attrName;
  60.532 +        private final Element errElement;
  60.533 +        private final AnnotationMirror errAnnotationMirror;
  60.534 +        private final AnnotationValue errAnnotationValue;
  60.535 +
  60.536 +        public DumpAnnotationValue(LayerBuilder builder, File annotationFolder, String attrName, Element errElement, AnnotationMirror errAnnotationMirror, AnnotationValue errAnnotationValue) {
  60.537 +            this.builder = builder;
  60.538 +            this.annotationFolder = annotationFolder;
  60.539 +            this.attrName = attrName;
  60.540 +            this.errElement = errElement;
  60.541 +            this.errAnnotationMirror = errAnnotationMirror;
  60.542 +            this.errAnnotationValue = errAnnotationValue;
  60.543 +        }
  60.544 +
  60.545 +        public Void visitBoolean(boolean b, Void p) {
  60.546 +            annotationFolder.boolvalue(attrName, b);
  60.547 +            return null;
  60.548 +        }
  60.549 +
  60.550 +        public Void visitByte(byte b, Void p) {
  60.551 +            annotationFolder.bytevalue(attrName, b);
  60.552 +            return null;
  60.553 +        }
  60.554 +
  60.555 +        public Void visitChar(char c, Void p) {
  60.556 +            annotationFolder.charvalue(attrName, c);
  60.557 +            return null;
  60.558 +        }
  60.559 +
  60.560 +        public Void visitDouble(double d, Void p) {
  60.561 +            annotationFolder.doublevalue(attrName, d);
  60.562 +            return null;
  60.563 +        }
  60.564 +
  60.565 +        public Void visitFloat(float f, Void p) {
  60.566 +            annotationFolder.floatvalue(attrName, f);
  60.567 +            return null;
  60.568 +        }
  60.569 +
  60.570 +        public Void visitInt(int i, Void p) {
  60.571 +            annotationFolder.intvalue(attrName, i);
  60.572 +            return null;
  60.573 +        }
  60.574 +
  60.575 +        public Void visitLong(long i, Void p) {
  60.576 +            annotationFolder.longvalue(attrName, i);
  60.577 +            return null;
  60.578 +        }
  60.579 +
  60.580 +        public Void visitShort(short s, Void p) {
  60.581 +            annotationFolder.shortvalue(attrName, s);
  60.582 +            return null;
  60.583 +        }
  60.584 +
  60.585 +        public Void visitString(String s, Void p) {
  60.586 +            if ("displayName".equals(attrName) || "description".equals(attrName) || "tooltip".equals(attrName)) {
  60.587 +                try {
  60.588 +                    annotationFolder.bundlevalue(attrName, s);
  60.589 +                } catch (LayerGenerationException ex) {
  60.590 +                   processingEnv.getMessager().printMessage(Kind.ERROR, ex.getLocalizedMessage(), errElement, errAnnotationMirror, errAnnotationValue);
  60.591 +                }
  60.592 +            } else {
  60.593 +                annotationFolder.stringvalue(attrName, s);
  60.594 +            }
  60.595 +            return null;
  60.596 +        }
  60.597 +
  60.598 +        public Void visitType(TypeMirror t, Void p) {
  60.599 +            annotationFolder.stringvalue(attrName, getFQN(((TypeElement) ((DeclaredType) t).asElement())));
  60.600 +            return null;
  60.601 +        }
  60.602 +
  60.603 +        public Void visitEnumConstant(VariableElement c, Void p) {
  60.604 +            TypeElement owner = (TypeElement) c.getEnclosingElement();
  60.605 +            annotationFolder.stringvalue(attrName, getFQN(owner) + "." + c.getSimpleName());
  60.606 +            return null;
  60.607 +        }
  60.608 +
  60.609 +        public Void visitAnnotation(AnnotationMirror a, Void p) {
  60.610 +            File f = builder.folder(annotationFolder.getPath() + "/" + attrName);
  60.611 +            
  60.612 +            dumpAnnotation(builder, f, errElement, a, false);
  60.613 +
  60.614 +            f.write();
  60.615 +            return null;
  60.616 +        }
  60.617 +
  60.618 +        public Void visitArray(List<? extends AnnotationValue> vals, Void p) {
  60.619 +            File arr = builder.folder(annotationFolder.getPath() + "/" + attrName);
  60.620 +            int c = 0;
  60.621 +
  60.622 +            for (AnnotationValue av : vals) {
  60.623 +                av.accept(new DumpAnnotationValue(builder, arr, "item" + c, errElement, errAnnotationMirror, av), null);
  60.624 +                c++;
  60.625 +            }
  60.626 +
  60.627 +            arr.write();
  60.628 +
  60.629 +            return null;
  60.630 +        }
  60.631 +    }
  60.632 +    
  60.633 +    @SuppressWarnings("unchecked")
  60.634 +    private static <T extends Throwable> void rethrowAsRuntime(Throwable t) throws T {
  60.635 +        throw (T) t;
  60.636 +    }
  60.637 +
  60.638 +}
    61.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    61.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/BooleanOption.java	Wed May 08 21:47:42 2013 +0200
    61.3 @@ -0,0 +1,87 @@
    61.4 +/*
    61.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    61.6 + *
    61.7 + * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
    61.8 + *
    61.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   61.10 + * Other names may be trademarks of their respective owners.
   61.11 + *
   61.12 + * The contents of this file are subject to the terms of either the GNU
   61.13 + * General Public License Version 2 only ("GPL") or the Common
   61.14 + * Development and Distribution License("CDDL") (collectively, the
   61.15 + * "License"). You may not use this file except in compliance with the
   61.16 + * License. You can obtain a copy of the License at
   61.17 + * http://www.netbeans.org/cddl-gplv2.html
   61.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   61.19 + * specific language governing permissions and limitations under the
   61.20 + * License.  When distributing the software, include this License Header
   61.21 + * Notice in each file and include the License file at
   61.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   61.23 + * particular file as subject to the "Classpath" exception as provided
   61.24 + * by Oracle in the GPL Version 2 section of the License file that
   61.25 + * accompanied this code. If applicable, add the following below the
   61.26 + * License Header, with the fields enclosed by brackets [] replaced by
   61.27 + * your own identifying information:
   61.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   61.29 + *
   61.30 + * If you wish your version of this file to be governed by only the CDDL
   61.31 + * or only the GPL Version 2, indicate your decision by adding
   61.32 + * "[Contributor] elects to include this software in this distribution
   61.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   61.34 + * single choice of license, a recipient has the option to distribute
   61.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   61.36 + * to extend the choice of license to its licensees as provided above.
   61.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   61.38 + * Version 2 license, then the option applies only if the new code is
   61.39 + * made subject to such option by the copyright holder.
   61.40 + *
   61.41 + * Contributor(s):
   61.42 + *
   61.43 + * Portions Copyrighted 2012 Sun Microsystems, Inc.
   61.44 + */
   61.45 +package org.netbeans.spi.java.hints;
   61.46 +
   61.47 +import java.lang.annotation.ElementType;
   61.48 +import java.lang.annotation.Retention;
   61.49 +import java.lang.annotation.RetentionPolicy;
   61.50 +import java.lang.annotation.Target;
   61.51 +import java.util.prefs.Preferences;
   61.52 +
   61.53 +/**Specify an option that affects the way the hint works.
   61.54 + *
   61.55 + * Only {@code static final String} compile-time constant can be marked with this
   61.56 + * annotation. The value of the constant will be used as the key to the hint's {@link Preferences}.
   61.57 + *
   61.58 + * For hints that consist of a class, all options that are directly enclosed in the class
   61.59 + * will be used in their source order.
   61.60 + *
   61.61 + * For hints that consist of a single method, use {@link UseOptions} to specify which options
   61.62 + * from the enclosing class should be used. The order of the options will be the order in which
   61.63 + * they appear in the source code of the enclosing class.
   61.64 + *
   61.65 + * The customizer will be generated automatically when {@link BooleanOption} is used.
   61.66 + *
   61.67 + * Two keys need to be defined in the corresponding {@code Bundle.properties}:
   61.68 + * {@code LBL_<class-fqn>.<field_name>}, which will be used as the display name of
   61.69 + * the corresponding checkbox in the customizer, and {@code TP_<class-fqn>.<field_name>}
   61.70 + * which will be used as the tooltip of the checkbox.
   61.71 + *
   61.72 + * @author lahvac
   61.73 + */
   61.74 +@Retention(RetentionPolicy.SOURCE)
   61.75 +@Target(ElementType.FIELD)
   61.76 +public @interface BooleanOption {
   61.77 +
   61.78 +    /**The options' display name. Will be used as the display name of the
   61.79 +     * checkbox in the customizer.
   61.80 +     */
   61.81 +    public String displayName();
   61.82 +    /**The tooltip of the checkbox in the customizer.
   61.83 +     */
   61.84 +    public String tooltip();
   61.85 +    
   61.86 +    /**The default value of the option.
   61.87 +     */
   61.88 +    public boolean defaultValue();
   61.89 +    
   61.90 +}
    62.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    62.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/Bundle.properties	Wed May 08 21:47:42 2013 +0200
    62.3 @@ -0,0 +1,7 @@
    62.4 +#{0}: hint/suggestion name
    62.5 +FIX_DisableHint=Disable "{0}" Hint
    62.6 +FIX_ConfigureHint=Configure "{0}" Hint
    62.7 +FIX_DisableSuggestion=Disable "{0}" Suggestion
    62.8 +FIX_ConfigureSuggestion=Configure "{0}" Suggestion
    62.9 +#{0}: Key of the warning
   62.10 +LBL_FIX_Suppress_Waning=Suppress Warning - {0}
    63.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    63.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/ConstraintVariableType.java	Wed May 08 21:47:42 2013 +0200
    63.3 @@ -0,0 +1,73 @@
    63.4 +/*
    63.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    63.6 + *
    63.7 + * Copyright 2008-2010 Oracle and/or its affiliates. All rights reserved.
    63.8 + *
    63.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   63.10 + * Other names may be trademarks of their respective owners.
   63.11 + *
   63.12 + * The contents of this file are subject to the terms of either the GNU
   63.13 + * General Public License Version 2 only ("GPL") or the Common
   63.14 + * Development and Distribution License("CDDL") (collectively, the
   63.15 + * "License"). You may not use this file except in compliance with the
   63.16 + * License. You can obtain a copy of the License at
   63.17 + * http://www.netbeans.org/cddl-gplv2.html
   63.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   63.19 + * specific language governing permissions and limitations under the
   63.20 + * License.  When distributing the software, include this License Header
   63.21 + * Notice in each file and include the License file at
   63.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   63.23 + * particular file as subject to the "Classpath" exception as provided
   63.24 + * by Oracle in the GPL Version 2 section of the License file that
   63.25 + * accompanied this code. If applicable, add the following below the
   63.26 + * License Header, with the fields enclosed by brackets [] replaced by
   63.27 + * your own identifying information:
   63.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   63.29 + *
   63.30 + * If you wish your version of this file to be governed by only the CDDL
   63.31 + * or only the GPL Version 2, indicate your decision by adding
   63.32 + * "[Contributor] elects to include this software in this distribution
   63.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   63.34 + * single choice of license, a recipient has the option to distribute
   63.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   63.36 + * to extend the choice of license to its licensees as provided above.
   63.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   63.38 + * Version 2 license, then the option applies only if the new code is
   63.39 + * made subject to such option by the copyright holder.
   63.40 + *
   63.41 + * Contributor(s):
   63.42 + *
   63.43 + * Portions Copyrighted 2008-2009 Sun Microsystems, Inc.
   63.44 + */
   63.45 +
   63.46 +package org.netbeans.spi.java.hints;
   63.47 +
   63.48 +import java.lang.annotation.Target;
   63.49 +
   63.50 +/**Specifies a type of a variable. During the matching process, only those
   63.51 + * sections of the source code that have the given type are considered.
   63.52 + *
   63.53 + * @author Jan Lahoda
   63.54 + */
   63.55 +@Target({})
   63.56 +public @interface ConstraintVariableType {
   63.57 +
   63.58 +    /**Variable name, must start with the dollar sign (<code>$</code>).
   63.59 +     * Variable<code>$this</code> is automatically bound to the current class.
   63.60 +     */
   63.61 +    public String variable();
   63.62 +
   63.63 +    /**The required type of the section of source code. The value must be a type
   63.64 +     * per JLS 4.1, i.e. a primitive type (JLS 4.2), or a reference type (JLS 4.3).
   63.65 +     * All elements of the type must be resolvable when written to any Java file,
   63.66 +     * they may not contain e.g. references to type variables, simple names, etc.
   63.67 +     *
   63.68 +     * The type may include any actual type arguments, including wildcard.
   63.69 +     *
   63.70 +     * While matching, the type of the tree that corresponds to the variable in
   63.71 +     * the actual occurrence candidate is accepted if it is assignable into the
   63.72 +     * variable defined by the attribute.
   63.73 +     */
   63.74 +    public String type();
   63.75 +    
   63.76 +}
    64.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    64.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/CustomizerProvider.java	Wed May 08 21:47:42 2013 +0200
    64.3 @@ -0,0 +1,66 @@
    64.4 +/*
    64.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    64.6 + *
    64.7 + * Copyright 2010-2012 Oracle and/or its affiliates. All rights reserved.
    64.8 + *
    64.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   64.10 + * Other names may be trademarks of their respective owners.
   64.11 + *
   64.12 + * The contents of this file are subject to the terms of either the GNU
   64.13 + * General Public License Version 2 only ("GPL") or the Common
   64.14 + * Development and Distribution License("CDDL") (collectively, the
   64.15 + * "License"). You may not use this file except in compliance with the
   64.16 + * License. You can obtain a copy of the License at
   64.17 + * http://www.netbeans.org/cddl-gplv2.html
   64.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   64.19 + * specific language governing permissions and limitations under the
   64.20 + * License.  When distributing the software, include this License Header
   64.21 + * Notice in each file and include the License file at
   64.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   64.23 + * particular file as subject to the "Classpath" exception as provided
   64.24 + * by Oracle in the GPL Version 2 section of the License file that
   64.25 + * accompanied this code. If applicable, add the following below the
   64.26 + * License Header, with the fields enclosed by brackets [] replaced by
   64.27 + * your own identifying information:
   64.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   64.29 + *
   64.30 + * If you wish your version of this file to be governed by only the CDDL
   64.31 + * or only the GPL Version 2, indicate your decision by adding
   64.32 + * "[Contributor] elects to include this software in this distribution
   64.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   64.34 + * single choice of license, a recipient has the option to distribute
   64.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   64.36 + * to extend the choice of license to its licensees as provided above.
   64.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   64.38 + * Version 2 license, then the option applies only if the new code is
   64.39 + * made subject to such option by the copyright holder.
   64.40 + *
   64.41 + * Contributor(s):
   64.42 + *
   64.43 + * Portions Copyrighted 2010-2012 Sun Microsystems, Inc.
   64.44 + */
   64.45 +
   64.46 +package org.netbeans.spi.java.hints;
   64.47 +
   64.48 +import java.util.prefs.Preferences;
   64.49 +import javax.swing.JComponent;
   64.50 +import org.netbeans.api.annotations.common.NonNull;
   64.51 +
   64.52 +/**A factory for hint customizer.
   64.53 + *
   64.54 + * @author lahvac
   64.55 + */
   64.56 +public interface CustomizerProvider {
   64.57 +
   64.58 +    /**Create a customizer component. The hint settings are in the given
   64.59 +     * {@link Preferences}. The customizer can write into the provided {@link Preferences}
   64.60 +     * immediately, the values will be persisted or rolled-back automatically
   64.61 +     * based on the user's gesture.
   64.62 +     *
   64.63 +     * @param prefs the hints preferences from which the data to show should be read,
   64.64 +     *              and to which the new settings should be written
   64.65 +     * @return a customizer component
   64.66 +     */
   64.67 +    public @NonNull JComponent getCustomizer(@NonNull Preferences prefs);
   64.68 +
   64.69 +}
    65.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    65.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/ErrorDescriptionFactory.java	Wed May 08 21:47:42 2013 +0200
    65.3 @@ -0,0 +1,619 @@
    65.4 +/*
    65.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    65.6 + *
    65.7 + * Copyright 2008-2010 Oracle and/or its affiliates. All rights reserved.
    65.8 + *
    65.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   65.10 + * Other names may be trademarks of their respective owners.
   65.11 + *
   65.12 + * The contents of this file are subject to the terms of either the GNU
   65.13 + * General Public License Version 2 only ("GPL") or the Common
   65.14 + * Development and Distribution License("CDDL") (collectively, the
   65.15 + * "License"). You may not use this file except in compliance with the
   65.16 + * License. You can obtain a copy of the License at
   65.17 + * http://www.netbeans.org/cddl-gplv2.html
   65.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   65.19 + * specific language governing permissions and limitations under the
   65.20 + * License.  When distributing the software, include this License Header
   65.21 + * Notice in each file and include the License file at
   65.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   65.23 + * particular file as subject to the "Classpath" exception as provided
   65.24 + * by Oracle in the GPL Version 2 section of the License file that
   65.25 + * accompanied this code. If applicable, add the following below the
   65.26 + * License Header, with the fields enclosed by brackets [] replaced by
   65.27 + * your own identifying information:
   65.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   65.29 + *
   65.30 + * If you wish your version of this file to be governed by only the CDDL
   65.31 + * or only the GPL Version 2, indicate your decision by adding
   65.32 + * "[Contributor] elects to include this software in this distribution
   65.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   65.34 + * single choice of license, a recipient has the option to distribute
   65.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   65.36 + * to extend the choice of license to its licensees as provided above.
   65.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   65.38 + * Version 2 license, then the option applies only if the new code is
   65.39 + * made subject to such option by the copyright holder.
   65.40 + *
   65.41 + * Contributor(s):
   65.42 + *
   65.43 + * Portions Copyrighted 2008-2010 Sun Microsystems, Inc.
   65.44 + */
   65.45 +
   65.46 +package org.netbeans.spi.java.hints;
   65.47 +
   65.48 +import com.sun.source.tree.BlockTree;
   65.49 +import com.sun.source.tree.ClassTree;
   65.50 +import com.sun.source.tree.LiteralTree;
   65.51 +import com.sun.source.tree.MemberSelectTree;
   65.52 +import com.sun.source.tree.MethodInvocationTree;
   65.53 +import com.sun.source.tree.MethodTree;
   65.54 +import com.sun.source.tree.ModifiersTree;
   65.55 +import com.sun.source.tree.StatementTree;
   65.56 +import com.sun.source.tree.Tree;
   65.57 +import com.sun.source.tree.Tree.Kind;
   65.58 +import com.sun.source.tree.VariableTree;
   65.59 +import com.sun.source.util.TreePath;
   65.60 +import java.io.IOException;
   65.61 +import java.util.Arrays;
   65.62 +import java.util.Collection;
   65.63 +import java.util.Collections;
   65.64 +import java.util.EnumSet;
   65.65 +import java.util.LinkedHashSet;
   65.66 +import java.util.LinkedList;
   65.67 +import java.util.List;
   65.68 +import java.util.Set;
   65.69 +import javax.lang.model.SourceVersion;
   65.70 +import javax.lang.model.element.TypeElement;
   65.71 +import javax.swing.SwingUtilities;
   65.72 +import org.netbeans.api.annotations.common.NonNull;
   65.73 +import org.netbeans.api.java.source.CompilationInfo;
   65.74 +import org.netbeans.api.java.source.GeneratorUtilities;
   65.75 +import org.netbeans.api.java.source.JavaSource;
   65.76 +import org.netbeans.api.java.source.JavaSource.Phase;
   65.77 +import org.netbeans.api.java.source.Task;
   65.78 +import org.netbeans.api.java.source.TreePathHandle;
   65.79 +import org.netbeans.api.java.source.WorkingCopy;
   65.80 +import org.netbeans.api.lexer.TokenSequence;
   65.81 +import org.netbeans.api.options.OptionsDisplayer;
   65.82 +import org.netbeans.modules.analysis.api.CodeAnalysis;
   65.83 +import org.netbeans.modules.analysis.spi.Analyzer.WarningDescription;
   65.84 +import org.netbeans.modules.java.hints.providers.spi.HintMetadata;
   65.85 +import org.netbeans.modules.java.hints.providers.spi.HintMetadata.Options;
   65.86 +import org.netbeans.modules.java.hints.spiimpl.Hacks.InspectAndTransformOpener;
   65.87 +import org.netbeans.modules.java.hints.spiimpl.SPIAccessor;
   65.88 +import org.netbeans.modules.java.hints.spiimpl.SyntheticFix;
   65.89 +import org.netbeans.modules.java.hints.spiimpl.options.HintsSettings;
   65.90 +import org.netbeans.spi.editor.hints.ChangeInfo;
   65.91 +import org.netbeans.spi.editor.hints.EnhancedFix;
   65.92 +import org.netbeans.spi.editor.hints.ErrorDescription;
   65.93 +import org.netbeans.spi.editor.hints.Fix;
   65.94 +import org.netbeans.spi.editor.hints.LazyFixList;
   65.95 +import org.openide.filesystems.FileObject;
   65.96 +import org.openide.util.Lookup;
   65.97 +import org.openide.util.NbBundle;
   65.98 +import org.openide.util.NbBundle.Messages;
   65.99 +import org.openide.util.Parameters;
  65.100 +
  65.101 +/**
  65.102 + *
  65.103 + * @author Jan Lahoda
  65.104 + */
  65.105 +public class ErrorDescriptionFactory {
  65.106 +
  65.107 +    private ErrorDescriptionFactory() {
  65.108 +    }
  65.109 +
  65.110 +//    public static ErrorDescription forTree(HintContext context, String text, Fix... fixes) {
  65.111 +//        return forTree(context, context.getContext(), text, fixes);
  65.112 +//    }
  65.113 +
  65.114 +    public static ErrorDescription forTree(HintContext context, TreePath tree, String text, Fix... fixes) {
  65.115 +        return forTree(context, tree.getLeaf(), text, fixes);
  65.116 +    }
  65.117 +    
  65.118 +    public static ErrorDescription forTree(HintContext context, Tree tree, String text, Fix... fixes) {
  65.119 +        int start;
  65.120 +        int end;
  65.121 +
  65.122 +        if (context.getHintMetadata().kind == Hint.Kind.INSPECTION) {
  65.123 +            start = (int) context.getInfo().getTrees().getSourcePositions().getStartPosition(context.getInfo().getCompilationUnit(), tree);
  65.124 +            end = (int) context.getInfo().getTrees().getSourcePositions().getEndPosition(context.getInfo().getCompilationUnit(), tree);
  65.125 +        } else {
  65.126 +            start = end = context.getCaretLocation();
  65.127 +        }
  65.128 +
  65.129 +        if (start != (-1) && end != (-1)) {
  65.130 +            LazyFixList fixesForED = org.netbeans.spi.editor.hints.ErrorDescriptionFactory.lazyListForFixes(resolveDefaultFixes(context, fixes));
  65.131 +            return org.netbeans.spi.editor.hints.ErrorDescriptionFactory.createErrorDescription("text/x-java:" + context.getHintMetadata().id, context.getSeverity(), text, context.getHintMetadata().description, fixesForED, context.getInfo().getFileObject(), start, end);
  65.132 +        }
  65.133 +
  65.134 +        return null;
  65.135 +    }
  65.136 +    
  65.137 +    /**Create a new {@link ErrorDescription}. Severity is automatically inferred from the {@link HintContext},
  65.138 +     * and the {@link ErrorDescription} is created to be consistent with {@link ErrorDescription}s created
  65.139 +     * by the other factory methods in this class.
  65.140 +     * 
  65.141 +     * @param context from which the {@link Severity} and other properties are inferred.
  65.142 +     * @param start start of the warning
  65.143 +     * @param end end of the warning
  65.144 +     * @param text the warning text
  65.145 +     * @param fixes one or more {@link Fix}es to show shown to the user.
  65.146 +     * @return a standard {@link ErrorDescription} for use in Java source
  65.147 +     * @since 1.9
  65.148 +     */
  65.149 +    public static ErrorDescription forSpan(HintContext context, int start, int end, String text, Fix... fixes) {
  65.150 +        if (context.getHintMetadata().kind != Hint.Kind.INSPECTION) {
  65.151 +            start = end = context.getCaretLocation();
  65.152 +        }
  65.153 +
  65.154 +        if (start != (-1) && end != (-1)) {
  65.155 +            LazyFixList fixesForED = org.netbeans.spi.editor.hints.ErrorDescriptionFactory.lazyListForFixes(resolveDefaultFixes(context, fixes));
  65.156 +            return org.netbeans.spi.editor.hints.ErrorDescriptionFactory.createErrorDescription("text/x-java:" + context.getHintMetadata().id, context.getSeverity(), text, context.getHintMetadata().description, fixesForED, context.getInfo().getFileObject(), start, end);
  65.157 +        }
  65.158 +
  65.159 +        return null;
  65.160 +    }
  65.161 +    
  65.162 +    public static ErrorDescription forName(HintContext context, TreePath tree, String text, Fix... fixes) {
  65.163 +        return forName(context, tree.getLeaf(), text, fixes);
  65.164 +    }
  65.165 +
  65.166 +    public static ErrorDescription forName(HintContext context, Tree tree, String text, Fix... fixes) {
  65.167 +        int[] span;
  65.168 +        
  65.169 +        if (context.getHintMetadata().kind == Hint.Kind.INSPECTION) {
  65.170 +            span = computeNameSpan(tree, context);
  65.171 +        } else {
  65.172 +            span = new int[] {context.getCaretLocation(), context.getCaretLocation()};
  65.173 +        }
  65.174 +        
  65.175 +        if (span != null && span[0] != (-1) && span[1] != (-1)) {
  65.176 +            LazyFixList fixesForED = org.netbeans.spi.editor.hints.ErrorDescriptionFactory.lazyListForFixes(resolveDefaultFixes(context, fixes));
  65.177 +            return org.netbeans.spi.editor.hints.ErrorDescriptionFactory.createErrorDescription("text/x-java:" + context.getHintMetadata().id, context.getSeverity(), text, context.getHintMetadata().description, fixesForED, context.getInfo().getFileObject(), span[0], span[1]);
  65.178 +        }
  65.179 +
  65.180 +        return null;
  65.181 +    }
  65.182 +
  65.183 +    private static int[] computeNameSpan(Tree tree, HintContext context) {
  65.184 +        switch (tree.getKind()) {
  65.185 +            case METHOD:
  65.186 +                return context.getInfo().getTreeUtilities().findNameSpan((MethodTree) tree);
  65.187 +            case ANNOTATION_TYPE:
  65.188 +            case CLASS:
  65.189 +            case ENUM:
  65.190 +            case INTERFACE:
  65.191 +                return context.getInfo().getTreeUtilities().findNameSpan((ClassTree) tree);
  65.192 +            case VARIABLE:
  65.193 +                return context.getInfo().getTreeUtilities().findNameSpan((VariableTree) tree);
  65.194 +            case MEMBER_SELECT:
  65.195 +                //XXX:
  65.196 +                MemberSelectTree mst = (MemberSelectTree) tree;
  65.197 +                int[] span = context.getInfo().getTreeUtilities().findNameSpan(mst);
  65.198 +
  65.199 +                if (span == null) {
  65.200 +                    int end = (int) context.getInfo().getTrees().getSourcePositions().getEndPosition(context.getInfo().getCompilationUnit(), tree);
  65.201 +                    span = new int[] {end - mst.getIdentifier().length(), end};
  65.202 +                }
  65.203 +                return span;
  65.204 +            case METHOD_INVOCATION:
  65.205 +                return computeNameSpan(((MethodInvocationTree) tree).getMethodSelect(), context);
  65.206 +            case BLOCK:
  65.207 +                Collection<? extends TreePath> prefix = context.getMultiVariables().get("$$1$");
  65.208 +                
  65.209 +                if (prefix != null) {
  65.210 +                    BlockTree bt = (BlockTree) tree;
  65.211 +                    
  65.212 +                    if (bt.getStatements().size() > prefix.size()) {
  65.213 +                        return computeNameSpan(bt.getStatements().get(prefix.size()), context);
  65.214 +                    }
  65.215 +                }
  65.216 +            default:
  65.217 +                int start = (int) context.getInfo().getTrees().getSourcePositions().getStartPosition(context.getInfo().getCompilationUnit(), tree);
  65.218 +                if (    StatementTree.class.isAssignableFrom(tree.getKind().asInterface())
  65.219 +                    && tree.getKind() != Kind.EXPRESSION_STATEMENT
  65.220 +                    && tree.getKind() != Kind.BLOCK) {
  65.221 +                    TokenSequence<?> ts = context.getInfo().getTokenHierarchy().tokenSequence();
  65.222 +                    ts.move(start);
  65.223 +                    if (ts.moveNext()) {
  65.224 +                        return new int[] {ts.offset(), ts.offset() + ts.token().length()};
  65.225 +                    }
  65.226 +                }
  65.227 +                return new int[] {
  65.228 +                    start,
  65.229 +                    (int) context.getInfo().getTrees().getSourcePositions().getEndPosition(context.getInfo().getCompilationUnit(), tree),
  65.230 +                };
  65.231 +        }
  65.232 +    }
  65.233 +
  65.234 +    static List<Fix> resolveDefaultFixes(HintContext ctx, Fix... provided) {
  65.235 +        List<Fix> auxiliaryFixes = new LinkedList<Fix>();
  65.236 +        HintMetadata hm = SPIAccessor.getINSTANCE().getHintMetadata(ctx);
  65.237 +
  65.238 +        if (hm != null) {
  65.239 +            Set<String> suppressWarningsKeys = new LinkedHashSet<String>();
  65.240 +
  65.241 +            for (String key : hm.suppressWarnings) {
  65.242 +                if (key == null || key.length() == 0) {
  65.243 +                    break;
  65.244 +                }
  65.245 +
  65.246 +                suppressWarningsKeys.add(key);
  65.247 +            }
  65.248 +
  65.249 +
  65.250 +            auxiliaryFixes.add(new DisableConfigure(hm, true, SPIAccessor.getINSTANCE().getHintSettings(ctx)));
  65.251 +            auxiliaryFixes.add(new DisableConfigure(hm, false, null));
  65.252 +
  65.253 +            if (hm.kind == Hint.Kind.INSPECTION) {
  65.254 +                auxiliaryFixes.add(new InspectFix(hm, false));
  65.255 +                if (!hm.options.contains(Options.QUERY)) {
  65.256 +                    auxiliaryFixes.add(new InspectFix(hm, true));
  65.257 +                }
  65.258 +            }
  65.259 +            
  65.260 +            if (!suppressWarningsKeys.isEmpty()) {
  65.261 +                auxiliaryFixes.addAll(createSuppressWarnings(ctx.getInfo(), ctx.getPath(), suppressWarningsKeys.toArray(new String[0])));
  65.262 +            }
  65.263 +
  65.264 +            List<Fix> result = new LinkedList<Fix>();
  65.265 +
  65.266 +            for (Fix f : provided != null ? provided : new Fix[0]) {
  65.267 +                if (f == null) continue;
  65.268 +                
  65.269 +                result.add(org.netbeans.spi.editor.hints.ErrorDescriptionFactory.attachSubfixes(f, auxiliaryFixes));
  65.270 +            }
  65.271 +
  65.272 +            if (result.isEmpty()) {
  65.273 +                result.add(org.netbeans.spi.editor.hints.ErrorDescriptionFactory.attachSubfixes(new TopLevelConfigureFix(hm), auxiliaryFixes));
  65.274 +            }
  65.275 +
  65.276 +            return result;
  65.277 +        }
  65.278 +
  65.279 +        return Arrays.asList(provided);
  65.280 +    }
  65.281 +
  65.282 +    private static class DisableConfigure implements Fix, SyntheticFix {
  65.283 +        private final @NonNull HintMetadata metadata;
  65.284 +        private final boolean disable;
  65.285 +        private final HintsSettings hintsSettings;
  65.286 +
  65.287 +        DisableConfigure(@NonNull HintMetadata metadata, boolean disable, HintsSettings hintsSettings) {
  65.288 +            this.metadata = metadata;
  65.289 +            this.disable = disable;
  65.290 +            this.hintsSettings = hintsSettings;
  65.291 +        }
  65.292 +
  65.293 +        @Override
  65.294 +        public String getText() {
  65.295 +            String displayName = metadata.displayName;
  65.296 +            String key;
  65.297 +            switch (metadata.kind) {
  65.298 +                case INSPECTION:
  65.299 +                    key = disable ? "FIX_DisableHint" : "FIX_ConfigureHint";
  65.300 +                    break;
  65.301 +                case ACTION:
  65.302 +                    key = disable ? "FIX_DisableSuggestion" : "FIX_ConfigureSuggestion";
  65.303 +                    break;
  65.304 +                default:
  65.305 +                    throw new IllegalStateException();
  65.306 +            }
  65.307 +
  65.308 +            return NbBundle.getMessage(ErrorDescriptionFactory.class, key, displayName);
  65.309 +        }
  65.310 +
  65.311 +        @Override
  65.312 +        public ChangeInfo implement() throws Exception {
  65.313 +            if (disable) {
  65.314 +                hintsSettings.setEnabled(metadata, false);
  65.315 +                //XXX: re-run hints task
  65.316 +            } else {
  65.317 +                OptionsDisplayer.getDefault().open("Editor/Hints/text/x-java/" + metadata.id);
  65.318 +            }
  65.319 +
  65.320 +            return null;
  65.321 +        }
  65.322 +
  65.323 +        @Override
  65.324 +        public boolean equals(Object obj) {
  65.325 +            if (obj == null) {
  65.326 +                return false;
  65.327 +            }
  65.328 +            if (this.getClass() != obj.getClass()) {
  65.329 +                return false;
  65.330 +            }
  65.331 +            final DisableConfigure other = (DisableConfigure) obj;
  65.332 +            if (this.metadata != other.metadata && (this.metadata == null || !this.metadata.equals(other.metadata))) {
  65.333 +                return false;
  65.334 +            }
  65.335 +            if (this.disable != other.disable) {
  65.336 +                return false;
  65.337 +            }
  65.338 +            return true;
  65.339 +        }
  65.340 +
  65.341 +        @Override
  65.342 +        public int hashCode() {
  65.343 +            int hash = 7;
  65.344 +            hash = 43 * hash + (this.metadata != null ? this.metadata.hashCode() : 0);
  65.345 +            hash = 43 * hash + (this.disable ? 1 : 0);
  65.346 +            return hash;
  65.347 +        }
  65.348 +
  65.349 +
  65.350 +    }
  65.351 +
  65.352 +    private static final class TopLevelConfigureFix extends DisableConfigure implements EnhancedFix {
  65.353 +
  65.354 +        public TopLevelConfigureFix(@NonNull HintMetadata metadata) {
  65.355 +            super(metadata, false, null);
  65.356 +        }
  65.357 +
  65.358 +        @Override
  65.359 +        public CharSequence getSortText() {
  65.360 +            return "\uFFFFzz";
  65.361 +        }
  65.362 +        
  65.363 +    }
  65.364 +
  65.365 +    private static class InspectFix implements Fix, SyntheticFix {
  65.366 +        private final @NonNull HintMetadata metadata;
  65.367 +        private final boolean transform;
  65.368 +
  65.369 +        InspectFix(@NonNull HintMetadata metadata, boolean transform) {
  65.370 +            this.metadata = metadata;
  65.371 +            this.transform = transform;
  65.372 +        }
  65.373 +
  65.374 +        @Override
  65.375 +        @Messages({
  65.376 +            "DN_InspectAndTransform=Run Inspect&Transform on...",
  65.377 +            "DN_Inspect=Run Inspect on..."
  65.378 +        })
  65.379 +        public String getText() {
  65.380 +            return transform ? Bundle.DN_InspectAndTransform() : Bundle.DN_Inspect();
  65.381 +        }
  65.382 +
  65.383 +        @Override
  65.384 +        public ChangeInfo implement() throws Exception {
  65.385 +            SwingUtilities.invokeLater(new Runnable() {
  65.386 +                @Override
  65.387 +                public void run() {
  65.388 +                    if (transform) {
  65.389 +                        final InspectAndTransformOpener o = Lookup.getDefault().lookup(InspectAndTransformOpener.class);
  65.390 +
  65.391 +                        if (o != null) {
  65.392 +                            o.openIAT(metadata);
  65.393 +                        } else {
  65.394 +                            //warn
  65.395 +                        }
  65.396 +                    } else {
  65.397 +                        CodeAnalysis.open(WarningDescription.create("text/x-java:" + metadata.id, null, null, null));
  65.398 +                    }
  65.399 +                }
  65.400 +            });
  65.401 +            
  65.402 +            return null;
  65.403 +        }
  65.404 +
  65.405 +        @Override
  65.406 +        public boolean equals(Object obj) {
  65.407 +            if (obj == null) {
  65.408 +                return false;
  65.409 +            }
  65.410 +            if (this.getClass() != obj.getClass()) {
  65.411 +                return false;
  65.412 +            }
  65.413 +            final InspectFix other = (InspectFix) obj;
  65.414 +            if (this.metadata != other.metadata && (this.metadata == null || !this.metadata.equals(other.metadata))) {
  65.415 +                return false;
  65.416 +            }
  65.417 +            if (this.transform != other.transform) {
  65.418 +                return false;
  65.419 +            }
  65.420 +            return true;
  65.421 +        }
  65.422 +
  65.423 +        @Override
  65.424 +        public int hashCode() {
  65.425 +            int hash = 7;
  65.426 +            hash = 43 * hash + (this.metadata != null ? this.metadata.hashCode() : 0);
  65.427 +            hash = 43 * hash + (this.transform ? 1 : 0);
  65.428 +            return hash;
  65.429 +        }
  65.430 +
  65.431 +
  65.432 +    }
  65.433 +    
  65.434 +    /** Creates a fix, which when invoked adds @SuppresWarnings(keys) to
  65.435 +     * nearest declaration.
  65.436 +     * @param compilationInfo CompilationInfo to work on
  65.437 +     * @param treePath TreePath to a tree. The method will find nearest outer
  65.438 +     *        declaration. (type, method, field or local variable)
  65.439 +     * @param keys keys to be contained in the SuppresWarnings annotation. E.g.
  65.440 +     *        @SuppresWarnings( "key" ) or @SuppresWarnings( {"key1", "key2", ..., "keyN" } ).
  65.441 +     * @throws IllegalArgumentException if keys are null or empty or id no suitable element
  65.442 +     *         to put the annotation on is found (e.g. if TreePath to CompilationUnit is given")
  65.443 +     */
  65.444 +    static Fix createSuppressWarningsFix(CompilationInfo compilationInfo, TreePath treePath, String... keys ) {
  65.445 +        Parameters.notNull("compilationInfo", compilationInfo);
  65.446 +        Parameters.notNull("treePath", treePath);
  65.447 +        Parameters.notNull("keys", keys);
  65.448 +
  65.449 +        if (keys.length == 0) {
  65.450 +            throw new IllegalArgumentException("key must not be empty"); // NOI18N
  65.451 +        }
  65.452 +
  65.453 +        if (!isSuppressWarningsSupported(compilationInfo)) {
  65.454 +            return null;
  65.455 +        }
  65.456 +
  65.457 +        while (treePath.getLeaf().getKind() != Kind.COMPILATION_UNIT && !DECLARATION.contains(treePath.getLeaf().getKind())) {
  65.458 +            treePath = treePath.getParentPath();
  65.459 +        }
  65.460 +
  65.461 +        if (treePath.getLeaf().getKind() != Kind.COMPILATION_UNIT) {
  65.462 +            return new FixImpl(TreePathHandle.create(treePath, compilationInfo), compilationInfo.getFileObject(), keys);
  65.463 +        } else {
  65.464 +            return null;
  65.465 +        }
  65.466 +    }
  65.467 +
  65.468 +    /** Creates a fix, which when invoked adds @SuppresWarnings(keys) to
  65.469 +     * nearest declaration.
  65.470 +     * @param compilationInfo CompilationInfo to work on
  65.471 +     * @param treePath TreePath to a tree. The method will find nearest outer
  65.472 +     *        declaration. (type, method, field or local variable)
  65.473 +     * @param keys keys to be contained in the SuppresWarnings annotation. E.g.
  65.474 +     *        @SuppresWarnings( "key" ) or @SuppresWarnings( {"key1", "key2", ..., "keyN" } ).
  65.475 +     * @throws IllegalArgumentException if keys are null or empty or id no suitable element
  65.476 +     *         to put the annotation on is found (e.g. if TreePath to CompilationUnit is given")
  65.477 +     */
  65.478 +    static List<Fix> createSuppressWarnings(CompilationInfo compilationInfo, TreePath treePath, String... keys ) {
  65.479 +        Parameters.notNull("compilationInfo", compilationInfo);
  65.480 +        Parameters.notNull("treePath", treePath);
  65.481 +        Parameters.notNull("keys", keys);
  65.482 +
  65.483 +        if (keys.length == 0) {
  65.484 +            throw new IllegalArgumentException("key must not be empty"); // NOI18N
  65.485 +        }
  65.486 +
  65.487 +        Fix f = createSuppressWarningsFix(compilationInfo, treePath, keys);
  65.488 +
  65.489 +        if (f != null) {
  65.490 +            return Collections.<Fix>singletonList(f);
  65.491 +        } else {
  65.492 +            return Collections.emptyList();
  65.493 +        }
  65.494 +    }
  65.495 +
  65.496 +    private static boolean isSuppressWarningsSupported(CompilationInfo info) {
  65.497 +        //cannot suppress if there is no SuppressWarnings annotation in the platform:
  65.498 +        if (info.getElements().getTypeElement("java.lang.SuppressWarnings") == null)
  65.499 +            return false;
  65.500 +
  65.501 +        return info.getSourceVersion().compareTo(SourceVersion.RELEASE_5) >= 0;
  65.502 +    }
  65.503 +
  65.504 +    private static final Set<Kind> DECLARATION = EnumSet.of(Kind.ANNOTATION_TYPE, Kind.CLASS, Kind.ENUM, Kind.INTERFACE, Kind.METHOD, Kind.VARIABLE);
  65.505 +
  65.506 +    private static final class FixImpl implements Fix, SyntheticFix {
  65.507 +
  65.508 +        private String keys[];
  65.509 +        private TreePathHandle handle;
  65.510 +        private FileObject file;
  65.511 +
  65.512 +        public FixImpl(TreePathHandle handle, FileObject file, String... keys) {
  65.513 +            this.keys = keys;
  65.514 +            this.handle = handle;
  65.515 +            this.file = file;
  65.516 +        }
  65.517 +
  65.518 +        public String getText() {
  65.519 +            StringBuilder keyNames = new StringBuilder();
  65.520 +            for (int i = 0; i < keys.length; i++) {
  65.521 +                String string = keys[i];
  65.522 +                keyNames.append(string);
  65.523 +                if ( i < keys.length - 1) {
  65.524 +                    keyNames.append(", "); // NOI18N
  65.525 +                }
  65.526 +            }
  65.527 +
  65.528 +            return NbBundle.getMessage(ErrorDescriptionFactory.class, "LBL_FIX_Suppress_Waning",  keyNames.toString() );  // NOI18N
  65.529 +        }
  65.530 +
  65.531 +        public ChangeInfo implement() throws IOException {
  65.532 +            JavaSource js = JavaSource.forFileObject(file);
  65.533 +
  65.534 +            js.runModificationTask(new Task<WorkingCopy>() {
  65.535 +                public void run(WorkingCopy copy) throws IOException {
  65.536 +                    copy.toPhase(Phase.RESOLVED); //XXX: performance
  65.537 +                    TreePath path = handle.resolve(copy);
  65.538 +
  65.539 +                    while (path != null && path.getLeaf().getKind() != Kind.COMPILATION_UNIT && !DECLARATION.contains(path.getLeaf().getKind())) {
  65.540 +                        path = path.getParentPath();
  65.541 +                    }
  65.542 +
  65.543 +                    if (path.getLeaf().getKind() == Kind.COMPILATION_UNIT) {
  65.544 +                        return ;
  65.545 +                    }
  65.546 +
  65.547 +                    Tree top = path.getLeaf();
  65.548 +                    ModifiersTree modifiers = null;
  65.549 +
  65.550 +                    switch (top.getKind()) {
  65.551 +                        case ANNOTATION_TYPE:
  65.552 +                        case CLASS:
  65.553 +                        case ENUM:
  65.554 +                        case INTERFACE:
  65.555 +                            modifiers = ((ClassTree) top).getModifiers();
  65.556 +                            break;
  65.557 +                        case METHOD:
  65.558 +                            modifiers = ((MethodTree) top).getModifiers();
  65.559 +                            break;
  65.560 +                        case VARIABLE:
  65.561 +                            modifiers = ((VariableTree) top).getModifiers();
  65.562 +                            break;
  65.563 +                        default: assert false : "Unhandled Tree.Kind";  // NOI18N
  65.564 +                    }
  65.565 +
  65.566 +                    if (modifiers == null) {
  65.567 +                        return ;
  65.568 +                    }
  65.569 +
  65.570 +                    TypeElement el = copy.getElements().getTypeElement("java.lang.SuppressWarnings");  // NOI18N
  65.571 +
  65.572 +                    if (el == null) {
  65.573 +                        return ;
  65.574 +                    }
  65.575 +
  65.576 +                    LiteralTree[] keyLiterals = new LiteralTree[keys.length];
  65.577 +
  65.578 +                    for (int i = 0; i < keys.length; i++) {
  65.579 +                        keyLiterals[i] = copy.getTreeMaker().
  65.580 +                                Literal(keys[i]);
  65.581 +                    }
  65.582 +
  65.583 +                    ModifiersTree nueMods = GeneratorUtilities.get(copy).appendToAnnotationValue(modifiers, el, "value", keyLiterals);
  65.584 +
  65.585 +                    copy.rewrite(modifiers, nueMods);
  65.586 +                }
  65.587 +            }).commit();
  65.588 +
  65.589 +            return null;
  65.590 +        }
  65.591 +
  65.592 +        @Override
  65.593 +        public boolean equals(Object obj) {
  65.594 +            if (obj == null) {
  65.595 +                return false;
  65.596 +            }
  65.597 +            if (getClass() != obj.getClass()) {
  65.598 +                return false;
  65.599 +            }
  65.600 +            final FixImpl other = (FixImpl) obj;
  65.601 +            if (!Arrays.deepEquals(this.keys, other.keys)) {
  65.602 +                return false;
  65.603 +            }
  65.604 +            if (this.handle != other.handle && (this.handle == null || !this.handle.equals(other.handle))) {
  65.605 +                return false;
  65.606 +            }
  65.607 +            if (this.file != other.file && (this.file == null || !this.file.equals(other.file))) {
  65.608 +                return false;
  65.609 +            }
  65.610 +            return true;
  65.611 +        }
  65.612 +
  65.613 +        @Override
  65.614 +        public int hashCode() {
  65.615 +            int hash = 5;
  65.616 +            hash = 79 * hash + Arrays.deepHashCode(this.keys);
  65.617 +            hash = 79 * hash + (this.handle != null ? this.handle.hashCode() : 0);
  65.618 +            hash = 79 * hash + (this.file != null ? this.file.hashCode() : 0);
  65.619 +            return hash;
  65.620 +        }
  65.621 +    }
  65.622 +}
    66.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    66.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/Hint.java	Wed May 08 21:47:42 2013 +0200
    66.3 @@ -0,0 +1,128 @@
    66.4 +/*
    66.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    66.6 + *
    66.7 + * Copyright 2008-2010 Oracle and/or its affiliates. All rights reserved.
    66.8 + *
    66.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   66.10 + * Other names may be trademarks of their respective owners.
   66.11 + *
   66.12 + * The contents of this file are subject to the terms of either the GNU
   66.13 + * General Public License Version 2 only ("GPL") or the Common
   66.14 + * Development and Distribution License("CDDL") (collectively, the
   66.15 + * "License"). You may not use this file except in compliance with the
   66.16 + * License. You can obtain a copy of the License at
   66.17 + * http://www.netbeans.org/cddl-gplv2.html
   66.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   66.19 + * specific language governing permissions and limitations under the
   66.20 + * License.  When distributing the software, include this License Header
   66.21 + * Notice in each file and include the License file at
   66.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   66.23 + * particular file as subject to the "Classpath" exception as provided
   66.24 + * by Oracle in the GPL Version 2 section of the License file that
   66.25 + * accompanied this code. If applicable, add the following below the
   66.26 + * License Header, with the fields enclosed by brackets [] replaced by
   66.27 + * your own identifying information:
   66.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   66.29 + *
   66.30 + * If you wish your version of this file to be governed by only the CDDL
   66.31 + * or only the GPL Version 2, indicate your decision by adding
   66.32 + * "[Contributor] elects to include this software in this distribution
   66.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   66.34 + * single choice of license, a recipient has the option to distribute
   66.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   66.36 + * to extend the choice of license to its licensees as provided above.
   66.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   66.38 + * Version 2 license, then the option applies only if the new code is
   66.39 + * made subject to such option by the copyright holder.
   66.40 + *
   66.41 + * Contributor(s):
   66.42 + *
   66.43 + * Portions Copyrighted 2008-2010 Sun Microsystems, Inc.
   66.44 + */
   66.45 +
   66.46 +package org.netbeans.spi.java.hints;
   66.47 +
   66.48 +import java.lang.annotation.ElementType;
   66.49 +import java.lang.annotation.Retention;
   66.50 +import java.lang.annotation.RetentionPolicy;
   66.51 +import java.lang.annotation.Target;
   66.52 +import org.netbeans.spi.editor.hints.Severity;
   66.53 +
   66.54 +/** Description of a hint.
   66.55 + * When applied to a class, any enclosed method marked with a trigger
   66.56 + * will be considered to be part of this hint. When applied to a method, only this specific
   66.57 + * method will be considered to the part of the hint.
   66.58 + * Currently recognized triggers include {@link TriggerPattern} and {@link TriggerTreeKind}.
   66.59 + * @author lahvac, Petr Hrebejk
   66.60 + */
   66.61 +@Target({ElementType.TYPE, ElementType.METHOD})
   66.62 +@Retention(RetentionPolicy.SOURCE)
   66.63 +public @interface Hint {
   66.64 +    /**Manually specify the hint's id. Use only reorganizing code to keep compatibility with settings
   66.65 +     * from previous version. Id will be generated automatically is not specified.
   66.66 +     */
   66.67 +    public String id() default "";
   66.68 +    /** The hint's display name.
   66.69 +     */
   66.70 +    public String displayName();
   66.71 +    /** The hint's long description.
   66.72 +     */
   66.73 +    public String description();
   66.74 +    /**Category where the hint belongs.
   66.75 +     */
   66.76 +    public String category();
   66.77 +    /**Should the hint be enabled by default?*/
   66.78 +    public boolean enabled() default true;
   66.79 +    /**Default severity of the hint. {@link Severity#HINT} will typically be shown
   66.80 +     * only on the line with the caret.*/
   66.81 +    public Severity severity() default Severity.VERIFIER;
   66.82 +    /**Suppress warnings keys that should automatically suppress the hint.*/
   66.83 +    public String[] suppressWarnings() default {};
   66.84 +    /**A customizer that allows to customize hint's preferences.
   66.85 +     */
   66.86 +    public Class<? extends CustomizerProvider> customizerProvider() default CustomizerProvider.class;
   66.87 +    /**Whether the hint should be considered an {@link Kind#INSPECTION inspection}, i.e. it detects a code smell,
   66.88 +     * or otherwise leads to improving the code, or a {@link Kind#SUGGESTION}, which is simply
   66.89 +     * an offer to do automatically do something for the user.
   66.90 +     */
   66.91 +    public Kind hintKind() default Kind.INSPECTION;
   66.92 +    /**Specify various options for the hint*/
   66.93 +    public Options[] options() default {};
   66.94 +
   66.95 +    /**Whether the hint should be considered a {@link Kind#HINT hint}, e.g. it
   66.96 +     * detects a code smell, or otherwise leads to improving the code, or a {@link Kind#ACTION},
   66.97 +     * which is simply an offer to do automatically do something for the user.
   66.98 +     */
   66.99 +   public enum Kind {
  66.100 +       /**The hint represents a code-smell detector, or alike. It marks code that
  66.101 +        * is not correct (in some sense).
  66.102 +        */
  66.103 +       INSPECTION,
  66.104 +       
  66.105 +       /**The hint represents an offer to the user to automatically alter the code.
  66.106 +        * The transformation is not intended to improve the code, only allow the
  66.107 +        * user to do some kind of code transformation quickly.
  66.108 +        *
  66.109 +        * The only meaningful severity for suggestions if {@link Severity#CURRENT_LINE_WARNING}.
  66.110 +        */
  66.111 +       ACTION;
  66.112 +    }
  66.113 +
  66.114 +   /**Various options to altering the behavior of the hint.
  66.115 +    */
  66.116 +    public enum Options {
  66.117 +        /**The hint does not produce any automatic transformations that could be run
  66.118 +         * inside the Inspect&Refactor dialog.
  66.119 +         */
  66.120 +        QUERY,
  66.121 +        /**The hint cannot be run inside the Inspect&Refactor dialog.
  66.122 +         */
  66.123 +        NO_BATCH,
  66.124 +        /**
  66.125 +         * The hint requires heavyweight processing so it should be run explicitly only by Inspect, Refactor (or similar) 
  66.126 +         * features
  66.127 +         */
  66.128 +        HEAVY;
  66.129 +    }
  66.130 +
  66.131 +}
    67.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    67.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/HintContext.java	Wed May 08 21:47:42 2013 +0200
    67.3 @@ -0,0 +1,197 @@
    67.4 +/*
    67.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    67.6 + *
    67.7 + * Copyright 2008-2010 Oracle and/or its affiliates. All rights reserved.
    67.8 + *
    67.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   67.10 + * Other names may be trademarks of their respective owners.
   67.11 + *
   67.12 + * The contents of this file are subject to the terms of either the GNU
   67.13 + * General Public License Version 2 only ("GPL") or the Common
   67.14 + * Development and Distribution License("CDDL") (collectively, the
   67.15 + * "License"). You may not use this file except in compliance with the
   67.16 + * License. You can obtain a copy of the License at
   67.17 + * http://www.netbeans.org/cddl-gplv2.html
   67.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   67.19 + * specific language governing permissions and limitations under the
   67.20 + * License.  When distributing the software, include this License Header
   67.21 + * Notice in each file and include the License file at
   67.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   67.23 + * particular file as subject to the "Classpath" exception as provided
   67.24 + * by Oracle in the GPL Version 2 section of the License file that
   67.25 + * accompanied this code. If applicable, add the following below the
   67.26 + * License Header, with the fields enclosed by brackets [] replaced by
   67.27 + * your own identifying information:
   67.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   67.29 + *
   67.30 + * If you wish your version of this file to be governed by only the CDDL
   67.31 + * or only the GPL Version 2, indicate your decision by adding
   67.32 + * "[Contributor] elects to include this software in this distribution
   67.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   67.34 + * single choice of license, a recipient has the option to distribute
   67.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   67.36 + * to extend the choice of license to its licensees as provided above.
   67.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   67.38 + * Version 2 license, then the option applies only if the new code is
   67.39 + * made subject to such option by the copyright holder.
   67.40 + *
   67.41 + * Contributor(s):
   67.42 + *
   67.43 + * Portions Copyrighted 2008-2010 Sun Microsystems, Inc.
   67.44 + */
   67.45 +
   67.46 +package org.netbeans.spi.java.hints;
   67.47 +
   67.48 +import com.sun.source.util.TreePath;
   67.49 +import java.util.Collection;
   67.50 +import java.util.Collections;
   67.51 +import java.util.HashMap;
   67.52 +import java.util.LinkedList;
   67.53 +import java.util.Map;
   67.54 +import java.util.concurrent.atomic.AtomicBoolean;
   67.55 +import java.util.prefs.Preferences;
   67.56 +import javax.lang.model.type.TypeMirror;
   67.57 +import org.netbeans.api.java.source.CompilationInfo;
   67.58 +import org.netbeans.modules.java.hints.providers.spi.HintMetadata;
   67.59 +import org.netbeans.modules.java.hints.spiimpl.MessageImpl;
   67.60 +import org.netbeans.modules.java.hints.spiimpl.SPIAccessor;
   67.61 +import org.netbeans.modules.java.hints.spiimpl.options.HintsSettings;
   67.62 +import org.netbeans.spi.editor.hints.Severity;
   67.63 +import org.netbeans.spi.java.hints.Hint.Kind;
   67.64 +
   67.65 +/**
   67.66 + *
   67.67 + * @author Jan Lahoda
   67.68 + */
   67.69 +public class HintContext {
   67.70 +
   67.71 +    private final CompilationInfo info;
   67.72 +    private final HintsSettings settings;
   67.73 +    private final Preferences preferences;
   67.74 +    private final Severity severity;
   67.75 +    private final HintMetadata metadata;
   67.76 +    private final TreePath path;
   67.77 +    private final Map<String, TreePath> variables;
   67.78 +    private final Map<String, Collection<? extends TreePath>> multiVariables;
   67.79 +    private final Map<String, String> variableNames;
   67.80 +    private final Collection<? super MessageImpl> messages;
   67.81 +    private final Map<String, TypeMirror> constraints;
   67.82 +    private final boolean bulkMode;
   67.83 +    private final AtomicBoolean cancel;
   67.84 +    private final int caret;
   67.85 +
   67.86 +    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) {
   67.87 +        this.info = info;
   67.88 +        this.settings = settings;
   67.89 +        this.preferences = metadata != null ? settings.getHintPreferences(metadata) : null;
   67.90 +        this.severity = preferences != null ? settings.getSeverity(metadata) : Severity.ERROR;
   67.91 +        this.metadata = metadata;
   67.92 +        this.path = path;
   67.93 +
   67.94 +        variables = new HashMap<String, TreePath>(variables);
   67.95 +        variables.put("$_", path);
   67.96 +        
   67.97 +        this.variables = variables;
   67.98 +        this.multiVariables = multiVariables;
   67.99 +        this.variableNames = variableNames;
  67.100 +        this.messages = problems;
  67.101 +        this.constraints = constraints;
  67.102 +        this.bulkMode = bulkMode;
  67.103 +        this.cancel = cancel;
  67.104 +        this.caret = caret;
  67.105 +    }
  67.106 +
  67.107 +    public CompilationInfo getInfo() {
  67.108 +        return info;
  67.109 +    }
  67.110 +
  67.111 +    public Preferences getPreferences() {
  67.112 +        return preferences;
  67.113 +    }
  67.114 +
  67.115 +    public Severity getSeverity() {
  67.116 +        return severity;
  67.117 +    }
  67.118 +
  67.119 +    public TreePath getPath() {
  67.120 +        return path;
  67.121 +    }
  67.122 +
  67.123 +    public Map<String, TreePath> getVariables() {
  67.124 +        return variables;
  67.125 +    }
  67.126 +
  67.127 +    public Map<String, Collection<? extends TreePath>> getMultiVariables() {
  67.128 +        return multiVariables;
  67.129 +    }
  67.130 +
  67.131 +    public Map<String, String> getVariableNames() {
  67.132 +        return variableNames;
  67.133 +    }
  67.134 +
  67.135 +    HintMetadata getHintMetadata() {
  67.136 +        return metadata;
  67.137 +    }
  67.138 +
  67.139 +    //TODO: not sure it should be here:
  67.140 +    public Map<String, TypeMirror> getConstraints() {
  67.141 +        return constraints;
  67.142 +    }
  67.143 +
  67.144 +    /**
  67.145 +     * Will be used only for refactoring(s), will be ignored for hints.
  67.146 +     * 
  67.147 +     * @param kind
  67.148 +     * @param text
  67.149 +     */
  67.150 +    public void reportMessage(MessageKind kind, String text) {
  67.151 +        messages.add(new MessageImpl(kind, text));
  67.152 +    }
  67.153 +
  67.154 +    /**Returns {@code true} if the hint is being run in over many files, {@code false}
  67.155 +     * if only the file opened in the editor is being inspected.
  67.156 +     *
  67.157 +     * @return {@code true} if the hint is being run in over many files.
  67.158 +     */
  67.159 +    public boolean isBulkMode() {
  67.160 +        return bulkMode;
  67.161 +    }
  67.162 +
  67.163 +    /**Returns {@code true} if the computation has been canceled.
  67.164 +     *
  67.165 +     * @return {@code true} if the computation has been canceled.
  67.166 +     */
  67.167 +    public boolean isCanceled() {
  67.168 +        return cancel.get();
  67.169 +    }
  67.170 +
  67.171 +    /**For suggestions, returns the caret location for the editor
  67.172 +     * for which the suggestion is being computed. Returns -1 for hints.
  67.173 +     *
  67.174 +     * @return for suggestions, returns the caret location, -1 otherwise
  67.175 +     */
  67.176 +    public int getCaretLocation() {
  67.177 +        return metadata.kind == Kind.ACTION ? caret : -1;
  67.178 +    }
  67.179 +    
  67.180 +    public enum MessageKind {
  67.181 +        WARNING, ERROR;
  67.182 +    }
  67.183 +    
  67.184 +    static {
  67.185 +        SPIAccessor.setINSTANCE(new SPIAccessor() {
  67.186 +            @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) {
  67.187 +                return new HintContext(info, settings, metadata, path, variables, multiVariables, variableNames, constraints, problems, bulkMode, cancel, caret);
  67.188 +            }
  67.189 +            @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) {
  67.190 +                return new HintContext(info, settings, metadata, path, variables, multiVariables, variableNames, Collections.<String, TypeMirror>emptyMap(), new LinkedList<MessageImpl>(), false, new AtomicBoolean(), -1);
  67.191 +            }
  67.192 +            @Override public HintMetadata getHintMetadata(HintContext ctx) {
  67.193 +                return ctx.getHintMetadata();
  67.194 +            }
  67.195 +            @Override public HintsSettings getHintSettings(HintContext ctx) {
  67.196 +                return ctx.settings;
  67.197 +            }
  67.198 +        });
  67.199 +    }
  67.200 +}
    68.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    68.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/HintSeverity.java	Wed May 08 21:47:42 2013 +0200
    68.3 @@ -0,0 +1,69 @@
    68.4 +/*
    68.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    68.6 + *
    68.7 + * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
    68.8 + *
    68.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   68.10 + * Other names may be trademarks of their respective owners.
   68.11 + *
   68.12 + * The contents of this file are subject to the terms of either the GNU
   68.13 + * General Public License Version 2 only ("GPL") or the Common
   68.14 + * Development and Distribution License("CDDL") (collectively, the
   68.15 + * "License"). You may not use this file except in compliance with the
   68.16 + * License. You can obtain a copy of the License at
   68.17 + * http://www.netbeans.org/cddl-gplv2.html
   68.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   68.19 + * specific language governing permissions and limitations under the
   68.20 + * License.  When distributing the software, include this License Header
   68.21 + * Notice in each file and include the License file at
   68.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   68.23 + * particular file as subject to the "Classpath" exception as provided
   68.24 + * by Oracle in the GPL Version 2 section of the License file that
   68.25 + * accompanied this code. If applicable, add the following below the
   68.26 + * License Header, with the fields enclosed by brackets [] replaced by
   68.27 + * your own identifying information:
   68.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   68.29 + *
   68.30 + * If you wish your version of this file to be governed by only the CDDL
   68.31 + * or only the GPL Version 2, indicate your decision by adding
   68.32 + * "[Contributor] elects to include this software in this distribution
   68.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   68.34 + * single choice of license, a recipient has the option to distribute
   68.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   68.36 + * to extend the choice of license to its licensees as provided above.
   68.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   68.38 + * Version 2 license, then the option applies only if the new code is
   68.39 + * made subject to such option by the copyright holder.
   68.40 + *
   68.41 + * Contributor(s):
   68.42 + *
   68.43 + * Portions Copyrighted 2011 Sun Microsystems, Inc.
   68.44 + */
   68.45 +package org.netbeans.spi.java.hints;
   68.46 +
   68.47 +import org.netbeans.spi.editor.hints.Severity;
   68.48 +
   68.49 +/** Severity of hint
   68.50 + *  <li><code>ERROR</code>  - will show up as error
   68.51 + *  <li><code>WARNING</code>  - will show up as warning
   68.52 + *  <li><code>CURRENT_LINE_WARNING</code>  - will only show up when the caret is placed in the erroneous element
   68.53 + * @author Petr Hrebejk
   68.54 + */
   68.55 +public enum HintSeverity {
   68.56 +    ERROR,
   68.57 +    WARNING,
   68.58 +    CURRENT_LINE_WARNING;
   68.59 +
   68.60 +    public Severity toEditorSeverity() {
   68.61 +        switch ( this ) {
   68.62 +            case ERROR:
   68.63 +                return Severity.ERROR;
   68.64 +            case WARNING:
   68.65 +                return Severity.VERIFIER;
   68.66 +            case CURRENT_LINE_WARNING:
   68.67 +                return Severity.HINT;
   68.68 +            default:
   68.69 +                return null;
   68.70 +        }
   68.71 +    }
   68.72 +}
    69.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    69.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/IntegerOption.java	Wed May 08 21:47:42 2013 +0200
    69.3 @@ -0,0 +1,99 @@
    69.4 +/*
    69.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    69.6 + *
    69.7 + * Copyright 2013 Oracle and/or its affiliates. All rights reserved.
    69.8 + *
    69.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   69.10 + * Other names may be trademarks of their respective owners.
   69.11 + *
   69.12 + * The contents of this file are subject to the terms of either the GNU
   69.13 + * General Public License Version 2 only ("GPL") or the Common
   69.14 + * Development and Distribution License("CDDL") (collectively, the
   69.15 + * "License"). You may not use this file except in compliance with the
   69.16 + * License. You can obtain a copy of the License at
   69.17 + * http://www.netbeans.org/cddl-gplv2.html
   69.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   69.19 + * specific language governing permissions and limitations under the
   69.20 + * License.  When distributing the software, include this License Header
   69.21 + * Notice in each file and include the License file at
   69.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   69.23 + * particular file as subject to the "Classpath" exception as provided
   69.24 + * by Oracle in the GPL Version 2 section of the License file that
   69.25 + * accompanied this code. If applicable, add the following below the
   69.26 + * License Header, with the fields enclosed by brackets [] replaced by
   69.27 + * your own identifying information:
   69.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   69.29 + *
   69.30 + * If you wish your version of this file to be governed by only the CDDL
   69.31 + * or only the GPL Version 2, indicate your decision by adding
   69.32 + * "[Contributor] elects to include this software in this distribution
   69.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   69.34 + * single choice of license, a recipient has the option to distribute
   69.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   69.36 + * to extend the choice of license to its licensees as provided above.
   69.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   69.38 + * Version 2 license, then the option applies only if the new code is
   69.39 + * made subject to such option by the copyright holder.
   69.40 + *
   69.41 + * Contributor(s):
   69.42 + *
   69.43 + * Portions Copyrighted 2013 Sun Microsystems, Inc.
   69.44 + */
   69.45 +package org.netbeans.spi.java.hints;
   69.46 +
   69.47 +import java.lang.annotation.Documented;
   69.48 +import java.lang.annotation.ElementType;
   69.49 +import java.lang.annotation.Retention;
   69.50 +import java.lang.annotation.RetentionPolicy;
   69.51 +import java.lang.annotation.Target;
   69.52 +
   69.53 +/**
   69.54 + *  Declares an int-value option that affects hint processing.
   69.55 + *  If the Hint mixes integer and boolean options, the integer options
   69.56 + *  come first, boolean second in the UI.
   69.57 + * 
   69.58 + *  @author sdedic
   69.59 + */
   69.60 +@Retention(RetentionPolicy.SOURCE)
   69.61 +@Target(ElementType.FIELD)
   69.62 +@Documented
   69.63 +public @interface IntegerOption {
   69.64 +    /**
   69.65 +     * @return Display name of the option
   69.66 +     */
   69.67 +    public String displayName();
   69.68 +    
   69.69 +    /**
   69.70 +     * @return tooltip for mouse hover over the option
   69.71 +     */
   69.72 +    public String tooltip() default "";
   69.73 +    
   69.74 +    /**
   69.75 +     * @return default value for the option
   69.76 +     */
   69.77 +    public int defaultValue() default 0;
   69.78 +    
   69.79 +    /**
   69.80 +     * Minimum value for the option. If Integer.MIN_VALUE (the default),
   69.81 +     * no minimum will be enforced.
   69.82 +     * 
   69.83 +     * @return minimum value.
   69.84 +     */
   69.85 +    public int minValue() default 0;
   69.86 +    
   69.87 +    /**
   69.88 +     * Maximum value for the option. If Integer.MAX_VALUE (the default),
   69.89 +     * no maximum will be enforced. Please do choose a reasonable maximum value,
   69.90 +     * as the UI may size the input box to accommodate all digits of the maximum
   69.91 +     * permitted value, and the input box may seem unreasonably large.
   69.92 +     * 
   69.93 +     * @return maximum value
   69.94 +     */
   69.95 +    public int maxValue() default Integer.MAX_VALUE;
   69.96 +    
   69.97 +    /**
   69.98 +     * If non-zero, a spinner will be created with the specified step. If zero (the default),
   69.99 +     * a plain input will be presented. Negative values are not accepted at the moment and are reserved.
  69.100 +     */
  69.101 +    public int step() default 0;
  69.102 +}
    70.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    70.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/JavaFix.java	Wed May 08 21:47:42 2013 +0200
    70.3 @@ -0,0 +1,328 @@
    70.4 +/*
    70.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    70.6 + *
    70.7 + * Copyright 2008-2012 Oracle and/or its affiliates. All rights reserved.
    70.8 + *
    70.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   70.10 + * Other names may be trademarks of their respective owners.
   70.11 + *
   70.12 + * The contents of this file are subject to the terms of either the GNU
   70.13 + * General Public License Version 2 only ("GPL") or the Common
   70.14 + * Development and Distribution License("CDDL") (collectively, the
   70.15 + * "License"). You may not use this file except in compliance with the
   70.16 + * License. You can obtain a copy of the License at
   70.17 + * http://www.netbeans.org/cddl-gplv2.html
   70.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   70.19 + * specific language governing permissions and limitations under the
   70.20 + * License.  When distributing the software, include this License Header
   70.21 + * Notice in each file and include the License file at
   70.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   70.23 + * particular file as subject to the "Classpath" exception as provided
   70.24 + * by Oracle in the GPL Version 2 section of the License file that
   70.25 + * accompanied this code. If applicable, add the following below the
   70.26 + * License Header, with the fields enclosed by brackets [] replaced by
   70.27 + * your own identifying information:
   70.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   70.29 + *
   70.30 + * If you wish your version of this file to be governed by only the CDDL
   70.31 + * or only the GPL Version 2, indicate your decision by adding
   70.32 + * "[Contributor] elects to include this software in this distribution
   70.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   70.34 + * single choice of license, a recipient has the option to distribute
   70.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   70.36 + * to extend the choice of license to its licensees as provided above.
   70.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   70.38 + * Version 2 license, then the option applies only if the new code is
   70.39 + * made subject to such option by the copyright holder.
   70.40 + *
   70.41 + * Contributor(s):
   70.42 + *
   70.43 + * Portions Copyrighted 2008-2012 Sun Microsystems, Inc.
   70.44 + */
   70.45 +
   70.46 +package org.netbeans.spi.java.hints;
   70.47 +
   70.48 +import com.sun.source.util.TreePath;
   70.49 +import java.io.ByteArrayInputStream;
   70.50 +import java.io.ByteArrayOutputStream;
   70.51 +import java.io.IOException;
   70.52 +import java.io.InputStream;
   70.53 +import java.io.OutputStream;
   70.54 +import java.nio.ByteBuffer;
   70.55 +import java.util.Collection;
   70.56 +import java.util.Collections;
   70.57 +import java.util.HashMap;
   70.58 +import java.util.List;
   70.59 +import java.util.Map;
   70.60 +import java.util.logging.Level;
   70.61 +import java.util.logging.Logger;
   70.62 +import javax.lang.model.type.TypeMirror;
   70.63 +import javax.swing.text.BadLocationException;
   70.64 +import javax.swing.text.Document;
   70.65 +import org.netbeans.api.annotations.common.CheckForNull;
   70.66 +import org.netbeans.api.annotations.common.NonNull;
   70.67 +import org.netbeans.api.java.source.CompilationInfo;
   70.68 +import org.netbeans.api.java.source.TreePathHandle;
   70.69 +import org.netbeans.api.java.source.WorkingCopy;
   70.70 +import org.netbeans.api.queries.FileEncodingQuery;
   70.71 +import org.netbeans.modules.java.hints.spiimpl.JavaFixImpl;
   70.72 +import org.netbeans.modules.refactoring.spi.RefactoringElementImplementation;
   70.73 +import org.netbeans.spi.editor.hints.ChangeInfo;
   70.74 +import org.netbeans.spi.editor.hints.Fix;
   70.75 +import org.openide.cookies.EditorCookie;
   70.76 +import org.openide.filesystems.FileObject;
   70.77 +import org.openide.loaders.DataObject;
   70.78 +import org.openide.loaders.DataObjectNotFoundException;
   70.79 +import org.openide.util.Exceptions;
   70.80 +import org.openide.util.Parameters;
   70.81 +
   70.82 +/**A base class for fixes that modify Java source code. Using this class
   70.83 + * as a base class makes creating the fix somewhat simpler, but also supports
   70.84 + * running the hint in the Inspect&Transform dialog. The fix can be converted
   70.85 + * to {@link Fix} by means of the {@link #toEditorFix() } method.
   70.86 + *
   70.87 + * @see JavaFixUtilities for various predefined fixes.
   70.88 + * @author Jan Lahoda
   70.89 + */
   70.90 +public abstract class JavaFix {
   70.91 +
   70.92 +    private final TreePathHandle handle;
   70.93 +    private final Map<String, String> options;
   70.94 +
   70.95 +    /**Create JavaFix with the given base {@link TreePath}. The base {@link TreePath}
   70.96 +     * will be passed back to the real implementation of the fix.
   70.97 +     *
   70.98 +     * @param info a {@link CompilationInfo} from which the given {@link TreePath} originates
   70.99 +     * @param tp a {@link TreePath} that will be passed back to the
  70.100 +     *           {@link #performRewrite(org.netbeans.spi.java.hints.JavaFix.TransformationContext) } method
  70.101 +     */
  70.102 +    protected JavaFix(@NonNull CompilationInfo info, @NonNull TreePath tp) {
  70.103 +        this(info, tp, Collections.<String, String>emptyMap());
  70.104 +    }
  70.105 +
  70.106 +    JavaFix(CompilationInfo info, TreePath tp, Map<String, String> options) {
  70.107 +        this.handle = TreePathHandle.create(tp, info);
  70.108 +        this.options = Collections.unmodifiableMap(new HashMap<String, String>(options));
  70.109 +    }
  70.110 +
  70.111 +    /**Create JavaFix with the given base {@link TreePathHandle}. The base {@link TreePathHandle}
  70.112 +     * will be resolved and passed back to the real implementation of the fix.
  70.113 +     *
  70.114 +     * @param handle a {@link TreePathHandle} that will be resolved and passed back to the
  70.115 +     *              {@link #performRewrite(org.netbeans.spi.java.hints.JavaFix.TransformationContext) } method
  70.116 +     */
  70.117 +    protected JavaFix(@NonNull TreePathHandle handle) {
  70.118 +        this(handle, Collections.<String, String>emptyMap());
  70.119 +    }
  70.120 +
  70.121 +    JavaFix(TreePathHandle handle, Map<String, String> options) {
  70.122 +        this.handle = handle;
  70.123 +        this.options = Collections.unmodifiableMap(new HashMap<String, String>(options));
  70.124 +    }
  70.125 +
  70.126 +    /**The display text of the fix.
  70.127 +     *
  70.128 +     * @return the display text of the fix.
  70.129 +     */
  70.130 +    protected abstract @NonNull String getText();
  70.131 +
  70.132 +    /**Do the transformations needed to implement the hint's function.
  70.133 +     *
  70.134 +     * @param ctx a context over which the fix should operate
  70.135 +     * @throws Exception if something goes wrong while performing the transformation
  70.136 +     *                   - will be logged by the infrastructure
  70.137 +     */
  70.138 +    protected abstract void performRewrite(@NonNull TransformationContext ctx) throws Exception;
  70.139 +
  70.140 +    /**Convert this {@link JavaFix} into the Editor Hints {@link Fix}.
  70.141 +     *
  70.142 +     * @return a {@link Fix}, that when invoked, will invoke {@link #performRewrite(org.netbeans.spi.java.hints.JavaFix.TransformationContext) }
  70.143 +     * method on this {@link JavaFix}.
  70.144 +     */
  70.145 +    public final Fix toEditorFix() {
  70.146 +        return new JavaFixImpl(this);
  70.147 +    }
  70.148 +
  70.149 +    static {
  70.150 +        JavaFixImpl.Accessor.INSTANCE = new JavaFixImpl.Accessor() {
  70.151 +            @Override
  70.152 +            public String getText(JavaFix jf) {
  70.153 +                return jf.getText();
  70.154 +            }
  70.155 +            @Override
  70.156 +            public ChangeInfo process(JavaFix jf, WorkingCopy wc, boolean canShowUI, Map<FileObject, byte[]> resourceContent, Collection<? super RefactoringElementImplementation> fileChanges) throws Exception {
  70.157 +                TreePath tp = jf.handle.resolve(wc);
  70.158 +
  70.159 +                if (tp == null) {
  70.160 +                    Logger.getLogger(JavaFix.class.getName()).log(Level.SEVERE, "Cannot resolve handle={0}", jf.handle);
  70.161 +                    return null;
  70.162 +                }
  70.163 +
  70.164 +                jf.performRewrite(new TransformationContext(wc, tp, canShowUI, resourceContent, fileChanges));
  70.165 +
  70.166 +                return null;
  70.167 +            }
  70.168 +            @Override
  70.169 +            public FileObject getFile(JavaFix jf) {
  70.170 +                return jf.handle.getFileObject();
  70.171 +            }
  70.172 +            @Override
  70.173 +            public Map<String, String> getOptions(JavaFix jf) {
  70.174 +                return jf.options;
  70.175 +            }
  70.176 +
  70.177 +            @Override
  70.178 +            public Fix rewriteFix(CompilationInfo info, String displayName, TreePath what, String to, Map<String, TreePath> parameters, Map<String, Collection<? extends TreePath>> parametersMulti, Map<String, String> parameterNames, Map<String, TypeMirror> constraints, Map<String, String> options, String... imports) {
  70.179 +                return JavaFixUtilities.rewriteFix(info, displayName, what, to, parameters, parametersMulti, parameterNames, constraints, options, imports);
  70.180 +            }
  70.181 +
  70.182 +            @Override
  70.183 +            public Fix createSuppressWarningsFix(CompilationInfo compilationInfo, TreePath treePath, String... keys) {
  70.184 +                return ErrorDescriptionFactory.createSuppressWarningsFix(compilationInfo, treePath, keys);
  70.185 +            }
  70.186 +
  70.187 +            @Override
  70.188 +            public List<Fix> createSuppressWarnings(CompilationInfo compilationInfo, TreePath treePath, String... keys) {
  70.189 +                return ErrorDescriptionFactory.createSuppressWarnings(compilationInfo, treePath, keys);
  70.190 +            }
  70.191 +
  70.192 +            @Override
  70.193 +            public List<Fix> resolveDefaultFixes(HintContext ctx, Fix... provided) {
  70.194 +                return ErrorDescriptionFactory.resolveDefaultFixes(ctx, provided);
  70.195 +            }
  70.196 +        };
  70.197 +    }
  70.198 +
  70.199 +    /**A context that contains a reference to a {@link WorkingCopy} through which
  70.200 +     * modifications of Java source code can be made.
  70.201 +     *
  70.202 +     */
  70.203 +    public static final class TransformationContext {
  70.204 +        private final WorkingCopy workingCopy;
  70.205 +        private final TreePath path;
  70.206 +        private final boolean canShowUI;
  70.207 +        private final Map<FileObject, byte[]> resourceContentChanges;
  70.208 +        private final Collection<? super RefactoringElementImplementation> fileChanges;
  70.209 +        TransformationContext(WorkingCopy workingCopy, TreePath path, boolean canShowUI, Map<FileObject, byte[]> resourceContentChanges, Collection<? super RefactoringElementImplementation> fileChanges) {
  70.210 +            this.workingCopy = workingCopy;
  70.211 +            this.path = path;
  70.212 +            this.canShowUI = canShowUI;
  70.213 +            this.resourceContentChanges = resourceContentChanges;
  70.214 +            this.fileChanges = fileChanges;
  70.215 +        }
  70.216 +
  70.217 +        boolean isCanShowUI() {
  70.218 +            return canShowUI;
  70.219 +        }
  70.220 +
  70.221 +        /**Returns the {@link TreePath} that was passed to a {@link JavaFix} constructor.
  70.222 +         *
  70.223 +         * @return the {@link TreePath} that was passed to a {@link JavaFix} constructor.
  70.224 +         */
  70.225 +        public @NonNull TreePath getPath() {
  70.226 +            return path;
  70.227 +        }
  70.228 +
  70.229 +        /**A {@link WorkingCopy} over which the transformation should operate.
  70.230 +         * @return {@link WorkingCopy} over which the transformation should operate.
  70.231 +         */
  70.232 +        public @NonNull WorkingCopy getWorkingCopy() {
  70.233 +            return workingCopy;
  70.234 +        }
  70.235 +
  70.236 +        /**Allows access to non-Java resources. The content of this InputStream will
  70.237 +         * include all changes done through {@link #getResourceOutput(org.openide.filesystems.FileObject) }
  70.238 +         * before calling this method.
  70.239 +         *
  70.240 +         * @param file whose content should be returned
  70.241 +         * @return the file's content
  70.242 +         * @throws IOException if something goes wrong while opening the file
  70.243 +         * @throws IllegalArgumentException if {@code file} parameter is null, or
  70.244 +         *                                  if it represents a Java file
  70.245 +         */
  70.246 +        public @NonNull InputStream getResourceContent(@NonNull FileObject file) throws IOException, IllegalArgumentException {
  70.247 +            Parameters.notNull("file", file);
  70.248 +            if ("text/x-java".equals(file.getMIMEType("text/x-java")))
  70.249 +                throw new IllegalArgumentException("Cannot access Java files");
  70.250 +
  70.251 +            byte[] newContent = resourceContentChanges != null ? resourceContentChanges.get(file) : null;
  70.252 +
  70.253 +            if (newContent == null) {
  70.254 +                final Document doc = getDocument(file);
  70.255 +
  70.256 +                if (doc != null) {
  70.257 +                    final String[] result = new String[1];
  70.258 +
  70.259 +                    doc.render(new Runnable() {
  70.260 +                        @Override public void run() {
  70.261 +                            try {
  70.262 +                                result[0] = doc.getText(0, doc.getLength());
  70.263 +                            } catch (BadLocationException ex) {
  70.264 +                                Exceptions.printStackTrace(ex);
  70.265 +                            }
  70.266 +                        }
  70.267 +                    });
  70.268 +
  70.269 +                    if (result[0] != null) {
  70.270 +                        ByteBuffer encoded = FileEncodingQuery.getEncoding(file).encode(result[0]);
  70.271 +                        byte[] encodedBytes = new byte[encoded.remaining()];
  70.272 +
  70.273 +                        encoded.get(encodedBytes);
  70.274 +
  70.275 +                        return new ByteArrayInputStream(encodedBytes);
  70.276 +                    }
  70.277 +                }
  70.278 +                
  70.279 +                return file.getInputStream();
  70.280 +            } else {
  70.281 +                return new ByteArrayInputStream(newContent);
  70.282 +            }
  70.283 +        }
  70.284 +
  70.285 +        /**Record a changed version of a file. The changes will be applied altogether with
  70.286 +         * changes to the Java file. In Inspect&Transform, changes done through this
  70.287 +         * method will be part of the preview.
  70.288 +         *
  70.289 +         * @param file whose content should be changed
  70.290 +         * @return an {@link java.io.OutputStream} into which the new content of the file should be written
  70.291 +         * @throws IOException if something goes wrong while opening the file
  70.292 +         * @throws IllegalArgumentException if {@code file} parameter is null, or
  70.293 +         *                                  if it represents a Java file
  70.294 +         */
  70.295 +        public @NonNull OutputStream getResourceOutput(@NonNull final FileObject file) throws IOException {
  70.296 +            Parameters.notNull("file", file);
  70.297 +            if ("text/x-java".equals(file.getMIMEType("text/x-java")))
  70.298 +                throw new IllegalArgumentException("Cannot access Java files");
  70.299 +            if (resourceContentChanges == null) return file.getOutputStream();
  70.300 +
  70.301 +            return new ByteArrayOutputStream() {
  70.302 +                @Override public void close() throws IOException {
  70.303 +                    super.close();
  70.304 +                    resourceContentChanges.put(file, toByteArray());
  70.305 +                }
  70.306 +            };
  70.307 +        }
  70.308 +
  70.309 +        Collection<? super RefactoringElementImplementation> getFileChanges() {
  70.310 +            return fileChanges;
  70.311 +        }
  70.312 +
  70.313 +        private @CheckForNull Document getDocument(@NonNull FileObject file) {
  70.314 +            try {
  70.315 +                DataObject od = DataObject.find(file);
  70.316 +                EditorCookie ec = od.getLookup().lookup(EditorCookie.class);
  70.317 +
  70.318 +                if (ec == null) return null;
  70.319 +
  70.320 +                return ec.getDocument();
  70.321 +            } catch (DataObjectNotFoundException ex) {
  70.322 +                LOG.log(Level.FINE, null, ex);
  70.323 +                return null;
  70.324 +            }
  70.325 +        }
  70.326 +
  70.327 +    }
  70.328 +
  70.329 +    private static final Logger LOG = Logger.getLogger(JavaFix.class.getName());
  70.330 +
  70.331 +}
    71.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    71.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/JavaFixUtilities.java	Wed May 08 21:47:42 2013 +0200
    71.3 @@ -0,0 +1,1631 @@
    71.4 +/*
    71.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    71.6 + *
    71.7 + * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
    71.8 + *
    71.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   71.10 + * Other names may be trademarks of their respective owners.
   71.11 + *
   71.12 + * The contents of this file are subject to the terms of either the GNU
   71.13 + * General Public License Version 2 only ("GPL") or the Common
   71.14 + * Development and Distribution License("CDDL") (collectively, the
   71.15 + * "License"). You may not use this file except in compliance with the
   71.16 + * License. You can obtain a copy of the License at
   71.17 + * http://www.netbeans.org/cddl-gplv2.html
   71.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   71.19 + * specific language governing permissions and limitations under the
   71.20 + * License.  When distributing the software, include this License Header
   71.21 + * Notice in each file and include the License file at
   71.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   71.23 + * particular file as subject to the "Classpath" exception as provided
   71.24 + * by Oracle in the GPL Version 2 section of the License file that
   71.25 + * accompanied this code. If applicable, add the following below the
   71.26 + * License Header, with the fields enclosed by brackets [] replaced by
   71.27 + * your own identifying information:
   71.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   71.29 + *
   71.30 + * If you wish your version of this file to be governed by only the CDDL
   71.31 + * or only the GPL Version 2, indicate your decision by adding
   71.32 + * "[Contributor] elects to include this software in this distribution
   71.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   71.34 + * single choice of license, a recipient has the option to distribute
   71.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   71.36 + * to extend the choice of license to its licensees as provided above.
   71.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   71.38 + * Version 2 license, then the option applies only if the new code is
   71.39 + * made subject to such option by the copyright holder.
   71.40 + *
   71.41 + * Contributor(s):
   71.42 + *
   71.43 + * Portions Copyrighted 2012 Sun Microsystems, Inc.
   71.44 + */
   71.45 +package org.netbeans.spi.java.hints;
   71.46 +
   71.47 +import com.sun.javadoc.Doc;
   71.48 +import com.sun.javadoc.Tag;
   71.49 +import com.sun.source.tree.AnnotationTree;
   71.50 +import com.sun.source.tree.AssignmentTree;
   71.51 +import com.sun.source.tree.BinaryTree;
   71.52 +import com.sun.source.tree.BlockTree;
   71.53 +import com.sun.source.tree.CaseTree;
   71.54 +import com.sun.source.tree.CatchTree;
   71.55 +import com.sun.source.tree.ClassTree;
   71.56 +import com.sun.source.tree.CompilationUnitTree;
   71.57 +import com.sun.source.tree.CompoundAssignmentTree;
   71.58 +import com.sun.source.tree.ExpressionStatementTree;
   71.59 +import com.sun.source.tree.ExpressionTree;
   71.60 +import com.sun.source.tree.IdentifierTree;
   71.61 +import com.sun.source.tree.IfTree;
   71.62 +import com.sun.source.tree.LambdaExpressionTree;
   71.63 +import com.sun.source.tree.LiteralTree;
   71.64 +import com.sun.source.tree.MemberSelectTree;
   71.65 +import com.sun.source.tree.MethodInvocationTree;
   71.66 +import com.sun.source.tree.MethodTree;
   71.67 +import com.sun.source.tree.ModifiersTree;
   71.68 +import com.sun.source.tree.NewArrayTree;
   71.69 +import com.sun.source.tree.NewClassTree;
   71.70 +import com.sun.source.tree.ParameterizedTypeTree;
   71.71 +import com.sun.source.tree.ParenthesizedTree;
   71.72 +import com.sun.source.tree.Scope;
   71.73 +import com.sun.source.tree.StatementTree;
   71.74 +import com.sun.source.tree.SwitchTree;
   71.75 +import com.sun.source.tree.Tree;
   71.76 +import com.sun.source.tree.Tree.Kind;
   71.77 +import com.sun.source.tree.TryTree;
   71.78 +import com.sun.source.tree.TypeParameterTree;
   71.79 +import com.sun.source.tree.UnaryTree;
   71.80 +import com.sun.source.tree.UnionTypeTree;
   71.81 +import com.sun.source.tree.VariableTree;
   71.82 +import com.sun.source.util.SourcePositions;
   71.83 +import com.sun.source.util.TreePath;
   71.84 +import com.sun.source.util.TreePathScanner;
   71.85 +import com.sun.source.util.TreeScanner;
   71.86 +import java.io.IOException;
   71.87 +import java.util.ArrayList;
   71.88 +import java.util.Arrays;
   71.89 +import java.util.Collection;
   71.90 +import java.util.Collections;
   71.91 +import java.util.EnumMap;
   71.92 +import java.util.EnumSet;
   71.93 +import java.util.HashMap;
   71.94 +import java.util.IdentityHashMap;
   71.95 +import java.util.Iterator;
   71.96 +import java.util.LinkedList;
   71.97 +import java.util.List;
   71.98 +import java.util.Map;
   71.99 +import java.util.Map.Entry;
  71.100 +import java.util.Set;
  71.101 +import java.util.concurrent.Callable;
  71.102 +import java.util.logging.Level;
  71.103 +import java.util.logging.Logger;
  71.104 +import java.util.regex.Matcher;
  71.105 +import javax.lang.model.element.Element;
  71.106 +import javax.lang.model.element.ElementKind;
  71.107 +import javax.lang.model.element.Modifier;
  71.108 +import javax.lang.model.element.TypeElement;
  71.109 +import javax.lang.model.type.TypeKind;
  71.110 +import javax.lang.model.type.TypeMirror;
  71.111 +import org.netbeans.api.java.classpath.ClassPath;
  71.112 +import org.netbeans.api.java.classpath.ClassPath.PathConversionMode;
  71.113 +import org.netbeans.api.java.queries.SourceForBinaryQuery;
  71.114 +import org.netbeans.api.java.source.ClasspathInfo;
  71.115 +import org.netbeans.api.java.source.ClasspathInfo.PathKind;
  71.116 +import org.netbeans.api.java.source.CompilationInfo;
  71.117 +import org.netbeans.api.java.source.SourceUtils;
  71.118 +import org.netbeans.api.java.source.TreeMaker;
  71.119 +import org.netbeans.api.java.source.TreePathHandle;
  71.120 +import org.netbeans.api.java.source.TypeMirrorHandle;
  71.121 +import org.netbeans.api.java.source.WorkingCopy;
  71.122 +import org.netbeans.api.java.source.matching.Occurrence;
  71.123 +import org.netbeans.api.java.source.matching.Pattern;
  71.124 +import org.netbeans.api.project.FileOwnerQuery;
  71.125 +import org.netbeans.api.project.Project;
  71.126 +import org.netbeans.modules.java.hints.spiimpl.Hacks;
  71.127 +import org.netbeans.modules.java.hints.spiimpl.Utilities;
  71.128 +import org.netbeans.modules.java.hints.spiimpl.ipi.upgrade.ProjectDependencyUpgrader;
  71.129 +import org.netbeans.modules.refactoring.spi.SimpleRefactoringElementImplementation;
  71.130 +import org.netbeans.spi.editor.hints.Fix;
  71.131 +import org.netbeans.spi.java.classpath.support.ClassPathSupport;
  71.132 +import org.netbeans.spi.java.hints.JavaFix.TransformationContext;
  71.133 +import org.openide.filesystems.FileObject;
  71.134 +import org.openide.filesystems.FileUtil;
  71.135 +import org.openide.loaders.DataFolder;
  71.136 +import org.openide.loaders.DataObject;
  71.137 +import org.openide.loaders.DataObjectNotFoundException;
  71.138 +import org.openide.modules.SpecificationVersion;
  71.139 +import org.openide.text.PositionBounds;
  71.140 +import org.openide.util.Exceptions;
  71.141 +import org.openide.util.Lookup;
  71.142 +import org.openide.util.NbBundle.Messages;
  71.143 +import org.openide.util.NbCollections;
  71.144 +
  71.145 +/**Factory methods for various predefined {@link JavaFix} implementations.
  71.146 + *
  71.147 + * @author lahvac
  71.148 + */
  71.149 +public class JavaFixUtilities {
  71.150 +
  71.151 +    /**Prepare a fix that will replace the given tree node ({@code what}) with the
  71.152 +     * given code. Any variables in the {@code to} pattern will be replaced with their
  71.153 +     * values from {@link HintContext#getVariables() }, {@link HintContext#getMultiVariables() }
  71.154 +     * and {@link HintContext#getVariableNames() }.
  71.155 +     *
  71.156 +     * @param ctx basic context for which the fix should be created
  71.157 +     * @param displayName the display name of the fix
  71.158 +     * @param what the tree node that should be replaced
  71.159 +     * @param to the new code that should replaced the {@code what} tree node
  71.160 +     * @return an editor fix that performs the required transformation
  71.161 +     */
  71.162 +    public static Fix rewriteFix(HintContext ctx, String displayName, TreePath what, final String to) {
  71.163 +        return rewriteFix(ctx.getInfo(), displayName, what, to, ctx.getVariables(), ctx.getMultiVariables(), ctx.getVariableNames(), ctx.getConstraints(), Collections.<String, String>emptyMap());
  71.164 +    }
  71.165 +
  71.166 +    static Fix rewriteFix(CompilationInfo info, String displayName, TreePath what, final String to, Map<String, TreePath> parameters, Map<String, Collection<? extends TreePath>> parametersMulti, final Map<String, String> parameterNames, Map<String, TypeMirror> constraints, Map<String, String> options, String... imports) {
  71.167 +        final Map<String, TreePathHandle> params = new HashMap<String, TreePathHandle>();
  71.168 +        final Map<String, Object> extraParamsData = new HashMap<String, Object>();
  71.169 +
  71.170 +        for (Entry<String, TreePath> e : parameters.entrySet()) {
  71.171 +            params.put(e.getKey(), TreePathHandle.create(e.getValue(), info));
  71.172 +            if (e.getValue() instanceof Callable) {
  71.173 +                try {
  71.174 +                    extraParamsData.put(e.getKey(), ((Callable) e.getValue()).call());
  71.175 +                } catch (Exception ex) {
  71.176 +                    Exceptions.printStackTrace(ex);
  71.177 +                }
  71.178 +            }
  71.179 +        }
  71.180 +
  71.181 +        final Map<String, Collection<TreePathHandle>> paramsMulti = new HashMap<String, Collection<TreePathHandle>>();
  71.182 +
  71.183 +        for (Entry<String, Collection<? extends TreePath>> e : parametersMulti.entrySet()) {
  71.184 +            Collection<TreePathHandle> tph = new LinkedList<TreePathHandle>();
  71.185 +
  71.186 +            for (TreePath tp : e.getValue()) {
  71.187 +                tph.add(TreePathHandle.create(tp, info));
  71.188 +            }
  71.189 +
  71.190 +            paramsMulti.put(e.getKey(), tph);
  71.191 +        }
  71.192 +
  71.193 +        final Map<String, TypeMirrorHandle<?>> constraintsHandles = new HashMap<String, TypeMirrorHandle<?>>();
  71.194 +
  71.195 +        for (Entry<String, TypeMirror> c : constraints.entrySet()) {
  71.196 +            constraintsHandles.put(c.getKey(), TypeMirrorHandle.create(c.getValue()));
  71.197 +        }
  71.198 +
  71.199 +        if (displayName == null) {
  71.200 +            displayName = defaultFixDisplayName(info, parameters, to);
  71.201 +        }
  71.202 +
  71.203 +        return new JavaFixRealImpl(info, what, options, displayName, to, params, extraParamsData, paramsMulti, parameterNames, constraintsHandles, Arrays.asList(imports)).toEditorFix();
  71.204 +    }
  71.205 +
  71.206 +    /**Creates a fix that removes the given code corresponding to the given tree
  71.207 +     * node from the source code.
  71.208 +     * 
  71.209 +     * @param ctx basic context for which the fix should be created
  71.210 +     * @param displayName the display name of the fix
  71.211 +     * @param what the tree node that should be removed
  71.212 +     * @return an editor fix that removes the give tree from the source code
  71.213 +     */
  71.214 +    public static Fix removeFromParent(HintContext ctx, String displayName, TreePath what) {
  71.215 +        return new RemoveFromParent(displayName, ctx.getInfo(), what).toEditorFix();
  71.216 +    }
  71.217 +
  71.218 +    private static String defaultFixDisplayName(CompilationInfo info, Map<String, TreePath> variables, String replaceTarget) {
  71.219 +        Map<String, String> stringsForVariables = new HashMap<String, String>();
  71.220 +
  71.221 +        for (Entry<String, TreePath> e : variables.entrySet()) {
  71.222 +            Tree t = e.getValue().getLeaf();
  71.223 +            SourcePositions sp = info.getTrees().getSourcePositions();
  71.224 +            int startPos = (int) sp.getStartPosition(info.getCompilationUnit(), t);
  71.225 +            int endPos = (int) sp.getEndPosition(info.getCompilationUnit(), t);
  71.226 +
  71.227 +            if (startPos >= 0 && endPos >= 0) {
  71.228 +                stringsForVariables.put(e.getKey(), info.getText().substring(startPos, endPos));
  71.229 +            } else {
  71.230 +                stringsForVariables.put(e.getKey(), "");
  71.231 +            }
  71.232 +        }
  71.233 +
  71.234 +        if (!stringsForVariables.containsKey("$this")) {
  71.235 +            //XXX: is this correct?
  71.236 +            stringsForVariables.put("$this", "this");
  71.237 +        }
  71.238 +
  71.239 +        for (Entry<String, String> e : stringsForVariables.entrySet()) {
  71.240 +            String quotedVariable = java.util.regex.Pattern.quote(e.getKey());
  71.241 +            String quotedTarget = Matcher.quoteReplacement(e.getValue());
  71.242 +            replaceTarget = replaceTarget.replaceAll(quotedVariable, quotedTarget);
  71.243 +        }
  71.244 +
  71.245 +        return "Rewrite to " + replaceTarget;
  71.246 +    }
  71.247 +
  71.248 +    private static void checkDependency(CompilationInfo copy, Element e, boolean canShowUI) {
  71.249 +        SpecificationVersion sv = computeSpecVersion(copy, e);
  71.250 +
  71.251 +        while (sv == null && e.getKind() != ElementKind.PACKAGE) {
  71.252 +            e = e.getEnclosingElement();
  71.253 +            sv = computeSpecVersion(copy, e);
  71.254 +        }
  71.255 +
  71.256 +        if (sv == null) {
  71.257 +            return ;
  71.258 +        }
  71.259 +
  71.260 +        Project currentProject = FileOwnerQuery.getOwner(copy.getFileObject());
  71.261 +
  71.262 +        if (currentProject == null) {
  71.263 +            return ;
  71.264 +        }
  71.265 +
  71.266 +        FileObject file = getFile(copy, e);
  71.267 +
  71.268 +        if (file == null) {
  71.269 +            return ;
  71.270 +        }
  71.271 +
  71.272 +        FileObject root = findRootForFile(file, copy.getClasspathInfo());
  71.273 +
  71.274 +        if (root == null) {
  71.275 +            return ;
  71.276 +        }
  71.277 +
  71.278 +        Project referedProject = FileOwnerQuery.getOwner(file);
  71.279 +
  71.280 +        if (referedProject != null && currentProject.getProjectDirectory().equals(referedProject.getProjectDirectory())) {
  71.281 +            return ;
  71.282 +        }
  71.283 +
  71.284 +        for (ProjectDependencyUpgrader pdu : Lookup.getDefault().lookupAll(ProjectDependencyUpgrader.class)) {
  71.285 +            if (pdu.ensureDependency(currentProject, root, sv, canShowUI)) {
  71.286 +                return ;
  71.287 +            }
  71.288 +        }
  71.289 +    }
  71.290 +
  71.291 +    private static java.util.regex.Pattern SPEC_VERSION = java.util.regex.Pattern.compile("[0-9]+(\\.[0-9]+)+");
  71.292 +
  71.293 +    static SpecificationVersion computeSpecVersion(CompilationInfo info, Element el) {
  71.294 +        if (!Utilities.isJavadocSupported(info)) return null;
  71.295 +
  71.296 +        Doc javaDoc = info.getElementUtilities().javaDocFor(el);
  71.297 +
  71.298 +        if (javaDoc == null) return null;
  71.299 +
  71.300 +        for (Tag since : javaDoc.tags("@since")) {
  71.301 +            String text = since.text();
  71.302 +
  71.303 +            Matcher m = SPEC_VERSION.matcher(text);
  71.304 +
  71.305 +            if (!m.find()) {
  71.306 +                continue;
  71.307 +            }
  71.308 +
  71.309 +            return new SpecificationVersion(m.group()/*ver.toString()*/);
  71.310 +        }
  71.311 +
  71.312 +        return null;
  71.313 +    }
  71.314 +
  71.315 +    @SuppressWarnings("deprecation")
  71.316 +    private static FileObject getFile(CompilationInfo copy, Element e) {
  71.317 +        return SourceUtils.getFile(e, copy.getClasspathInfo());
  71.318 +    }
  71.319 +
  71.320 +    private static FileObject findRootForFile(final FileObject file, final ClasspathInfo cpInfo) {
  71.321 +        ClassPath cp = ClassPathSupport.createProxyClassPath(
  71.322 +            new ClassPath[] {
  71.323 +                cpInfo.getClassPath(ClasspathInfo.PathKind.SOURCE),
  71.324 +                cpInfo.getClassPath(ClasspathInfo.PathKind.BOOT),
  71.325 +                cpInfo.getClassPath(ClasspathInfo.PathKind.COMPILE),
  71.326 +            });
  71.327 +
  71.328 +        FileObject root = cp.findOwnerRoot(file);
  71.329 +
  71.330 +        if (root != null) {
  71.331 +            return root;
  71.332 +        }
  71.333 +
  71.334 +        for (ClassPath.Entry e : cp.entries()) {
  71.335 +            FileObject[] sourceRoots = SourceForBinaryQuery.findSourceRoots(e.getURL()).getRoots();
  71.336 +
  71.337 +            if (sourceRoots.length == 0) continue;
  71.338 +
  71.339 +            ClassPath sourcePath = ClassPathSupport.createClassPath(sourceRoots);
  71.340 +
  71.341 +            root = sourcePath.findOwnerRoot(file);
  71.342 +
  71.343 +            if (root != null) {
  71.344 +                return root;
  71.345 +            }
  71.346 +        }
  71.347 +        return null;
  71.348 +    }
  71.349 +
  71.350 +    private static boolean isStaticElement(Element el) {
  71.351 +        if (el == null) return false;
  71.352 +
  71.353 +        if (el.asType() == null || el.asType().getKind() == TypeKind.ERROR) {
  71.354 +            return false;
  71.355 +        }
  71.356 +
  71.357 +        if (el.getModifiers().contains(Modifier.STATIC)) {
  71.358 +            //XXX:
  71.359 +            if (!el.getKind().isClass() && !el.getKind().isInterface()) {
  71.360 +                return false;
  71.361 +            }
  71.362 +
  71.363 +            return true;
  71.364 +        }
  71.365 +
  71.366 +        if (el.getKind().isClass() || el.getKind().isInterface()) {
  71.367 +            return el.getEnclosingElement().getKind() == ElementKind.PACKAGE;
  71.368 +        }
  71.369 +
  71.370 +        return false;
  71.371 +    }
  71.372 +
  71.373 +    private static class JavaFixRealImpl extends JavaFix {
  71.374 +        private final String displayName;
  71.375 +        private final Map<String, TreePathHandle> params;
  71.376 +        private final Map<String, Object> extraParamsData;
  71.377 +        private final Map<String, Collection<TreePathHandle>> paramsMulti;
  71.378 +        private final Map<String, String> parameterNames;
  71.379 +        private final Map<String, TypeMirrorHandle<?>> constraintsHandles;
  71.380 +        private final Iterable<? extends String> imports;
  71.381 +        private final String to;
  71.382 +
  71.383 +        public JavaFixRealImpl(CompilationInfo info, TreePath what, Map<String, String> options, String displayName, String to, Map<String, TreePathHandle> params, Map<String, Object> extraParamsData, Map<String, Collection<TreePathHandle>> paramsMulti, final Map<String, String> parameterNames, Map<String, TypeMirrorHandle<?>> constraintsHandles, Iterable<? extends String> imports) {
  71.384 +            super(info, what, options);
  71.385 +
  71.386 +            this.displayName = displayName;
  71.387 +            this.to = to;
  71.388 +            this.params = params;
  71.389 +            this.extraParamsData = extraParamsData;
  71.390 +            this.paramsMulti = paramsMulti;
  71.391 +            this.parameterNames = parameterNames;
  71.392 +            this.constraintsHandles = constraintsHandles;
  71.393 +            this.imports = imports;
  71.394 +        }
  71.395 +
  71.396 +        @Override
  71.397 +        protected String getText() {
  71.398 +            return displayName;
  71.399 +        }
  71.400 +
  71.401 +        @Override
  71.402 +        protected void performRewrite(TransformationContext ctx) {
  71.403 +            final WorkingCopy wc = ctx.getWorkingCopy();
  71.404 +            TreePath tp = ctx.getPath();
  71.405 +            final Map<String, TreePath> parameters = new HashMap<String, TreePath>();
  71.406 +
  71.407 +            for (Entry<String, TreePathHandle> e : params.entrySet()) {
  71.408 +                TreePath p = e.getValue().resolve(wc);
  71.409 +
  71.410 +                if (p == null) {
  71.411 +                    Logger.getLogger(JavaFix.class.getName()).log(Level.SEVERE, "Cannot resolve handle={0}", e.getValue());
  71.412 +                }
  71.413 +
  71.414 +                parameters.put(e.getKey(), p);
  71.415 +            }
  71.416 +
  71.417 +            final Map<String, Collection<TreePath>> parametersMulti = new HashMap<String, Collection<TreePath>>();
  71.418 +
  71.419 +            for (Entry<String, Collection<TreePathHandle>> e : paramsMulti.entrySet()) {
  71.420 +                Collection<TreePath> tps = new LinkedList<TreePath>();
  71.421 +
  71.422 +                for (TreePathHandle tph : e.getValue()) {
  71.423 +                    TreePath p = tph.resolve(wc);
  71.424 +
  71.425 +                    if (p == null) {
  71.426 +                        Logger.getLogger(JavaFix.class.getName()).log(Level.SEVERE, "Cannot resolve handle={0}", e.getValue());
  71.427 +                    }
  71.428 +
  71.429 +                    tps.add(p);
  71.430 +                }
  71.431 +
  71.432 +                parametersMulti.put(e.getKey(), tps);
  71.433 +            }
  71.434 +
  71.435 +            Map<String, TypeMirror> constraints = new HashMap<String, TypeMirror>();
  71.436 +
  71.437 +            for (Entry<String, TypeMirrorHandle<?>> c : constraintsHandles.entrySet()) {
  71.438 +                constraints.put(c.getKey(), c.getValue().resolve(wc));
  71.439 +            }
  71.440 +
  71.441 +            Scope scope = Utilities.constructScope(wc, constraints, imports);
  71.442 +
  71.443 +            assert scope != null;
  71.444 +
  71.445 +            Tree parsed = Utilities.parseAndAttribute(wc, to, scope);
  71.446 +            
  71.447 +            if (parsed.getKind() == Kind.EXPRESSION_STATEMENT && ExpressionTree.class.isAssignableFrom(tp.getLeaf().getKind().asInterface())) {
  71.448 +                parsed = ((ExpressionStatementTree) parsed).getExpression();
  71.449 +            }
  71.450 +            
  71.451 +            Map<Tree, Tree> rewriteFromTo = new IdentityHashMap<Tree, Tree>();
  71.452 +            Tree original;
  71.453 +
  71.454 +            if (Utilities.isFakeBlock(parsed)) {
  71.455 +                TreePath parent = tp.getParentPath();
  71.456 +                List<? extends StatementTree> statements = ((BlockTree) parsed).getStatements();
  71.457 +                
  71.458 +                if (tp.getLeaf().getKind() == Kind.BLOCK) {
  71.459 +                    BlockTree real = (BlockTree) tp.getLeaf();
  71.460 +                    rewriteFromTo.put(original = real, wc.getTreeMaker().Block(statements, real.isStatic()));
  71.461 +                } else {
  71.462 +                    statements = statements.subList(1, statements.size() - 1);
  71.463 +
  71.464 +                    if (parent.getLeaf().getKind() == Kind.BLOCK) {
  71.465 +                        List<StatementTree> newStatements = new LinkedList<StatementTree>();
  71.466 +
  71.467 +                        for (StatementTree st : ((BlockTree) parent.getLeaf()).getStatements()) {
  71.468 +                            if (st == tp.getLeaf()) {
  71.469 +                                newStatements.addAll(statements);
  71.470 +                            } else {
  71.471 +                                newStatements.add(st);
  71.472 +                            }
  71.473 +                        }
  71.474 +
  71.475 +                        rewriteFromTo.put(original = parent.getLeaf(), wc.getTreeMaker().Block(newStatements, ((BlockTree) parent.getLeaf()).isStatic()));
  71.476 +                    } else {
  71.477 +                        rewriteFromTo.put(original = tp.getLeaf(), wc.getTreeMaker().Block(statements, false));
  71.478 +                    }
  71.479 +                }
  71.480 +            } else if (Utilities.isFakeClass(parsed)) {
  71.481 +                TreePath parent = tp.getParentPath();
  71.482 +                List<? extends Tree> members = ((ClassTree) parsed).getMembers();
  71.483 +
  71.484 +                members = members.subList(1, members.size());
  71.485 +
  71.486 +                assert parent.getLeaf().getKind() == Kind.CLASS;
  71.487 +
  71.488 +                List<Tree> newMembers = new LinkedList<Tree>();
  71.489 +
  71.490 +                ClassTree ct = (ClassTree) parent.getLeaf();
  71.491 +
  71.492 +                for (Tree t : ct.getMembers()) {
  71.493 +                    if (t == tp.getLeaf()) {
  71.494 +                        newMembers.addAll(members);
  71.495 +                    } else {
  71.496 +                        newMembers.add(t);
  71.497 +                    }
  71.498 +                }
  71.499 +
  71.500 +                rewriteFromTo.put(original = parent.getLeaf(), wc.getTreeMaker().Class(ct.getModifiers(), ct.getSimpleName(), ct.getTypeParameters(), ct.getExtendsClause(), ct.getImplementsClause(), newMembers));
  71.501 +            } else if (tp.getLeaf().getKind() == Kind.BLOCK && parametersMulti.containsKey("$$1$") && parsed.getKind() != Kind.BLOCK && StatementTree.class.isAssignableFrom(parsed.getKind().asInterface())) {
  71.502 +                List<StatementTree> newStatements = new LinkedList<StatementTree>();
  71.503 +
  71.504 +                newStatements.add(wc.getTreeMaker().ExpressionStatement(wc.getTreeMaker().Identifier("$$1$")));
  71.505 +                newStatements.add((StatementTree) parsed);
  71.506 +                newStatements.add(wc.getTreeMaker().ExpressionStatement(wc.getTreeMaker().Identifier("$$2$")));
  71.507 +
  71.508 +                parsed = wc.getTreeMaker().Block(newStatements, ((BlockTree) tp.getLeaf()).isStatic());
  71.509 +
  71.510 +                rewriteFromTo.put(original = tp.getLeaf(), parsed);
  71.511 +            } else {
  71.512 +                while (   tp.getParentPath().getLeaf().getKind() == Kind.PARENTHESIZED
  71.513 +                       && tp.getLeaf().getKind() != parsed.getKind()
  71.514 +                       && tp.getParentPath() != null
  71.515 +                       && tp.getParentPath().getParentPath() != null
  71.516 +                       && !requiresParenthesis(parsed, tp.getParentPath().getLeaf(), tp.getParentPath().getParentPath().getLeaf())
  71.517 +                       && requiresParenthesis(tp.getLeaf(), tp.getParentPath().getLeaf(), tp.getParentPath().getParentPath().getLeaf()))
  71.518 +                    tp = tp.getParentPath();
  71.519 +                rewriteFromTo.put(original = tp.getLeaf(), parsed);
  71.520 +            }
  71.521 +
  71.522 +            //prevent generating QualIdents inside import clauses - might be better to solve that inside ImportAnalysis2,
  71.523 +            //but that seems not to be straightforward:
  71.524 +            boolean inImport = parsed.getKind() == Kind.IMPORT;
  71.525 +            boolean inPackage = false;
  71.526 +            TreePath w = tp;
  71.527 +
  71.528 +            while (!inImport && w != null) {
  71.529 +                inImport |= w.getLeaf().getKind() == Kind.IMPORT;
  71.530 +                inPackage |= w.getParentPath() != null && w.getParentPath().getLeaf().getKind() == Kind.COMPILATION_UNIT && ((CompilationUnitTree) w.getParentPath().getLeaf()).getPackageName() == w.getLeaf();
  71.531 +                w = w.getParentPath();
  71.532 +            }
  71.533 +
  71.534 +            final Set<Tree> originalTrees = Collections.newSetFromMap(new IdentityHashMap<Tree, Boolean>());
  71.535 +            
  71.536 +            new TreeScanner<Void, Void>() {
  71.537 +                @Override public Void scan(Tree tree, Void p) {
  71.538 +                    originalTrees.add(tree);
  71.539 +                    return super.scan(tree, p);
  71.540 +                }
  71.541 +            }.scan(original, null);
  71.542 +            
  71.543 +            new ReplaceParameters(wc, ctx.isCanShowUI(), inImport, parameters, extraParamsData, parametersMulti, parameterNames, rewriteFromTo, originalTrees).scan(new TreePath(tp.getParentPath(), rewriteFromTo.get(original)), null);
  71.544 +
  71.545 +            if (inPackage) {
  71.546 +                String newPackage = wc.getTreeUtilities().translate(wc.getCompilationUnit().getPackageName(), new IdentityHashMap<Tree, Tree>(rewriteFromTo))./*XXX: not correct*/toString();
  71.547 +
  71.548 +                ClassPath source = wc.getClasspathInfo().getClassPath(PathKind.SOURCE);
  71.549 +                FileObject ownerRoot = source.findOwnerRoot(wc.getFileObject());
  71.550 +
  71.551 +                if (ownerRoot != null) {
  71.552 +                    ctx.getFileChanges().add(new MoveFile(wc.getFileObject(), ownerRoot, newPackage.replace('.', '/')));
  71.553 +                } else {
  71.554 +                    Logger.getLogger(JavaFix.class.getName()).log(Level.WARNING, "{0} not on its source path ({1})", new Object[] {FileUtil.getFileDisplayName(wc.getFileObject()), source.toString(PathConversionMode.PRINT)});
  71.555 +                }
  71.556 +            }
  71.557 +            
  71.558 +            for (Entry<Tree, Tree> e : rewriteFromTo.entrySet()) {
  71.559 +                wc.rewrite(e.getKey(), e.getValue());
  71.560 +            }
  71.561 +        }
  71.562 +    }
  71.563 +
  71.564 +    private static final Set<Kind> NUMBER_LITERAL_KINDS = EnumSet.of(Kind.FLOAT_LITERAL, Kind.DOUBLE_LITERAL, Kind.INT_LITERAL, Kind.LONG_LITERAL);
  71.565 +
  71.566 +    private static class ReplaceParameters extends TreePathScanner<Number, Void> {
  71.567 +
  71.568 +        private final CompilationInfo info;
  71.569 +        private final TreeMaker make;
  71.570 +        private final boolean canShowUI;
  71.571 +        private final boolean inImport;
  71.572 +        private final Map<String, TreePath> parameters;
  71.573 +        private final Map<String, Object> extraParamsData;
  71.574 +        private final Map<String, Collection<TreePath>> parametersMulti;
  71.575 +        private final Map<String, String> parameterNames;
  71.576 +        private final Map<Tree, Tree> rewriteFromTo;
  71.577 +        private final Set<Tree> originalTrees;
  71.578 +
  71.579 +        public ReplaceParameters(WorkingCopy wc, boolean canShowUI, boolean inImport, Map<String, TreePath> parameters, Map<String, Object> extraParamsData, Map<String, Collection<TreePath>> parametersMulti, Map<String, String> parameterNames, Map<Tree, Tree> rewriteFromTo, Set<Tree> originalTrees) {
  71.580 +            this.parameters = parameters;
  71.581 +            this.info = wc;
  71.582 +            this.make = wc.getTreeMaker();
  71.583 +            this.canShowUI = canShowUI;
  71.584 +            this.inImport = inImport;
  71.585 +            this.extraParamsData = extraParamsData;
  71.586 +            this.parametersMulti = parametersMulti;
  71.587 +            this.parameterNames = parameterNames;
  71.588 +            this.rewriteFromTo = rewriteFromTo;
  71.589 +            this.originalTrees = originalTrees;
  71.590 +        }
  71.591 +
  71.592 +        @Override
  71.593 +        public Number visitIdentifier(IdentifierTree node, Void p) {
  71.594 +            String name = node.getName().toString();
  71.595 +            Tree newNode = handleIdentifier(name, node);
  71.596 +            
  71.597 +            if (newNode != null) {
  71.598 +                rewrite(node, newNode);
  71.599 +                if (NUMBER_LITERAL_KINDS.contains(newNode.getKind())) {
  71.600 +                    return (Number) ((LiteralTree) newNode).getValue();
  71.601 +                }
  71.602 +            }
  71.603 +
  71.604 +            Element e = info.getTrees().getElement(getCurrentPath());
  71.605 +
  71.606 +            if (e != null && isStaticElement(e) && !inImport) {
  71.607 +                rewrite(node, make.QualIdent(e));
  71.608 +            }
  71.609 +
  71.610 +            return super.visitIdentifier(node, p);
  71.611 +        }
  71.612 +
  71.613 +        @Override
  71.614 +        public Number visitTypeParameter(TypeParameterTree node, Void p) {
  71.615 +            String name = node.getName().toString();
  71.616 +            Tree newNode = handleIdentifier(name, node);
  71.617 +            
  71.618 +            if (newNode != null) {
  71.619 +                rewrite(node, newNode);
  71.620 +                if (NUMBER_LITERAL_KINDS.contains(newNode.getKind())) {
  71.621 +                    return (Number) ((LiteralTree) newNode).getValue();
  71.622 +                }
  71.623 +            }
  71.624 +            
  71.625 +            return super.visitTypeParameter(node, p);
  71.626 +        }
  71.627 +        
  71.628 +        private Tree handleIdentifier(String name, Tree node) {
  71.629 +            TreePath tp = parameters.get(name);
  71.630 +
  71.631 +            if (tp != null) {
  71.632 +                if (tp.getLeaf() instanceof Hacks.RenameTree) {
  71.633 +                    Hacks.RenameTree rt = (Hacks.RenameTree) tp.getLeaf();
  71.634 +                    return make.setLabel(rt.originalTree, rt.newName);
  71.635 +                }
  71.636 +                if (!parameterNames.containsKey(name)) {
  71.637 +                    Tree target = tp.getLeaf();
  71.638 +                    if (NUMBER_LITERAL_KINDS.contains(target.getKind())) {
  71.639 +                        return target;
  71.640 +                    }
  71.641 +                    //TODO: might also remove parenthesis, but needs to ensure the diff will still be minimal
  71.642 +//                    while (target.getKind() == Kind.PARENTHESIZED
  71.643 +//                           && !requiresParenthesis(((ParenthesizedTree) target).getExpression(), getCurrentPath().getParentPath().getLeaf())) {
  71.644 +//                        target = ((ParenthesizedTree) target).getExpression();
  71.645 +//                    }
  71.646 +                    if (   getCurrentPath().getParentPath() != null
  71.647 +                        && getCurrentPath().getParentPath().getLeaf().getKind() == Kind.LOGICAL_COMPLEMENT
  71.648 +                        && (   tp.getParentPath() == null
  71.649 +                            || tp.getParentPath().getLeaf().getKind() != Kind.LOGICAL_COMPLEMENT)) {
  71.650 +                        Tree negated = negate((ExpressionTree) tp.getLeaf(), getCurrentPath().getParentPath().getParentPath().getLeaf(), true);
  71.651 +                        
  71.652 +                        if (negated != null) {
  71.653 +                            rewrite(getCurrentPath().getParentPath().getLeaf(), negated);
  71.654 +                        }
  71.655 +                    }
  71.656 +                    if (requiresParenthesis(target, node, getCurrentPath().getParentPath().getLeaf())) {
  71.657 +                        target = make.Parenthesized((ExpressionTree) target);
  71.658 +                    }
  71.659 +                    return target;
  71.660 +                }
  71.661 +            }
  71.662 +
  71.663 +            String variableName = parameterNames.get(name);
  71.664 +
  71.665 +            if (variableName != null) {
  71.666 +                return make.Identifier(variableName);
  71.667 +            }
  71.668 +            
  71.669 +            return null;
  71.670 +        }
  71.671 +
  71.672 +        @Override
  71.673 +        public Number visitMemberSelect(MemberSelectTree node, Void p) {
  71.674 +            Element e = info.getTrees().getElement(getCurrentPath());
  71.675 +
  71.676 +            if (e != null && (e.getKind() != ElementKind.CLASS || ((TypeElement) e).asType().getKind() != TypeKind.ERROR)) {
  71.677 +                //check correct dependency:
  71.678 +                checkDependency(info, e, canShowUI);
  71.679 +
  71.680 +                if (isStaticElement(e) && !inImport) {
  71.681 +                    rewrite(node, make.QualIdent(e));
  71.682 +
  71.683 +                    return null;
  71.684 +                }
  71.685 +            }
  71.686 +            
  71.687 +            MemberSelectTree nue = node;
  71.688 +            String selectedName = node.getIdentifier().toString();
  71.689 +
  71.690 +            if (selectedName.startsWith("$") && parameterNames.get(selectedName) != null) {
  71.691 +                nue = make.MemberSelect(node.getExpression(), parameterNames.get(selectedName));
  71.692 +            }
  71.693 +
  71.694 +            if (nue.getExpression().getKind() == Kind.IDENTIFIER) {
  71.695 +                String name = ((IdentifierTree) nue.getExpression()).getName().toString();
  71.696 +
  71.697 +                if (name.startsWith("$") && parameters.get(name) == null) {
  71.698 +                    //XXX: unbound variable, use identifier instead of member select - may cause problems?
  71.699 +                    rewrite(node, make.Identifier(nue.getIdentifier()));
  71.700 +                    return null;
  71.701 +                }
  71.702 +            }
  71.703 +
  71.704 +            if (nue != node) {
  71.705 +                rewrite(node, nue);
  71.706 +            }
  71.707 +            
  71.708 +            return super.visitMemberSelect(node, p);
  71.709 +        }
  71.710 +
  71.711 +        @Override
  71.712 +        public Number visitVariable(VariableTree node, Void p) {
  71.713 +            String name = node.getName().toString();
  71.714 +
  71.715 +            if (name.startsWith("$")) {
  71.716 +                String nueName = parameterNames.get(name);
  71.717 +
  71.718 +                if (nueName != null) {
  71.719 +                    name = nueName;
  71.720 +                }
  71.721 +            }
  71.722 +            
  71.723 +            VariableTree nue = make.Variable(node.getModifiers(), name, node.getType(), resolveOptionalValue(node.getInitializer()));
  71.724 +
  71.725 +            rewrite(node, nue);
  71.726 +
  71.727 +            return super.visitVariable(nue, p);
  71.728 +        }
  71.729 +
  71.730 +        @Override
  71.731 +        public Number visitIf(IfTree node, Void p) {
  71.732 +            IfTree nue = make.If(node.getCondition(), node.getThenStatement(), resolveOptionalValue(node.getElseStatement()));
  71.733 +            
  71.734 +            rewrite(node, nue);
  71.735 +            
  71.736 +            return super.visitIf(nue, p);
  71.737 +        }
  71.738 +
  71.739 +        @Override
  71.740 +        public Number visitMethod(MethodTree node, Void p) {
  71.741 +            String name = node.getName().toString();
  71.742 +            String newName = name;
  71.743 +
  71.744 +            if (name.startsWith("$")) {
  71.745 +                if (parameterNames.containsKey(name)) {
  71.746 +                    newName = parameterNames.get(name);
  71.747 +                }
  71.748 +            }
  71.749 +
  71.750 +            List<? extends TypeParameterTree> typeParams = resolveMultiParameters(node.getTypeParameters());
  71.751 +            List<? extends VariableTree> params = resolveMultiParameters(node.getParameters());
  71.752 +            List<? extends ExpressionTree> thrown = resolveMultiParameters(node.getThrows());
  71.753 +            
  71.754 +            MethodTree nue = make.Method(node.getModifiers(), newName, node.getReturnType(), typeParams, params, thrown, node.getBody(), (ExpressionTree) node.getDefaultValue());
  71.755 +            
  71.756 +            rewrite(node, nue);
  71.757 +            
  71.758 +            return super.visitMethod(nue, p);
  71.759 +        }
  71.760 +
  71.761 +        @Override
  71.762 +        public Number visitClass(ClassTree node, Void p) {
  71.763 +            String name = node.getSimpleName().toString();
  71.764 +            String newName = name;
  71.765 +
  71.766 +            if (name.startsWith("$")) {
  71.767 +                if (parameterNames.containsKey(name)) {
  71.768 +                    newName = parameterNames.get(name);
  71.769 +                }
  71.770 +            }
  71.771 +
  71.772 +            List<? extends TypeParameterTree> typeParams = resolveMultiParameters(node.getTypeParameters());
  71.773 +            List<? extends Tree> implementsClauses = resolveMultiParameters(node.getImplementsClause());
  71.774 +            List<? extends Tree> members = resolveMultiParameters(Utilities.filterHidden(getCurrentPath(), node.getMembers()));
  71.775 +            Tree extend = resolveOptionalValue(node.getExtendsClause());
  71.776 +            ClassTree nue = make.Class(node.getModifiers(), newName, typeParams, extend, implementsClauses, members);
  71.777 +            
  71.778 +            rewrite(node, nue);
  71.779 +            
  71.780 +            return super.visitClass(nue, p);
  71.781 +        }
  71.782 +
  71.783 +        @Override
  71.784 +        public Number visitExpressionStatement(ExpressionStatementTree node, Void p) {
  71.785 +            CharSequence name = Utilities.getWildcardTreeName(node);
  71.786 +
  71.787 +            if (name != null) {
  71.788 +                TreePath tp = parameters.get(name.toString());
  71.789 +
  71.790 +                if (tp != null) {
  71.791 +                    rewrite(node, tp.getLeaf());
  71.792 +                    return null;
  71.793 +                }
  71.794 +            }
  71.795 +
  71.796 +            return super.visitExpressionStatement(node, p);
  71.797 +        }
  71.798 +
  71.799 +        @Override
  71.800 +        public Number visitLiteral(LiteralTree node, Void p) {
  71.801 +            if (node.getValue() instanceof Number) {
  71.802 +                return (Number) node.getValue();
  71.803 +            }
  71.804 +
  71.805 +            return super.visitLiteral(node, p);
  71.806 +        }
  71.807 +
  71.808 +        @Override
  71.809 +        public Number visitBinary(BinaryTree node, Void p) {
  71.810 +            Number left  = scan(node.getLeftOperand(), p);
  71.811 +            Number right = scan(node.getRightOperand(), p);
  71.812 +
  71.813 +            if (left != null && right != null) {
  71.814 +                Number result = null;
  71.815 +                switch (node.getKind()) {
  71.816 +                    case MULTIPLY:
  71.817 +                            if (left instanceof Double || right instanceof Double) {
  71.818 +                                result = left.doubleValue() * right.doubleValue();
  71.819 +                            } else if (left instanceof Float || right instanceof Float) {
  71.820 +                                result = left.floatValue() * right.floatValue();
  71.821 +                            } else if (left instanceof Long || right instanceof Long) {
  71.822 +                                result = left.longValue() * right.longValue();
  71.823 +                            } else if (left instanceof Integer || right instanceof Integer) {
  71.824 +                                result = left.intValue() * right.intValue();
  71.825 +                            } else {
  71.826 +                                throw new IllegalStateException("left=" + left.getClass() + ", right=" + right.getClass());
  71.827 +                            }
  71.828 +                            break;
  71.829 +
  71.830 +                    case DIVIDE:
  71.831 +                            if (left instanceof Double || right instanceof Double) {
  71.832 +                                result = left.doubleValue() / right.doubleValue();
  71.833 +                            } else if (left instanceof Float || right instanceof Float) {
  71.834 +                                result = left.floatValue() / right.floatValue();
  71.835 +                            } else if (left instanceof Long || right instanceof Long) {
  71.836 +                                result = left.longValue() / right.longValue();
  71.837 +                            } else if (left instanceof Integer || right instanceof Integer) {
  71.838 +                                result = left.intValue() / right.intValue();
  71.839 +                            } else {
  71.840 +                                throw new IllegalStateException("left=" + left.getClass() + ", right=" + right.getClass());
  71.841 +                            }
  71.842 +                            break;
  71.843 +
  71.844 +                    case REMAINDER:
  71.845 +                            if (left instanceof Double || right instanceof Double) {
  71.846 +                                result = left.doubleValue() % right.doubleValue();
  71.847 +                            } else if (left instanceof Float || right instanceof Float) {
  71.848 +                                result = left.floatValue() % right.floatValue();
  71.849 +                            } else if (left instanceof Long || right instanceof Long) {
  71.850 +                                result = left.longValue() % right.longValue();
  71.851 +                            } else if (left instanceof Integer || right instanceof Integer) {
  71.852 +                                result = left.intValue() % right.intValue();
  71.853 +                            } else {
  71.854 +                                throw new IllegalStateException("left=" + left.getClass() + ", right=" + right.getClass());
  71.855 +                            }
  71.856 +                            break;
  71.857 +
  71.858 +                    case PLUS:
  71.859 +                            if (left instanceof Double || right instanceof Double) {
  71.860 +                                result = left.doubleValue() + right.doubleValue();
  71.861 +                            } else if (left instanceof Float || right instanceof Float) {
  71.862 +                                result = left.floatValue() + right.floatValue();
  71.863 +                            } else if (left instanceof Long || right instanceof Long) {
  71.864 +                                result = left.longValue() + right.longValue();
  71.865 +                            } else if (left instanceof Integer || right instanceof Integer) {
  71.866 +                                result = left.intValue() + right.intValue();
  71.867 +                            } else {
  71.868 +                                throw new IllegalStateException("left=" + left.getClass() + ", right=" + right.getClass());
  71.869 +                            }
  71.870 +                            break;
  71.871 +
  71.872 +                    case MINUS:
  71.873 +                            if (left instanceof Double || right instanceof Double) {
  71.874 +                                result = left.doubleValue() - right.doubleValue();
  71.875 +                            } else if (left instanceof Float || right instanceof Float) {
  71.876 +                                result = left.floatValue() - right.floatValue();
  71.877 +                            } else if (left instanceof Long || right instanceof Long) {
  71.878 +                                result = left.longValue() - right.longValue();
  71.879 +                            } else if (left instanceof Integer || right instanceof Integer) {
  71.880 +                                result = left.intValue() - right.intValue();
  71.881 +                            } else {
  71.882 +                                throw new IllegalStateException("left=" + left.getClass() + ", right=" + right.getClass());
  71.883 +                            }
  71.884 +                            break;
  71.885 +
  71.886 +                    case LEFT_SHIFT:
  71.887 +                            if (left instanceof Long || right instanceof Long) {
  71.888 +                                result = left.longValue() << right.longValue();
  71.889 +                            } else if (left instanceof Integer || right instanceof Integer) {
  71.890 +                                result = left.intValue() << right.intValue();
  71.891 +                            } else {
  71.892 +                                throw new IllegalStateException("left=" + left.getClass() + ", right=" + right.getClass());
  71.893 +                            }
  71.894 +                            break;
  71.895 +
  71.896 +                    case RIGHT_SHIFT:
  71.897 +                            if (left instanceof Long || right instanceof Long) {
  71.898 +                                result = left.longValue() >> right.longValue();
  71.899 +                            } else if (left instanceof Integer || right instanceof Integer) {
  71.900 +                                result = left.intValue() >> right.intValue();
  71.901 +                            } else {
  71.902 +                                throw new IllegalStateException("left=" + left.getClass() + ", right=" + right.getClass());
  71.903 +                            }
  71.904 +                            break;
  71.905 +
  71.906 +                    case UNSIGNED_RIGHT_SHIFT:
  71.907 +                            if (left instanceof Long || right instanceof Long) {
  71.908 +                                result = left.longValue() >>> right.longValue();
  71.909 +                            } else if (left instanceof Integer || right instanceof Integer) {
  71.910 +                                result = left.intValue() >>> right.intValue();
  71.911 +                            } else {
  71.912 +                                throw new IllegalStateException("left=" + left.getClass() + ", right=" + right.getClass());
  71.913 +                            }
  71.914 +                            break;
  71.915 +
  71.916 +                    case AND:
  71.917 +                            if (left instanceof Long || right instanceof Long) {
  71.918 +                                result = left.longValue() & right.longValue();
  71.919 +                            } else if (left instanceof Integer || right instanceof Integer) {
  71.920 +                                result = left.intValue() & right.intValue();
  71.921 +                            } else {
  71.922 +                                throw new IllegalStateException("left=" + left.getClass() + ", right=" + right.getClass());
  71.923 +                            }
  71.924 +                            break;
  71.925 +
  71.926 +                    case XOR:
  71.927 +                            if (left instanceof Long || right instanceof Long) {
  71.928 +                                result = left.longValue() ^ right.longValue();
  71.929 +                            } else if (left instanceof Integer || right instanceof Integer) {
  71.930 +                                result = left.intValue() ^ right.intValue();
  71.931 +                            } else {
  71.932 +                                throw new IllegalStateException("left=" + left.getClass() + ", right=" + right.getClass());
  71.933 +                            }
  71.934 +                            break;
  71.935 +
  71.936 +                    case OR:
  71.937 +                            if (left instanceof Long || right instanceof Long) {
  71.938 +                                result = left.longValue() | right.longValue();
  71.939 +                            } else if (left instanceof Integer || right instanceof Integer) {
  71.940 +                                result = left.intValue() | right.intValue();
  71.941 +                            } else {
  71.942 +                                throw new IllegalStateException("left=" + left.getClass() + ", right=" + right.getClass());
  71.943 +                            }
  71.944 +                            break;
  71.945 +                }
  71.946 +
  71.947 +                if (result != null) {
  71.948 +                    rewrite(node, make.Literal(result));
  71.949 +
  71.950 +                    return result;
  71.951 +                }
  71.952 +            }
  71.953 +
  71.954 +            return null;
  71.955 +        }
  71.956 +
  71.957 +        @Override
  71.958 +        public Number visitUnary(UnaryTree node, Void p) {
  71.959 +            Number op  = scan(node.getExpression(), p);
  71.960 +
  71.961 +            if (op != null) {
  71.962 +                Number result = null;
  71.963 +                switch (node.getKind()) {
  71.964 +                    case UNARY_MINUS:
  71.965 +                            if (op instanceof Double) {
  71.966 +                                result = -op.doubleValue();
  71.967 +                            } else if (op instanceof Float) {
  71.968 +                                result = -op.floatValue();
  71.969 +                            } else if (op instanceof Long) {
  71.970 +                                result = -op.longValue();
  71.971 +                            } else if (op instanceof Integer) {
  71.972 +                                result = -op.intValue();
  71.973 +                            } else {
  71.974 +                                throw new IllegalStateException("op=" + op.getClass());
  71.975 +                            }
  71.976 +                            break;
  71.977 +                    case UNARY_PLUS:
  71.978 +                        result = op;
  71.979 +                        break;
  71.980 +                }
  71.981 +
  71.982 +                if (result != null) {
  71.983 +                    rewrite(node, make.Literal(result));
  71.984 +
  71.985 +                    return result;
  71.986 +                }
  71.987 +            }
  71.988 +
  71.989 +            return super.visitUnary(node, p);
  71.990 +        }
  71.991 +
  71.992 +        @Override
  71.993 +        public Number visitBlock(BlockTree node, Void p) {
  71.994 +            List<? extends StatementTree> nueStatement = resolveMultiParameters(node.getStatements());
  71.995 +            BlockTree nue = make.Block(nueStatement, node.isStatic());
  71.996 +
  71.997 +            rewrite(node, nue);
  71.998 +
  71.999 +            return super.visitBlock(nue, p);
 71.1000 +        }
 71.1001 +
 71.1002 +        @Override
 71.1003 +        public Number visitCase(CaseTree node, Void p) {
 71.1004 +            List<? extends StatementTree> statements = (List<? extends StatementTree>) resolveMultiParameters(node.getStatements());
 71.1005 +            CaseTree nue = make.Case(node.getExpression(), statements);
 71.1006 +
 71.1007 +            rewrite(node, nue);
 71.1008 +            return super.visitCase(node, p);
 71.1009 +        }
 71.1010 +
 71.1011 +        @Override
 71.1012 +        public Number visitMethodInvocation(MethodInvocationTree node, Void p) {
 71.1013 +            List<? extends ExpressionTree> typeArgs = (List<? extends ExpressionTree>) resolveMultiParameters(node.getTypeArguments());
 71.1014 +            List<? extends ExpressionTree> args = resolveMultiParameters(node.getArguments());
 71.1015 +            MethodInvocationTree nue = make.MethodInvocation(typeArgs, node.getMethodSelect(), args);
 71.1016 +
 71.1017 +            rewrite(node, nue);
 71.1018 +
 71.1019 +            return super.visitMethodInvocation(nue, p);
 71.1020 +        }
 71.1021 +
 71.1022 +        @Override
 71.1023 +        public Number visitNewClass(NewClassTree node, Void p) {
 71.1024 +            List<? extends ExpressionTree> typeArgs = (List<? extends ExpressionTree>) resolveMultiParameters(node.getTypeArguments());
 71.1025 +            List<? extends ExpressionTree> args = resolveMultiParameters(node.getArguments());
 71.1026 +            NewClassTree nue = make.NewClass(node.getEnclosingExpression(), typeArgs, node.getIdentifier(), args, node.getClassBody());
 71.1027 +
 71.1028 +            rewrite(node, nue);
 71.1029 +            return super.visitNewClass(nue, p);
 71.1030 +        }
 71.1031 +
 71.1032 +        @Override
 71.1033 +        public Number visitParameterizedType(ParameterizedTypeTree node, Void p) {
 71.1034 +            List<? extends ExpressionTree> typeArgs = (List<? extends ExpressionTree>) resolveMultiParameters(node.getTypeArguments());
 71.1035 +            ParameterizedTypeTree nue = make.ParameterizedType(node.getType(), typeArgs);
 71.1036 +
 71.1037 +            rewrite(node, nue);
 71.1038 +            return super.visitParameterizedType(node, p);
 71.1039 +        }
 71.1040 +
 71.1041 +        @Override
 71.1042 +        public Number visitSwitch(SwitchTree node, Void p) {
 71.1043 +            List<? extends CaseTree> cases = (List<? extends CaseTree>) resolveMultiParameters(node.getCases());
 71.1044 +            SwitchTree nue = make.Switch(node.getExpression(), cases);
 71.1045 +
 71.1046 +            rewrite(node, nue);
 71.1047 +            return super.visitSwitch(node, p);
 71.1048 +        }
 71.1049 +
 71.1050 +        @Override
 71.1051 +        public Number visitTry(TryTree node, Void p) {
 71.1052 +            List<? extends Tree> resources = (List<? extends Tree>) resolveMultiParameters(node.getResources());
 71.1053 +            List<? extends CatchTree> catches = (List<? extends CatchTree>) resolveMultiParameters(node.getCatches());
 71.1054 +            TryTree nue = make.Try(resources, node.getBlock(), catches, node.getFinallyBlock());
 71.1055 +
 71.1056 +            rewrite(node, nue);
 71.1057 +            return super.visitTry(node, p);
 71.1058 +        }
 71.1059 +
 71.1060 +        @Override
 71.1061 +        public Number visitModifiers(ModifiersTree node, Void p) {
 71.1062 +            List<AnnotationTree> annotations = new ArrayList<AnnotationTree>(node.getAnnotations());
 71.1063 +            IdentifierTree ident = !annotations.isEmpty() && annotations.get(0).getAnnotationType().getKind() == Kind.IDENTIFIER ? (IdentifierTree) annotations.get(0).getAnnotationType() : null;
 71.1064 +
 71.1065 +            if (ident != null) {
 71.1066 +                annotations.remove(0);
 71.1067 +                
 71.1068 +                String name = ident.getName().toString();
 71.1069 +                TreePath orig = parameters.get(name);
 71.1070 +                ModifiersTree nue;
 71.1071 +                
 71.1072 +                if (orig != null && orig.getLeaf().getKind() == Kind.MODIFIERS) {
 71.1073 +                    ModifiersTree origMods = (ModifiersTree) orig.getLeaf();
 71.1074 +                    Object actualContent = extraParamsData.get(name);
 71.1075 +                    Set<Modifier> actualFlags = EnumSet.noneOf(Modifier.class);
 71.1076 +                    boolean[] actualAnnotationsMask = new boolean[0];
 71.1077 +                    
 71.1078 +                    if (actualContent instanceof Object[] && ((Object[]) actualContent)[0] instanceof Set) {
 71.1079 +                        actualFlags.addAll(NbCollections.checkedSetByFilter((Set) ((Object[]) actualContent)[0], Modifier.class, false));
 71.1080 +                    }
 71.1081 +                    
 71.1082 +                    if (actualContent instanceof Object[] && ((Object[]) actualContent)[1] instanceof boolean[]) {
 71.1083 +                        actualAnnotationsMask = (boolean[]) ((Object[]) actualContent)[1];
 71.1084 +                    }
 71.1085 +                    
 71.1086 +                    nue = origMods;
 71.1087 +                    
 71.1088 +                    for (Modifier m : origMods.getFlags()) {
 71.1089 +                        if (actualFlags.contains(m)) continue;
 71.1090 +                        nue = make.removeModifiersModifier(nue, m);
 71.1091 +                    }
 71.1092 +                    
 71.1093 +                    for (Modifier m : node.getFlags()) {
 71.1094 +                        nue = make.addModifiersModifier(nue, m);
 71.1095 +                    }
 71.1096 +                    
 71.1097 +                    int ai = 0;
 71.1098 +                    
 71.1099 +                    OUTER: for (AnnotationTree a : origMods.getAnnotations()) {
 71.1100 +                        if (actualAnnotationsMask.length <= ai || actualAnnotationsMask[ai++]) continue;
 71.1101 +                        for (Iterator<AnnotationTree> it = annotations.iterator(); it.hasNext();) {
 71.1102 +                            AnnotationTree toCheck = it.next();
 71.1103 +                            Collection<? extends Occurrence> match = org.netbeans.api.java.source.matching.Matcher.create(info).setTreeTopSearch().setSearchRoot(new TreePath(getCurrentPath(), a)).match(Pattern.createSimplePattern(new TreePath(getCurrentPath(), toCheck)));
 71.1104 +                            
 71.1105 +                            if (!match.isEmpty()) {
 71.1106 +                                //should be kept:
 71.1107 +                                it.remove();
 71.1108 +                                break OUTER;
 71.1109 +                            }
 71.1110 +                        }
 71.1111 +                        
 71.1112 +                        nue = make.removeModifiersAnnotation(nue, a);
 71.1113 +                    }
 71.1114 +                    
 71.1115 +                    for (AnnotationTree a : annotations) {
 71.1116 +                        nue = make.addModifiersAnnotation(nue, a);
 71.1117 +                        scan(a, p);
 71.1118 +                    }
 71.1119 +                } else {
 71.1120 +                    nue = make.removeModifiersAnnotation(node, 0);
 71.1121 +                }
 71.1122 +                
 71.1123 +                rewrite(node, nue);
 71.1124 +                
 71.1125 +                return null;
 71.1126 +            }
 71.1127 +            
 71.1128 +            return super.visitModifiers(node, p);
 71.1129 +        }
 71.1130 +
 71.1131 +        @Override
 71.1132 +        public Number visitNewArray(NewArrayTree node, Void p) {
 71.1133 +            List<? extends ExpressionTree> dimensions = (List<? extends ExpressionTree>) resolveMultiParameters(node.getDimensions());
 71.1134 +            List<? extends ExpressionTree> initializers = (List<? extends ExpressionTree>) resolveMultiParameters(node.getInitializers());
 71.1135 +            NewArrayTree nue = make.NewArray(node.getType(), dimensions, initializers);
 71.1136 +
 71.1137 +            rewrite(node, nue);
 71.1138 +            return super.visitNewArray(node, p);
 71.1139 +        }
 71.1140 +
 71.1141 +        @Override
 71.1142 +        public Number visitLambdaExpression(LambdaExpressionTree node, Void p) {
 71.1143 +            List<? extends VariableTree> args = resolveMultiParameters(node.getParameters());
 71.1144 +            LambdaExpressionTree nue = make.LambdaExpression(args, node.getBody());
 71.1145 +
 71.1146 +            rewrite(node, nue);
 71.1147 +
 71.1148 +            return super.visitLambdaExpression(node, p);
 71.1149 +        }
 71.1150 +
 71.1151 +        private <T extends Tree> List<T> resolveMultiParameters(List<T> list) {
 71.1152 +            if (list == null) return null;
 71.1153 +            if (!Utilities.containsMultistatementTrees(list)) return list;
 71.1154 +
 71.1155 +            List<T> result = new LinkedList<T>();
 71.1156 +
 71.1157 +            for (T t : list) {
 71.1158 +                if (Utilities.isMultistatementWildcardTree(t)) {
 71.1159 +                    Collection<TreePath> embedded = parametersMulti.get(Utilities.getWildcardTreeName(t).toString());
 71.1160 +
 71.1161 +                    if (embedded != null) {
 71.1162 +                        for (TreePath tp : embedded) {
 71.1163 +                            result.add((T) tp.getLeaf());
 71.1164 +                        }
 71.1165 +                    }
 71.1166 +                } else {
 71.1167 +                    result.add(t);
 71.1168 +                }
 71.1169 +            }
 71.1170 +
 71.1171 +            return result;
 71.1172 +        }
 71.1173 +        
 71.1174 +        private <T extends Tree> T resolveOptionalValue(T in) {
 71.1175 +            if (in != null && Utilities.isMultistatementWildcardTree(in)) {
 71.1176 +                TreePath out = parameters.get(Utilities.getWildcardTreeName(in).toString());
 71.1177 +                if (out != null) return (T) out.getLeaf();
 71.1178 +                return null;
 71.1179 +            }
 71.1180 +            
 71.1181 +            return in;
 71.1182 +        }
 71.1183 +
 71.1184 +        private ExpressionTree negate(ExpressionTree original, Tree parent, boolean nullOnPlainNeg) {
 71.1185 +            ExpressionTree newTree;
 71.1186 +            switch (original.getKind()) {
 71.1187 +                case PARENTHESIZED:
 71.1188 +                    ExpressionTree expr = ((ParenthesizedTree) original).getExpression();
 71.1189 +                    return negate(expr, original, nullOnPlainNeg);
 71.1190 +                case LOGICAL_COMPLEMENT:
 71.1191 +                    newTree = ((UnaryTree) original).getExpression();
 71.1192 +                    while (newTree.getKind() == Kind.PARENTHESIZED && !JavaFixUtilities.requiresParenthesis(((ParenthesizedTree) newTree).getExpression(), original, parent)) {
 71.1193 +                        newTree = ((ParenthesizedTree) newTree).getExpression();
 71.1194 +                    }
 71.1195 +                    break;
 71.1196 +                case NOT_EQUAL_TO:
 71.1197 +                    newTree = negateBinaryOperator(original, Kind.EQUAL_TO, false);
 71.1198 +                    break;
 71.1199 +                case EQUAL_TO:
 71.1200 +                    newTree = negateBinaryOperator(original, Kind.NOT_EQUAL_TO, false);
 71.1201 +                    break;
 71.1202 +                case BOOLEAN_LITERAL:
 71.1203 +                    newTree = make.Literal(!(Boolean) ((LiteralTree) original).getValue());
 71.1204 +                    break;
 71.1205 +                case CONDITIONAL_AND:
 71.1206 +                    newTree = negateBinaryOperator(original, Kind.CONDITIONAL_OR, true);
 71.1207 +                    break;
 71.1208 +                case CONDITIONAL_OR:
 71.1209 +                    newTree = negateBinaryOperator(original, Kind.CONDITIONAL_AND, true);
 71.1210 +                    break;
 71.1211 +                case LESS_THAN:
 71.1212 +                    newTree = negateBinaryOperator(original, Kind.GREATER_THAN_EQUAL, false);
 71.1213 +                    break;
 71.1214 +                case LESS_THAN_EQUAL:
 71.1215 +                    newTree = negateBinaryOperator(original, Kind.GREATER_THAN, false);
 71.1216 +                    break;
 71.1217 +                case GREATER_THAN:
 71.1218 +                    newTree = negateBinaryOperator(original, Kind.LESS_THAN_EQUAL, false);
 71.1219 +                    break;
 71.1220 +                case GREATER_THAN_EQUAL:
 71.1221 +                    newTree = negateBinaryOperator(original, Kind.LESS_THAN, false);
 71.1222 +                    break;
 71.1223 +                default:
 71.1224 +                    if (nullOnPlainNeg)
 71.1225 +                        return null;
 71.1226 +                    newTree = make.Unary(Kind.LOGICAL_COMPLEMENT, original);
 71.1227 +            }
 71.1228 +         
 71.1229 +            if (JavaFixUtilities.requiresParenthesis(newTree, original, parent)) {
 71.1230 +                newTree = make.Parenthesized(newTree);
 71.1231 +            }
 71.1232 +            
 71.1233 +            return newTree;
 71.1234 +        }
 71.1235 +        
 71.1236 +        private ExpressionTree negateBinaryOperator(Tree original, Kind newKind, boolean negateOperands) {
 71.1237 +            BinaryTree bt = (BinaryTree) original;
 71.1238 +            if (negateOperands) {
 71.1239 +                ExpressionTree lo = negate(bt.getLeftOperand(), original, false);
 71.1240 +                ExpressionTree ro = negate(bt.getRightOperand(), original, false);
 71.1241 +                return make.Binary(newKind,
 71.1242 +                                   lo != null ? lo : bt.getLeftOperand(),
 71.1243 +                                   ro != null ? ro : bt.getRightOperand());
 71.1244 +            }
 71.1245 +            return make.Binary(newKind,
 71.1246 +                               bt.getLeftOperand(),
 71.1247 +                               bt.getRightOperand());
 71.1248 +        }
 71.1249 +        
 71.1250 +        private void rewrite(Tree from, Tree to) {
 71.1251 +            if (originalTrees.contains(from)) return ;
 71.1252 +            rewriteFromTo.put(from, to);
 71.1253 +        }
 71.1254 +    }
 71.1255 +
 71.1256 +    private static final Map<Kind, Integer> OPERATOR_PRIORITIES;
 71.1257 +
 71.1258 +    static {
 71.1259 +        OPERATOR_PRIORITIES = new EnumMap<Kind, Integer>(Kind.class);
 71.1260 +
 71.1261 +        OPERATOR_PRIORITIES.put(Kind.IDENTIFIER, 0);
 71.1262 +
 71.1263 +        for (Kind k : Kind.values()) {
 71.1264 +            if (k.asInterface() == LiteralTree.class) {
 71.1265 +                OPERATOR_PRIORITIES.put(k, 0);
 71.1266 +            }
 71.1267 +        }
 71.1268 +
 71.1269 +        OPERATOR_PRIORITIES.put(Kind.ARRAY_ACCESS, 1);
 71.1270 +        OPERATOR_PRIORITIES.put(Kind.METHOD_INVOCATION, 1);
 71.1271 +        OPERATOR_PRIORITIES.put(Kind.MEMBER_SELECT, 1);
 71.1272 +        OPERATOR_PRIORITIES.put(Kind.POSTFIX_DECREMENT, 1);
 71.1273 +        OPERATOR_PRIORITIES.put(Kind.POSTFIX_INCREMENT, 1);
 71.1274 +        OPERATOR_PRIORITIES.put(Kind.NEW_ARRAY, 1);
 71.1275 +        OPERATOR_PRIORITIES.put(Kind.NEW_CLASS, 1);
 71.1276 +
 71.1277 +        OPERATOR_PRIORITIES.put(Kind.BITWISE_COMPLEMENT, 2);
 71.1278 +        OPERATOR_PRIORITIES.put(Kind.LOGICAL_COMPLEMENT, 2);
 71.1279 +        OPERATOR_PRIORITIES.put(Kind.PREFIX_DECREMENT, 2);
 71.1280 +        OPERATOR_PRIORITIES.put(Kind.PREFIX_INCREMENT, 2);
 71.1281 +        OPERATOR_PRIORITIES.put(Kind.UNARY_MINUS, 2);
 71.1282 +        OPERATOR_PRIORITIES.put(Kind.UNARY_PLUS, 2);
 71.1283 +
 71.1284 +        OPERATOR_PRIORITIES.put(Kind.TYPE_CAST, 3);
 71.1285 +
 71.1286 +        OPERATOR_PRIORITIES.put(Kind.DIVIDE, 4);
 71.1287 +        OPERATOR_PRIORITIES.put(Kind.MULTIPLY, 4);
 71.1288 +        OPERATOR_PRIORITIES.put(Kind.REMAINDER, 4);
 71.1289 +
 71.1290 +        OPERATOR_PRIORITIES.put(Kind.MINUS, 5);
 71.1291 +        OPERATOR_PRIORITIES.put(Kind.PLUS, 5);
 71.1292 +
 71.1293 +        OPERATOR_PRIORITIES.put(Kind.LEFT_SHIFT, 6);
 71.1294 +        OPERATOR_PRIORITIES.put(Kind.RIGHT_SHIFT, 6);
 71.1295 +        OPERATOR_PRIORITIES.put(Kind.UNSIGNED_RIGHT_SHIFT, 6);
 71.1296 +
 71.1297 +        OPERATOR_PRIORITIES.put(Kind.INSTANCE_OF, 7);
 71.1298 +        OPERATOR_PRIORITIES.put(Kind.GREATER_THAN, 7);
 71.1299 +        OPERATOR_PRIORITIES.put(Kind.GREATER_THAN_EQUAL, 7);
 71.1300 +        OPERATOR_PRIORITIES.put(Kind.LESS_THAN, 7);
 71.1301 +        OPERATOR_PRIORITIES.put(Kind.LESS_THAN_EQUAL, 7);
 71.1302 +
 71.1303 +        OPERATOR_PRIORITIES.put(Kind.EQUAL_TO, 8);
 71.1304 +        OPERATOR_PRIORITIES.put(Kind.NOT_EQUAL_TO, 8);
 71.1305 +
 71.1306 +        OPERATOR_PRIORITIES.put(Kind.AND, 9);
 71.1307 +        OPERATOR_PRIORITIES.put(Kind.OR, 11);
 71.1308 +        OPERATOR_PRIORITIES.put(Kind.XOR, 10);
 71.1309 +
 71.1310 +        OPERATOR_PRIORITIES.put(Kind.CONDITIONAL_AND, 12);
 71.1311 +        OPERATOR_PRIORITIES.put(Kind.CONDITIONAL_OR, 13);
 71.1312 +
 71.1313 +        OPERATOR_PRIORITIES.put(Kind.CONDITIONAL_EXPRESSION, 14);
 71.1314 +
 71.1315 +        OPERATOR_PRIORITIES.put(Kind.AND_ASSIGNMENT, 15);
 71.1316 +        OPERATOR_PRIORITIES.put(Kind.ASSIGNMENT, 15);
 71.1317 +        OPERATOR_PRIORITIES.put(Kind.DIVIDE_ASSIGNMENT, 15);
 71.1318 +        OPERATOR_PRIORITIES.put(Kind.LEFT_SHIFT_ASSIGNMENT, 15);
 71.1319 +        OPERATOR_PRIORITIES.put(Kind.MINUS_ASSIGNMENT, 15);
 71.1320 +        OPERATOR_PRIORITIES.put(Kind.MULTIPLY_ASSIGNMENT, 15);
 71.1321 +        OPERATOR_PRIORITIES.put(Kind.OR_ASSIGNMENT, 15);
 71.1322 +        OPERATOR_PRIORITIES.put(Kind.PLUS_ASSIGNMENT, 15);
 71.1323 +        OPERATOR_PRIORITIES.put(Kind.REMAINDER_ASSIGNMENT, 15);
 71.1324 +        OPERATOR_PRIORITIES.put(Kind.RIGHT_SHIFT_ASSIGNMENT, 15);
 71.1325 +        OPERATOR_PRIORITIES.put(Kind.UNSIGNED_RIGHT_SHIFT_ASSIGNMENT, 15);
 71.1326 +        OPERATOR_PRIORITIES.put(Kind.XOR_ASSIGNMENT, 15);
 71.1327 +    }
 71.1328 +
 71.1329 +    /**Checks whether putting {@code inner} tree into {@code outter} tree,
 71.1330 +     * when {@code original} is being replaced with {@code inner} requires parentheses.
 71.1331 +     *
 71.1332 +     * @param inner    the new tree node that will be placed under {@code outter}
 71.1333 +     * @param original the tree node that is being replaced with {@code inner}
 71.1334 +     * @param outter   the future parent node of {@code inner}
 71.1335 +     * @return true if and only if inner needs to be wrapped using {@link TreeMaker#Parenthesized(com.sun.source.tree.ExpressionTree) }
 71.1336 +     *              to keep the original meaning.
 71.1337 +     */
 71.1338 +    public static boolean requiresParenthesis(Tree inner, Tree original, Tree outter) {
 71.1339 +        if (!ExpressionTree.class.isAssignableFrom(inner.getKind().asInterface())) return false;
 71.1340 +        if (!ExpressionTree.class.isAssignableFrom(outter.getKind().asInterface())) return false;
 71.1341 +
 71.1342 +        if (outter.getKind() == Kind.PARENTHESIZED || inner.getKind() == Kind.PARENTHESIZED) return false;
 71.1343 +
 71.1344 +        if (outter.getKind() == Kind.METHOD_INVOCATION) {
 71.1345 +            if (((MethodInvocationTree) outter).getArguments().contains(original)) return false;
 71.1346 +        }
 71.1347 +
 71.1348 +        if (outter.getKind() == Kind.NEW_CLASS) {
 71.1349 +            if (((NewClassTree) outter).getArguments().contains(original)) return false;
 71.1350 +        }
 71.1351 +
 71.1352 +        Integer innerPriority = OPERATOR_PRIORITIES.get(inner.getKind());
 71.1353 +        Integer outterPriority = OPERATOR_PRIORITIES.get(outter.getKind());
 71.1354 +
 71.1355 +        if (innerPriority == null || outterPriority == null) {
 71.1356 +            Logger.getLogger(JavaFix.class.getName()).log(Level.WARNING, "Unknown tree kind(s): {0}/{1}", new Object[] {inner.getKind(), outter.getKind()});
 71.1357 +            return true;
 71.1358 +        }
 71.1359 +
 71.1360 +        if (innerPriority > outterPriority) {
 71.1361 +            return true;
 71.1362 +        }
 71.1363 +
 71.1364 +        if (innerPriority < outterPriority) {
 71.1365 +            return false;
 71.1366 +        }
 71.1367 +
 71.1368 +        //associativity
 71.1369 +        if (BinaryTree.class.isAssignableFrom(outter.getKind().asInterface())) {
 71.1370 +            BinaryTree ot = (BinaryTree) outter;
 71.1371 +
 71.1372 +            //TODO: for + it might be possible to skip the parenthesis:
 71.1373 +            return ot.getRightOperand() == original;
 71.1374 +        }
 71.1375 +
 71.1376 +        if (CompoundAssignmentTree.class.isAssignableFrom(outter.getKind().asInterface())) {
 71.1377 +            CompoundAssignmentTree ot = (CompoundAssignmentTree) outter;
 71.1378 +
 71.1379 +            return ot.getVariable() == original;
 71.1380 +        }
 71.1381 +
 71.1382 +        if (AssignmentTree.class.isAssignableFrom(outter.getKind().asInterface())) {
 71.1383 +            AssignmentTree ot = (AssignmentTree) outter;
 71.1384 +
 71.1385 +            return ot.getVariable() == original;
 71.1386 +        }
 71.1387 +
 71.1388 +        return false;
 71.1389 +    }
 71.1390 +
 71.1391 +    private static final class RemoveFromParent extends JavaFix {
 71.1392 +
 71.1393 +        private final String displayName;
 71.1394 +
 71.1395 +        public RemoveFromParent(String displayName, CompilationInfo info, TreePath toRemove) {
 71.1396 +            super(info, toRemove);
 71.1397 +            this.displayName = displayName;
 71.1398 +        }
 71.1399 +
 71.1400 +        @Override
 71.1401 +        protected String getText() {
 71.1402 +            return displayName;
 71.1403 +        }
 71.1404 +
 71.1405 +        @Override
 71.1406 +        protected void performRewrite(TransformationContext ctx) {
 71.1407 +            WorkingCopy wc = ctx.getWorkingCopy();
 71.1408 +            TreePath tp = ctx.getPath();
 71.1409 +            
 71.1410 +            doRemoveFromParent(wc, tp);
 71.1411 +        }
 71.1412 +        
 71.1413 +        private void doRemoveFromParent(WorkingCopy wc, TreePath what) {
 71.1414 +            TreeMaker make = wc.getTreeMaker();
 71.1415 +            Tree leaf = what.getLeaf();
 71.1416 +            Tree parentLeaf = what.getParentPath().getLeaf();
 71.1417 +
 71.1418 +            switch (parentLeaf.getKind()) {
 71.1419 +                case ANNOTATION:
 71.1420 +                    AnnotationTree at = (AnnotationTree) parentLeaf;
 71.1421 +                    AnnotationTree newAnnot;
 71.1422 +
 71.1423 +                    newAnnot = make.removeAnnotationAttrValue(at, (ExpressionTree) leaf);
 71.1424 +
 71.1425 +                    wc.rewrite(at, newAnnot);
 71.1426 +                    break;
 71.1427 +                case BLOCK:
 71.1428 +                    BlockTree bt = (BlockTree) parentLeaf;
 71.1429 +
 71.1430 +                    wc.rewrite(bt, make.removeBlockStatement(bt, (StatementTree) leaf));
 71.1431 +                    break;
 71.1432 +                case CASE:
 71.1433 +                    CaseTree caseTree = (CaseTree) parentLeaf;
 71.1434 +
 71.1435 +                    wc.rewrite(caseTree, make.removeCaseStatement(caseTree, (StatementTree) leaf));
 71.1436 +                    break;
 71.1437 +                case CLASS:
 71.1438 +                    ClassTree classTree = (ClassTree) parentLeaf;
 71.1439 +                    ClassTree nueClassTree;
 71.1440 +
 71.1441 +                    if (classTree.getTypeParameters().contains(leaf)) {
 71.1442 +                        nueClassTree = make.removeClassTypeParameter(classTree, (TypeParameterTree) leaf);
 71.1443 +                    } else if (classTree.getExtendsClause() == leaf) {
 71.1444 +                        nueClassTree = make.Class(classTree.getModifiers(), classTree.getSimpleName(), classTree.getTypeParameters(), null, classTree.getImplementsClause(), classTree.getMembers());
 71.1445 +                    } else if (classTree.getImplementsClause().contains(leaf)) {
 71.1446 +                        nueClassTree = make.removeClassImplementsClause(classTree, leaf);
 71.1447 +                    } else if (classTree.getMembers().contains(leaf)) {
 71.1448 +                        nueClassTree = make.removeClassMember(classTree, leaf);
 71.1449 +                    } else {
 71.1450 +                        throw new UnsupportedOperationException();
 71.1451 +                    }
 71.1452 +
 71.1453 +                    wc.rewrite(classTree, nueClassTree);
 71.1454 +                    break;
 71.1455 +                case UNION_TYPE:
 71.1456 +                    UnionTypeTree disjunct = (UnionTypeTree) parentLeaf;
 71.1457 +                    List<? extends Tree> alternatives = new LinkedList<Tree>(disjunct.getTypeAlternatives());
 71.1458 +
 71.1459 +                    alternatives.remove(leaf);
 71.1460 +
 71.1461 +                    wc.rewrite(disjunct, make.UnionType(alternatives));
 71.1462 +                    break;
 71.1463 +                case METHOD:
 71.1464 +                    MethodTree mTree = (MethodTree) parentLeaf;
 71.1465 +                    MethodTree newMethod;
 71.1466 +
 71.1467 +                    if (mTree.getTypeParameters().contains(leaf)) {
 71.1468 +                        newMethod = make.removeMethodTypeParameter(mTree, (TypeParameterTree) leaf);
 71.1469 +                    } else if (mTree.getParameters().contains(leaf)) {
 71.1470 +                        newMethod = make.removeMethodParameter(mTree, (VariableTree) leaf);
 71.1471 +                    } else if (mTree.getThrows().contains(leaf)) {
 71.1472 +                        newMethod = make.removeMethodThrows(mTree, (ExpressionTree) leaf);
 71.1473 +                    } else {
 71.1474 +                        throw new UnsupportedOperationException();
 71.1475 +                    }
 71.1476 +
 71.1477 +                    wc.rewrite(mTree, newMethod);
 71.1478 +                    break;
 71.1479 +                case METHOD_INVOCATION:
 71.1480 +                    MethodInvocationTree iTree = (MethodInvocationTree) parentLeaf;
 71.1481 +                    MethodInvocationTree newInvocation;
 71.1482 +
 71.1483 +                    if (iTree.getTypeArguments().contains(leaf)) {
 71.1484 +                        newInvocation = make.removeMethodInvocationTypeArgument(iTree, (ExpressionTree) leaf);
 71.1485 +                    } else if (iTree.getArguments().contains(leaf)) {
 71.1486 +                        newInvocation = make.removeMethodInvocationArgument(iTree, (ExpressionTree) leaf);
 71.1487 +                    } else {
 71.1488 +                        throw new UnsupportedOperationException();
 71.1489 +                    }
 71.1490 +
 71.1491 +                    wc.rewrite(iTree, newInvocation);
 71.1492 +                    break;
 71.1493 +                case MODIFIERS:
 71.1494 +                    ModifiersTree modsTree = (ModifiersTree) parentLeaf;
 71.1495 +
 71.1496 +                    wc.rewrite(modsTree, make.removeModifiersAnnotation(modsTree, (AnnotationTree) leaf));
 71.1497 +                    break;
 71.1498 +                case NEW_CLASS:
 71.1499 +                    NewClassTree newCTree = (NewClassTree) parentLeaf;
 71.1500 +                    NewClassTree newNCT;
 71.1501 +
 71.1502 +                    if (newCTree.getTypeArguments().contains(leaf)) {
 71.1503 +                        newNCT = make.removeNewClassTypeArgument(newCTree, (ExpressionTree) leaf);
 71.1504 +                    } else if (newCTree.getArguments().contains(leaf)) {
 71.1505 +                        newNCT = make.removeNewClassArgument(newCTree, (ExpressionTree) leaf);
 71.1506 +                    } else {
 71.1507 +                        throw new UnsupportedOperationException();
 71.1508 +                    }
 71.1509 +
 71.1510 +                    wc.rewrite(newCTree, newNCT);
 71.1511 +                    break;
 71.1512 +                case PARAMETERIZED_TYPE:
 71.1513 +                    ParameterizedTypeTree parTree = (ParameterizedTypeTree) parentLeaf;
 71.1514 +
 71.1515 +                    wc.rewrite(parTree, make.removeParameterizedTypeTypeArgument(parTree, (ExpressionTree) leaf));
 71.1516 +                    break;
 71.1517 +                case SWITCH:
 71.1518 +                    SwitchTree switchTree = (SwitchTree) parentLeaf;
 71.1519 +                    SwitchTree newSwitch;
 71.1520 +
 71.1521 +                    if (switchTree.getCases().contains(leaf)) {
 71.1522 +                        newSwitch = make.removeSwitchCase(switchTree, (CaseTree) leaf);
 71.1523 +                    } else {
 71.1524 +                        throw new UnsupportedOperationException();
 71.1525 +                    }
 71.1526 +
 71.1527 +                    wc.rewrite(switchTree, newSwitch);
 71.1528 +                    break;
 71.1529 +                case TRY:
 71.1530 +                    TryTree tryTree = (TryTree) parentLeaf;
 71.1531 +                    TryTree newTry;
 71.1532 +
 71.1533 +                    if (tryTree.getResources().contains(leaf)) {
 71.1534 +                        LinkedList<Tree> resources = new LinkedList<Tree>(tryTree.getResources());
 71.1535 +
 71.1536 +                        resources.remove(leaf);
 71.1537 +
 71.1538 +                        newTry = make.Try(resources, tryTree.getBlock(), tryTree.getCatches(), tryTree.getFinallyBlock());
 71.1539 +                    } else if (tryTree.getCatches().contains(leaf)) {
 71.1540 +                        newTry = make.removeTryCatch(tryTree, (CatchTree) leaf);
 71.1541 +                    } else {
 71.1542 +                        throw new UnsupportedOperationException();
 71.1543 +                    }
 71.1544 +
 71.1545 +                    wc.rewrite(tryTree, newTry);
 71.1546 +                    break;
 71.1547 +                case EXPRESSION_STATEMENT:
 71.1548 +                    doRemoveFromParent(wc, what.getParentPath());
 71.1549 +                    break;
 71.1550 +                default:
 71.1551 +                    wc.rewrite(what.getLeaf(), make.Block(Collections.<StatementTree>emptyList(), false));
 71.1552 +                    break;
 71.1553 +            }
 71.1554 +        }
 71.1555 +
 71.1556 +    }
 71.1557 +
 71.1558 +    //TODO: from FileMovePlugin
 71.1559 +    private static class MoveFile extends SimpleRefactoringElementImplementation {
 71.1560 +
 71.1561 +        private FileObject toMove;
 71.1562 +        private final FileObject sourceRoot;
 71.1563 +        private final String targetFolderName;
 71.1564 +
 71.1565 +        public MoveFile(FileObject toMove, FileObject sourceRoot, String targetFolderName) {
 71.1566 +            this.toMove = toMove;
 71.1567 +            this.sourceRoot = sourceRoot;
 71.1568 +            this.targetFolderName = targetFolderName;
 71.1569 +        }
 71.1570 +
 71.1571 +        @Override
 71.1572 +        @Messages({"#{0} - original file name", "TXT_MoveFile=Move {0}"})
 71.1573 +        public String getText() {
 71.1574 +            return Bundle.TXT_MoveFile(toMove.getNameExt());
 71.1575 +        }
 71.1576 +
 71.1577 +        @Override
 71.1578 +        public String getDisplayText() {
 71.1579 +            return getText();
 71.1580 +        }
 71.1581 +
 71.1582 +        DataFolder sourceFolder;
 71.1583 +        DataObject source;
 71.1584 +        @Override
 71.1585 +        public void performChange() {
 71.1586 +            try {
 71.1587 +                FileObject target = FileUtil.createFolder(sourceRoot, targetFolderName);
 71.1588 +                DataFolder targetFolder = DataFolder.findFolder(target);
 71.1589 +                if (!toMove.isValid()) {
 71.1590 +                    String path = FileUtil.getFileDisplayName(toMove);
 71.1591 +                    Logger.getLogger(JavaFix.class.getName()).fine("Invalid FileObject " + path + "trying to recreate...");
 71.1592 +                    toMove = FileUtil.toFileObject(FileUtil.toFile(toMove));
 71.1593 +                    if (toMove==null) {
 71.1594 +                        Logger.getLogger(JavaFix.class.getName()).severe("Invalid FileObject " + path + "\n. File not found.");
 71.1595 +                        return;
 71.1596 +                    }
 71.1597 +                }
 71.1598 +                source = DataObject.find(toMove);
 71.1599 +                sourceFolder = source.getFolder();
 71.1600 +                source.move(targetFolder);
 71.1601 +            } catch (DataObjectNotFoundException ex) {
 71.1602 +                ex.printStackTrace();
 71.1603 +            } catch (IOException ex) {
 71.1604 +                ex.printStackTrace();
 71.1605 +            }
 71.1606 +        }
 71.1607 +
 71.1608 +        @Override
 71.1609 +        public void undoChange() {
 71.1610 +            try {
 71.1611 +                source.move(sourceFolder);
 71.1612 +            } catch (DataObjectNotFoundException ex) {
 71.1613 +                ex.printStackTrace();
 71.1614 +            } catch (IOException ex) {
 71.1615 +                ex.printStackTrace();
 71.1616 +            }
 71.1617 +        }
 71.1618 +
 71.1619 +        @Override
 71.1620 +        public Lookup getLookup() {
 71.1621 +            return Lookup.EMPTY;
 71.1622 +        }
 71.1623 +
 71.1624 +        @Override
 71.1625 +        public FileObject getParentFile() {
 71.1626 +            return toMove;
 71.1627 +        }
 71.1628 +
 71.1629 +        @Override
 71.1630 +        public PositionBounds getPosition() {
 71.1631 +            return null;
 71.1632 +        }
 71.1633 +    }
 71.1634 +}
    72.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    72.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/MatcherUtilities.java	Wed May 08 21:47:42 2013 +0200
    72.3 @@ -0,0 +1,157 @@
    72.4 +/*
    72.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    72.6 + *
    72.7 + * Copyright 2010 Oracle and/or its affiliates. All rights reserved.
    72.8 + *
    72.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   72.10 + * Other names may be trademarks of their respective owners.
   72.11 + *
   72.12 + * The contents of this file are subject to the terms of either the GNU
   72.13 + * General Public License Version 2 only ("GPL") or the Common
   72.14 + * Development and Distribution License("CDDL") (collectively, the
   72.15 + * "License"). You may not use this file except in compliance with the
   72.16 + * License. You can obtain a copy of the License at
   72.17 + * http://www.netbeans.org/cddl-gplv2.html
   72.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   72.19 + * specific language governing permissions and limitations under the
   72.20 + * License.  When distributing the software, include this License Header
   72.21 + * Notice in each file and include the License file at
   72.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   72.23 + * particular file as subject to the "Classpath" exception as provided
   72.24 + * by Oracle in the GPL Version 2 section of the License file that
   72.25 + * accompanied this code. If applicable, add the following below the
   72.26 + * License Header, with the fields enclosed by brackets [] replaced by
   72.27 + * your own identifying information:
   72.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   72.29 + *
   72.30 + * If you wish your version of this file to be governed by only the CDDL
   72.31 + * or only the GPL Version 2, indicate your decision by adding
   72.32 + * "[Contributor] elects to include this software in this distribution
   72.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   72.34 + * single choice of license, a recipient has the option to distribute
   72.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   72.36 + * to extend the choice of license to its licensees as provided above.
   72.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   72.38 + * Version 2 license, then the option applies only if the new code is
   72.39 + * made subject to such option by the copyright holder.
   72.40 + *
   72.41 + * Contributor(s):
   72.42 + *
   72.43 + * Portions Copyrighted 2009 Sun Microsystems, Inc.
   72.44 + */
   72.45 +
   72.46 +package org.netbeans.spi.java.hints;
   72.47 +
   72.48 +import com.sun.source.tree.BlockTree;
   72.49 +import com.sun.source.tree.Scope;
   72.50 +import com.sun.source.tree.StatementTree;
   72.51 +import com.sun.source.tree.Tree;
   72.52 +import com.sun.source.util.TreePath;
   72.53 +import java.util.Collection;
   72.54 +import java.util.Collections;
   72.55 +import java.util.HashMap;
   72.56 +import java.util.Iterator;
   72.57 +import java.util.List;
   72.58 +import java.util.Map;
   72.59 +import java.util.concurrent.atomic.AtomicBoolean;
   72.60 +import javax.lang.model.type.TypeMirror;
   72.61 +import org.netbeans.api.annotations.common.NonNull;
   72.62 +import org.netbeans.modules.java.hints.spiimpl.Utilities;
   72.63 +import org.netbeans.modules.java.hints.spiimpl.pm.PatternCompiler;
   72.64 +import org.netbeans.api.java.source.matching.Matcher;
   72.65 +import org.netbeans.api.java.source.matching.Occurrence;
   72.66 +import org.netbeans.api.java.source.matching.Pattern;
   72.67 +
   72.68 +/**XXX: cancelability
   72.69 + * TODO: needed?
   72.70 + *
   72.71 + * @author lahvac
   72.72 + */
   72.73 +public class MatcherUtilities {
   72.74 +
   72.75 +    public static boolean matches(@NonNull HintContext ctx, @NonNull TreePath variable, @NonNull String pattern) {
   72.76 +        return matches(ctx, variable, pattern, null, null, null);
   72.77 +    }
   72.78 +
   72.79 +    public static boolean matches(@NonNull HintContext ctx, @NonNull TreePath variable, @NonNull String pattern, boolean fillInVariablesHack) {
   72.80 +        return matches(ctx, variable, pattern, ctx.getVariables(), ctx.getMultiVariables(), ctx.getVariableNames());
   72.81 +    }
   72.82 +
   72.83 +    public static boolean matches(@NonNull HintContext ctx, @NonNull TreePath variable, @NonNull String pattern, Map<String, TreePath> outVariables, Map<String, Collection<? extends TreePath>> outMultiVariables, Map<String, String> outVariables2Names) {
   72.84 +        Pattern p = PatternCompiler.compile(ctx.getInfo(), pattern, Collections.<String, TypeMirror>emptyMap(), Collections.<String>emptyList());
   72.85 +        Map<String, TreePath> variables = new HashMap<String, TreePath>(ctx.getVariables());
   72.86 +        Map<String, Collection<? extends TreePath>> multiVariables = new HashMap<String, Collection<? extends TreePath>>(ctx.getMultiVariables());
   72.87 +        Map<String, String> variables2Names = new HashMap<String, String>(ctx.getVariableNames());
   72.88 +        Iterable<? extends Occurrence> occurrences = Matcher.create(ctx.getInfo()).setCancel(new AtomicBoolean()).setPresetVariable(variables, multiVariables, variables2Names).setSearchRoot(variable).setTreeTopSearch().match(p);
   72.89 +
   72.90 +        if (occurrences.iterator().hasNext()) {
   72.91 +            Occurrence od = occurrences.iterator().next();
   72.92 +            outVariables(outVariables, od.getVariables(), ctx.getVariables());
   72.93 +            outVariables(outMultiVariables, od.getMultiVariables(), ctx.getMultiVariables());
   72.94 +            outVariables(outVariables2Names, od.getVariables2Names(), ctx.getVariableNames());
   72.95 +
   72.96 +            return true;
   72.97 +        }
   72.98 +
   72.99 +        return false;
  72.100 +    }
  72.101 +
  72.102 +    public static boolean matches(@NonNull HintContext ctx, @NonNull Collection<? extends TreePath> variable, @NonNull String pattern, Map<String, TreePath> outVariables, Map<String, Collection<? extends TreePath>> outMultiVariables, Map<String, String> outVariables2Names) {
  72.103 +        Scope s = Utilities.constructScope(ctx.getInfo(), Collections.<String, TypeMirror>emptyMap());
  72.104 +        Tree  patternTree = Utilities.parseAndAttribute(ctx.getInfo(), pattern, s);
  72.105 +        List<? extends Tree> patternTrees;
  72.106 +
  72.107 +        if (Utilities.isFakeBlock(patternTree)) {
  72.108 +            List<? extends StatementTree> statements = ((BlockTree) patternTree).getStatements();
  72.109 +
  72.110 +            patternTrees = statements.subList(1, statements.size() - 1);
  72.111 +        } else {
  72.112 +            patternTrees = Collections.singletonList(patternTree);
  72.113 +        }
  72.114 +
  72.115 +        if (variable.size() != patternTrees.size()) return false;
  72.116 +        
  72.117 +        Map<String, TreePath> variables = new HashMap<String, TreePath>(ctx.getVariables());
  72.118 +        Map<String, Collection<? extends TreePath>> multiVariables = new HashMap<String, Collection<? extends TreePath>>(ctx.getMultiVariables());
  72.119 +        Map<String, String> variables2Names = new HashMap<String, String>(ctx.getVariableNames());
  72.120 +        Iterator<? extends TreePath> variableIt = variable.iterator();
  72.121 +        Iterator<? extends Tree> patternTreesIt = patternTrees.iterator();
  72.122 +
  72.123 +        while (variableIt.hasNext() && patternTreesIt.hasNext()) {
  72.124 +            TreePath patternTreePath = new TreePath(new TreePath(ctx.getInfo().getCompilationUnit()), patternTreesIt.next());
  72.125 +            Pattern p = Pattern.createPatternWithFreeVariables(patternTreePath, Collections.<String, TypeMirror>emptyMap());
  72.126 +            Iterable<? extends Occurrence> occurrences = Matcher.create(ctx.getInfo()).setCancel(new AtomicBoolean()).setPresetVariable(variables, multiVariables, variables2Names).setSearchRoot(variableIt.next()).setTreeTopSearch().match(p);
  72.127 +
  72.128 +            if (!occurrences.iterator().hasNext()) {
  72.129 +                return false;
  72.130 +            }
  72.131 +
  72.132 +            Occurrence od = occurrences.iterator().next();
  72.133 +
  72.134 +            variables = od.getVariables();
  72.135 +            multiVariables = od.getMultiVariables();
  72.136 +            variables2Names = od.getVariables2Names();
  72.137 +        }
  72.138 +
  72.139 +        if (variableIt.hasNext() == patternTreesIt.hasNext()) {
  72.140 +            outVariables(outVariables, variables, ctx.getVariables());
  72.141 +            outVariables(outMultiVariables, multiVariables, ctx.getMultiVariables());
  72.142 +            outVariables(outVariables2Names, variables2Names, ctx.getVariableNames());
  72.143 +
  72.144 +            return true;
  72.145 +        }
  72.146 +
  72.147 +        return false;
  72.148 +    }
  72.149 +
  72.150 +    private static <T> void outVariables(Map<String, T> outMap, Map<String, T> currentValues, Map<String, T> origValues) {
  72.151 +        if (outMap == null) return;
  72.152 +
  72.153 +        for (String key : origValues.keySet()) {
  72.154 +            currentValues.remove(key);
  72.155 +        }
  72.156 +
  72.157 +        outMap.putAll(currentValues);
  72.158 +    }
  72.159 +
  72.160 +}
    73.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    73.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/TriggerPattern.java	Wed May 08 21:47:42 2013 +0200
    73.3 @@ -0,0 +1,93 @@
    73.4 +/*
    73.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    73.6 + *
    73.7 + * Copyright 2008-2010 Oracle and/or its affiliates. All rights reserved.
    73.8 + *
    73.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   73.10 + * Other names may be trademarks of their respective owners.
   73.11 + *
   73.12 + * The contents of this file are subject to the terms of either the GNU
   73.13 + * General Public License Version 2 only ("GPL") or the Common
   73.14 + * Development and Distribution License("CDDL") (collectively, the
   73.15 + * "License"). You may not use this file except in compliance with the
   73.16 + * License. You can obtain a copy of the License at
   73.17 + * http://www.netbeans.org/cddl-gplv2.html
   73.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   73.19 + * specific language governing permissions and limitations under the
   73.20 + * License.  When distributing the software, include this License Header
   73.21 + * Notice in each file and include the License file at
   73.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   73.23 + * particular file as subject to the "Classpath" exception as provided
   73.24 + * by Oracle in the GPL Version 2 section of the License file that
   73.25 + * accompanied this code. If applicable, add the following below the
   73.26 + * License Header, with the fields enclosed by brackets [] replaced by
   73.27 + * your own identifying information:
   73.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   73.29 + *
   73.30 + * If you wish your version of this file to be governed by only the CDDL
   73.31 + * or only the GPL Version 2, indicate your decision by adding
   73.32 + * "[Contributor] elects to include this software in this distribution
   73.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   73.34 + * single choice of license, a recipient has the option to distribute
   73.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   73.36 + * to extend the choice of license to its licensees as provided above.
   73.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   73.38 + * Version 2 license, then the option applies only if the new code is
   73.39 + * made subject to such option by the copyright holder.
   73.40 + *
   73.41 + * Contributor(s):
   73.42 + *
   73.43 + * Portions Copyrighted 2008-2010 Sun Microsystems, Inc.
   73.44 + */
   73.45 +
   73.46 +package org.netbeans.spi.java.hints;
   73.47 +
   73.48 +import java.lang.annotation.ElementType;
   73.49 +import java.lang.annotation.Retention;
   73.50 +import java.lang.annotation.RetentionPolicy;
   73.51 +import java.lang.annotation.Target;
   73.52 +import org.netbeans.spi.editor.hints.ErrorDescription;
   73.53 +
   73.54 +/**Find parts of the source code that satisfy the given pattern, and invoke the method
   73.55 + * that is annotated with this annotation.
   73.56 + *
   73.57 + * The method must be {@code public static}, the return type must either be assignable to
   73.58 + * {@link ErrorDescription} or to {@link Iterable}{@code <? extends }{@link ErrorDescription}{@code >}.
   73.59 + * Its sole parameter must be {@link HintContext}.
   73.60 + *
   73.61 + * @author lahvac
   73.62 + */
   73.63 +@Retention(RetentionPolicy.SOURCE)
   73.64 +@Target(ElementType.METHOD)
   73.65 +public @interface TriggerPattern {
   73.66 +
   73.67 +    /**
   73.68 +     * Pattern to match on.
   73.69 +     * The pattern consists of:
   73.70 +     * <ul>
   73.71 +     *     <li>a single Java expression</li>
   73.72 +     *     <li>a single Java statement</li>
   73.73 +     *     <li>multiple Java statements</li>
   73.74 +     *     <li>a Java field, method or class</li>
   73.75 +     * </ul>
   73.76 +     *
   73.77 +     * Variables (identifiers starting with {@code $}) can be used to replace part of the pattern.
   73.78 +     * During matching, the actual part of the AST that corresponds to the variable in the pattern
   73.79 +     * will be "bound" to the variable. Variables whose names that do not end with a {@code $} ("single" variables)
   73.80 +     * will be bound to exactly one AST node, whereas variables whose names end with a {@code $} ("multi" variables)
   73.81 +     * will be bound to any number of consecutive AST nodes (with the same AST node as a parent).
   73.82 +     *
   73.83 +     * The actual AST nodes that were bound to single variables are available through {@link HintContext#getVariables() },
   73.84 +     * nodes bound to multi variables are available through {@link HintContext#getMultiVariables() }.
   73.85 +     *
   73.86 +     * For variables that represent an expression, a type constraint can be specified using the
   73.87 +     * {@link #constraints() } attribute.
   73.88 +     *
   73.89 +     * All classes should be referred to using FQNs.
   73.90 +     */
   73.91 +    public String value();
   73.92 +    /**Expected types for variables from the {@link #value() pattern}.
   73.93 +     */
   73.94 +    public ConstraintVariableType[] constraints() default {};
   73.95 +
   73.96 +}
    74.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    74.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/TriggerPatterns.java	Wed May 08 21:47:42 2013 +0200
    74.3 @@ -0,0 +1,60 @@
    74.4 +/*
    74.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    74.6 + *
    74.7 + * Copyright 2008-2010 Oracle and/or its affiliates. All rights reserved.
    74.8 + *
    74.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   74.10 + * Other names may be trademarks of their respective owners.
   74.11 + *
   74.12 + * The contents of this file are subject to the terms of either the GNU
   74.13 + * General Public License Version 2 only ("GPL") or the Common
   74.14 + * Development and Distribution License("CDDL") (collectively, the
   74.15 + * "License"). You may not use this file except in compliance with the
   74.16 + * License. You can obtain a copy of the License at
   74.17 + * http://www.netbeans.org/cddl-gplv2.html
   74.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   74.19 + * specific language governing permissions and limitations under the
   74.20 + * License.  When distributing the software, include this License Header
   74.21 + * Notice in each file and include the License file at
   74.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   74.23 + * particular file as subject to the "Classpath" exception as provided
   74.24 + * by Oracle in the GPL Version 2 section of the License file that
   74.25 + * accompanied this code. If applicable, add the following below the
   74.26 + * License Header, with the fields enclosed by brackets [] replaced by
   74.27 + * your own identifying information:
   74.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   74.29 + *
   74.30 + * If you wish your version of this file to be governed by only the CDDL
   74.31 + * or only the GPL Version 2, indicate your decision by adding
   74.32 + * "[Contributor] elects to include this software in this distribution
   74.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   74.34 + * single choice of license, a recipient has the option to distribute
   74.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   74.36 + * to extend the choice of license to its licensees as provided above.
   74.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   74.38 + * Version 2 license, then the option applies only if the new code is
   74.39 + * made subject to such option by the copyright holder.
   74.40 + *
   74.41 + * Contributor(s):
   74.42 + *
   74.43 + * Portions Copyrighted 2008-2010 Sun Microsystems, Inc.
   74.44 + */
   74.45 +
   74.46 +package org.netbeans.spi.java.hints;
   74.47 +
   74.48 +import java.lang.annotation.ElementType;
   74.49 +import java.lang.annotation.Retention;
   74.50 +import java.lang.annotation.RetentionPolicy;
   74.51 +import java.lang.annotation.Target;
   74.52 +
   74.53 +/**Multiple {@link TriggerPattern}s.
   74.54 + *
   74.55 + * @author lahvac
   74.56 + */
   74.57 +@Retention(RetentionPolicy.SOURCE)
   74.58 +@Target(ElementType.METHOD)
   74.59 +public @interface TriggerPatterns {
   74.60 +
   74.61 +    public TriggerPattern[] value();
   74.62 +    
   74.63 +}
    75.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    75.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/TriggerTreeKind.java	Wed May 08 21:47:42 2013 +0200
    75.3 @@ -0,0 +1,66 @@
    75.4 +/*
    75.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    75.6 + *
    75.7 + * Copyright 2008-2010 Oracle and/or its affiliates. All rights reserved.
    75.8 + *
    75.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   75.10 + * Other names may be trademarks of their respective owners.
   75.11 + *
   75.12 + * The contents of this file are subject to the terms of either the GNU
   75.13 + * General Public License Version 2 only ("GPL") or the Common
   75.14 + * Development and Distribution License("CDDL") (collectively, the
   75.15 + * "License"). You may not use this file except in compliance with the
   75.16 + * License. You can obtain a copy of the License at
   75.17 + * http://www.netbeans.org/cddl-gplv2.html
   75.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   75.19 + * specific language governing permissions and limitations under the
   75.20 + * License.  When distributing the software, include this License Header
   75.21 + * Notice in each file and include the License file at
   75.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   75.23 + * particular file as subject to the "Classpath" exception as provided
   75.24 + * by Oracle in the GPL Version 2 section of the License file that
   75.25 + * accompanied this code. If applicable, add the following below the
   75.26 + * License Header, with the fields enclosed by brackets [] replaced by
   75.27 + * your own identifying information:
   75.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   75.29 + *
   75.30 + * If you wish your version of this file to be governed by only the CDDL
   75.31 + * or only the GPL Version 2, indicate your decision by adding
   75.32 + * "[Contributor] elects to include this software in this distribution
   75.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   75.34 + * single choice of license, a recipient has the option to distribute
   75.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   75.36 + * to extend the choice of license to its licensees as provided above.
   75.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   75.38 + * Version 2 license, then the option applies only if the new code is
   75.39 + * made subject to such option by the copyright holder.
   75.40 + *
   75.41 + * Contributor(s):
   75.42 + *
   75.43 + * Portions Copyrighted 2008-2010 Sun Microsystems, Inc.
   75.44 + */
   75.45 +
   75.46 +package org.netbeans.spi.java.hints;
   75.47 +
   75.48 +import com.sun.source.tree.Tree.Kind;
   75.49 +import com.sun.source.util.TreePath;
   75.50 +import java.lang.annotation.ElementType;
   75.51 +import java.lang.annotation.Retention;
   75.52 +import java.lang.annotation.RetentionPolicy;
   75.53 +import java.lang.annotation.Target;
   75.54 +
   75.55 +/**Invoke the method for {@link TreePath}s of the given kind.
   75.56 + *
   75.57 + * The method must be {@code public static}, the return type must either be assignable to
   75.58 + * {@link ErrorDescription} or to {@link Iterable}{@code <? extends }{@link ErrorDescription}{@code >}.
   75.59 + * Its sole parameter must be {@link HintContext}.
   75.60 + *
   75.61 + * @author lahvac
   75.62 + */
   75.63 +@Retention(RetentionPolicy.SOURCE)
   75.64 +@Target(ElementType.METHOD)
   75.65 +public @interface TriggerTreeKind {
   75.66 +
   75.67 +    public Kind[] value();
   75.68 +
   75.69 +}
    76.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    76.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/UseOptions.java	Wed May 08 21:47:42 2013 +0200
    76.3 @@ -0,0 +1,64 @@
    76.4 +/*
    76.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    76.6 + *
    76.7 + * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
    76.8 + *
    76.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   76.10 + * Other names may be trademarks of their respective owners.
   76.11 + *
   76.12 + * The contents of this file are subject to the terms of either the GNU
   76.13 + * General Public License Version 2 only ("GPL") or the Common
   76.14 + * Development and Distribution License("CDDL") (collectively, the
   76.15 + * "License"). You may not use this file except in compliance with the
   76.16 + * License. You can obtain a copy of the License at
   76.17 + * http://www.netbeans.org/cddl-gplv2.html
   76.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   76.19 + * specific language governing permissions and limitations under the
   76.20 + * License.  When distributing the software, include this License Header
   76.21 + * Notice in each file and include the License file at
   76.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   76.23 + * particular file as subject to the "Classpath" exception as provided
   76.24 + * by Oracle in the GPL Version 2 section of the License file that
   76.25 + * accompanied this code. If applicable, add the following below the
   76.26 + * License Header, with the fields enclosed by brackets [] replaced by
   76.27 + * your own identifying information:
   76.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   76.29 + *
   76.30 + * If you wish your version of this file to be governed by only the CDDL
   76.31 + * or only the GPL Version 2, indicate your decision by adding
   76.32 + * "[Contributor] elects to include this software in this distribution
   76.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   76.34 + * single choice of license, a recipient has the option to distribute
   76.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   76.36 + * to extend the choice of license to its licensees as provided above.
   76.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   76.38 + * Version 2 license, then the option applies only if the new code is
   76.39 + * made subject to such option by the copyright holder.
   76.40 + *
   76.41 + * Contributor(s):
   76.42 + *
   76.43 + * Portions Copyrighted 2012 Sun Microsystems, Inc.
   76.44 + */
   76.45 +package org.netbeans.spi.java.hints;
   76.46 +
   76.47 +import java.lang.annotation.ElementType;
   76.48 +import java.lang.annotation.Retention;
   76.49 +import java.lang.annotation.RetentionPolicy;
   76.50 +import java.lang.annotation.Target;
   76.51 +
   76.52 +/**Specifies which options from the enclosing class should be used for this hint.
   76.53 + *
   76.54 + * Only applies to methods marked with the {@link Hint} annotation.
   76.55 + *
   76.56 + * @author lahvac
   76.57 + */
   76.58 +@Retention(RetentionPolicy.SOURCE)
   76.59 +@Target(ElementType.METHOD)
   76.60 +public @interface UseOptions {
   76.61 +
   76.62 +    /**Keys (values of the compile-time constants) of the options that should be used
   76.63 +     * for this hint method.
   76.64 +     */
   76.65 +    public String[] value();
   76.66 +    
   76.67 +}
    77.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    77.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/support/FixFactory.java	Wed May 08 21:47:42 2013 +0200
    77.3 @@ -0,0 +1,171 @@
    77.4 +/*
    77.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    77.6 + *
    77.7 + * Copyright 1997-2012 Oracle and/or its affiliates. All rights reserved.
    77.8 + *
    77.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   77.10 + * Other names may be trademarks of their respective owners.
   77.11 + *
   77.12 + * The contents of this file are subject to the terms of either the GNU
   77.13 + * General Public License Version 2 only ("GPL") or the Common
   77.14 + * Development and Distribution License("CDDL") (collectively, the
   77.15 + * "License"). You may not use this file except in compliance with the
   77.16 + * License. You can obtain a copy of the License at
   77.17 + * http://www.netbeans.org/cddl-gplv2.html
   77.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   77.19 + * specific language governing permissions and limitations under the
   77.20 + * License.  When distributing the software, include this License Header
   77.21 + * Notice in each file and include the License file at
   77.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   77.23 + * particular file as subject to the "Classpath" exception as provided
   77.24 + * by Oracle in the GPL Version 2 section of the License file that
   77.25 + * accompanied this code. If applicable, add the following below the
   77.26 + * License Header, with the fields enclosed by brackets [] replaced by
   77.27 + * your own identifying information:
   77.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   77.29 + *
   77.30 + * Contributor(s):
   77.31 + *
   77.32 + * Portions Copyrighted 2007-2012 Sun Microsystems, Inc.
   77.33 + */
   77.34 +package org.netbeans.spi.java.hints.support;
   77.35 +
   77.36 +import com.sun.source.tree.ModifiersTree;
   77.37 +import com.sun.source.tree.Tree.Kind;
   77.38 +import com.sun.source.util.TreePath;
   77.39 +import java.util.Collections;
   77.40 +import java.util.EnumSet;
   77.41 +import java.util.Set;
   77.42 +import javax.lang.model.element.Modifier;
   77.43 +import org.netbeans.api.java.source.CompilationInfo;
   77.44 +import org.netbeans.api.java.source.TreeMaker;
   77.45 +import org.netbeans.api.java.source.TreePathHandle;
   77.46 +import org.netbeans.api.java.source.WorkingCopy;
   77.47 +import org.netbeans.spi.editor.hints.Fix;
   77.48 +import org.netbeans.spi.java.hints.JavaFix;
   77.49 +import org.openide.util.Parameters;
   77.50 +
   77.51 +/** Factory for creating generally useful fixes. Currently, changes to the modifiers
   77.52 + *  are supported.
   77.53 + *
   77.54 + * @author Dusan Balek
   77.55 + */
   77.56 +public final class FixFactory {
   77.57 +
   77.58 +    private FixFactory() {}
   77.59 +
   77.60 +    /** Creates a fix, which when invoked adds a set of modifiers to the existing ones
   77.61 +     * @param compilationInfo CompilationInfo to work on
   77.62 +     * @param treePath TreePath to a ModifiersTree.
   77.63 +     * @param toAdd set of Modifiers to add
   77.64 +     * @param text text displayed as a fix description
   77.65 +     */
   77.66 +    public static final Fix addModifiersFix(CompilationInfo compilationInfo, TreePath treePath, Set<Modifier> toAdd, String text) {
   77.67 +        Parameters.notNull("compilationInfo", compilationInfo);
   77.68 +        Parameters.notNull("treePath", treePath);
   77.69 +        Parameters.notNull("toAdd", toAdd);
   77.70 +        Parameters.notNull("text", text);
   77.71 +
   77.72 +        return changeModifiersFix(compilationInfo, treePath, toAdd, Collections.<Modifier>emptySet(), text);
   77.73 +    }
   77.74 +
   77.75 +    /** Creates a fix, which when invoked removes a set of modifiers from the existing ones
   77.76 +     * @param compilationInfo CompilationInfo to work on
   77.77 +     * @param treePath TreePath to a ModifiersTree.
   77.78 +     * @param toRemove set of Modifiers to remove
   77.79 +     * @param text text displayed as a fix description
   77.80 +     */
   77.81 +    public static final Fix removeModifiersFix(CompilationInfo compilationInfo, TreePath treePath, Set<Modifier> toRemove, String text) {
   77.82 +        Parameters.notNull("compilationInfo", compilationInfo);
   77.83 +        Parameters.notNull("treePath", treePath);
   77.84 +        Parameters.notNull("toRemove", toRemove);
   77.85 +        Parameters.notNull("text", text);
   77.86 +
   77.87 +        return changeModifiersFix(compilationInfo, treePath, Collections.<Modifier>emptySet(), toRemove, text);
   77.88 +    }
   77.89 +
   77.90 +    /** Creates a fix, which when invoked changes the existing modifiers
   77.91 +     * @param compilationInfo CompilationInfo to work on
   77.92 +     * @param treePath TreePath to a ModifiersTree.
   77.93 +     * @param toAdd set of Modifiers to add
   77.94 +     * @param toRemove set of Modifiers to remove
   77.95 +     * @param text text displayed as a fix description
   77.96 +     */
   77.97 +    public static final Fix changeModifiersFix(CompilationInfo compilationInfo, TreePath treePath, Set<Modifier> toAdd, Set<Modifier> toRemove, String text) {
   77.98 +        Parameters.notNull("compilationInfo", compilationInfo);
   77.99 +        Parameters.notNull("treePath", treePath);
  77.100 +        Parameters.notNull("toAdd", toAdd);
  77.101 +        Parameters.notNull("toRemove", toRemove);
  77.102 +        Parameters.notNull("text", text);
  77.103 +
  77.104 +        if (treePath.getLeaf().getKind() != Kind.MODIFIERS) {
  77.105 +            return null;
  77.106 +        }
  77.107 +        return new ChangeModifiersFixImpl(TreePathHandle.create(treePath, compilationInfo), toAdd, toRemove, text).toEditorFix();
  77.108 +    }
  77.109 +
  77.110 +    private static final class ChangeModifiersFixImpl extends JavaFix {
  77.111 +
  77.112 +        private final TreePathHandle modsHandle;
  77.113 +        private final Set<Modifier> toAdd;
  77.114 +        private final Set<Modifier> toRemove;
  77.115 +        private final String text;
  77.116 +
  77.117 +        public ChangeModifiersFixImpl(TreePathHandle modsHandle, Set<Modifier> toAdd, Set<Modifier> toRemove, String text) {
  77.118 +            super(modsHandle);
  77.119 +            this.modsHandle = modsHandle;
  77.120 +            this.toAdd = toAdd;
  77.121 +            this.toRemove = toRemove;
  77.122 +            this.text = text;
  77.123 +        }
  77.124 +
  77.125 +        public String getText() {
  77.126 +            return text;
  77.127 +        }
  77.128 +
  77.129 +        @Override
  77.130 +        protected void performRewrite(TransformationContext ctx) {
  77.131 +            WorkingCopy wc = ctx.getWorkingCopy();
  77.132 +            TreePath path = ctx.getPath();
  77.133 +            TreeMaker make = wc.getTreeMaker();
  77.134 +            ModifiersTree newMods = (ModifiersTree) path.getLeaf();
  77.135 +            for (Modifier a : toAdd) {
  77.136 +                newMods = make.addModifiersModifier(newMods, a);
  77.137 +            }
  77.138 +            for (Modifier r : toRemove) {
  77.139 +                newMods = make.removeModifiersModifier(newMods, r);
  77.140 +            }
  77.141 +            wc.rewrite(path.getLeaf(), newMods);
  77.142 +        }
  77.143 +
  77.144 +        @Override
  77.145 +        public boolean equals(Object obj) {
  77.146 +            if (obj == null) {
  77.147 +                return false;
  77.148 +            }
  77.149 +            if (getClass() != obj.getClass()) {
  77.150 +                return false;
  77.151 +            }
  77.152 +            final ChangeModifiersFixImpl other = (ChangeModifiersFixImpl) obj;
  77.153 +            if (this.modsHandle != other.modsHandle && (this.modsHandle == null || !this.modsHandle.equals(other.modsHandle))) {
  77.154 +                return false;
  77.155 +            }
  77.156 +            if (this.toAdd != other.toAdd && (this.toAdd == null || !this.toAdd.equals(other.toAdd))) {
  77.157 +                return false;
  77.158 +            }
  77.159 +            if (this.toRemove != other.toRemove && (this.toRemove == null || !this.toRemove.equals(other.toRemove))) {
  77.160 +                return false;
  77.161 +            }
  77.162 +            return true;
  77.163 +        }
  77.164 +
  77.165 +        @Override
  77.166 +        public int hashCode() {
  77.167 +            int hash = 5;
  77.168 +            hash = 71 * hash + (this.modsHandle != null ? this.modsHandle.hashCode() : 0);
  77.169 +            hash = 71 * hash + (this.toAdd != null ? this.toAdd.hashCode() : 0);
  77.170 +            hash = 71 * hash + (this.toRemove != null ? this.toRemove.hashCode() : 0);
  77.171 +            return hash;
  77.172 +        }
  77.173 +    }
  77.174 +}
    78.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    78.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/support/TransformationSupport.java	Wed May 08 21:47:42 2013 +0200
    78.3 @@ -0,0 +1,311 @@
    78.4 +/*
    78.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    78.6 + *
    78.7 + * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
    78.8 + *
    78.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   78.10 + * Other names may be trademarks of their respective owners.
   78.11 + *
   78.12 + * The contents of this file are subject to the terms of either the GNU
   78.13 + * General Public License Version 2 only ("GPL") or the Common
   78.14 + * Development and Distribution License("CDDL") (collectively, the
   78.15 + * "License"). You may not use this file except in compliance with the
   78.16 + * License. You can obtain a copy of the License at
   78.17 + * http://www.netbeans.org/cddl-gplv2.html
   78.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   78.19 + * specific language governing permissions and limitations under the
   78.20 + * License.  When distributing the software, include this License Header
   78.21 + * Notice in each file and include the License file at
   78.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   78.23 + * particular file as subject to the "Classpath" exception as provided
   78.24 + * by Oracle in the GPL Version 2 section of the License file that
   78.25 + * accompanied this code. If applicable, add the following below the
   78.26 + * License Header, with the fields enclosed by brackets [] replaced by
   78.27 + * your own identifying information:
   78.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   78.29 + *
   78.30 + * If you wish your version of this file to be governed by only the CDDL
   78.31 + * or only the GPL Version 2, indicate your decision by adding
   78.32 + * "[Contributor] elects to include this software in this distribution
   78.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   78.34 + * single choice of license, a recipient has the option to distribute
   78.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   78.36 + * to extend the choice of license to its licensees as provided above.
   78.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   78.38 + * Version 2 license, then the option applies only if the new code is
   78.39 + * made subject to such option by the copyright holder.
   78.40 + *
   78.41 + * Contributor(s):
   78.42 + *
   78.43 + * Portions Copyrighted 2012 Sun Microsystems, Inc.
   78.44 + */
   78.45 +package org.netbeans.spi.java.hints.support;
   78.46 +
   78.47 +import com.sun.source.util.TreePath;
   78.48 +import java.util.*;
   78.49 +import java.util.Map.Entry;
   78.50 +import java.util.concurrent.atomic.AtomicBoolean;
   78.51 +import javax.lang.model.type.TypeMirror;
   78.52 +import org.netbeans.api.annotations.common.NonNull;
   78.53 +import org.netbeans.api.java.source.CompilationInfo;
   78.54 +import org.netbeans.api.java.source.ModificationResult;
   78.55 +import org.netbeans.api.java.source.TypeMirrorHandle;
   78.56 +import org.netbeans.api.java.source.WorkingCopy;
   78.57 +import org.netbeans.api.java.source.matching.Matcher;
   78.58 +import org.netbeans.api.java.source.matching.Occurrence;
   78.59 +import org.netbeans.api.java.source.matching.Pattern;
   78.60 +import org.netbeans.api.project.Project;
   78.61 +import org.netbeans.modules.java.hints.jackpot.spi.PatternConvertor;
   78.62 +import org.netbeans.modules.java.hints.providers.spi.HintDescription;
   78.63 +import org.netbeans.modules.java.hints.providers.spi.HintDescriptionFactory;
   78.64 +import org.netbeans.modules.java.hints.providers.spi.Trigger;
   78.65 +import org.netbeans.modules.java.hints.spiimpl.JavaFixImpl;
   78.66 +import org.netbeans.modules.java.hints.spiimpl.MessageImpl;
   78.67 +import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch;
   78.68 +import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.BatchResult;
   78.69 +import org.netbeans.modules.java.hints.spiimpl.batch.BatchUtilities;
   78.70 +import org.netbeans.modules.java.hints.spiimpl.batch.ProgressHandleWrapper;
   78.71 +import org.netbeans.modules.java.hints.spiimpl.batch.Scopes;
   78.72 +import org.netbeans.modules.java.hints.spiimpl.hints.HintsInvoker;
   78.73 +import org.netbeans.modules.java.hints.spiimpl.options.HintsSettings;
   78.74 +import org.netbeans.modules.java.hints.spiimpl.pm.PatternCompiler;
   78.75 +import org.netbeans.modules.refactoring.spi.RefactoringElementImplementation;
   78.76 +import org.netbeans.spi.editor.hints.*;
   78.77 +import org.netbeans.spi.java.hints.HintContext;
   78.78 +import org.netbeans.spi.java.hints.JavaFix;
   78.79 +import org.openide.util.Exceptions;
   78.80 +
   78.81 +/**
   78.82 + * Static utility classes for processing jackpot patterns.
   78.83 + * <a href="https://bitbucket.org/jlahoda/jackpot30/wiki/RulesLanguage">Rules Language</a>
   78.84 + * @author Jan Becicka
   78.85 + * @since 1.1
   78.86 + */
   78.87 +public final class TransformationSupport {
   78.88 +
   78.89 +    private String jackpotPattern;
   78.90 +    private Transformer transformer;
   78.91 +    private AtomicBoolean cancel = new AtomicBoolean();
   78.92 +
   78.93 +    private TransformationSupport(String jackpotPattern, Transformer transformer) {
   78.94 +        this.jackpotPattern = jackpotPattern;
   78.95 +        this.transformer = transformer;
   78.96 +    }
   78.97 +    
   78.98 +    /**
   78.99 +     * Creates new TransformationSupport representing given jackpotPattern.
  78.100 +     * @param jackpotPattern
  78.101 +     * @return
  78.102 +     */
  78.103 +    public static @NonNull TransformationSupport create(@NonNull String jackpotPattern) {
  78.104 +        return new TransformationSupport(jackpotPattern, null);
  78.105 +    }
  78.106 +
  78.107 +    /**
  78.108 +     * Creates new TransformationSupport representing given jackpotPattern with custom Transformer.
  78.109 +     * @param inputJackpotPattern
  78.110 +     * @param t
  78.111 +     * @see Transformer
  78.112 +     * @return
  78.113 +     */
  78.114 +    public static @NonNull TransformationSupport create(@NonNull String inputJackpotPattern, @NonNull Transformer t) {
  78.115 +        return new TransformationSupport(inputJackpotPattern, t);
  78.116 +    }
  78.117 +
  78.118 +    /**
  78.119 +     * Option to cancel query.
  78.120 +     * @param cancel
  78.121 +     * @return
  78.122 +     */
  78.123 +    public @NonNull TransformationSupport setCancel(@NonNull AtomicBoolean cancel) {
  78.124 +        this.cancel = cancel;
  78.125 +        return this;
  78.126 +    }
  78.127 +
  78.128 +
  78.129 +    /**
  78.130 +     * Run current transformation on all projects and collect results.
  78.131 +     * @return collection of {@link ModificationResult}
  78.132 +     */
  78.133 +    public @NonNull Collection<? extends ModificationResult> processAllProjects() {
  78.134 +        if (transformer!=null) {
  78.135 +            return performTransformation(jackpotPattern, transformer, cancel);
  78.136 +        } else {
  78.137 +            return performTransformation(jackpotPattern, cancel);
  78.138 +        }
  78.139 +    }
  78.140 +
  78.141 +    
  78.142 +    /**
  78.143 +     * Process current transformation on given treePath and performs rewrite on
  78.144 +     * workingCopy.
  78.145 +     * @param workingCopy
  78.146 +     * @param treePath 
  78.147 +     */
  78.148 +    public void transformTreePath(@NonNull WorkingCopy workingCopy, @NonNull TreePath treePath) {
  78.149 +        if (transformer!=null) {
  78.150 +            throw new UnsupportedOperationException("Not implemented yet");
  78.151 +        } else {
  78.152 +            performTransformation(workingCopy, treePath, jackpotPattern, cancel);
  78.153 +        }
  78.154 +    }
  78.155 +
  78.156 +
  78.157 +    /**
  78.158 +     * Transformer callback which is called for each occurrence during processing 
  78.159 +     * of {@link #performTransformation(java.lang.String, org.netbeans.spi.java.hints.support.JackpotSupport.Transformer, java.util.concurrent.atomic.AtomicBoolean)    
  78.160 +     */
  78.161 +    public interface Transformer {
  78.162 +
  78.163 +        /**
  78.164 +         * Implement custom transformation of occurrence here.
  78.165 +         * @param copy
  78.166 +         * @param occurrence
  78.167 +         */
  78.168 +        public void transform(WorkingCopy copy, Occurrence occurrence);
  78.169 +
  78.170 +    }
  78.171 +    
  78.172 +    
  78.173 +    
  78.174 +    /**
  78.175 +     * Performs transformation described by jackpotPattern on given workingCopy.
  78.176 +     * @param workingCopy
  78.177 +     * @param jackpotPattern
  78.178 +     * @param cancel
  78.179 +     */
  78.180 +    private static void performTransformation(WorkingCopy workingCopy, TreePath on, String jackpotPattern, AtomicBoolean cancel) {
  78.181 +        Iterable<? extends HintDescription> hints = PatternConvertor.create(jackpotPattern);
  78.182 +        HintsInvoker inv = new HintsInvoker(HintsSettings.getSettingsFor(workingCopy.getFileObject()), cancel);
  78.183 +        Map<HintDescription, List<ErrorDescription>> computeHints = inv.computeHints(workingCopy, on, false, hints, new ArrayList<MessageImpl>());
  78.184 +        
  78.185 +        if (computeHints == null || cancel.get()) return ;
  78.186 +        
  78.187 +        List<ErrorDescription> errs = new ArrayList<ErrorDescription>();
  78.188 +        for (Entry<HintDescription, List<ErrorDescription>> entry: computeHints.entrySet()) {
  78.189 +            errs.addAll(entry.getValue());
  78.190 +        }
  78.191 +        List<MessageImpl> problems = new LinkedList<MessageImpl>();
  78.192 +
  78.193 +        try {
  78.194 +            if (BatchUtilities.applyFixes(workingCopy, Collections.<Project, Set<String>>emptyMap(), errs, null, new ArrayList<RefactoringElementImplementation>(), problems)) {
  78.195 +                throw new IllegalStateException();
  78.196 +            }
  78.197 +        } catch (IllegalStateException ex) {
  78.198 +            Exceptions.printStackTrace(ex);
  78.199 +        } catch (Exception ex) {
  78.200 +            Exceptions.printStackTrace(ex);
  78.201 +        }
  78.202 +
  78.203 +        if (!problems.isEmpty()) {
  78.204 +            throw new IllegalStateException(problems.get(0).text);
  78.205 +        }
  78.206 +    }
  78.207 +    
  78.208 +    /**
  78.209 +     * Performs jackpotPattern transformation in all open projects.
  78.210 +     * @param jackpotPattern
  78.211 +     * @param cancel
  78.212 +     * @return
  78.213 +     */
  78.214 +    private static  Collection<? extends ModificationResult> performTransformation(String jackpotPattern, AtomicBoolean cancel) {
  78.215 +        Collection<MessageImpl> problems = new LinkedList<MessageImpl>();
  78.216 +        BatchResult batchResult = BatchSearch.findOccurrences(PatternConvertor.create(jackpotPattern), Scopes.allOpenedProjectsScope());
  78.217 +        return BatchUtilities.applyFixes(batchResult, new ProgressHandleWrapper(1, 1), cancel, problems);
  78.218 +    }
  78.219 +    
  78.220 +    /**
  78.221 +     * Performs transformation defined by transformer on all occurrences, which matches inputJackpotPattern.
  78.222 +     * @param inputJackpotPattern
  78.223 +     * @param transformer
  78.224 +     * @return collection of ModificationResults.
  78.225 +     */
  78.226 +    private static Collection<? extends ModificationResult> performTransformation(final String inputJackpotPattern, final Transformer transformer, AtomicBoolean cancel) {
  78.227 +        List<HintDescription> descriptions = new ArrayList<HintDescription>();
  78.228 +
  78.229 +        for (HintDescription hd : PatternConvertor.create(inputJackpotPattern)) {
  78.230 +            final String triggerPattern = ((Trigger.PatternDescription) hd.getTrigger()).getPattern();
  78.231 +            descriptions.add(HintDescriptionFactory.create().setTrigger(hd.getTrigger()).setWorker(new HintDescription.Worker() {
  78.232 +                @Override public Collection<? extends ErrorDescription> createErrors(HintContext ctx) {
  78.233 +                    final Map<String, TypeMirrorHandle<?>> constraintsHandles = new HashMap<String, TypeMirrorHandle<?>>();
  78.234 +
  78.235 +                    for (Map.Entry<String, TypeMirror> c : ctx.getConstraints().entrySet()) {
  78.236 +                        constraintsHandles.put(c.getKey(), TypeMirrorHandle.create(c.getValue()));
  78.237 +                    }
  78.238 +
  78.239 +                    Fix fix = new JavaFix(ctx.getInfo(), ctx.getPath()) {
  78.240 +                        @Override protected String getText() {
  78.241 +                            return "";
  78.242 +                        }
  78.243 +                        @Override protected void performRewrite(JavaFix.TransformationContext ctx) {
  78.244 +                            WorkingCopy wc = ctx.getWorkingCopy();
  78.245 +                            Map<String, TypeMirror> constraints = new HashMap<String, TypeMirror>();
  78.246 +
  78.247 +                            for (Map.Entry<String, TypeMirrorHandle<?>> c : constraintsHandles.entrySet()) {
  78.248 +                                constraints.put(c.getKey(), c.getValue().resolve(wc));
  78.249 +                            }
  78.250 +
  78.251 +                            Pattern pattern = PatternCompiler.compile(wc, triggerPattern, constraints, Collections.<String>emptyList());
  78.252 +                            Collection<? extends Occurrence> occurrence = Matcher.create(wc).setTreeTopSearch().setSearchRoot(ctx.getPath()).match(pattern);
  78.253 +
  78.254 +                            assert occurrence.size() == 1;
  78.255 +
  78.256 +                            transformer.transform(wc, occurrence.iterator().next());
  78.257 +                        }
  78.258 +                    }.toEditorFix();
  78.259 +                    
  78.260 +                    return Collections.singletonList(ErrorDescriptionFactory.createErrorDescription(Severity.WARNING, "", Collections.singletonList(fix), ctx.getInfo().getFileObject(), 0, 0));
  78.261 +                }
  78.262 +            }).produce());
  78.263 +
  78.264 +        }
  78.265 +        
  78.266 +        BatchSearch.BatchResult batchResult = BatchSearch.findOccurrences(descriptions, Scopes.allOpenedProjectsScope());
  78.267 +        return BatchUtilities.applyFixes(batchResult, new ProgressHandleWrapper(1, 1), cancel, new ArrayList<MessageImpl>());
  78.268 +    }
  78.269 +    
  78.270 +    /**
  78.271 +     * Performs transformation described by transformationJackpotPattern on all occurences described by inputJackpotPattern.
  78.272 +     * @param inputJackpotPattern
  78.273 +     * @param transformationJackpotPattern
  78.274 +     * @param cancel 
  78.275 +     * @return
  78.276 +     */
  78.277 +    private static Collection<? extends ModificationResult> performTransformation(String inputJackpotPattern, final String transformationJackpotPattern, AtomicBoolean cancel) {
  78.278 +        return performTransformation(inputJackpotPattern, new Transformer() {
  78.279 +
  78.280 +            @Override
  78.281 +            public void transform(WorkingCopy copy, Occurrence occurrence) {
  78.282 +                try {
  78.283 +                    Fix toFix = TransformationSupport.rewriteFix(copy, "whatever", occurrence.getOccurrenceRoot(), transformationJackpotPattern, occurrence.getVariables(), occurrence.getMultiVariables(), occurrence.getVariables2Names(), Collections.<String, TypeMirror>emptyMap(), Collections.<String, String>emptyMap());
  78.284 +                    TransformationSupport.process(((JavaFixImpl) toFix).jf, copy, false, null, new ArrayList<RefactoringElementImplementation>());
  78.285 +                } catch (Exception ex) {
  78.286 +                    Exceptions.printStackTrace(ex);
  78.287 +                }
  78.288 +            }
  78.289 +        }, cancel);
  78.290 +    }
  78.291 +
  78.292 +    private static ChangeInfo process(JavaFix jf, WorkingCopy wc, boolean canShowUI, Map<org.openide.filesystems.FileObject, byte[]> resourceContent, Collection<? super RefactoringElementImplementation> fileChanges) throws Exception {
  78.293 +        return JavaFixImpl.Accessor.INSTANCE.process(jf, wc, canShowUI, resourceContent, fileChanges);
  78.294 +    }
  78.295 +
  78.296 +    /**
  78.297 +     * 
  78.298 +     * @param info
  78.299 +     * @param displayName
  78.300 +     * @param what
  78.301 +     * @param to
  78.302 +     * @param parameters
  78.303 +     * @param parametersMulti
  78.304 +     * @param parameterNames
  78.305 +     * @param constraints
  78.306 +     * @param options
  78.307 +     * @param imports
  78.308 +     * @return
  78.309 +     */
  78.310 +    private static Fix rewriteFix(CompilationInfo info, String displayName, TreePath what, final String to, Map<String, TreePath> parameters, Map<String, Collection<? extends TreePath>> parametersMulti, final Map<String, String> parameterNames, Map<String, TypeMirror> constraints, Map<String, String> options, String... imports) {
  78.311 +        return JavaFixImpl.Accessor.INSTANCE.rewriteFix(info, displayName, what, to, parameters, parametersMulti, parameterNames, constraints, options, imports);
  78.312 +    }
  78.313 +    
  78.314 +}
    79.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    79.2 +++ b/java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/providers/code/CodeHintProviderImplTest.java	Wed May 08 21:47:42 2013 +0200
    79.3 @@ -0,0 +1,114 @@
    79.4 +/*
    79.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    79.6 + *
    79.7 + * Copyright 2009-2010 Oracle and/or its affiliates. All rights reserved.
    79.8 + *
    79.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   79.10 + * Other names may be trademarks of their respective owners.
   79.11 + *
   79.12 + * The contents of this file are subject to the terms of either the GNU
   79.13 + * General Public License Version 2 only ("GPL") or the Common
   79.14 + * Development and Distribution License("CDDL") (collectively, the
   79.15 + * "License"). You may not use this file except in compliance with the
   79.16 + * License. You can obtain a copy of the License at
   79.17 + * http://www.netbeans.org/cddl-gplv2.html
   79.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   79.19 + * specific language governing permissions and limitations under the
   79.20 + * License.  When distributing the software, include this License Header
   79.21 + * Notice in each file and include the License file at
   79.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   79.23 + * particular file as subject to the "Classpath" exception as provided
   79.24 + * by Oracle in the GPL Version 2 section of the License file that
   79.25 + * accompanied this code. If applicable, add the following below the
   79.26 + * License Header, with the fields enclosed by brackets [] replaced by
   79.27 + * your own identifying information:
   79.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   79.29 + *
   79.30 + * If you wish your version of this file to be governed by only the CDDL
   79.31 + * or only the GPL Version 2, indicate your decision by adding
   79.32 + * "[Contributor] elects to include this software in this distribution
   79.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   79.34 + * single choice of license, a recipient has the option to distribute
   79.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   79.36 + * to extend the choice of license to its licensees as provided above.
   79.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   79.38 + * Version 2 license, then the option applies only if the new code is
   79.39 + * made subject to such option by the copyright holder.
   79.40 + *
   79.41 + * Contributor(s):
   79.42 + *
   79.43 + * Portions Copyrighted 2009-2010 Sun Microsystems, Inc.
   79.44 + */
   79.45 +
   79.46 +package org.netbeans.modules.java.hints.providers.code;
   79.47 +
   79.48 +import com.sun.source.tree.Tree.Kind;
   79.49 +import java.util.Arrays;
   79.50 +import java.util.Collection;
   79.51 +import java.util.HashSet;
   79.52 +import java.util.Map;
   79.53 +import java.util.Set;
   79.54 +import org.junit.Test;
   79.55 +import org.netbeans.spi.java.hints.ConstraintVariableType;
   79.56 +import org.netbeans.spi.java.hints.Hint;
   79.57 +import org.netbeans.spi.java.hints.TriggerPattern;
   79.58 +import org.netbeans.spi.java.hints.TriggerTreeKind;
   79.59 +import org.netbeans.spi.java.hints.HintContext;
   79.60 +import static org.junit.Assert.*;
   79.61 +import org.netbeans.modules.java.hints.providers.code.CodeHintProviderImpl.WorkerImpl;
   79.62 +import org.netbeans.modules.java.hints.spiimpl.SPIAccessor;
   79.63 +import org.netbeans.modules.java.hints.providers.spi.HintDescription;
   79.64 +import org.netbeans.modules.java.hints.providers.spi.HintMetadata;
   79.65 +import org.netbeans.spi.editor.hints.ErrorDescription;
   79.66 +
   79.67 +/**
   79.68 + *
   79.69 + * @author lahvac
   79.70 + */
   79.71 +@Hint(displayName="foo", description="bar", id="hintPattern", category="general")
   79.72 +public class CodeHintProviderImplTest {
   79.73 +
   79.74 +    public CodeHintProviderImplTest() {
   79.75 +    }
   79.76 +
   79.77 +    @Test
   79.78 +    public void testComputeHints() throws Exception {
   79.79 +        Map<HintMetadata, ? extends Collection<? extends HintDescription>> hints = new CodeHintProviderImpl().computeHints();
   79.80 +
   79.81 +        Set<String> golden = new HashSet<String>(Arrays.asList(
   79.82 +            "$1.toURL():public static org.netbeans.spi.editor.hints.ErrorDescription org.netbeans.modules.java.hints.providers.code.CodeHintProviderImplTest.hintPattern1(org.netbeans.spi.java.hints.HintContext)",
   79.83 +            "[METHOD_INVOCATION]:public static org.netbeans.spi.editor.hints.ErrorDescription org.netbeans.modules.java.hints.providers.code.CodeHintProviderImplTest.hintPattern2(org.netbeans.spi.java.hints.HintContext)"
   79.84 +        ));
   79.85 +
   79.86 +        for (Collection<? extends HintDescription> hds : hints.values()) {
   79.87 +            for (HintDescription d : hds) {
   79.88 +                golden.remove(toString(d));
   79.89 +            }
   79.90 +        }
   79.91 +
   79.92 +        assertTrue(golden.toString(), golden.isEmpty());
   79.93 +    }
   79.94 +
   79.95 +    private static String toString(HintDescription hd) throws Exception {
   79.96 +        StringBuilder sb = new StringBuilder();
   79.97 +
   79.98 +        sb.append(hd.getTrigger());
   79.99 +        sb.append(":");
  79.100 +        
  79.101 +        //TODO: constraints
  79.102 +        sb.append(((WorkerImpl) hd.getWorker()).getMethod().toGenericString());
  79.103 +
  79.104 +        return sb.toString();
  79.105 +    }
  79.106 +
  79.107 +    @TriggerPattern(value="$1.toURL()", constraints=@ConstraintVariableType(variable="$1", type="java.io.File"))
  79.108 +    public static ErrorDescription hintPattern1(HintContext ctx) {
  79.109 +        return null;
  79.110 +    }
  79.111 +
  79.112 +    @TriggerTreeKind(Kind.METHOD_INVOCATION)
  79.113 +    public static ErrorDescription hintPattern2(HintContext ctx) {
  79.114 +        return null;
  79.115 +    }
  79.116 +
  79.117 +}
  79.118 \ No newline at end of file
    80.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    80.2 +++ b/java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/providers/code/FSWrapperTest.java	Wed May 08 21:47:42 2013 +0200
    80.3 @@ -0,0 +1,221 @@
    80.4 +/*
    80.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    80.6 + *
    80.7 + * Copyright 2010 Oracle and/or its affiliates. All rights reserved.
    80.8 + *
    80.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   80.10 + * Other names may be trademarks of their respective owners.
   80.11 + *
   80.12 + * The contents of this file are subject to the terms of either the GNU
   80.13 + * General Public License Version 2 only ("GPL") or the Common
   80.14 + * Development and Distribution License("CDDL") (collectively, the
   80.15 + * "License"). You may not use this file except in compliance with the
   80.16 + * License. You can obtain a copy of the License at
   80.17 + * http://www.netbeans.org/cddl-gplv2.html
   80.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   80.19 + * specific language governing permissions and limitations under the
   80.20 + * License.  When distributing the software, include this License Header
   80.21 + * Notice in each file and include the License file at
   80.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   80.23 + * particular file as subject to the "Classpath" exception as provided
   80.24 + * by Oracle in the GPL Version 2 section of the License file that
   80.25 + * accompanied this code. If applicable, add the following below the
   80.26 + * License Header, with the fields enclosed by brackets [] replaced by
   80.27 + * your own identifying information:
   80.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   80.29 + *
   80.30 + * If you wish your version of this file to be governed by only the CDDL
   80.31 + * or only the GPL Version 2, indicate your decision by adding
   80.32 + * "[Contributor] elects to include this software in this distribution
   80.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   80.34 + * single choice of license, a recipient has the option to distribute
   80.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   80.36 + * to extend the choice of license to its licensees as provided above.
   80.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   80.38 + * Version 2 license, then the option applies only if the new code is
   80.39 + * made subject to such option by the copyright holder.
   80.40 + *
   80.41 + * Contributor(s):
   80.42 + *
   80.43 + * Portions Copyrighted 2010 Sun Microsystems, Inc.
   80.44 + */
   80.45 +
   80.46 +package org.netbeans.modules.java.hints.providers.code;
   80.47 +
   80.48 +import java.lang.annotation.Annotation;
   80.49 +import java.lang.reflect.AnnotatedElement;
   80.50 +import java.lang.reflect.Array;
   80.51 +import java.lang.reflect.Method;
   80.52 +import java.util.ArrayList;
   80.53 +import java.util.LinkedList;
   80.54 +import java.util.List;
   80.55 +import java.util.Map;
   80.56 +import java.util.prefs.Preferences;
   80.57 +import javax.sound.sampled.LineListener;
   80.58 +import javax.swing.JComponent;
   80.59 +import javax.swing.JPanel;
   80.60 +import static org.junit.Assert.assertEquals;
   80.61 +import static org.junit.Assert.assertNotNull;
   80.62 +import static org.junit.Assert.fail;
   80.63 +import org.junit.Test;
   80.64 +import org.netbeans.modules.java.hints.providers.code.FSWrapper.AnnotatableWrapper;
   80.65 +import org.netbeans.modules.java.hints.providers.code.FSWrapper.ClassWrapper;
   80.66 +import org.netbeans.modules.java.hints.providers.code.FSWrapper.MethodWrapper;
   80.67 +import org.netbeans.spi.java.hints.CustomizerProvider;
   80.68 +import org.netbeans.spi.java.hints.Hint;
   80.69 +import org.netbeans.spi.java.hints.HintContext;
   80.70 +import org.netbeans.spi.java.hints.TestAnnotations.TestAnnotation1;
   80.71 +import org.netbeans.spi.java.hints.TestAnnotations.TestAnnotation2;
   80.72 +import org.netbeans.spi.java.hints.TestAnnotations.TestAnnotation3;
   80.73 +import org.netbeans.spi.java.hints.TestAnnotations.TestEnum;
   80.74 +
   80.75 +/**
   80.76 + *
   80.77 + * @author lahvac
   80.78 + */
   80.79 +public class FSWrapperTest {
   80.80 +
   80.81 +    public FSWrapperTest() {
   80.82 +    }
   80.83 +
   80.84 +    @Test
   80.85 +    public void testWrappedClasses() throws Exception {
   80.86 +        Class[] classes = new Class[] {TestClass.class};
   80.87 +        Iterable<? extends ClassWrapper> wrapped = FSWrapper.listClasses();
   80.88 +
   80.89 +        OUTER: for (Class<?> c : classes) {
   80.90 +            for (ClassWrapper w : wrapped) {
   80.91 +                if (w.getName().equals(c.getName())) {
   80.92 +                    checkClassWrapper(c, w);
   80.93 +                    continue OUTER;
   80.94 +                }
   80.95 +            }
   80.96 +
   80.97 +            fail(c.getName());
   80.98 +        }
   80.99 +    }
  80.100 +
  80.101 +    private static void checkClassWrapper(Class<?> c, ClassWrapper cw) throws Exception {
  80.102 +        checkAnnotations(c, cw);
  80.103 +
  80.104 +        OUTER: for (Method m : c.getDeclaredMethods()) {
  80.105 +            if (m.getAnnotations().length == 0) continue;
  80.106 +            
  80.107 +            for (MethodWrapper wrapped : cw.getMethods()) {
  80.108 +                if (wrapped.getName().equals(m.getName())) {
  80.109 +                    assertEquals(m, FSWrapper.resolveMethod(wrapped.getClazz().getName(), wrapped.getName()));
  80.110 +                    checkAnnotations(m, wrapped);
  80.111 +                    continue OUTER;
  80.112 +                }
  80.113 +            }
  80.114 +            
  80.115 +            fail(m.getName());
  80.116 +        }
  80.117 +    }
  80.118 +
  80.119 +    private static void checkAnnotations(AnnotatedElement el, AnnotatableWrapper aw) throws Exception {
  80.120 +        for (Annotation ann : el.getAnnotations()) {
  80.121 +            Annotation wrapper = aw.getAnnotation(ann.annotationType());
  80.122 +
  80.123 +            assertNotNull(ann.annotationType().getName(), wrapper);
  80.124 +
  80.125 +            checkAnnotation(ann, wrapper);
  80.126 +        }
  80.127 +    }
  80.128 +
  80.129 +    private static void checkAnnotation(Annotation real, Annotation wrapped) throws Exception {
  80.130 +        for (Method m : real.annotationType().getDeclaredMethods()) {
  80.131 +            Object realValue = m.invoke(real);
  80.132 +            Object wrappedValue = m.invoke(wrapped);
  80.133 +
  80.134 +            checkValue(realValue, wrappedValue);
  80.135 +        }
  80.136 +    }
  80.137 +
  80.138 +    private static void checkValue(Object o1, Object o2) throws Exception {
  80.139 +        assertEquals(o1.getClass().isAnnotation(), o2.getClass().isAnnotation());
  80.140 +        if (o1.getClass().isAnnotation()) {
  80.141 +            assertEquals(((Annotation) o1).annotationType(), ((Annotation) o2).annotationType());
  80.142 +        } else {
  80.143 +            assertEquals(o1.getClass(), o2.getClass());
  80.144 +        }
  80.145 +
  80.146 +        if (o1.getClass().isArray()) {
  80.147 +            assertEquals(Array.getLength(o1), Array.getLength(o2));
  80.148 +
  80.149 +            for (int c = 0; c < Array.getLength(o1); c++) {
  80.150 +                checkValue(Array.get(o1, c), Array.get(o2, c));
  80.151 +            }
  80.152 +        } else if (o1.getClass().isAnnotation()) {
  80.153 +            checkAnnotation((Annotation) o1, (Annotation) o2);
  80.154 +        } else {
  80.155 +            assertEquals(o1, o2);
  80.156 +        }
  80.157 +    }
  80.158 +
  80.159 +    @Hint(displayName="foo", description="bar", category="")
  80.160 +    @TestAnnotation1(
  80.161 +        b1=true,
  80.162 +        b3=true,
  80.163 +        i1=42,
  80.164 +        i3=84,
  80.165 +        s1="a42",
  80.166 +        s3="a84",
  80.167 +        a1=@TestAnnotation2(a1=@TestAnnotation3(as1={"u1a2", "u1b2"}, as3="u1c2")),
  80.168 +//        a3=@TestAnnotation2(a1=@TestAnnotation3(as1={"u1a2", "u1b2"}, as3="u1c2")),
  80.169 +        c1=String.class,
  80.170 +        c3=String.class,
  80.171 +        e1=TestEnum.C,
  80.172 +        e3=TestEnum.D,
  80.173 +        ab1={false, true},
  80.174 +        ab3={false, true, false},
  80.175 +        ai1={84, 42},
  80.176 +        ai3={84, 42, 84},
  80.177 +        as1={"c42", "c84"},
  80.178 +        as3={"c42", "c84", "c42"},
  80.179 +        aa1={@TestAnnotation2(a1=@TestAnnotation3(as1={"u3a2", "u3b2"}, as3="u3c2")), @TestAnnotation2(a1=@TestAnnotation3(as1={"u4a2", "u4b2"}, as3="u4c2"))},
  80.180 +//        aa3={@TestAnnotation2(a1=@TestAnnotation3(as1={"u5a2", "u5b2"}, as3="u5c2")), @TestAnnotation2(a1=@TestAnnotation3(as1={"u6a2", "u6b2"}, as3="u6c2"))},
  80.181 +        ac1={List.class, Integer.class},
  80.182 +        ac3={LineListener.class, LinkedList.class},
  80.183 +        ae1={TestEnum.C, TestEnum.D},
  80.184 +        ae3={TestEnum.D, TestEnum.C}
  80.185 +    )
  80.186 +    public static class TestClass {
  80.187 +        @TestAnnotation1(
  80.188 +            b1=false,
  80.189 +            b2=true,
  80.190 +            i1=43,
  80.191 +            i2=85,
  80.192 +            s1="w42",
  80.193 +            s2="w84",
  80.194 +            a1=@TestAnnotation2(a1=@TestAnnotation3(as1={"u7a2", "u7b2"}, as3="u7c2")),
  80.195 +//            a2=@TestAnnotation2(a1=@TestAnnotation3(as1={"u8a2", "u8b2"}, as3="u8c2")),
  80.196 +            c1=String.class,
  80.197 +            c2=String.class,
  80.198 +            e1=TestEnum.C,
  80.199 +            e3=TestEnum.D,
  80.200 +            ab1={false, true},
  80.201 +            ab2={false, true, false},
  80.202 +            ai1={85, 43},
  80.203 +            ai2={85, 43, 85},
  80.204 +            as1={"d42", "d84"},
  80.205 +            as2={"e42", "e84", "e42"},
  80.206 +            aa1={@TestAnnotation2(a1=@TestAnnotation3(as1={"u9a2", "u9b2"}, as3="u9c2")), @TestAnnotation2(a1=@TestAnnotation3(as1={"uaa2", "u4b2"}, as3="uac2"))},
  80.207 +//            aa2={@TestAnnotation2(a1=@TestAnnotation3(as1={"uba2", "ubb2"}, as3="ubc2")), @TestAnnotation2(a1=@TestAnnotation3(as1={"uca2", "ucb2"}, as3="ucc2"))},
  80.208 +            ac1={ArrayList.class, Float.class},
  80.209 +            ac2={StringBuilder.class, Map.class},
  80.210 +            ae1={TestEnum.C, TestEnum.D},
  80.211 +            ae3={TestEnum.D, TestEnum.C}
  80.212 +        )
  80.213 +        public static void test(HintContext ctx) {
  80.214 +            
  80.215 +        }
  80.216 +    }
  80.217 +
  80.218 +    public static class CustomizerImpl implements CustomizerProvider {
  80.219 +        @Override public JComponent getCustomizer(Preferences prefs) {
  80.220 +            return new JPanel();
  80.221 +        }
  80.222 +    }
  80.223 +
  80.224 +}
    81.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    81.2 +++ b/java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/providers/code/TestAnnotations.java	Wed May 08 21:47:42 2013 +0200
    81.3 @@ -0,0 +1,109 @@
    81.4 +/*
    81.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    81.6 + *
    81.7 + * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
    81.8 + *
    81.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   81.10 + * Other names may be trademarks of their respective owners.
   81.11 + *
   81.12 + * The contents of this file are subject to the terms of either the GNU
   81.13 + * General Public License Version 2 only ("GPL") or the Common
   81.14 + * Development and Distribution License("CDDL") (collectively, the
   81.15 + * "License"). You may not use this file except in compliance with the
   81.16 + * License. You can obtain a copy of the License at
   81.17 + * http://www.netbeans.org/cddl-gplv2.html
   81.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   81.19 + * specific language governing permissions and limitations under the
   81.20 + * License.  When distributing the software, include this License Header
   81.21 + * Notice in each file and include the License file at
   81.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   81.23 + * particular file as subject to the "Classpath" exception as provided
   81.24 + * by Oracle in the GPL Version 2 section of the License file that
   81.25 + * accompanied this code. If applicable, add the following below the
   81.26 + * License Header, with the fields enclosed by brackets [] replaced by
   81.27 + * your own identifying information:
   81.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   81.29 + *
   81.30 + * If you wish your version of this file to be governed by only the CDDL
   81.31 + * or only the GPL Version 2, indicate your decision by adding
   81.32 + * "[Contributor] elects to include this software in this distribution
   81.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   81.34 + * single choice of license, a recipient has the option to distribute
   81.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   81.36 + * to extend the choice of license to its licensees as provided above.
   81.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   81.38 + * Version 2 license, then the option applies only if the new code is
   81.39 + * made subject to such option by the copyright holder.
   81.40 + *
   81.41 + * Contributor(s):
   81.42 + *
   81.43 + * Portions Copyrighted 2012 Sun Microsystems, Inc.
   81.44 + */
   81.45 +//placed in this package intentionally: the JavaHintsAnnotationProcessor ignores all annotations outside this package
   81.46 +package org.netbeans.spi.java.hints;
   81.47 +
   81.48 +import java.lang.annotation.Retention;
   81.49 +import java.lang.annotation.RetentionPolicy;
   81.50 +
   81.51 +/**
   81.52 + *
   81.53 + * @author lahvac
   81.54 + */
   81.55 +public class TestAnnotations {
   81.56 +    
   81.57 +    @Retention(RetentionPolicy.RUNTIME)
   81.58 +    public @interface TestAnnotation1 {
   81.59 +        public boolean b1();
   81.60 +        public boolean b2() default false;
   81.61 +        public boolean b3() default false;
   81.62 +        public int     i1();
   81.63 +        public int     i2() default 1;
   81.64 +        public int     i3() default 1;
   81.65 +        public String  s1();
   81.66 +        public String  s2() default "";
   81.67 +        public String  s3() default "";
   81.68 +        public TestAnnotation2 a1();
   81.69 +//        public TestAnnotation2 a2() default @TestAnnotation2(a1=@TestAnnotation3(as1={"a", "b"}, as3="c"));
   81.70 +//        public TestAnnotation2 a3() default @TestAnnotation2(a1=@TestAnnotation3(as1={"a2", "b2"}, as3="c2"));
   81.71 +        public Class   c1();
   81.72 +        public Class   c2() default Void.class;
   81.73 +        public Class   c3() default Void.class;
   81.74 +        public TestEnum e1();
   81.75 +//        public TestEnum e2() default TestEnum.A;
   81.76 +        public TestEnum e3()/* default TestEnum.A*/;
   81.77 +        public boolean[] ab1();
   81.78 +        public boolean[] ab2() default false;
   81.79 +        public boolean[] ab3() default false;
   81.80 +        public int[]     ai1();
   81.81 +        public int[]     ai2() default 1;
   81.82 +        public int[]     ai3() default 1;
   81.83 +        public String[]  as1();
   81.84 +        public String[]  as2() default "";
   81.85 +        public String[]  as3() default "";
   81.86 +        public TestAnnotation2[] aa1();
   81.87 +//        public TestAnnotation2[] aa2() default @TestAnnotation2(a1=@TestAnnotation3(as1={"a", "b"}, as3="c"));
   81.88 +//        public TestAnnotation2[] aa3() default @TestAnnotation2(a1=@TestAnnotation3(as1={"a2", "b2"}, as3="c2"));
   81.89 +        public Class[]   ac1();
   81.90 +        public Class[]   ac2() default Void.class;
   81.91 +        public Class[]   ac3() default Void.class;
   81.92 +        public TestEnum[] ae1();
   81.93 +//        public TestEnum[] ae2() default TestEnum.A;
   81.94 +        public TestEnum[] ae3()/* default TestEnum.A*/;
   81.95 +    }
   81.96 +
   81.97 +    public @interface TestAnnotation2 {
   81.98 +        public TestAnnotation3 a1();
   81.99 +//        public TestAnnotation3 a2() default @TestAnnotation3(as1={"d", "e"}, as3="f");
  81.100 +//        public TestAnnotation3 a3() default @TestAnnotation3(as1={"g", "h"}, as3="i");
  81.101 +    }
  81.102 +
  81.103 +    public @interface TestAnnotation3 {
  81.104 +        public String[] as1();
  81.105 +        public String[] as2() default {""};
  81.106 +        public String[] as3() default {""};
  81.107 +    }
  81.108 +
  81.109 +    public enum TestEnum {
  81.110 +        A, B, C, D;
  81.111 +    }
  81.112 +}
    82.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    82.2 +++ b/java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/TestBase.java	Wed May 08 21:47:42 2013 +0200
    82.3 @@ -0,0 +1,124 @@
    82.4 +/*
    82.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    82.6 + *
    82.7 + * Copyright 2008-2010 Oracle and/or its affiliates. All rights reserved.
    82.8 + *
    82.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   82.10 + * Other names may be trademarks of their respective owners.
   82.11 + *
   82.12 + * The contents of this file are subject to the terms of either the GNU
   82.13 + * General Public License Version 2 only ("GPL") or the Common
   82.14 + * Development and Distribution License("CDDL") (collectively, the
   82.15 + * "License"). You may not use this file except in compliance with the
   82.16 + * License. You can obtain a copy of the License at
   82.17 + * http://www.netbeans.org/cddl-gplv2.html
   82.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   82.19 + * specific language governing permissions and limitations under the
   82.20 + * License.  When distributing the software, include this License Header
   82.21 + * Notice in each file and include the License file at
   82.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   82.23 + * particular file as subject to the "Classpath" exception as provided
   82.24 + * by Oracle in the GPL Version 2 section of the License file that
   82.25 + * accompanied this code. If applicable, add the following below the
   82.26 + * License Header, with the fields enclosed by brackets [] replaced by
   82.27 + * your own identifying information:
   82.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   82.29 + *
   82.30 + * If you wish your version of this file to be governed by only the CDDL
   82.31 + * or only the GPL Version 2, indicate your decision by adding
   82.32 + * "[Contributor] elects to include this software in this distribution
   82.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   82.34 + * single choice of license, a recipient has the option to distribute
   82.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   82.36 + * to extend the choice of license to its licensees as provided above.
   82.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   82.38 + * Version 2 license, then the option applies only if the new code is
   82.39 + * made subject to such option by the copyright holder.
   82.40 + *
   82.41 + * Contributor(s):
   82.42 + *
   82.43 + * Portions Copyrighted 2008-2009 Sun Microsystems, Inc.
   82.44 + */
   82.45 +
   82.46 +package org.netbeans.modules.java.hints.spiimpl;
   82.47 +
   82.48 +import java.io.File;
   82.49 +import javax.swing.text.Document;
   82.50 +import org.netbeans.api.java.lexer.JavaTokenId;
   82.51 +import org.netbeans.api.java.source.CompilationInfo;
   82.52 +import org.netbeans.api.java.source.JavaSource;
   82.53 +import org.netbeans.api.java.source.JavaSource.Phase;
   82.54 +import org.netbeans.api.java.source.SourceUtilsTestUtil;
   82.55 +import org.netbeans.api.java.source.TestUtilities;
   82.56 +import org.netbeans.api.lexer.Language;
   82.57 +import org.netbeans.junit.NbTestCase;
   82.58 +import org.netbeans.modules.java.source.TreeLoader;
   82.59 +import org.openide.cookies.EditorCookie;
   82.60 +import org.openide.filesystems.FileObject;
   82.61 +import org.openide.filesystems.FileUtil;
   82.62 +import org.openide.loaders.DataObject;
   82.63 +
   82.64 +/**
   82.65 + *
   82.66 + * @author Jan Lahoda
   82.67 + */
   82.68 +public class TestBase extends NbTestCase {
   82.69 +
   82.70 +    public TestBase(String name) {
   82.71 +        super(name);
   82.72 +    }
   82.73 +
   82.74 +    @Override
   82.75 +    protected void setUp() throws Exception {
   82.76 +        super.setUp();
   82.77 +        SourceUtilsTestUtil.prepareTest(new String[0], new Object[0]);
   82.78 +        TreeLoader.DISABLE_CONFINEMENT_TEST = true;
   82.79 +        clearWorkDir();
   82.80 +
   82.81 +        FileUtil.refreshFor(File.listRoots());
   82.82 +    }
   82.83 +
   82.84 +    private int workDirPart = 0;
   82.85 +    
   82.86 +    protected void prepareTest(String fileName, String code) throws Exception {
   82.87 +        FileObject workFO = FileUtil.createFolder(new File(getWorkDir(), String.valueOf(workDirPart++)));
   82.88 +
   82.89 +        assertNotNull(workFO);
   82.90 +
   82.91 +        workFO.refresh();
   82.92 +
   82.93 +        sourceRoot = workFO.createFolder("src");
   82.94 +        FileObject buildRoot  = workFO.createFolder("build");
   82.95 +        FileObject cache = workFO.createFolder("cache");
   82.96 +
   82.97 +        FileObject data = FileUtil.createData(sourceRoot, fileName);
   82.98 +        File dataFile = FileUtil.toFile(data);
   82.99 +
  82.100 +        assertNotNull(dataFile);
  82.101 +
  82.102 +        TestUtilities.copyStringToFile(dataFile, code);
  82.103 +
  82.104 +        SourceUtilsTestUtil.prepareTest(sourceRoot, buildRoot, cache);
  82.105 +
  82.106 +        DataObject od = DataObject.find(data);
  82.107 +        EditorCookie ec = od.getLookup().lookup(EditorCookie.class);
  82.108 +
  82.109 +        assertNotNull(ec);
  82.110 +
  82.111 +        doc = ec.openDocument();
  82.112 +        doc.putProperty(Language.class, JavaTokenId.language());
  82.113 +
  82.114 +        JavaSource js = JavaSource.forFileObject(data);
  82.115 +
  82.116 +        assertNotNull(js);
  82.117 +
  82.118 +        info = SourceUtilsTestUtil.getCompilationInfo(js, Phase.RESOLVED);
  82.119 +
  82.120 +        assertNotNull(info);
  82.121 +    }
  82.122 +
  82.123 +    protected FileObject sourceRoot;
  82.124 +    protected CompilationInfo info;
  82.125 +    protected Document doc;
  82.126 +
  82.127 +}
    83.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    83.2 +++ b/java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/TestUtilities.java	Wed May 08 21:47:42 2013 +0200
    83.3 @@ -0,0 +1,67 @@
    83.4 +/*
    83.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    83.6 + *
    83.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    83.8 + *
    83.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   83.10 + * Other names may be trademarks of their respective owners.
   83.11 + *
   83.12 + * The contents of this file are subject to the terms of either the GNU
   83.13 + * General Public License Version 2 only ("GPL") or the Common
   83.14 + * Development and Distribution License("CDDL") (collectively, the
   83.15 + * "License"). You may not use this file except in compliance with the
   83.16 + * License. You can obtain a copy of the License at
   83.17 + * http://www.netbeans.org/cddl-gplv2.html
   83.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   83.19 + * specific language governing permissions and limitations under the
   83.20 + * License.  When distributing the software, include this License Header
   83.21 + * Notice in each file and include the License file at
   83.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   83.23 + * particular file as subject to the "Classpath" exception as provided
   83.24 + * by Oracle in the GPL Version 2 section of the License file that
   83.25 + * accompanied this code. If applicable, add the following below the
   83.26 + * License Header, with the fields enclosed by brackets [] replaced by
   83.27 + * your own identifying information:
   83.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   83.29 + *
   83.30 + * Contributor(s):
   83.31 + *
   83.32 + * Portions Copyrighted 2007 Sun Microsystems, Inc.
   83.33 + */
   83.34 +package org.netbeans.modules.java.hints.spiimpl;
   83.35 +
   83.36 +import junit.framework.Assert;
   83.37 +
   83.38 +/**
   83.39 + *
   83.40 + * @author Jan Lahoda
   83.41 + */
   83.42 +public class TestUtilities {
   83.43 +
   83.44 +    private TestUtilities() {
   83.45 +    }
   83.46 +
   83.47 +    public static String detectOffsets(String source, int[] positionOrSpan) {
   83.48 +        return detectOffsets(source, positionOrSpan, "\\|");
   83.49 +    }
   83.50 +
   83.51 +    public static String detectOffsets(String source, int[] positionOrSpan, String delimiter) {
   83.52 +        //for now, the position/span delimiter is '|', without possibility of escaping:
   83.53 +        String[] split = source.split(delimiter);
   83.54 +        
   83.55 +        Assert.assertTrue("incorrect number of position markers (|)", positionOrSpan.length == split.length - 1);
   83.56 +        
   83.57 +        StringBuilder sb = new StringBuilder();
   83.58 +        int index = 0;
   83.59 +        int offset = 0;
   83.60 +        
   83.61 +        for (String s : split) {
   83.62 +            sb.append(s);
   83.63 +            if (index < positionOrSpan.length)
   83.64 +                positionOrSpan[index++] = (offset += s.length());
   83.65 +        }
   83.66 +        
   83.67 +        return sb.toString();
   83.68 +    }
   83.69 +
   83.70 +}
    84.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    84.2 +++ b/java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/UtilitiesTest.java	Wed May 08 21:47:42 2013 +0200
    84.3 @@ -0,0 +1,632 @@
    84.4 +/*
    84.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    84.6 + *
    84.7 + * Copyright 2010 Oracle and/or its affiliates. All rights reserved.
    84.8 + *
    84.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   84.10 + * Other names may be trademarks of their respective owners.
   84.11 + *
   84.12 + * The contents of this file are subject to the terms of either the GNU
   84.13 + * General Public License Version 2 only ("GPL") or the Common
   84.14 + * Development and Distribution License("CDDL") (collectively, the
   84.15 + * "License"). You may not use this file except in compliance with the
   84.16 + * License. You can obtain a copy of the License at
   84.17 + * http://www.netbeans.org/cddl-gplv2.html
   84.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   84.19 + * specific language governing permissions and limitations under the
   84.20 + * License.  When distributing the software, include this License Header
   84.21 + * Notice in each file and include the License file at
   84.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   84.23 + * particular file as subject to the "Classpath" exception as provided
   84.24 + * by Oracle in the GPL Version 2 section of the License file that
   84.25 + * accompanied this code. If applicable, add the following below the
   84.26 + * License Header, with the fields enclosed by brackets [] replaced by
   84.27 + * your own identifying information:
   84.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   84.29 + *
   84.30 + * If you wish your version of this file to be governed by only the CDDL
   84.31 + * or only the GPL Version 2, indicate your decision by adding
   84.32 + * "[Contributor] elects to include this software in this distribution
   84.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   84.34 + * single choice of license, a recipient has the option to distribute
   84.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   84.36 + * to extend the choice of license to its licensees as provided above.
   84.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   84.38 + * Version 2 license, then the option applies only if the new code is
   84.39 + * made subject to such option by the copyright holder.
   84.40 + *
   84.41 + * Contributor(s):
   84.42 + *
   84.43 + * Portions Copyrighted 2009-2010 Sun Microsystems, Inc.
   84.44 + */
   84.45 +
   84.46 +package org.netbeans.modules.java.hints.spiimpl;
   84.47 +
   84.48 +import com.sun.source.tree.IfTree;
   84.49 +import com.sun.source.tree.LambdaExpressionTree;
   84.50 +import com.sun.source.tree.MemberSelectTree;
   84.51 +import com.sun.source.tree.ModifiersTree;
   84.52 +import com.sun.source.tree.Scope;
   84.53 +import com.sun.source.tree.Tree;
   84.54 +import com.sun.source.tree.Tree.Kind;
   84.55 +import com.sun.source.tree.VariableTree;
   84.56 +import com.sun.source.util.SourcePositions;
   84.57 +import com.sun.source.util.TreePath;
   84.58 +import com.sun.source.util.TreeScanner;
   84.59 +import com.sun.tools.javac.tree.JCTree;
   84.60 +import java.util.ArrayList;
   84.61 +import java.util.Arrays;
   84.62 +import java.util.Collection;
   84.63 +import java.util.Collections;
   84.64 +import java.util.LinkedList;
   84.65 +import java.util.List;
   84.66 +import javax.lang.model.element.Element;
   84.67 +import javax.lang.model.element.ElementKind;
   84.68 +import javax.lang.model.type.TypeMirror;
   84.69 +import javax.tools.Diagnostic;
   84.70 +import javax.tools.JavaFileObject;
   84.71 +import org.netbeans.api.java.classpath.ClassPath;
   84.72 +import org.netbeans.api.java.source.ClasspathInfo;
   84.73 +import org.netbeans.api.java.source.CompilationController;
   84.74 +import org.netbeans.api.java.source.JavaSource;
   84.75 +import org.netbeans.api.java.source.JavaSource.Phase;
   84.76 +import org.netbeans.api.java.source.Task;
   84.77 +import org.netbeans.junit.RandomlyFails;
   84.78 +import org.netbeans.modules.java.source.pretty.VeryPretty;
   84.79 +import org.netbeans.modules.java.source.save.DiffContext;
   84.80 +
   84.81 +/**
   84.82 + *
   84.83 + * @author lahvac
   84.84 + */
   84.85 +public class UtilitiesTest extends TestBase {
   84.86 +
   84.87 +    public UtilitiesTest(String name) {
   84.88 +        super(name);
   84.89 +    }
   84.90 +
   84.91 +    public void testParseAndAttributeExpressionStatement() throws Exception {
   84.92 +        prepareTest("test/Test.java", "package test; public class Test{}");
   84.93 +
   84.94 +        Scope s = Utilities.constructScope(info, Collections.singletonMap("$1", info.getTreeUtilities().parseType("int", info.getTopLevelElements().get(0))));
   84.95 +        Tree result = Utilities.parseAndAttribute(info, "$1 = 1;", s);
   84.96 +
   84.97 +        assertTrue(result.getKind().name(), result.getKind() == Kind.EXPRESSION_STATEMENT);
   84.98 +    }
   84.99 +
  84.100 +    public void testParseAndAttributeVariable() throws Exception {
  84.101 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.102 +
  84.103 +        Scope s = Utilities.constructScope(info, Collections.singletonMap("$1", info.getTreeUtilities().parseType("int", info.getTopLevelElements().get(0))));
  84.104 +        Tree result = Utilities.parseAndAttribute(info, "int $2 = $1;", s);
  84.105 +
  84.106 +        assertTrue(result.getKind().name(), result.getKind() == Kind.VARIABLE);
  84.107 +    }
  84.108 +
  84.109 +    public void testParseAndAttributeMultipleStatements() throws Exception {
  84.110 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.111 +
  84.112 +        Scope s = Utilities.constructScope(info, Collections.<String, TypeMirror>emptyMap());
  84.113 +        Tree result = Utilities.parseAndAttribute(info, "String $2 = $1; int $l = $2.length(); System.err.println($l);", s);
  84.114 +
  84.115 +        assertTrue(result.getKind().name(), result.getKind() == Kind.BLOCK);
  84.116 +
  84.117 +        String golden = "{\n" +
  84.118 +                        "    $$1$;\n" +
  84.119 +                        "    String $2 = $1;\n" +
  84.120 +                        "    int $l = $2.length();\n" +
  84.121 +                        "    System.err.println($l);\n" +
  84.122 +                        "    $$2$;\n" +
  84.123 +                        "}";
  84.124 +        assertEquals(golden.replaceAll("[ \n\r]+", " "), result.toString().replaceAll("[ \n\r]+", " "));
  84.125 +    }
  84.126 +
  84.127 +    public void testParseAndAttributeMethod() throws Exception {
  84.128 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.129 +
  84.130 +        Scope s = Utilities.constructScope(info, Collections.singletonMap("$1", info.getTreeUtilities().parseType("int", info.getTopLevelElements().get(0))));
  84.131 +        String methodCode = "private int test(int i) { return i; }";
  84.132 +        Tree result = Utilities.parseAndAttribute(info, methodCode, s);
  84.133 +
  84.134 +        assertEquals(Kind.METHOD, result.getKind());
  84.135 +        assertEquals(methodCode.replaceAll("[ \n\r]+", " "), result.toString().replaceAll("[ \n\r]+", " ").trim());
  84.136 +    }
  84.137 +
  84.138 +    public void testParseAndAttributeMultipleClassMembers() throws Exception {
  84.139 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.140 +
  84.141 +        Scope s = Utilities.constructScope(info, Collections.singletonMap("$1", info.getTreeUtilities().parseType("int", info.getTopLevelElements().get(0))));
  84.142 +        String code = "private int i; private int getI() { return i; } private void setI(int i) { this.i = i; }";
  84.143 +        Tree result = Utilities.parseAndAttribute(info, code, s);
  84.144 +
  84.145 +        String golden = "class $ {\n" +
  84.146 +                        "    $$1$;\n" +
  84.147 +                        "    private int i;\n" +
  84.148 +                        "    private int getI() {\n" +
  84.149 +                        "        return i;\n" +
  84.150 +                        "    }\n" +
  84.151 +                        "    private void setI(int i) {\n" +
  84.152 +                        "        this.i = i;\n" +
  84.153 +                        "    }\n" +
  84.154 +                        "}";
  84.155 +
  84.156 +        assertEquals(golden.replaceAll("[ \n\r]+", " "), result.toString().replaceAll("[ \n\r]+", " ").trim());
  84.157 +    }
  84.158 +
  84.159 +    public void testParseAndAttributeFieldModifiersVariable() throws Exception {
  84.160 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.161 +
  84.162 +        Scope s = Utilities.constructScope(info, Collections.<String, TypeMirror>emptyMap());
  84.163 +        String code = "$mods$ java.lang.String $name;";
  84.164 +        Tree result = Utilities.parseAndAttribute(info, code, s);
  84.165 +
  84.166 +        String golden = "$mods$ java.lang.String $name";
  84.167 +
  84.168 +        assertEquals(golden.replaceAll("[ \n\r]+", " "), result.toString().replaceAll("[ \n\r]+", " ").trim());
  84.169 +    }
  84.170 +
  84.171 +    public void testParseAndAttributeIfWithParenthetised() throws Exception {
  84.172 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.173 +
  84.174 +        Scope s = Utilities.constructScope(info, Collections.<String, TypeMirror>emptyMap());
  84.175 +        String code = "if ($c) { $1$; System.err.println('a'); $2$; }";
  84.176 +        Tree result = Utilities.parseAndAttribute(info, code, s);
  84.177 +
  84.178 +        IfTree it = (IfTree) result;
  84.179 +
  84.180 +        assertEquals(Kind.PARENTHESIZED, it.getCondition().getKind());
  84.181 +
  84.182 +        String golden = "if ($c) { $1$; System.err.println('a'); $2$; }";
  84.183 +
  84.184 +        assertEquals(golden.replaceAll("[ \n\r]+", " "), result.toString().replaceAll("[ \n\r]+", " ").trim());
  84.185 +    }
  84.186 +
  84.187 +    public void testParseAndAttributeMultipleStatements2() throws Exception {
  84.188 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.189 +
  84.190 +        Scope s = Utilities.constructScope(info, Collections.<String, TypeMirror>emptyMap());
  84.191 +        Tree result = Utilities.parseAndAttribute(info, "$type $name = $map.get($key); if ($name == null) { $map.put($key, $name = $init); }", s);
  84.192 +
  84.193 +        assertTrue(result.getKind().name(), result.getKind() == Kind.BLOCK);
  84.194 +
  84.195 +        String golden = "{" +
  84.196 +                        "    $$1$;" +
  84.197 +                        "    $type $name = $map.get($key);" +
  84.198 +                        "    if ($name == null) {" +
  84.199 +                        "        $map.put($key, $name = $init);" +
  84.200 +                        "    }" +
  84.201 +                        "    $$2$;\n" +
  84.202 +                        "}";
  84.203 +        assertEquals(golden.replaceAll("[ \n\r]+", " "), result.toString().replaceAll("[ \n\r]+", " "));
  84.204 +    }
  84.205 +
  84.206 +    public void testParseAndAttributeMethodDeclarationWithMultiparameters() throws Exception {
  84.207 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.208 +
  84.209 +        Scope s = Utilities.constructScope(info, Collections.<String, TypeMirror>emptyMap());
  84.210 +        Tree result = Utilities.parseAndAttribute(info, "public void t($params$) {}", s);
  84.211 +
  84.212 +        assertTrue(result.getKind().name(), result.getKind() == Kind.METHOD);
  84.213 +
  84.214 +        String golden = " public void t($params$) { }";
  84.215 +        assertEquals(golden.replaceAll("[ \n\r]+", " "), result.toString().replaceAll("[ \n\r]+", " "));
  84.216 +    }
  84.217 +
  84.218 +    public void testParseAndAttributeMethodModifiersVariable() throws Exception {
  84.219 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.220 +
  84.221 +        Scope s = Utilities.constructScope(info, Collections.<String, TypeMirror>emptyMap());
  84.222 +        String code = "$mods$ $type $name() { $r$; }";
  84.223 +        Tree result = Utilities.parseAndAttribute(info, code, s);
  84.224 +
  84.225 +        String golden = "$mods$ $type $name() { $r$; }";
  84.226 +
  84.227 +        assertEquals(golden.replaceAll("[ \n\r]+", " "), result.toString().replaceAll("[ \n\r]+", " ").trim());
  84.228 +    }
  84.229 +
  84.230 +    public void testSimpleExpression() throws Exception {
  84.231 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.232 +
  84.233 +        Scope s = Utilities.constructScope(info, Collections.<String, TypeMirror>emptyMap());
  84.234 +        Tree result = Utilities.parseAndAttribute(info, "$1.isDirectory()", s);
  84.235 +
  84.236 +        assertTrue(result.getKind().name(), result.getKind() == Kind.METHOD_INVOCATION);
  84.237 +
  84.238 +        String golden = "$1.isDirectory()";
  84.239 +        assertEquals(golden.replaceAll("[ \n\r]+", " "), result.toString().replaceAll("[ \n\r]+", " "));
  84.240 +    }
  84.241 +    
  84.242 +    public void testARMResourceVariable1() throws Exception {
  84.243 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.244 +
  84.245 +        Scope s = Utilities.constructScope(info, Collections.<String, TypeMirror>emptyMap());
  84.246 +        Tree result = Utilities.parseAndAttribute(info, "try ($t$) { $stmts$; } catch $catches$", s);
  84.247 +
  84.248 +        assertTrue(result.getKind().name(), result.getKind() == Kind.TRY);
  84.249 +
  84.250 +        String golden = "try ($t$) { $stmts$; }$catches$";
  84.251 +        assertEquals(golden.replaceAll("[ \n\r]+", " "), result.toString().replaceAll("[ \n\r]+", " "));
  84.252 +    }
  84.253 +    
  84.254 +    public void testARMResourceVariable2() throws Exception {
  84.255 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.256 +
  84.257 +        Scope s = Utilities.constructScope(info, Collections.<String, TypeMirror>emptyMap());
  84.258 +        Tree result = Utilities.parseAndAttribute(info, "try ($t$; $type $name = $init) { $stmts$; } catch $catches$", s);
  84.259 +
  84.260 +        assertTrue(result.getKind().name(), result.getKind() == Kind.TRY);
  84.261 +
  84.262 +        String golden = "try ($t$ final $type $name = $init;) { $stmts$; }$catches$";
  84.263 +        assertEquals(golden.replaceAll("[ \n\r]+", " "), result.toString().replaceAll("[ \n\r]+", " "));
  84.264 +    }
  84.265 +    
  84.266 +    public void testARMResourceNotVariable() throws Exception {
  84.267 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.268 +
  84.269 +        Scope s = Utilities.constructScope(info, Collections.<String, TypeMirror>emptyMap());
  84.270 +        Tree result = Utilities.parseAndAttribute(info, "try ($t $n = $init$) { $stmts$; } catch $catches$", s);
  84.271 +
  84.272 +        assertTrue(result.getKind().name(), result.getKind() == Kind.TRY);
  84.273 +
  84.274 +        String golden = "try (final $t $n = $init$;) { $stmts$; }$catches$";
  84.275 +        assertEquals(golden.replaceAll("[ \n\r]+", " "), result.toString().replaceAll("[ \n\r]+", " "));
  84.276 +    }
  84.277 +
  84.278 +    public void testParseAndAttributeType() throws Exception {
  84.279 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.280 +
  84.281 +        Scope s = Utilities.constructScope(info, Collections.<String, TypeMirror>emptyMap());
  84.282 +        Tree result = Utilities.parseAndAttribute(info, "\njava. util \n.List \n", s);
  84.283 +
  84.284 +        assertTrue(result.getKind().name(), result.getKind() == Kind.MEMBER_SELECT);
  84.285 +
  84.286 +        assertEquals(ElementKind.INTERFACE, info.getTrees().getElement(new TreePath(new TreePath(info.getCompilationUnit()), result)).getKind());
  84.287 +        assertEquals(info.getElements().getTypeElement("java.util.List"), info.getTrees().getElement(new TreePath(new TreePath(info.getCompilationUnit()), result)));
  84.288 +    }
  84.289 +    
  84.290 +    public void testCatchMultiparam() throws Exception {
  84.291 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.292 +
  84.293 +        Scope s = Utilities.constructScope(info, Collections.<String, TypeMirror>emptyMap());
  84.294 +        Tree result = Utilities.parseAndAttribute(info, "try {\n }\n catch $catch$ finally {\n }\n", s);
  84.295 +
  84.296 +        assertTrue(result.getKind().name(), result.getKind() == Kind.TRY);
  84.297 +
  84.298 +        String golden = "try {\n }$catch$ finally {\n }";
  84.299 +        assertEquals(golden.replaceAll("[ \n\r]+", " "), result.toString().replaceAll("[ \n\r]+", " "));
  84.300 +    }
  84.301 +
  84.302 +    public void testCaseMultiparam() throws Exception {
  84.303 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.304 +
  84.305 +        Scope s = Utilities.constructScope(info, Collections.<String, TypeMirror>emptyMap());
  84.306 +        Tree result = Utilities.parseAndAttribute(info, "switch ($v) {case $c1$ case 1: ; case $c2$; case 3: ;}", s);
  84.307 +
  84.308 +        assertTrue(result.getKind().name(), result.getKind() == Kind.SWITCH);
  84.309 +
  84.310 +        String golden = "switch ($v) { $c1$ case 1: ; $c2$ case 3: ; }";
  84.311 +        assertEquals(golden.replaceAll("[ \n\r]+", " "), result.toString().replaceAll("[ \n\r]+", " "));
  84.312 +    }
  84.313 +    
  84.314 +    public void testOrdinaryCatch() throws Exception {
  84.315 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.316 +
  84.317 +        Scope s = Utilities.constructScope(info, Collections.<String, TypeMirror>emptyMap());
  84.318 +        Tree result = Utilities.parseAndAttribute(info, "try {\n }\n catch (NullPointerException ex) { } finally {\n }\n", s);
  84.319 +
  84.320 +        assertTrue(result.getKind().name(), result.getKind() == Kind.TRY);
  84.321 +
  84.322 +        String golden = "try {\n } catch (NullPointerException ex) { } finally {\n }";
  84.323 +        assertEquals(golden.replaceAll("[ \n\r]+", " "), result.toString().replaceAll("[ \n\r]+", " "));
  84.324 +    }
  84.325 +    
  84.326 +    public void testClassPattern() throws Exception {
  84.327 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.328 +
  84.329 +        Scope s = Utilities.constructScope(info, Collections.<String, TypeMirror>emptyMap());
  84.330 +        Tree result = Utilities.parseAndAttribute(info, "$mods$ class $name extends java.util.LinkedList { $methods$; }\n", s);
  84.331 +
  84.332 +        assertTrue(result.getKind().name(), result.getKind() == Kind.CLASS);
  84.333 +
  84.334 +        String golden = " $mods$ class $name extends java.util.LinkedList { $name() { super(); } $methods$ }";
  84.335 +        assertEquals(golden.replaceAll("[ \n\r]+", " "), result.toString().replaceAll("[ \n\r]+", " "));
  84.336 +    }
  84.337 +
  84.338 +    public void testErrorsForPatterns1() throws Exception {
  84.339 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.340 +
  84.341 +        SourcePositions[] positions = new SourcePositions[1];
  84.342 +        Collection<Diagnostic<? extends JavaFileObject>> errors = new LinkedList<Diagnostic<? extends JavaFileObject>>();
  84.343 +        String code = "foo bar";
  84.344 +        Tree result = Utilities.parseAndAttribute(info, code, null, positions, errors);
  84.345 +
  84.346 +        assertDiagnostics(errors, "7-7:compiler.err.expected");
  84.347 +        assertPositions(result, positions[0], code, "foo", "foo bar");
  84.348 +    }
  84.349 +
  84.350 +    @RandomlyFails
  84.351 +    public void testErrorsForPatterns2() throws Exception {
  84.352 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.353 +
  84.354 +        SourcePositions[] positions = new SourcePositions[1];
  84.355 +        Scope s = Utilities.constructScope(info, Collections.<String, TypeMirror>emptyMap());
  84.356 +        Collection<Diagnostic<? extends JavaFileObject>> errors = new LinkedList<Diagnostic<? extends JavaFileObject>>();
  84.357 +        String code = "$1.isDirectory()";
  84.358 +        Tree result = Utilities.parseAndAttribute(info, code, s, positions, errors);
  84.359 +
  84.360 +        assertDiagnostics(errors, "0-0:compiler.err.cant.resolve.location");
  84.361 +        assertPositions(result, positions[0], code, "$1", "$1.isDirectory", "$1.isDirectory()");
  84.362 +    }
  84.363 +
  84.364 +    public void testErrorsForPatterns3() throws Exception {
  84.365 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.366 +
  84.367 +        SourcePositions[] positions = new SourcePositions[1];
  84.368 +        Collection<Diagnostic<? extends JavaFileObject>> errors = new LinkedList<Diagnostic<? extends JavaFileObject>>();
  84.369 +        String code = "if ($cond) { foo() } else $else;";
  84.370 +        Tree result = Utilities.parseAndAttribute(info, code, null, positions, errors);
  84.371 +
  84.372 +        assertDiagnostics(errors, "18-18:compiler.err.expected");
  84.373 +        assertPositions(result, positions[0], code, "$cond", "$else", "$else;", "($cond)", "foo", "foo()", "foo() ", "if ($cond) { foo() } else $else;", "{ foo() }");
  84.374 +    }
  84.375 +
  84.376 +    public void testPositionsForCorrectStatement() throws Exception {
  84.377 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.378 +
  84.379 +        SourcePositions[] positions = new SourcePositions[1];
  84.380 +        Collection<Diagnostic<? extends JavaFileObject>> errors = new LinkedList<Diagnostic<? extends JavaFileObject>>();
  84.381 +        String code = "assert true;";
  84.382 +        Tree result = Utilities.parseAndAttribute(info, code, null, positions, errors);
  84.383 +
  84.384 +        assertTrue(errors.isEmpty());
  84.385 +        assertPositions(result, positions[0], code, "assert true;", "true");
  84.386 +    }
  84.387 +
  84.388 +    public void testCasePattern() throws Exception {
  84.389 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.390 +
  84.391 +        SourcePositions[] positions = new SourcePositions[1];
  84.392 +        Collection<Diagnostic<? extends JavaFileObject>> errors = new LinkedList<Diagnostic<? extends JavaFileObject>>();
  84.393 +        String code = "case $expr: foo bar $stmts$;\n";
  84.394 +        Tree result = Utilities.parseAndAttribute(info, code, null, positions, errors);
  84.395 +
  84.396 +        assertTrue(result.getKind().name(), result.getKind() == Kind.CASE);
  84.397 +
  84.398 +        String golden = "case $expr: foo bar; $stmts$; ";
  84.399 +        assertEquals(golden.replaceAll("[ \n\r]+", " "), result.toString().replaceAll("[ \n\r]+", " "));
  84.400 +        assertDiagnostics(errors, "19-19:compiler.err.expected");
  84.401 +        assertPositions(result, positions[0], code, "$expr", "$stmts$", "$stmts$;", "case $expr: foo bar $stmts$;", "foo", "foo bar ");
  84.402 +    }
  84.403 +
  84.404 +    public void testLambdaPattern() throws Exception {
  84.405 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.406 +
  84.407 +        Scope s = Utilities.constructScope(info, Collections.<String, TypeMirror>emptyMap());
  84.408 +        Tree result = Utilities.parseAndAttribute(info, "new $type() {\n $mods$ $resultType $methodName($args$) {\n $statements$;\n }\n }\n", s);
  84.409 +
  84.410 +        assertTrue(result.getKind().name(), result.getKind() == Kind.NEW_CLASS);
  84.411 +
  84.412 +        String golden = "new $type(){ $mods$ $resultType $methodName($args$) { $statements$; } }";
  84.413 +        assertEquals(golden.replaceAll("[ \n\r]+", " "), result.toString().replaceAll("[ \n\r]+", " "));
  84.414 +
  84.415 +        Collection<Diagnostic<? extends JavaFileObject>> errors = new LinkedList<Diagnostic<? extends JavaFileObject>>();
  84.416 +
  84.417 +        result = Utilities.parseAndAttribute(info, "new $type() {\n $mods$ $resultType $methodName($args$) {\n $statements$;\n }\n }\n", null, errors);
  84.418 +        assertTrue(result.getKind().name(), result.getKind() == Kind.NEW_CLASS);
  84.419 +
  84.420 +        golden = "new $type(){ $mods$ $resultType $methodName($args$) { $statements$; } }";
  84.421 +        assertEquals(golden.replaceAll("[ \n\r]+", " "), result.toString().replaceAll("[ \n\r]+", " "));
  84.422 +        assertTrue(errors.toString(), errors.isEmpty());
  84.423 +    }
  84.424 +    
  84.425 +    public void testPackagePattern() throws Exception {
  84.426 +        prepareTest("test/a/Test.java", "package test.a; public class Test{}");
  84.427 +
  84.428 +        Scope s = Utilities.constructScope(info, Collections.<String, TypeMirror>emptyMap());
  84.429 +        Tree result = Utilities.parseAndAttribute(info, "test.$1", s);
  84.430 +
  84.431 +        assertTrue(result.getKind().name(), result.getKind() == Kind.MEMBER_SELECT);
  84.432 +
  84.433 +        String golden = "test.$1";
  84.434 +        assertEquals(golden.replaceAll("[ \n\r]+", " "), result.toString().replaceAll("[ \n\r]+", " "));
  84.435 +        
  84.436 +        Element total = info.getTrees().getElement(new TreePath(new TreePath(info.getCompilationUnit()), result));
  84.437 +        
  84.438 +        assertTrue(Utilities.isError(total));
  84.439 +        
  84.440 +        Element testPack = info.getTrees().getElement(new TreePath(new TreePath(info.getCompilationUnit()), ((MemberSelectTree) result).getExpression()));
  84.441 +
  84.442 +        assertFalse(Utilities.isError(testPack));
  84.443 +        assertEquals(info.getElements().getPackageElement("test"), testPack);
  84.444 +    }
  84.445 +
  84.446 +    public void DtestMultiStatementVarWithModifiers() throws Exception {
  84.447 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.448 +
  84.449 +        Scope s = Utilities.constructScope(info, Collections.<String, TypeMirror>emptyMap());
  84.450 +        Tree result = Utilities.parseAndAttribute(info, "$mods$ $type $name; $name = $init;", s);
  84.451 +
  84.452 +        assertTrue(result.getKind().name(), result.getKind() == Kind.BLOCK);
  84.453 +
  84.454 +        String golden = "{ $$1$; $mods$$type $name; $name = $init; $$2$; }";
  84.455 +        assertEquals(golden.replaceAll("[ \n\r]+", " "), result.toString().replaceAll("[ \n\r]+", " "));
  84.456 +    }
  84.457 +
  84.458 +    public void testParseAndAttributeMultipleStatementsWithBefore() throws Exception {
  84.459 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.460 +
  84.461 +        Scope s = Utilities.constructScope(info, Collections.<String, TypeMirror>emptyMap());
  84.462 +        Tree result = Utilities.parseAndAttribute(info, "$before$; String $2 = $1; int $l = $2.length(); System.err.println($l);", s);
  84.463 +
  84.464 +        assertTrue(result.getKind().name(), result.getKind() == Kind.BLOCK);
  84.465 +
  84.466 +        String golden = "{\n" +
  84.467 +                        "    $before$;\n" +
  84.468 +                        "    String $2 = $1;\n" +
  84.469 +                        "    int $l = $2.length();\n" +
  84.470 +                        "    System.err.println($l);\n" +
  84.471 +                        "    $$2$;\n" +
  84.472 +                        "}";
  84.473 +        assertEquals(golden.replaceAll("[ \n\r]+", " "), result.toString().replaceAll("[ \n\r]+", " "));
  84.474 +    }
  84.475 +    
  84.476 +    public void testParseAndAttributeMultipleStatementsWithAfter() throws Exception {
  84.477 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.478 +
  84.479 +        Scope s = Utilities.constructScope(info, Collections.<String, TypeMirror>emptyMap());
  84.480 +        Tree result = Utilities.parseAndAttribute(info, "String $2 = $1; int $l = $2.length(); System.err.println($l); $after$;", s);
  84.481 +
  84.482 +        assertTrue(result.getKind().name(), result.getKind() == Kind.BLOCK);
  84.483 +
  84.484 +        String golden = "{\n" +
  84.485 +                        "    $$1$;\n" +
  84.486 +                        "    String $2 = $1;\n" +
  84.487 +                        "    int $l = $2.length();\n" +
  84.488 +                        "    System.err.println($l);\n" +
  84.489 +                        "    $after$;\n" +
  84.490 +                        "}";
  84.491 +        assertEquals(golden.replaceAll("[ \n\r]+", " "), result.toString().replaceAll("[ \n\r]+", " "));
  84.492 +    }
  84.493 +    
  84.494 +    public void testMethodFormalParams() throws Exception {
  84.495 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.496 +
  84.497 +        Scope s = Utilities.constructScope(info, Collections.<String, TypeMirror>emptyMap());
  84.498 +        Tree result = Utilities.parseAndAttribute(info, "$mods$ $ret $name($pref$, $type $name, $suff$) throws $throws$ { $body$; }", s);
  84.499 +
  84.500 +        assertTrue(result.getKind().name(), result.getKind() == Kind.METHOD);
  84.501 +
  84.502 +        String golden = " $mods$ $ret $name($pref$, $type $name, $suff$) throws $throws$ { $body$; }";
  84.503 +        assertEquals(golden.replaceAll("[ \n\r]+", " "), result.toString().replaceAll("[ \n\r]+", " "));
  84.504 +    }
  84.505 +    
  84.506 +    public void testPartialModifiers() throws Exception {
  84.507 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.508 +
  84.509 +        Scope s = Utilities.constructScope(info, Collections.<String, TypeMirror>emptyMap());
  84.510 +        Tree result = Utilities.parseAndAttribute(info, "$mods$ @Deprecated public $type $name;", s);
  84.511 +
  84.512 +        assertTrue(result.getKind().name(), result.getKind() == Kind.VARIABLE);
  84.513 +
  84.514 +        ModifiersTree mods = ((VariableTree) result).getModifiers();
  84.515 +        String golden = "$mods$,@Deprecated(), [public]";
  84.516 +        
  84.517 +        assertEquals(golden.replaceAll("[ \n\r]+", " "), mods.getAnnotations().toString() + ", " + mods.getFlags().toString());
  84.518 +    }
  84.519 +    
  84.520 +    public void testBrokenPlatform226678() throws Exception {
  84.521 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.522 +
  84.523 +        JavaSource.create(ClasspathInfo.create(ClassPath.EMPTY, ClassPath.EMPTY, ClassPath.EMPTY), info.getFileObject()).runUserActionTask(new Task<CompilationController>() {
  84.524 +            @Override public void run(CompilationController parameter) throws Exception {
  84.525 +                parameter.toPhase(Phase.RESOLVED);
  84.526 +                info = parameter;
  84.527 +            }
  84.528 +        }, true);
  84.529 +        Scope s = Utilities.constructScope(info, Collections.<String, TypeMirror>emptyMap());
  84.530 +        String methodCode = "private int test(int i) { return i; }";
  84.531 +        Tree result = Utilities.parseAndAttribute(info, methodCode, s);
  84.532 +
  84.533 +        assertEquals(Kind.METHOD, result.getKind());
  84.534 +        assertEquals(methodCode.replaceAll("[ \n\r]+", " "), result.toString().replaceAll("[ \n\r]+", " ").trim());
  84.535 +    }
  84.536 +    
  84.537 +    public void testLambdaExpression1() throws Exception {
  84.538 +        prepareTest("test/Test.java", "package test; public class Test{}");
  84.539 +
  84.540 +        Scope s = Utilities.constructScope(info, Collections.<String, TypeMirror>emptyMap());
  84.541 +        Tree result = Utilities.parseAndAttribute(info, "($args$) -> $expression", s);
  84.542 +
  84.543 +        assertTrue(result.getKind().name(), result.getKind() == Kind.LAMBDA_EXPRESSION);
  84.544 +
  84.545 +        LambdaExpressionTree let = (LambdaExpressionTree) result;
  84.546 +        
  84.547 +        assertEquals(Kind.IDENTIFIER, let.getParameters().get(0).getKind());
  84.548 +        String golden = "($args$)->$expression";
  84.549 +        
  84.550 +        assertEquals(golden.replaceAll("[ \n\r]+", " "), result.toString());
  84.551 +    }
  84.552 +    
  84.553 +    public void testToHumanReadableTime() {
  84.554 +        long time = 202;
  84.555 +        assertEquals(    "5s", Utilities.toHumanReadableTime(time +=           5 * 1000));
  84.556 +        assertEquals(  "3m5s", Utilities.toHumanReadableTime(time +=      3 * 60 * 1000));
  84.557 +        assertEquals("7h3m5s", Utilities.toHumanReadableTime(time += 7 * 60 * 60 * 1000));
  84.558 +    }
  84.559 +
  84.560 +    public void testGeneralization() throws Exception {
  84.561 +        performGeneralizationTest("package test;\n" +
  84.562 +                                  "public class Test {\n" +
  84.563 +                                  "    class Inner {\n" +
  84.564 +                                  "        Inner(int i) {}\n" +
  84.565 +                                  "    }\n" +
  84.566 +                                  "    public static void main(String[] args) {\n" +
  84.567 +                                  "        int i = 1;\n" +
  84.568 +                                  "        Test c = null;\n" +
  84.569 +                                  "        c.new Inner(i++) {};\n" +
  84.570 +                                  "    }\n" +
  84.571 +                                  "}\n",
  84.572 +                                  "package test;\n" +
  84.573 +                                  "public class Test {\n" +
  84.574 +                                  "    class Inner {\n" +
  84.575 +                                  "        Inner(int $0) { super(); }\n" +
  84.576 +                                  "    }\n" +
  84.577 +                                  "    public static void main(String[] $1) {\n" +
  84.578 +                                  "        int $2 = 1;\n" +
  84.579 +                                  "        Test $3 = null;\n" +
  84.580 +                                  "        $4;\n" + //XXX
  84.581 +                                  "    }\n" +
  84.582 +                                  "}\n");
  84.583 +    }
  84.584 +    private void performGeneralizationTest(String code, String generalized) throws Exception {
  84.585 +        prepareTest("test/Test.java", code);
  84.586 +
  84.587 +        Tree generalizedTree = Utilities.generalizePattern(info, new TreePath(info.getCompilationUnit()));
  84.588 +        VeryPretty vp = new VeryPretty(new DiffContext(info));
  84.589 +
  84.590 +        vp.print((JCTree) generalizedTree);
  84.591 +
  84.592 +        String repr = vp.toString();
  84.593 +
  84.594 +        assertEquals(generalized.replaceAll("[ \n\t]+", " "),
  84.595 +                     repr.replaceAll("[ \n\t]+", " "));
  84.596 +    }
  84.597 +
  84.598 +    private void assertDiagnostics(Collection<Diagnostic<? extends JavaFileObject>> errors, String... golden) {
  84.599 +        List<String> actual = new ArrayList<String>(errors.size());
  84.600 +
  84.601 +        for (Diagnostic<? extends JavaFileObject> d : errors) {
  84.602 +            actual.add(d.getStartPosition() + "-" + d.getEndPosition() + ":" + d.getCode());
  84.603 +        }
  84.604 +
  84.605 +        assertEquals(Arrays.asList(golden), actual);
  84.606 +    }
  84.607 +
  84.608 +    private void assertPositions(Tree t, final SourcePositions sp, final String code, String... golden) {
  84.609 +        final List<String> actual = new ArrayList<String>(golden.length);
  84.610 +
  84.611 +        new TreeScanner<Void, Void>() {
  84.612 +            @Override
  84.613 +            public Void scan(Tree node, Void p) {
  84.614 +                if (node != null) {
  84.615 +                    int start = (int) sp.getStartPosition(null, node);
  84.616 +                    int end = (int) sp.getEndPosition(null, node);
  84.617 +
  84.618 +                    if (start >= 0 && end >= 0) {
  84.619 +                        actual.add(code.substring(start, end));
  84.620 +                    }
  84.621 +                }
  84.622 +                return super.scan(node, p);
  84.623 +            }
  84.624 +        }.scan(t, null);
  84.625 +
  84.626 +        Collections.sort(actual);
  84.627 +
  84.628 +        List<String> goldenList = new ArrayList<String>(Arrays.asList(golden));
  84.629 +
  84.630 +        Collections.sort(goldenList);
  84.631 +
  84.632 +        assertEquals(goldenList, actual);
  84.633 +    }
  84.634 +
  84.635 +}
    85.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    85.2 +++ b/java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/batch/BatchSearchTest.java	Wed May 08 21:47:42 2013 +0200
    85.3 @@ -0,0 +1,458 @@
    85.4 +/*
    85.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    85.6 + *
    85.7 + * Copyright 2009-2011 Oracle and/or its affiliates. All rights reserved.
    85.8 + *
    85.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   85.10 + * Other names may be trademarks of their respective owners.
   85.11 + *
   85.12 + * The contents of this file are subject to the terms of either the GNU
   85.13 + * General Public License Version 2 only ("GPL") or the Common
   85.14 + * Development and Distribution License("CDDL") (collectively, the
   85.15 + * "License"). You may not use this file except in compliance with the
   85.16 + * License. You can obtain a copy of the License at
   85.17 + * http://www.netbeans.org/cddl-gplv2.html
   85.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   85.19 + * specific language governing permissions and limitations under the
   85.20 + * License.  When distributing the software, include this License Header
   85.21 + * Notice in each file and include the License file at
   85.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   85.23 + * particular file as subject to the "Classpath" exception as provided
   85.24 + * by Oracle in the GPL Version 2 section of the License file that
   85.25 + * accompanied this code. If applicable, add the following below the
   85.26 + * License Header, with the fields enclosed by brackets [] replaced by
   85.27 + * your own identifying information:
   85.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   85.29 + *
   85.30 + * If you wish your version of this file to be governed by only the CDDL
   85.31 + * or only the GPL Version 2, indicate your decision by adding
   85.32 + * "[Contributor] elects to include this software in this distribution
   85.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   85.34 + * single choice of license, a recipient has the option to distribute
   85.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   85.36 + * to extend the choice of license to its licensees as provided above.
   85.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   85.38 + * Version 2 license, then the option applies only if the new code is
   85.39 + * made subject to such option by the copyright holder.
   85.40 + *
   85.41 + * Contributor(s):
   85.42 + *
   85.43 + * Portions Copyrighted 2009-2011 Sun Microsystems, Inc.
   85.44 + */
   85.45 +package org.netbeans.modules.java.hints.spiimpl.batch;
   85.46 +
   85.47 +import org.netbeans.modules.java.hints.spiimpl.batch.TestUtils.File;
   85.48 +import org.netbeans.modules.java.hints.spiimpl.MessageImpl;
   85.49 +import org.netbeans.modules.java.hints.providers.spi.HintDescription;
   85.50 +import java.net.URL;
   85.51 +import java.util.ArrayList;
   85.52 +import java.util.Arrays;
   85.53 +import java.util.Collection;
   85.54 +import java.util.Collections;
   85.55 +import java.util.HashMap;
   85.56 +import java.util.HashSet;
   85.57 +import java.util.Iterator;
   85.58 +import java.util.LinkedList;
   85.59 +import java.util.List;
   85.60 +import java.util.Map;
   85.61 +import java.util.Map.Entry;
   85.62 +import java.util.Set;
   85.63 +import java.util.concurrent.atomic.AtomicBoolean;
   85.64 +import java.util.regex.Pattern;
   85.65 +import junit.framework.TestSuite;
   85.66 +import org.netbeans.api.java.classpath.ClassPath;
   85.67 +import org.netbeans.api.java.classpath.GlobalPathRegistry;
   85.68 +import org.netbeans.api.java.classpath.GlobalPathRegistryEvent;
   85.69 +import org.netbeans.api.java.classpath.GlobalPathRegistryListener;
   85.70 +import org.netbeans.api.java.source.CompilationController;
   85.71 +import org.netbeans.api.java.source.SourceUtilsTestUtil;
   85.72 +import org.netbeans.core.startup.Main;
   85.73 +import org.netbeans.junit.NbTestCase;
   85.74 +import org.netbeans.junit.NbTestSuite;
   85.75 +import org.netbeans.junit.RandomlyFails;
   85.76 +import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.BatchResult;
   85.77 +import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.Folder;
   85.78 +import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.Resource;
   85.79 +import org.netbeans.modules.parsing.impl.indexing.CacheFolder;
   85.80 +import org.netbeans.modules.parsing.impl.indexing.MimeTypes;
   85.81 +import org.netbeans.modules.parsing.impl.indexing.RepositoryUpdater;
   85.82 +import org.netbeans.spi.editor.hints.ErrorDescription;
   85.83 +import org.netbeans.spi.java.classpath.ClassPathProvider;
   85.84 +import org.netbeans.spi.java.classpath.support.ClassPathSupport;
   85.85 +import org.openide.filesystems.FileObject;
   85.86 +import org.openide.filesystems.FileStateInvalidException;
   85.87 +import org.openide.filesystems.FileUtil;
   85.88 +
   85.89 +import org.openide.util.Exceptions;
   85.90 +import org.openide.util.lookup.ServiceProvider;
   85.91 +import static org.netbeans.modules.java.hints.spiimpl.batch.TestUtils.writeFilesAndWaitForScan;
   85.92 +import static org.netbeans.modules.java.hints.spiimpl.batch.TestUtils.prepareHints;
   85.93 +
   85.94 +/**
   85.95 + *
   85.96 + * @author lahvac
   85.97 + */
   85.98 +public class BatchSearchTest extends NbTestCase {
   85.99 +
  85.100 +    public BatchSearchTest(String name) {
  85.101 +        super(name);
  85.102 +    }
  85.103 +
  85.104 +    public static TestSuite suite() {
  85.105 +        TestSuite result = new NbTestSuite();
  85.106 +
  85.107 +        result.addTestSuite(BatchSearchTest.class);
  85.108 +//        result.addTest(new BatchSearchTest("testBatchSearchFolderRemoteIndex"));
  85.109 +
  85.110 +        return result;
  85.111 +    }
  85.112 +
  85.113 +    //XXX: copied from CustomIndexerImplTest:
  85.114 +    @Override
  85.115 +    protected void setUp() throws Exception {
  85.116 +        SourceUtilsTestUtil.prepareTest(new String[0], new Object[0]);
  85.117 +        Main.initializeURLFactory();
  85.118 +        org.netbeans.api.project.ui.OpenProjects.getDefault().getOpenProjects();
  85.119 +        prepareTest();
  85.120 +        MimeTypes.setAllMimeTypes(Collections.singleton("text/x-java"));
  85.121 +        sourceCP = ClassPathSupport.createClassPath(src1, src2);
  85.122 +        GlobalPathRegistry.getDefault().register(ClassPath.SOURCE, new ClassPath[] {sourceCP});
  85.123 +        RepositoryUpdater.getDefault().start(true);
  85.124 +        super.setUp();
  85.125 +    }
  85.126 +
  85.127 +    @Override
  85.128 +    protected void tearDown() throws Exception {
  85.129 +        super.tearDown();
  85.130 +        GlobalPathRegistry.getDefault().unregister(ClassPath.SOURCE, new ClassPath[] {sourceCP});
  85.131 +    }
  85.132 +
  85.133 +    public void testBatchSearch1() throws Exception {
  85.134 +        writeFilesAndWaitForScan(src1,
  85.135 +                                 new File("test/Test1.java", "package test; public class Test1 { private void test() { java.io.File f = null; f.isDirectory(); } }"),
  85.136 +                                 new File("test/Test2.java", "package test; public class Test2 { private void test() { new javax.swing.ImageIcon(null); } }"));
  85.137 +        writeFilesAndWaitForScan(src2,
  85.138 +                                 new File("test/Test1.java", "package test; public class Test1 { private void test() { java.io.File f = null; f.isDirectory(); } }"),
  85.139 +                                 new File("test/Test2.java", "package test; public class Test2 { private void test() { new javax.swing.ImageIcon(null); } }"));
  85.140 +
  85.141 +        Iterable<? extends HintDescription> hints = prepareHints("$1.isDirectory()");
  85.142 +        BatchResult result = BatchSearch.findOccurrences(hints, Scopes.allOpenedProjectsScope());
  85.143 +        Map<String, Iterable<String>> output = new HashMap<String, Iterable<String>>();
  85.144 +
  85.145 +        for (Entry<FileObject, Collection<? extends Resource>> e : result.getResourcesWithRoots().entrySet()) {
  85.146 +            Collection<String> resourcesRepr = new LinkedList<String>();
  85.147 +
  85.148 +            for (Resource r : e.getValue()) {
  85.149 +                resourcesRepr.add(r.getRelativePath());
  85.150 +            }
  85.151 +
  85.152 +            output.put(e.getKey().getURL().toExternalForm(), resourcesRepr);
  85.153 +        }
  85.154 +
  85.155 +        Map<String, Iterable<String>> golden = new HashMap<String, Iterable<String>>();
  85.156 +
  85.157 +        golden.put(src1.getURL().toExternalForm(), Arrays.asList("test/Test1.java"));
  85.158 +        golden.put(src2.getURL().toExternalForm(), Arrays.asList("test/Test1.java"));
  85.159 +
  85.160 +        assertEquals(golden, output);
  85.161 +    }
  85.162 +
  85.163 +    public void testBatchSearchSpan() throws Exception {
  85.164 +        String code = "package test;\n" +
  85.165 +                      "public class Test {\n" +
  85.166 +                      "    private void m() {\n" +
  85.167 +                      "        a(c.i().getFileObject());\n" +
  85.168 +                      "        if (span != null && span[0] != (-1) && span[1] != (-1));\n" +
  85.169 +                      "        c.i().getFileObject(\"\");\n" +
  85.170 +                      "    }\n" +
  85.171 +                      "}\n";
  85.172 +
  85.173 +        writeFilesAndWaitForScan(src1, new File("test/Test.java", code));
  85.174 +
  85.175 +        Iterable<? extends HintDescription> hints = prepareHints("$0.getFileObject($1)");
  85.176 +        BatchResult result = BatchSearch.findOccurrences(hints, Scopes.allOpenedProjectsScope());
  85.177 +
  85.178 +        assertEquals(1, result.getResources().size());
  85.179 +        Iterator<? extends Resource> resources = result.getResources().iterator().next().iterator();
  85.180 +        Resource r = resources.next();
  85.181 +
  85.182 +        assertFalse(resources.hasNext());
  85.183 +
  85.184 +        Set<String> snipets = new HashSet<String>();
  85.185 +
  85.186 +        for (int[] span : r.getCandidateSpans()) {
  85.187 +            snipets.add(code.substring(span[0], span[1]));
  85.188 +        }
  85.189 +
  85.190 +        Set<String> golden = new HashSet<String>(Arrays.asList("c.i().getFileObject(\"\")"));
  85.191 +        assertEquals(golden, snipets);
  85.192 +    }
  85.193 +
  85.194 +    @RandomlyFails
  85.195 +    public void testBatchSearchNotIndexed() throws Exception {
  85.196 +        writeFilesAndWaitForScan(src1,
  85.197 +                                 new File("test/Test1.java", "package test; public class Test1 { private void test() { java.io.File f = null; f.isDirectory(); } }"),
  85.198 +                                 new File("test/Test2.java", "package test; public class Test2 { private void test() { new javax.swing.ImageIcon(null); } }"));
  85.199 +        writeFilesAndWaitForScan(src3,
  85.200 +                                 new File("test/Test1.java", "package test; public class Test1 { private void test() { Test2 f = null; f.isDirectory(); } }"),
  85.201 +                                 new File("test/Test2.java", "package test; public class Test2 { public boolean isDirectory() {return false} }"));
  85.202 +
  85.203 +        Iterable<? extends HintDescription> hints = prepareHints("$1.isDirectory()", "$1", "test.Test2");
  85.204 +        BatchResult result = BatchSearch.findOccurrences(hints, Scopes.specifiedFoldersScope(Folder.convert(src1, src3, empty)));
  85.205 +        Map<String, Iterable<String>> output = new HashMap<String, Iterable<String>>();
  85.206 +
  85.207 +        for (Entry<FileObject, Collection<? extends Resource>> e : result.getResourcesWithRoots().entrySet()) {
  85.208 +            Collection<String> resourcesRepr = new LinkedList<String>();
  85.209 +
  85.210 +            for (Resource r : e.getValue()) {
  85.211 +                resourcesRepr.add(r.getRelativePath());
  85.212 +            }
  85.213 +
  85.214 +            output.put(e.getKey().getURL().toExternalForm(), resourcesRepr);
  85.215 +        }
  85.216 +
  85.217 +        Map<String, Iterable<String>> golden = new HashMap<String, Iterable<String>>();
  85.218 +
  85.219 +        golden.put(src1.getURL().toExternalForm(), Arrays.asList("test/Test1.java"));
  85.220 +        golden.put(src3.getURL().toExternalForm(), Arrays.asList("test/Test1.java"));
  85.221 +
  85.222 +        assertEquals(golden, output);
  85.223 +
  85.224 +        //check verification:
  85.225 +        Map<String, Map<String, Iterable<String>>> verifiedOutput = verifiedSpans(result, false);
  85.226 +        Map<String, Map<String, Iterable<String>>> verifiedGolden = new HashMap<String, Map<String, Iterable<String>>>();
  85.227 +
  85.228 +        verifiedGolden.put(src1.getURL().toExternalForm(), Collections.<String, Iterable<String>>singletonMap("test/Test1.java", Arrays.<String>asList()));
  85.229 +        verifiedGolden.put(src3.getURL().toExternalForm(), Collections.<String, Iterable<String>>singletonMap("test/Test1.java", Arrays.asList("0:75-0:86:verifier:")));
  85.230 +
  85.231 +        assertEquals(verifiedGolden, verifiedOutput);
  85.232 +    }
  85.233 +
  85.234 +    public void testBatchSearchForceIndexingOfProperDirectory() throws Exception {
  85.235 +        FileObject data = FileUtil.createFolder(workdir, "data");
  85.236 +        FileObject dataSrc1 = FileUtil.createFolder(data, "src1");
  85.237 +        FileObject dataSrc2 = FileUtil.createFolder(data, "src2");
  85.238 +        writeFilesAndWaitForScan(dataSrc1,
  85.239 +                                 new File("test/Test1.java", "package test; public class Test1 { private void test() { java.io.File f = null; f.isDirectory(); } }"),
  85.240 +                                 new File("test/Test2.java", "package test; public class Test2 { private void test() { new javax.swing.ImageIcon(null); } }"));
  85.241 +        writeFilesAndWaitForScan(dataSrc2,
  85.242 +                                 new File("test/Test1.java", "package test; public class Test1 { private void test() { Test2 f = null; f.isDirectory(); } }"),
  85.243 +                                 new File("test/Test2.java", "package test; public class Test2 { public boolean isDirectory() {return false} }"));
  85.244 +
  85.245 +        ClassPathProviderImpl.setSourceRoots(Arrays.asList(dataSrc1, dataSrc2));
  85.246 +
  85.247 +        Iterable<? extends HintDescription> hints = prepareHints("$1.isDirectory()", "$1", "test.Test2");
  85.248 +        BatchResult result = BatchSearch.findOccurrences(hints, Scopes.specifiedFoldersScope(Folder.convert(data)));
  85.249 +        Map<String, Iterable<String>> output = new HashMap<String, Iterable<String>>();
  85.250 +
  85.251 +        for (Entry<FileObject, Collection<? extends Resource>> e : result.getResourcesWithRoots().entrySet()) {
  85.252 +            Collection<String> resourcesRepr = new HashSet<String>();
  85.253 +
  85.254 +            for (Resource r : e.getValue()) {
  85.255 +                resourcesRepr.add(r.getRelativePath());
  85.256 +            }
  85.257 +
  85.258 +            output.put(e.getKey().getURL().toExternalForm(), resourcesRepr);
  85.259 +        }
  85.260 +
  85.261 +        Map<String, Iterable<String>> golden = new HashMap<String, Iterable<String>>();
  85.262 +
  85.263 +        golden.put(data.getURL().toExternalForm(), new HashSet<String>(Arrays.asList("src1/test/Test1.java", "src2/test/Test1.java")));
  85.264 +
  85.265 +        assertEquals(golden, output);
  85.266 +
  85.267 +        //check verification:
  85.268 +        final Set<FileObject> added = new HashSet<FileObject>();
  85.269 +        final Set<FileObject> removed = new HashSet<FileObject>();
  85.270 +
  85.271 +        GlobalPathRegistry.getDefault().addGlobalPathRegistryListener(new GlobalPathRegistryListener() {
  85.272 +            public void pathsAdded(GlobalPathRegistryEvent event) {
  85.273 +                for (ClassPath cp : event.getChangedPaths()) {
  85.274 +                    added.addAll(Arrays.asList(cp.getRoots()));
  85.275 +                }
  85.276 +            }
  85.277 +            public void pathsRemoved(GlobalPathRegistryEvent event) {
  85.278 +                for (ClassPath cp : event.getChangedPaths()) {
  85.279 +                    removed.addAll(Arrays.asList(cp.getRoots()));
  85.280 +                }
  85.281 +            }
  85.282 +        });
  85.283 +
  85.284 +//        verifiedGolden.put(data.getURL().toExternalForm(), Arrays.asList("0:75-0:86:verifier:TODO: No display name"));
  85.285 +        Map<String, Map<String, Iterable<String>>> verifiedOutput = verifiedSpans(result, false);
  85.286 +        Map<String, Map<String, Iterable<String>>> verifiedGolden = new HashMap<String, Map<String, Iterable<String>>>();
  85.287 +
  85.288 +        Map<String, Iterable<String>> verifiedGoldenPart = new HashMap<String, Iterable<String>>();
  85.289 +
  85.290 +        verifiedGoldenPart.put("src1/test/Test1.java", Arrays.<String>asList());
  85.291 +        verifiedGoldenPart.put("src2/test/Test1.java", Arrays.<String>asList("0:75-0:86:verifier:"));
  85.292 +
  85.293 +        verifiedGolden.put(data.getURL().toExternalForm(), verifiedGoldenPart);
  85.294 +
  85.295 +        assertEquals(verifiedGolden, verifiedOutput);
  85.296 +        assertEquals(new HashSet<FileObject>(Arrays.asList(dataSrc1, dataSrc2)), added);
  85.297 +        assertEquals(new HashSet<FileObject>(Arrays.asList(dataSrc1, dataSrc2)), removed);
  85.298 +    }
  85.299 +
  85.300 +    public void testBatchSearchFolderNoIndex() throws Exception {
  85.301 +        FileObject data = FileUtil.createFolder(workdir, "data");
  85.302 +        FileObject dataSrc1 = FileUtil.createFolder(data, "src1");
  85.303 +        FileObject dataSrc2 = FileUtil.createFolder(data, "src2");
  85.304 +        writeFilesAndWaitForScan(dataSrc1,
  85.305 +                                 new File("test/Test1.java", "package test; public class Test1 { private void test() { java.io.File f = null; f.isDirectory(); } }"),
  85.306 +                                 new File("test/Test2.java", "package test; public class Test2 { private void test() { new javax.swing.ImageIcon(null); } }"));
  85.307 +        writeFilesAndWaitForScan(dataSrc2,
  85.308 +                                 new File("test/Test1.java", "package test; public class Test1 { private void test() { Test2 f = null; f.isDirectory(); } }"),
  85.309 +                                 new File("test/Test2.java", "package test; public class Test2 { public boolean isDirectory() {return false} }"));
  85.310 +
  85.311 +        Iterable<? extends HintDescription> hints = prepareHints("$1.isDirectory()");
  85.312 +        BatchResult result = BatchSearch.findOccurrences(hints, Scopes.specifiedFoldersScope(Folder.convert(Collections.singleton(data)))); //XXX: should be a no-index variant!
  85.313 +        Map<String, Iterable<String>> output = toDebugOutput(result);
  85.314 +        Map<String, Iterable<String>> golden = new HashMap<String, Iterable<String>>();
  85.315 +
  85.316 +        golden.put(data.getURL().toExternalForm(), new HashSet<String>(Arrays.asList("src1/test/Test1.java", "src2/test/Test1.java")));
  85.317 +
  85.318 +        assertEquals(golden, output);
  85.319 +    }
  85.320 +
  85.321 +    private FileObject workdir;
  85.322 +    private FileObject src1;
  85.323 +    private FileObject src2;
  85.324 +    private FileObject src3;
  85.325 +    private FileObject empty;
  85.326 +    private ClassPath sourceCP;
  85.327 +
  85.328 +    private void prepareTest() throws Exception {
  85.329 +        workdir = SourceUtilsTestUtil.makeScratchDir(this);
  85.330 +
  85.331 +        src1 = FileUtil.createFolder(workdir, "src1");
  85.332 +        src2 = FileUtil.createFolder(workdir, "src2");
  85.333 +        src3 = FileUtil.createFolder(workdir, "src3");
  85.334 +        empty = FileUtil.createFolder(workdir, "empty");
  85.335 +
  85.336 +        ClassPathProviderImpl.setSourceRoots(Arrays.asList(src1, src2, src3));
  85.337 +
  85.338 +        FileObject cache = FileUtil.createFolder(workdir, "cache");
  85.339 +
  85.340 +        CacheFolder.setCacheFolder(cache);
  85.341 +    }
  85.342 +
  85.343 +    private Map<String, Iterable<String>> toDebugOutput(BatchResult result) throws Exception {
  85.344 +        Map<String, Iterable<String>> output = new HashMap<String, Iterable<String>>();
  85.345 +
  85.346 +        for (Entry<FileObject, Collection<? extends Resource>> e : result.getResourcesWithRoots().entrySet()) {
  85.347 +            Collection<String> resourcesRepr = new HashSet<String>();
  85.348 +
  85.349 +            for (Resource r : e.getValue()) {
  85.350 +                resourcesRepr.add(r.getRelativePath());
  85.351 +            }
  85.352 +
  85.353 +            output.put(e.getKey().getURL().toExternalForm(), resourcesRepr);
  85.354 +        }
  85.355 +
  85.356 +        return output;
  85.357 +    }
  85.358 +
  85.359 +    private Map<String, Map<String, Iterable<String>>> verifiedSpans(BatchResult candidates, boolean doNotRegisterClassPath) throws Exception {
  85.360 +        final Map<String, Map<String, Iterable<String>>> result = new HashMap<String, Map<String, Iterable<String>>>();
  85.361 +        List<MessageImpl> errors = new LinkedList<MessageImpl>();
  85.362 +        BatchSearch.getVerifiedSpans(candidates, new ProgressHandleWrapper(1), new BatchSearch.VerifiedSpansCallBack() {
  85.363 +            public void groupStarted() {}
  85.364 +            public boolean spansVerified(CompilationController wc, Resource r, Collection<? extends ErrorDescription> hints) throws Exception {
  85.365 +                Map<String, Iterable<String>> files = result.get(r.getRoot().getURL().toExternalForm());
  85.366 +
  85.367 +                if (files == null) {
  85.368 +                    result.put(r.getRoot().getURL().toExternalForm(), files = new HashMap<String, Iterable<String>>());
  85.369 +                }
  85.370 +
  85.371 +                Collection<String> currentHints = new LinkedList<String>();
  85.372 +
  85.373 +                for (ErrorDescription ed : hints) {
  85.374 +                    currentHints.add(ed.toString());
  85.375 +                }
  85.376 +
  85.377 +                files.put(r.getRelativePath(), currentHints);
  85.378 +
  85.379 +                return true;
  85.380 +            }
  85.381 +            public void groupFinished() {}
  85.382 +            public void cannotVerifySpan(Resource r) {
  85.383 +                fail("Cannot verify: " +r.getRelativePath());
  85.384 +            }
  85.385 +        }, doNotRegisterClassPath, errors, new AtomicBoolean());
  85.386 +
  85.387 +        return result;
  85.388 +    }
  85.389 +
  85.390 +    @ServiceProvider(service=ClassPathProvider.class)
  85.391 +    public static final class ClassPathProviderImpl implements ClassPathProvider {
  85.392 +
  85.393 +        private static Collection<FileObject> sourceRoots;
  85.394 +
  85.395 +        public synchronized static void setSourceRoots(Collection<FileObject> sourceRoots) {
  85.396 +            ClassPathProviderImpl.sourceRoots = sourceRoots;
  85.397 +        }
  85.398 +
  85.399 +        public synchronized static Collection<FileObject> getSourceRoots() {
  85.400 +            return sourceRoots;
  85.401 +        }
  85.402 +
  85.403 +        public synchronized ClassPath findClassPath(FileObject file, String type) {
  85.404 +            if (ClassPath.BOOT.equals(type)) {
  85.405 +                return ClassPathSupport.createClassPath(getBootClassPath().toArray(new URL[0]));
  85.406 +            }
  85.407 +
  85.408 +            if (ClassPath.COMPILE.equals(type)) {
  85.409 +                return ClassPathSupport.createClassPath(new URL[0]);
  85.410 +            }
  85.411 +
  85.412 +            if (ClassPath.SOURCE.equals(type) && sourceRoots != null) {
  85.413 +                for (FileObject sr : sourceRoots) {
  85.414 +                    if (file.equals(sr) || FileUtil.isParentOf(sr, file)) {
  85.415 +                        return ClassPathSupport.createClassPath(sr);
  85.416 +                    }
  85.417 +                }
  85.418 +            }
  85.419 +
  85.420 +            return null;
  85.421 +        }
  85.422 +
  85.423 +    }
  85.424 +
  85.425 +    //TODO: copied from SourceUtilsTestUtil:
  85.426 +    private static List<URL> bootClassPath;
  85.427 +
  85.428 +    public static synchronized List<URL> getBootClassPath() {
  85.429 +        if (bootClassPath == null) {
  85.430 +            try {
  85.431 +                String cp = System.getProperty("sun.boot.class.path");
  85.432 +                List<URL> urls = new ArrayList<URL>();
  85.433 +                String[] paths = cp.split(Pattern.quote(System.getProperty("path.separator")));
  85.434 +
  85.435 +                for (String path : paths) {
  85.436 +                    java.io.File f = new java.io.File(path);
  85.437 +
  85.438 +                    if (!f.canRead())
  85.439 +                        continue;
  85.440 +
  85.441 +                    FileObject fo = FileUtil.toFileObject(f);
  85.442 +
  85.443 +                    if (FileUtil.isArchiveFile(fo)) {
  85.444 +                        fo = FileUtil.getArchiveRoot(fo);
  85.445 +                    }
  85.446 +
  85.447 +                    if (fo != null) {
  85.448 +                        urls.add(fo.getURL());
  85.449 +                    }
  85.450 +                }
  85.451 +
  85.452 +                bootClassPath = urls;
  85.453 +            } catch (FileStateInvalidException e) {
  85.454 +                Exceptions.printStackTrace(e);
  85.455 +            }
  85.456 +        }
  85.457 +
  85.458 +        return bootClassPath;
  85.459 +    }
  85.460 +
  85.461 +}
    86.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    86.2 +++ b/java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/batch/BatchUtilitiesTest.java	Wed May 08 21:47:42 2013 +0200
    86.3 @@ -0,0 +1,222 @@
    86.4 +/*
    86.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    86.6 + *
    86.7 + * Copyright 2009-2011 Oracle and/or its affiliates. All rights reserved.
    86.8 + *
    86.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   86.10 + * Other names may be trademarks of their respective owners.
   86.11 + *
   86.12 + * The contents of this file are subject to the terms of either the GNU
   86.13 + * General Public License Version 2 only ("GPL") or the Common
   86.14 + * Development and Distribution License("CDDL") (collectively, the
   86.15 + * "License"). You may not use this file except in compliance with the
   86.16 + * License. You can obtain a copy of the License at
   86.17 + * http://www.netbeans.org/cddl-gplv2.html
   86.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   86.19 + * specific language governing permissions and limitations under the
   86.20 + * License.  When distributing the software, include this License Header
   86.21 + * Notice in each file and include the License file at
   86.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   86.23 + * particular file as subject to the "Classpath" exception as provided
   86.24 + * by Oracle in the GPL Version 2 section of the License file that
   86.25 + * accompanied this code. If applicable, add the following below the
   86.26 + * License Header, with the fields enclosed by brackets [] replaced by
   86.27 + * your own identifying information:
   86.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   86.29 + *
   86.30 + * If you wish your version of this file to be governed by only the CDDL
   86.31 + * or only the GPL Version 2, indicate your decision by adding
   86.32 + * "[Contributor] elects to include this software in this distribution
   86.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   86.34 + * single choice of license, a recipient has the option to distribute
   86.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   86.36 + * to extend the choice of license to its licensees as provided above.
   86.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   86.38 + * Version 2 license, then the option applies only if the new code is
   86.39 + * made subject to such option by the copyright holder.
   86.40 + *
   86.41 + * Contributor(s):
   86.42 + *
   86.43 + * Portions Copyrighted 2009-2011 Sun Microsystems, Inc.
   86.44 + */
   86.45 +package org.netbeans.modules.java.hints.spiimpl.batch;
   86.46 +
   86.47 +import org.netbeans.modules.java.hints.spiimpl.batch.TestUtils.File;
   86.48 +import org.netbeans.modules.java.hints.spiimpl.MessageImpl;
   86.49 +import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearchTest.ClassPathProviderImpl;
   86.50 +import org.netbeans.modules.java.hints.providers.spi.HintDescription;
   86.51 +import java.util.Arrays;
   86.52 +import java.util.Collection;
   86.53 +import java.util.Collections;
   86.54 +import java.util.HashMap;
   86.55 +import java.util.LinkedList;
   86.56 +import java.util.List;
   86.57 +import java.util.Map;
   86.58 +import java.util.concurrent.atomic.AtomicBoolean;
   86.59 +import org.netbeans.api.editor.mimelookup.MimePath;
   86.60 +import org.netbeans.api.java.classpath.ClassPath;
   86.61 +import org.netbeans.api.java.classpath.GlobalPathRegistry;
   86.62 +import org.netbeans.api.java.lexer.JavaTokenId;
   86.63 +import org.netbeans.api.java.source.ModificationResult;
   86.64 +import org.netbeans.api.java.source.SourceUtilsTestUtil;
   86.65 +import org.netbeans.api.java.source.TestUtilities;
   86.66 +import org.netbeans.api.lexer.InputAttributes;
   86.67 +import org.netbeans.api.lexer.Language;
   86.68 +import org.netbeans.api.lexer.LanguagePath;
   86.69 +import org.netbeans.api.lexer.Token;
   86.70 +import org.netbeans.core.startup.Main;
   86.71 +import org.netbeans.junit.NbTestCase;
   86.72 +import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.BatchResult;
   86.73 +import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.Folder;
   86.74 +import org.netbeans.modules.java.source.parsing.JavacParser;
   86.75 +import org.netbeans.modules.parsing.impl.indexing.CacheFolder;
   86.76 +import org.netbeans.modules.parsing.impl.indexing.RepositoryUpdater;
   86.77 +import org.netbeans.spi.editor.mimelookup.MimeDataProvider;
   86.78 +import org.netbeans.spi.java.classpath.support.ClassPathSupport;
   86.79 +import org.netbeans.spi.lexer.LanguageEmbedding;
   86.80 +import org.netbeans.spi.lexer.LanguageProvider;
   86.81 +import org.openide.LifecycleManager;
   86.82 +import org.openide.filesystems.FileObject;
   86.83 +import org.openide.filesystems.FileUtil;
   86.84 +
   86.85 +import org.openide.loaders.DataObject;
   86.86 +import org.openide.util.Lookup;
   86.87 +import org.openide.util.lookup.Lookups;
   86.88 +import org.openide.util.lookup.ServiceProvider;
   86.89 +import static org.netbeans.modules.java.hints.spiimpl.batch.TestUtils.writeFilesAndWaitForScan;
   86.90 +import static org.netbeans.modules.java.hints.spiimpl.batch.TestUtils.prepareHints;
   86.91 +import org.netbeans.modules.parsing.impl.indexing.MimeTypes;
   86.92 +
   86.93 +/**
   86.94 + *
   86.95 + * @author lahvac
   86.96 + */
   86.97 +public class BatchUtilitiesTest extends NbTestCase {
   86.98 +
   86.99 +    public BatchUtilitiesTest(String name) {
  86.100 +        super(name);
  86.101 +    }
  86.102 +
  86.103 +    //XXX: copied from CustomIndexerImplTest:
  86.104 +    @Override
  86.105 +    protected void setUp() throws Exception {
  86.106 +        SourceUtilsTestUtil.prepareTest(new String[] {"org/netbeans/modules/java/source/resources/layer.xml", "org/netbeans/lib/java/lexer/layer.xml"}, new Object[0]);
  86.107 +        Main.initializeURLFactory();
  86.108 +        org.netbeans.api.project.ui.OpenProjects.getDefault().getOpenProjects();
  86.109 +        prepareTest();
  86.110 +        MimeTypes.setAllMimeTypes(Collections.singleton("text/x-java"));
  86.111 +        GlobalPathRegistry.getDefault().register(ClassPath.SOURCE, new ClassPath[] {ClassPathSupport.createClassPath(src1, src2)});
  86.112 +        RepositoryUpdater.getDefault().start(true);
  86.113 +        super.setUp();
  86.114 +    }
  86.115 +
  86.116 +    public void testBatchSearchNotIndexed() throws Exception {
  86.117 +        writeFilesAndWaitForScan(src1,
  86.118 +                                 new File("test/Test1.java", "package test; public class Test1 { private void test() { java.io.File f = null; f.isDirectory(); } }"),
  86.119 +                                 new File("test/Test2.java", "package test; public class Test2 { private void test() { new javax.swing.ImageIcon(null); } }"));
  86.120 +        writeFilesAndWaitForScan(src3,
  86.121 +                                 new File("test/Test1.java", "package test; public class Test1 { private void test() { java.io.File f = null; f.isDirectory(); } }"),
  86.122 +                                 new File("test/Test2.java", "package test; public class Test2 { public boolean isDirectory() {return false} }"));
  86.123 +
  86.124 +        Iterable<? extends HintDescription> hints = prepareHints("$1.isDirectory() => !$1.isFile()", "$1", "java.io.File");
  86.125 +        BatchResult result = BatchSearch.findOccurrences(hints, Scopes.specifiedFoldersScope(Folder.convert(src1, src3, empty)));
  86.126 +        List<MessageImpl> problems = new LinkedList<MessageImpl>();
  86.127 +        Collection<? extends ModificationResult> changes = BatchUtilities.applyFixes(result, new ProgressHandleWrapper(100), new AtomicBoolean(), problems);
  86.128 +
  86.129 +        assertTrue(problems.toString(), problems.isEmpty());
  86.130 +
  86.131 +        Map<FileObject, String> file2New = new HashMap<FileObject, String>();
  86.132 +
  86.133 +        for (ModificationResult mr : changes) {
  86.134 +            for (FileObject file : mr.getModifiedFileObjects()) {
  86.135 +                assertNull(file2New.put(file, mr.getResultingSource(file)));
  86.136 +            }
  86.137 +        }
  86.138 +
  86.139 +        FileObject src1Test1 = src1.getFileObject("test/Test1.java");
  86.140 +        String src1Test1Real = file2New.remove(src1Test1);
  86.141 +        String src1Test1Golden = "package test; public class Test1 { private void test() { java.io.File f = null; !f.isFile(); } }";
  86.142 +
  86.143 +        assertEquals(src1Test1Golden, src1Test1Real);
  86.144 +
  86.145 +        FileObject src3Test1 = src3.getFileObject("test/Test1.java");
  86.146 +        String src3Test1Real = file2New.remove(src3Test1);
  86.147 +        String src3Test1Golden = "package test; public class Test1 { private void test() { java.io.File f = null; !f.isFile(); } }";
  86.148 +
  86.149 +        assertEquals(src3Test1Golden, src3Test1Real);
  86.150 +
  86.151 +        assertTrue(file2New.toString(), file2New.isEmpty());
  86.152 +    }
  86.153 +
  86.154 +//    public void testRemoveUnusedImports() throws Exception {
  86.155 +//        writeFilesAndWaitForScan(src1,
  86.156 +//                                 new File("test/Test1.java", "package test;\n import java.util.List;\n public class Test1 { }"));
  86.157 +//        writeFilesAndWaitForScan(src2,
  86.158 +//                                 new File("test/Test2.java", "package test;\n import java.util.LinkedList;\n public class Test2 { }"));
  86.159 +//
  86.160 +//        FileObject test1 = src1.getFileObject("test/Test1.java");
  86.161 +//        FileObject test2 = src2.getFileObject("test/Test2.java");
  86.162 +//
  86.163 +//        System.err.println(DataObject.find(test1).getClass());
  86.164 +//        BatchUtilities.removeUnusedImports(Arrays.asList(test1, test2));
  86.165 +//
  86.166 +//        LifecycleManager.getDefault().saveAll();
  86.167 +//
  86.168 +//        assertEquals("package test;\n public class Test1 { }", TestUtilities.copyFileToString(FileUtil.toFile(test1)));
  86.169 +//        assertEquals("package test;\n public class Test2 { }", TestUtilities.copyFileToString(FileUtil.toFile(test2)));
  86.170 +//    }
  86.171 +
  86.172 +    private FileObject src1;
  86.173 +    private FileObject src2;
  86.174 +    private FileObject src3;
  86.175 +    private FileObject empty;
  86.176 +
  86.177 +    private void prepareTest() throws Exception {
  86.178 +        FileObject workdir = SourceUtilsTestUtil.makeScratchDir(this);
  86.179 +
  86.180 +        src1 = FileUtil.createFolder(workdir, "src1");
  86.181 +        src2 = FileUtil.createFolder(workdir, "src2");
  86.182 +        src3 = FileUtil.createFolder(workdir, "src3");
  86.183 +        empty = FileUtil.createFolder(workdir, "empty");
  86.184 +
  86.185 +        ClassPathProviderImpl.setSourceRoots(Arrays.asList(src1, src2, src3));
  86.186 +
  86.187 +        FileObject cache = FileUtil.createFolder(workdir, "cache");
  86.188 +
  86.189 +        CacheFolder.setCacheFolder(cache);
  86.190 +    }
  86.191 +
  86.192 +    @ServiceProvider(service=MimeDataProvider.class)
  86.193 +    public static final class JavaLexerProvider implements MimeDataProvider {
  86.194 +
  86.195 +        private Lookup javaLookup = Lookups.fixed(JavaTokenId.language());
  86.196 +
  86.197 +        public Lookup getLookup(MimePath mimePath) {
  86.198 +            if (mimePath.getPath().endsWith(JavacParser.MIME_TYPE)) {
  86.199 +                return javaLookup;
  86.200 +            }
  86.201 +
  86.202 +            return Lookup.EMPTY;
  86.203 +        }
  86.204 +
  86.205 +    }
  86.206 +
  86.207 +    @ServiceProvider(service=LanguageProvider.class)
  86.208 +    public static final class JavaLanguageProvider extends LanguageProvider {
  86.209 +
  86.210 +        @Override
  86.211 +        public Language<?> findLanguage(String mimeType) {
  86.212 +            if ("text/x-java".equals(mimeType)) {
  86.213 +                return JavaTokenId.language();
  86.214 +            }
  86.215 +
  86.216 +            return null;
  86.217 +        }
  86.218 +
  86.219 +        @Override
  86.220 +        public LanguageEmbedding<?> findLanguageEmbedding(Token<?> token, LanguagePath languagePath, InputAttributes inputAttributes) {
  86.221 +            return null;
  86.222 +        }
  86.223 +
  86.224 +    }
  86.225 +}
    87.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    87.2 +++ b/java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/batch/ProgressHandleWrapperTest.java	Wed May 08 21:47:42 2013 +0200
    87.3 @@ -0,0 +1,66 @@
    87.4 +/*
    87.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    87.6 + *
    87.7 + * Copyright 2009-2011 Oracle and/or its affiliates. All rights reserved.
    87.8 + *
    87.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   87.10 + * Other names may be trademarks of their respective owners.
   87.11 + *
   87.12 + * The contents of this file are subject to the terms of either the GNU
   87.13 + * General Public License Version 2 only ("GPL") or the Common
   87.14 + * Development and Distribution License("CDDL") (collectively, the
   87.15 + * "License"). You may not use this file except in compliance with the
   87.16 + * License. You can obtain a copy of the License at
   87.17 + * http://www.netbeans.org/cddl-gplv2.html
   87.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   87.19 + * specific language governing permissions and limitations under the
   87.20 + * License.  When distributing the software, include this License Header
   87.21 + * Notice in each file and include the License file at
   87.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   87.23 + * particular file as subject to the "Classpath" exception as provided
   87.24 + * by Oracle in the GPL Version 2 section of the License file that
   87.25 + * accompanied this code. If applicable, add the following below the
   87.26 + * License Header, with the fields enclosed by brackets [] replaced by
   87.27 + * your own identifying information:
   87.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   87.29 + *
   87.30 + * If you wish your version of this file to be governed by only the CDDL
   87.31 + * or only the GPL Version 2, indicate your decision by adding
   87.32 + * "[Contributor] elects to include this software in this distribution
   87.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   87.34 + * single choice of license, a recipient has the option to distribute
   87.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   87.36 + * to extend the choice of license to its licensees as provided above.
   87.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   87.38 + * Version 2 license, then the option applies only if the new code is
   87.39 + * made subject to such option by the copyright holder.
   87.40 + *
   87.41 + * Contributor(s):
   87.42 + *
   87.43 + * Portions Copyrighted 2009-2011 Sun Microsystems, Inc.
   87.44 + */
   87.45 +package org.netbeans.modules.java.hints.spiimpl.batch;
   87.46 +
   87.47 +import org.netbeans.junit.NbTestCase;
   87.48 +
   87.49 +/**
   87.50 + *
   87.51 + * @author lahvac
   87.52 + */
   87.53 +public class ProgressHandleWrapperTest extends NbTestCase {
   87.54 +
   87.55 +    public ProgressHandleWrapperTest(String name) {
   87.56 +        super(name);
   87.57 +    }
   87.58 +
   87.59 +    public void testNoProgress() {
   87.60 +        ProgressHandleWrapper w = new ProgressHandleWrapper(new ProgressHandleWrapper.ProgressHandleAbstraction() {
   87.61 +            public void start(int totalWork) {}
   87.62 +            public void progress(int currentWorkDone) {}
   87.63 +            public void progress(String message) {}
   87.64 +            public void finish() {}
   87.65 +        }, 1);
   87.66 +        
   87.67 +        w.finish();
   87.68 +    }
   87.69 +}
    88.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    88.2 +++ b/java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/batch/TestUtils.java	Wed May 08 21:47:42 2013 +0200
    88.3 @@ -0,0 +1,135 @@
    88.4 +/*
    88.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    88.6 + *
    88.7 + * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
    88.8 + *
    88.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   88.10 + * Other names may be trademarks of their respective owners.
   88.11 + *
   88.12 + * The contents of this file are subject to the terms of either the GNU
   88.13 + * General Public License Version 2 only ("GPL") or the Common
   88.14 + * Development and Distribution License("CDDL") (collectively, the
   88.15 + * "License"). You may not use this file except in compliance with the
   88.16 + * License. You can obtain a copy of the License at
   88.17 + * http://www.netbeans.org/cddl-gplv2.html
   88.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   88.19 + * specific language governing permissions and limitations under the
   88.20 + * License.  When distributing the software, include this License Header
   88.21 + * Notice in each file and include the License file at
   88.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   88.23 + * particular file as subject to the "Classpath" exception as provided
   88.24 + * by Oracle in the GPL Version 2 section of the License file that
   88.25 + * accompanied this code. If applicable, add the following below the
   88.26 + * License Header, with the fields enclosed by brackets [] replaced by
   88.27 + * your own identifying information:
   88.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   88.29 + *
   88.30 + * If you wish your version of this file to be governed by only the CDDL
   88.31 + * or only the GPL Version 2, indicate your decision by adding
   88.32 + * "[Contributor] elects to include this software in this distribution
   88.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   88.34 + * single choice of license, a recipient has the option to distribute
   88.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   88.36 + * to extend the choice of license to its licensees as provided above.
   88.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   88.38 + * Version 2 license, then the option applies only if the new code is
   88.39 + * made subject to such option by the copyright holder.
   88.40 + *
   88.41 + * Contributor(s):
   88.42 + *
   88.43 + * Portions Copyrighted 2011 Sun Microsystems, Inc.
   88.44 + */
   88.45 +package org.netbeans.modules.java.hints.spiimpl.batch;
   88.46 +
   88.47 +import java.util.Collection;
   88.48 +import java.util.Collections;
   88.49 +import org.netbeans.spi.java.hints.HintContext;
   88.50 +import org.netbeans.modules.java.hints.providers.spi.HintDescription.Worker;
   88.51 +import org.netbeans.modules.java.hints.providers.spi.Trigger.PatternDescription;
   88.52 +import org.netbeans.spi.java.hints.ErrorDescriptionFactory;
   88.53 +import org.netbeans.spi.editor.hints.ErrorDescription;
   88.54 +import org.netbeans.modules.java.hints.providers.spi.HintDescriptionFactory;
   88.55 +import java.util.HashMap;
   88.56 +import java.util.Map;
   88.57 +import org.netbeans.api.java.source.SourceUtils;
   88.58 +import org.netbeans.api.java.source.TestUtilities;
   88.59 +import org.netbeans.modules.java.hints.providers.spi.HintDescription;
   88.60 +import org.openide.filesystems.FileObject;
   88.61 +import org.openide.filesystems.FileUtil;
   88.62 +
   88.63 +import static org.junit.Assert.*;
   88.64 +import org.netbeans.spi.java.hints.JavaFixUtilities;
   88.65 +
   88.66 +/**
   88.67 + *
   88.68 + * @author lahvac
   88.69 + */
   88.70 +public class TestUtils {
   88.71 +
   88.72 +    public static void writeFiles(FileObject sourceRoot, File... files) throws Exception {
   88.73 +        for (FileObject c : sourceRoot.getChildren()) {
   88.74 +            c.delete();
   88.75 +        }
   88.76 +
   88.77 +        for (File f : files) {
   88.78 +            FileObject fo = FileUtil.createData(sourceRoot, f.filename);
   88.79 +            TestUtilities.copyStringToFile(fo, f.content);
   88.80 +        }
   88.81 +    }
   88.82 +
   88.83 +    public static void writeFilesAndWaitForScan(FileObject sourceRoot, File... files) throws Exception {
   88.84 +        writeFiles(sourceRoot, files);
   88.85 +        SourceUtils.waitScanFinished();
   88.86 +    }
   88.87 +    
   88.88 +    public static final class File {
   88.89 +        public final String filename;
   88.90 +        public final String content;
   88.91 +        public final boolean index;
   88.92 +
   88.93 +        public File(String filename, String content) {
   88.94 +            this(filename, content, true);
   88.95 +        }
   88.96 +
   88.97 +        public File(String filename, String content, boolean index) {
   88.98 +            this.filename = filename;
   88.99 +            this.content = content;
  88.100 +            this.index = index;
  88.101 +        }
  88.102 +    }
  88.103 +
  88.104 +    public static Iterable<? extends HintDescription> prepareHints(String rule, String... constraints) {
  88.105 +        final String[] split = rule.split("=>");
  88.106 +
  88.107 +        Worker w;
  88.108 +
  88.109 +        if (split.length == 2) {
  88.110 +            w = new HintDescription.Worker() {
  88.111 +                @Override public Collection<? extends ErrorDescription> createErrors(HintContext ctx) {
  88.112 +                    return Collections.singletonList(ErrorDescriptionFactory.forName(ctx, ctx.getPath(), "", JavaFixUtilities.rewriteFix(ctx, "", ctx.getPath(), split[1])));
  88.113 +                }
  88.114 +            };
  88.115 +        } else {
  88.116 +            w = new HintDescription.Worker() {
  88.117 +                @Override public Collection<? extends ErrorDescription> createErrors(HintContext ctx) {
  88.118 +                    return Collections.singletonList(ErrorDescriptionFactory.forName(ctx, ctx.getPath(), ""));
  88.119 +                }
  88.120 +            };
  88.121 +        }
  88.122 +
  88.123 +        assertTrue(constraints.length % 2 == 0);
  88.124 +
  88.125 +        Map<String, String> constr = new HashMap<String, String>();
  88.126 +
  88.127 +        for (int i = 0; i < constraints.length; i += 2) {
  88.128 +            constr.put(constraints[i], constraints[i + 1]);
  88.129 +        }
  88.130 +
  88.131 +        HintDescription hd = HintDescriptionFactory.create()
  88.132 +                                                   .setTrigger(PatternDescription.create(split[0], constr))
  88.133 +                                                   .setWorker(w)
  88.134 +                                                   .produce();
  88.135 +
  88.136 +        return Collections.singletonList(hd);
  88.137 +    }
  88.138 +}
    89.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    89.2 +++ b/java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/hints/HintsInvokerTest.java	Wed May 08 21:47:42 2013 +0200
    89.3 @@ -0,0 +1,895 @@
    89.4 +/*
    89.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    89.6 + *
    89.7 + * Copyright 2009-2010 Oracle and/or its affiliates. All rights reserved.
    89.8 + *
    89.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   89.10 + * Other names may be trademarks of their respective owners.
   89.11 + *
   89.12 + * The contents of this file are subject to the terms of either the GNU
   89.13 + * General Public License Version 2 only ("GPL") or the Common
   89.14 + * Development and Distribution License("CDDL") (collectively, the
   89.15 + * "License"). You may not use this file except in compliance with the
   89.16 + * License. You can obtain a copy of the License at
   89.17 + * http://www.netbeans.org/cddl-gplv2.html
   89.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   89.19 + * specific language governing permissions and limitations under the
   89.20 + * License.  When distributing the software, include this License Header
   89.21 + * Notice in each file and include the License file at
   89.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   89.23 + * particular file as subject to the "Classpath" exception as provided
   89.24 + * by Oracle in the GPL Version 2 section of the License file that
   89.25 + * accompanied this code. If applicable, add the following below the
   89.26 + * License Header, with the fields enclosed by brackets [] replaced by
   89.27 + * your own identifying information:
   89.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   89.29 + *
   89.30 + * If you wish your version of this file to be governed by only the CDDL
   89.31 + * or only the GPL Version 2, indicate your decision by adding
   89.32 + * "[Contributor] elects to include this software in this distribution
   89.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   89.34 + * single choice of license, a recipient has the option to distribute
   89.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   89.36 + * to extend the choice of license to its licensees as provided above.
   89.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   89.38 + * Version 2 license, then the option applies only if the new code is
   89.39 + * made subject to such option by the copyright holder.
   89.40 + *
   89.41 + * Contributor(s):
   89.42 + *
   89.43 + * Portions Copyrighted 2009-2010 Sun Microsystems, Inc.
   89.44 + */
   89.45 +
   89.46 +package org.netbeans.modules.java.hints.spiimpl.hints;
   89.47 +
   89.48 +import com.sun.source.tree.Tree.Kind;
   89.49 +import com.sun.source.util.TreePath;
   89.50 +import java.util.Arrays;
   89.51 +import java.util.Collection;
   89.52 +import java.util.Collections;
   89.53 +import java.util.EnumSet;
   89.54 +import java.util.HashMap;
   89.55 +import java.util.LinkedList;
   89.56 +import java.util.List;
   89.57 +import java.util.Map;
   89.58 +import java.util.concurrent.atomic.AtomicBoolean;
   89.59 +import javax.swing.text.Document;
   89.60 +import static org.junit.Assert.*;
   89.61 +import org.netbeans.api.java.source.CompilationInfo;
   89.62 +import org.netbeans.modules.java.hints.spiimpl.TestBase;
   89.63 +import org.netbeans.spi.java.hints.HintContext;
   89.64 +import org.netbeans.modules.java.hints.providers.spi.HintDescription;
   89.65 +import org.netbeans.modules.java.hints.providers.spi.HintDescription.Worker;
   89.66 +import org.netbeans.modules.java.hints.providers.spi.HintDescriptionFactory;
   89.67 +import org.netbeans.modules.java.hints.providers.spi.HintMetadata;
   89.68 +import org.netbeans.modules.java.hints.providers.spi.HintMetadata.Options;
   89.69 +import org.netbeans.modules.java.hints.providers.spi.Trigger.Kinds;
   89.70 +import org.netbeans.modules.java.hints.providers.spi.Trigger.PatternDescription;
   89.71 +import org.netbeans.modules.java.hints.spiimpl.options.HintsSettings;
   89.72 +import org.netbeans.spi.java.hints.ErrorDescriptionFactory;
   89.73 +import org.netbeans.spi.editor.hints.ErrorDescription;
   89.74 +import org.netbeans.spi.editor.hints.Fix;
   89.75 +import org.netbeans.spi.java.hints.JavaFixUtilities;
   89.76 +import org.openide.LifecycleManager;
   89.77 +import org.openide.cookies.EditorCookie;
   89.78 +import org.openide.filesystems.FileObject;
   89.79 +import org.openide.loaders.DataObject;
   89.80 +
   89.81 +/**
   89.82 + *
   89.83 + * @author user
   89.84 + */
   89.85 +public class HintsInvokerTest extends TestBase {
   89.86 +
   89.87 +    public HintsInvokerTest(String name) {
   89.88 +        super(name);
   89.89 +    }
   89.90 +
   89.91 +//    public static TestSuite suite() {
   89.92 +//        NbTestSuite r = new NbTestSuite();
   89.93 +//        r.addTest(new HintsInvokerTest("testPatternVariable1"));
   89.94 +//        return r;
   89.95 +//    }
   89.96 +
   89.97 +    public void testPattern1() throws Exception {
   89.98 +        performAnalysisTest("test/Test.java",
   89.99 +                            "|package test;\n" +
  89.100 +                            "import java.io.File;\n" +
  89.101 +                            "public class Test {\n" +
  89.102 +                            "     private void test(File f) {\n" +
  89.103 +                            "         f.toURL();\n" +
  89.104 +                            "     }\n" +
  89.105 +                            "}\n",
  89.106 +                            "4:11-4:16:verifier:HINT");
  89.107 +    }
  89.108 +
  89.109 +    public void testPattern2() throws Exception {
  89.110 +        performAnalysisTest("test/Test.java",
  89.111 +                            "|package test;\n" +
  89.112 +                            "\n" +
  89.113 +                            "public class Test {\n" +
  89.114 +                            "     private void test(java.io.File f) {\n" +
  89.115 +                            "         f.toURL();\n" +
  89.116 +                            "     }\n" +
  89.117 +                            "}\n",
  89.118 +                            "4:11-4:16:verifier:HINT");
  89.119 +    }
  89.120 +
  89.121 +    public void testKind1() throws Exception {
  89.122 +        performAnalysisTest("test/Test.java",
  89.123 +                            "|package test;\n" +
  89.124 +                            "\n" +
  89.125 +                            "public class Test {\n" +
  89.126 +                            "     private void test(java.io.File f) {\n" +
  89.127 +                            "         f.toURL();\n" +
  89.128 +                            "     }\n" +
  89.129 +                            "}\n",
  89.130 +                            "4:11-4:16:verifier:HINT");
  89.131 +    }
  89.132 +
  89.133 +    public void testPatternVariable1() throws Exception {
  89.134 +        performFixTest("test/Test.java",
  89.135 +                       "|package test;\n" +
  89.136 +                       "\n" +
  89.137 +                       "public class Test {\n" +
  89.138 +                       "     private void test() {\n" +
  89.139 +                       "         {\n" +
  89.140 +                       "             int y;\n" +
  89.141 +                       "             y = 1;\n" +
  89.142 +                       "         }\n" +
  89.143 +                       "         int z;\n" +
  89.144 +                       "         {\n" +
  89.145 +                       "             int y;\n" +
  89.146 +                       "             z = 1;\n" +
  89.147 +                       "         }\n" +
  89.148 +                       "     }\n" +
  89.149 +                       "}\n",
  89.150 +                       "4:9-7:10:verifier:HINT",
  89.151 +                       "FixImpl",
  89.152 +                       "package test; public class Test { private void test() { { int y = 1; } int z; { int y; z = 1; } } } ");
  89.153 +    }
  89.154 +
  89.155 +    public void testPatternAssert1() throws Exception {
  89.156 +        performAnalysisTest("test/Test.java",
  89.157 +                            "|package test;\n" +
  89.158 +                            "\n" +
  89.159 +                            "public class Test {\n" +
  89.160 +                            "     private void test() {\n" +
  89.161 +                            "         assert true : \"\";\n" +
  89.162 +                            "     }\n" +
  89.163 +                            "}\n",
  89.164 +                            "4:9-4:15:verifier:HINT");
  89.165 +    }
  89.166 +
  89.167 +    public void testPatternStatementAndSingleStatementBlockAreSame() throws Exception {
  89.168 +        performAnalysisTest("test/Test.java",
  89.169 +                            "|package test;\n" +
  89.170 +                            "\n" +
  89.171 +                            "public class Test {\n" +
  89.172 +                            "     private int test() {\n" +
  89.173 +                            "         if (true) {\n" +
  89.174 +                            "             return 0;\n" +
  89.175 +                            "         }\n" +
  89.176 +                            "     }\n" +
  89.177 +                            "}\n",
  89.178 +                            "4:9-4:11:verifier:HINT");
  89.179 +    }
  89.180 +
  89.181 +    public void testPatternFalseOccurrence() throws Exception {
  89.182 +        performAnalysisTest("test/Test.java",
  89.183 +                            "|package test;\n" +
  89.184 +                            "\n" +
  89.185 +                            "public class Test {\n" +
  89.186 +                            "     private int test(java.io.File f) {\n" +
  89.187 +                            "         f.toURI().toURL();\n" +
  89.188 +                            "     }\n" +
  89.189 +                            "}\n");
  89.190 +    }
  89.191 +
  89.192 +    public void testStatementVariables1() throws Exception {
  89.193 +        performFixTest("test/Test.java",
  89.194 +                       "|package test;\n" +
  89.195 +                       "\n" +
  89.196 +                       "public class Test {\n" +
  89.197 +                       "     private int test(java.io.File f) {\n" +
  89.198 +                       "         if (true)\n" +
  89.199 +                       "             System.err.println(1);\n" +
  89.200 +                       "         else\n" +
  89.201 +                       "             System.err.println(2);\n" +
  89.202 +                       "     }\n" +
  89.203 +                       "}\n",
  89.204 +                       "4:9-4:11:verifier:HINT",
  89.205 +                       "FixImpl",
  89.206 +                       ("package test;\n" +
  89.207 +                       "\n" +
  89.208 +                       "public class Test {\n" +
  89.209 +                       "     private int test(java.io.File f) {\n" +
  89.210 +                       "         if (false)\n" +
  89.211 +                       "             System.err.println(2);\n" +
  89.212 +                       "         else\n" +
  89.213 +                       "             System.err.println(1);\n" +
  89.214 +                       "     }\n" +
  89.215 +                       "}\n").replaceAll("[ \t\n]+", " "));
  89.216 +    }
  89.217 +
  89.218 +    public void testStatementVariables2() throws Exception {
  89.219 +        performFixTest("test/Test.java",
  89.220 +                       "|package test;\n" +
  89.221 +                       "\n" +
  89.222 +                       "public class Test {\n" +
  89.223 +                       "     private int test(java.io.File f) {\n" +
  89.224 +                       "         if (true)\n" +
  89.225 +                       "             return 1;\n" +
  89.226 +                       "         else\n" +
  89.227 +                       "             return 2;\n" +
  89.228 +                       "     }\n" +
  89.229 +                       "}\n",
  89.230 +                       "4:9-4:11:verifier:HINT",
  89.231 +                       "FixImpl",
  89.232 +                       ("package test;\n" +
  89.233 +                       "\n" +
  89.234 +                       "public class Test {\n" +
  89.235 +                       "     private int test(java.io.File f) {\n" +
  89.236 +                       "         if (false)\n" +
  89.237 +                       "             return 2;\n" +
  89.238 +                       "         else\n" +
  89.239 +                       "             return 1;\n" +
  89.240 +                       "     }\n" +
  89.241 +                       "}\n").replaceAll("[ \t\n]+", " "));
  89.242 +    }
  89.243 +
  89.244 +    public void testMultiStatementVariables1() throws Exception {
  89.245 +        performFixTest("test/Test.java",
  89.246 +                       "|package test;\n" +
  89.247 +                       "\n" +
  89.248 +                       "public class Test {\n" +
  89.249 +                       "     private int test(int j) {\n" +
  89.250 +                       "         j++;\n" +
  89.251 +                       "         j++;\n" +
  89.252 +                       "         int i = 3;\n" +
  89.253 +                       "         j++;\n" +
  89.254 +                       "         j++;\n" +
  89.255 +                       "         return i;\n" +
  89.256 +                       "     }\n" +
  89.257 +                       "}\n",
  89.258 +                       "3:29-10:6:verifier:HINT",
  89.259 +                       "FixImpl",
  89.260 +                       ("package test;\n" +
  89.261 +                       "\n" +
  89.262 +                       "public class Test {\n" +
  89.263 +                       "     private int test(int j) {\n" +
  89.264 +                       "         j++;\n" +
  89.265 +                       "         j++;\n" +
  89.266 +                       "         float i = 3;\n" +
  89.267 +                       "         j++;\n" +
  89.268 +                       "         j++;\n" +
  89.269 +                       "         return i;\n" +
  89.270 +                       "     }\n" +
  89.271 +                       "}\n").replaceAll("[ \t\n]+", " "));
  89.272 +    }
  89.273 +
  89.274 +    public void testMultiStatementVariables2() throws Exception {
  89.275 +        performFixTest("test/Test.java",
  89.276 +                       "|package test;\n" +
  89.277 +                       "\n" +
  89.278 +                       "public class Test {\n" +
  89.279 +                       "     private int test(int j) {\n" +
  89.280 +                       "         int i = 3;\n" +
  89.281 +                       "         return i;\n" +
  89.282 +                       "     }\n" +
  89.283 +                       "}\n",
  89.284 +                       "3:29-6:6:verifier:HINT",
  89.285 +                       "FixImpl",
  89.286 +                       ("package test;\n" +
  89.287 +                       "\n" +
  89.288 +                       "public class Test {\n" +
  89.289 +                       "     private int test(int j) {\n" +
  89.290 +                       "         float i = 3;\n" +
  89.291 +                       "         return i;\n" +
  89.292 +                       "     }\n" +
  89.293 +                       "}\n").replaceAll("[ \t\n]+", " "));
  89.294 +    }
  89.295 +
  89.296 +    public void testMultiStatementVariables3() throws Exception {
  89.297 +        performFixTest("test/Test.java",
  89.298 +                       "|package test;\n" +
  89.299 +                       "\n" +
  89.300 +                       "public class Test {\n" +
  89.301 +                       "     private int test() {\n" +
  89.302 +                       "         System.err.println();\n" +
  89.303 +                       "         System.err.println();\n" +
  89.304 +                       "         int i = 3;\n" +
  89.305 +                       "         System.err.println(i);\n" +
  89.306 +                       "         System.err.println(i);\n" +
  89.307 +                       "         return i;\n" +
  89.308 +                       "     }\n" +
  89.309 +                       "}\n",
  89.310 +                       "3:24-10:6:verifier:HINT",
  89.311 +                       "FixImpl",
  89.312 +                       ("package test;\n" +
  89.313 +                       "\n" +
  89.314 +                       "public class Test {\n" +
  89.315 +                       "     private int test() {\n" +
  89.316 +                       "         System.err.println();\n" +
  89.317 +                       "         System.err.println();\n" +
  89.318 +                       "         float i = 3;\n" +
  89.319 +                       "         System.err.println(i);\n" +
  89.320 +                       "         System.err.println(i);\n" +
  89.321 +                       "         return i;\n" +
  89.322 +                       "     }\n" +
  89.323 +                       "}\n").replaceAll("[ \t\n]+", " "));
  89.324 +    }
  89.325 +
  89.326 +    public void testMultiStatementVariablesAndBlocks() throws Exception {
  89.327 +        performFixTest("test/Test.java",
  89.328 +                       "|package test;\n" +
  89.329 +                       "\n" +
  89.330 +                       "public class Test {\n" +
  89.331 +                       "     private void test() {" +
  89.332 +                       "         if (true)\n" +
  89.333 +                       "             System.err.println();\n" +
  89.334 +                       "     }\n" +
  89.335 +                       "}\n",
  89.336 +                       "3:35-3:37:verifier:HINT",
  89.337 +                       "FixImpl",
  89.338 +                       ("package test;\n" +
  89.339 +                       "\n" +
  89.340 +                       "public class Test {\n" +
  89.341 +                       "     private void test() {" +
  89.342 +                       "         if (false) {\n" +
  89.343 +                       "             System.err.println();\n" +
  89.344 +                       "         }\n" +
  89.345 +                       "     }\n" +
  89.346 +                       "}\n").replaceAll("[ \t\n]+", " "));
  89.347 +    }
  89.348 +
  89.349 +    public void testOneStatement2MultipleBlock() throws Exception {
  89.350 +        performFixTest("test/Test.java",
  89.351 +                       "|package test;\n" +
  89.352 +                       "\n" +
  89.353 +                       "public class Test {\n" +
  89.354 +                       "     private void test() {\n" +
  89.355 +                       "         System.err.println(\"\");\n" +
  89.356 +                       "     }\n" +
  89.357 +                       "}\n",
  89.358 +                       "4:9-4:32:verifier:HINT",
  89.359 +                       "FixImpl",
  89.360 +                       ("package test;\n" +
  89.361 +                       "\n" +
  89.362 +                       "public class Test {\n" +
  89.363 +                       "     private void test() {\n" +
  89.364 +                       "         System.err.println(\"\");\n" +
  89.365 +                       "         System.err.println(\"\");\n" +
  89.366 +                       "     }\n" +
  89.367 +                       "}\n").replaceAll("[ \t\n]+", " "));
  89.368 +    }
  89.369 +
  89.370 +    public void testOneStatement2MultipleStatement() throws Exception {
  89.371 +        performFixTest("test/Test.java",
  89.372 +                       "|package test;\n" +
  89.373 +                       "\n" +
  89.374 +                       "public class Test {\n" +
  89.375 +                       "     private void test() {\n" +
  89.376 +                       "         if (true)\n" +
  89.377 +                       "             System.err.println(\"\");\n" +
  89.378 +                       "     }\n" +
  89.379 +                       "}\n",
  89.380 +                       "5:13-5:36:verifier:HINT",
  89.381 +                       "FixImpl",
  89.382 +                       ("package test;\n" +
  89.383 +                       "\n" +
  89.384 +                       "public class Test {\n" +
  89.385 +                       "     private void test() {\n" +
  89.386 +                       "         if (true) {\n" +
  89.387 +                       "             System.err.println(\"\");\n" +
  89.388 +                       "             System.err.println(\"\");\n" +
  89.389 +                       "         }\n" +
  89.390 +                       "     }\n" +
  89.391 +                       "}\n").replaceAll("[ \t\n]+", " "));
  89.392 +    }
  89.393 +
  89.394 +    public void testMultiple2OneStatement1() throws Exception {
  89.395 +        performFixTest("test/Test.java",
  89.396 +                       "|package test;\n" +
  89.397 +                       "\n" +
  89.398 +                       "public class Test {\n" +
  89.399 +                       "     private void test() {\n" +
  89.400 +                       "         System.err.println(\"\");\n" +
  89.401 +                       "         System.err.println(\"\");\n" +
  89.402 +                       "     }\n" +
  89.403 +                       "}\n",
  89.404 +                       "4:9-4:32:verifier:HINT",
  89.405 +                       "FixImpl",
  89.406 +                       ("package test;\n" +
  89.407 +                       "\n" +
  89.408 +                       "public class Test {\n" +
  89.409 +                       "     private void test() {\n" +
  89.410 +                       "         System.err.println(\"\");\n" +
  89.411 +                       "     }\n" +
  89.412 +                       "}\n").replaceAll("[ \t\n]+", " "));
  89.413 +    }
  89.414 +
  89.415 +    public void testMultiple2OneStatement2() throws Exception {
  89.416 +        performFixTest("test/Test.java",
  89.417 +                       "|package test;\n" +
  89.418 +                       "\n" +
  89.419 +                       "public class Test {\n" +
  89.420 +                       "     private void test() {\n" +
  89.421 +                       "         int i = 0;\n" +
  89.422 +                       "         System.err.println(\"\");\n" +
  89.423 +                       "         System.err.println(\"\");\n" +
  89.424 +                       "         i++;\n" +
  89.425 +                       "     }\n" +
  89.426 +                       "}\n",
  89.427 +                       "5:9-5:32:verifier:HINT",
  89.428 +                       "FixImpl",
  89.429 +                       ("package test;\n" +
  89.430 +                       "\n" +
  89.431 +                       "public class Test {\n" +
  89.432 +                       "     private void test() {\n" +
  89.433 +                       "         int i = 0;\n" +
  89.434 +                       "         System.err.println(\"\");\n" +
  89.435 +                       "         i++;\n" +
  89.436 +                       "     }\n" +
  89.437 +                       "}\n").replaceAll("[ \t\n]+", " "));
  89.438 +    }
  89.439 +
  89.440 +    public void testMemberSelectInsideMemberSelect() throws Exception {
  89.441 +        performFixTest("test/Test.java",
  89.442 +                       "|package test;\n" +
  89.443 +                       "\n" +
  89.444 +                       "public class Test {\n" +
  89.445 +                       "     public Test test;\n" +
  89.446 +                       "     public String name;\n" +
  89.447 +                       "     private void test() {\n" +
  89.448 +                       "         Test t = null;\n" +
  89.449 +                       "         String s = t.test.toString();\n" +
  89.450 +                       "     }\n" +
  89.451 +                       "}\n",
  89.452 +                       "7:22-7:26:verifier:HINT",
  89.453 +                       "FixImpl",
  89.454 +                       ("package test;\n" +
  89.455 +                       "\n" +
  89.456 +                       "public class Test {\n" +
  89.457 +                       "     public Test test;\n" +
  89.458 +                       "     public String name;\n" +
  89.459 +                       "     private void test() {\n" +
  89.460 +                       "         Test t = null;\n" +
  89.461 +                       "         String s = t.getTest().toString();\n" +
  89.462 +                       "     }\n" +
  89.463 +                       "}\n").replaceAll("[ \t\n]+", " "));
  89.464 +    }
  89.465 +
  89.466 +    public void testPackageInfo() throws Exception {
  89.467 +        performAnalysisTest("test/package-info.java",
  89.468 +                            "|package test;\n");
  89.469 +    }
  89.470 +
  89.471 +    public void testSuppressWarnings() throws Exception {
  89.472 +        performAnalysisTest("test/Test.java",
  89.473 +                            "|package test;\n" +
  89.474 +                            "@SuppressWarnings(\"test\")\n" +
  89.475 +                            "public class Test {\n" +
  89.476 +                            "     public Test test;\n" +
  89.477 +                            "     public String name;\n" +
  89.478 +                            "     private void test() {\n" +
  89.479 +                            "         Test t = null;\n" +
  89.480 +                            "         String s = t.test.toString();\n" +
  89.481 +                            "     }\n" +
  89.482 +                            "}\n");
  89.483 +    }
  89.484 +
  89.485 +    public void testRewriteOneToMultipleClassMembers() throws Exception {
  89.486 +        performFixTest("test/Test.java",
  89.487 +                       "|package test;\n" +
  89.488 +                       "\n" +
  89.489 +                       "public class Test {\n" +
  89.490 +                       "     private int i;\n" +
  89.491 +                       "}\n",
  89.492 +                       "3:17-3:18:verifier:HINT",
  89.493 +                       "FixImpl",
  89.494 +                       ("package test;\n" +
  89.495 +                       "\n" +
  89.496 +                       "public class Test {\n" +
  89.497 +                       "     private int i;\n" +
  89.498 +                       "     public int getI() {\n" +
  89.499 +                       "         return i;\n" +
  89.500 +                       "     }\n" +
  89.501 +                       "}\n").replaceAll("[ \t\n]+", " "));
  89.502 +    }
  89.503 +
  89.504 +    public void testImports1() throws Exception {
  89.505 +        performFixTest("test/Test.java",
  89.506 +                       "|package test;\n" +
  89.507 +                       "\n" +
  89.508 +                       "public class Test {\n" +
  89.509 +                       "     private void test() {\n" +
  89.510 +                       "         new java.util.LinkedList();\n" +
  89.511 +                       "     }" +
  89.512 +                       "}\n",
  89.513 +                       "4:9-4:35:verifier:HINT",
  89.514 +                       "FixImpl",
  89.515 +                       ("package test;\n" +
  89.516 +                       "import java.util.ArrayList;\n" +
  89.517 +                       "public class Test {\n" +
  89.518 +                       "     private void test() {\n" +
  89.519 +                       "         new ArrayList();\n" +
  89.520 +                       "     }" +
  89.521 +                       "}\n").replaceAll("[ \t\n]+", " "));
  89.522 +    }
  89.523 +
  89.524 +    public void testImports2() throws Exception {
  89.525 +        performFixTest("test/Test.java",
  89.526 +                       "|package test;\n" +
  89.527 +                       "import java.util.LinkedList;\n" +
  89.528 +                       "public class Test {\n" +
  89.529 +                       "     private void test() {\n" +
  89.530 +                       "         LinkedList l;\n" +
  89.531 +                       "     }" +
  89.532 +                       "}\n",
  89.533 +                       "4:20-4:21:verifier:HINT",
  89.534 +                       "FixImpl",
  89.535 +                       ("package test;\n" +
  89.536 +                       "import java.util.ArrayList;\n" +
  89.537 +                       "import java.util.LinkedList;\n" +
  89.538 +                       "public class Test {\n" +
  89.539 +                       "     private void test() {\n" +
  89.540 +                       "         ArrayList l;\n" +
  89.541 +                       "     }" +
  89.542 +                       "}\n").replaceAll("[ \t\n]+", " "));
  89.543 +    }
  89.544 +
  89.545 +    public void testMultiParameters() throws Exception {
  89.546 +        performFixTest("test/Test.java",
  89.547 +                       "|package test;\n" +
  89.548 +                       "import java.util.Arrays;\n" +
  89.549 +                       "public class Test {\n" +
  89.550 +                       "     { Arrays.asList(\"a\", \"b\", \"c\"); }\n" +
  89.551 +                       "}\n",
  89.552 +                       "3:14-3:20:verifier:HINT",
  89.553 +                       "FixImpl",
  89.554 +                       ("package test;\n" +
  89.555 +                       "import java.util.Arrays;\n" +
  89.556 +                       "public class Test {\n" +
  89.557 +                       "     { Arrays.asList(\"d\", \"a\", \"b\", \"c\"); }\n" +
  89.558 +                       "}\n").replaceAll("[ \t\n]+", " "));
  89.559 +    }
  89.560 +
  89.561 +    public void testTypeParametersMethod() throws Exception {
  89.562 +        performFixTest("test/Test.java",
  89.563 +                       "|package test;\n" +
  89.564 +                       "import java.util.Arrays;\n" +
  89.565 +                       "public class Test {\n" +
  89.566 +                       "     { Arrays.<String>asList(\"a\", \"b\", \"c\"); }\n" +
  89.567 +                       "}\n",
  89.568 +                       "3:22-3:28:verifier:HINT",
  89.569 +                       "FixImpl",
  89.570 +                       ("package test;\n" +
  89.571 +                       "import java.util.Arrays;\n" +
  89.572 +                       "public class Test {\n" +
  89.573 +                       "     { Arrays.<String>asList(\"d\", \"a\", \"b\", \"c\"); }\n" +
  89.574 +                       "}\n").replaceAll("[ \t\n]+", " "));
  89.575 +    }
  89.576 +
  89.577 +    public void testTypeParametersNewClass() throws Exception {
  89.578 +        performFixTest("test/Test.java",
  89.579 +                       "|package test;\n" +
  89.580 +                       "import java.util.Arrays;\n" +
  89.581 +                       "import java.util.HashSet;\n" +
  89.582 +                       "public class Test {\n" +
  89.583 +                       "     { new HashSet<String>(Arrays.<String>asList(\"a\", \"b\", \"c\")); }\n" +
  89.584 +                       "}\n",
  89.585 +                       "4:7-4:64:verifier:HINT",
  89.586 +                       "FixImpl",
  89.587 +                       ("package test;\n" +
  89.588 +                       "import java.util.Arrays;\n" +
  89.589 +                       "import java.util.HashSet;\n" +
  89.590 +                       "public class Test {\n" +
  89.591 +                       "     { new HashSet<String>(Arrays.<String>asList(\"d\", \"a\", \"b\", \"c\")); }\n" +
  89.592 +                       "}\n").replaceAll("[ \t\n]+", " "));
  89.593 +    }
  89.594 +
  89.595 +    public void testChangeFieldType1() throws Exception {
  89.596 +        performFixTest("test/Test.java",
  89.597 +                       "|package test;\n" +
  89.598 +                       "public class Test {\n" +
  89.599 +                       "     private String name = null;\n" +
  89.600 +                       "}\n",
  89.601 +                       "2:20-2:24:verifier:HINT",
  89.602 +                       "FixImpl",
  89.603 +                       ("package test;\n" +
  89.604 +                       "public class Test {\n" +
  89.605 +                       "     private CharSequence name = null;\n" +
  89.606 +                       "}\n").replaceAll("[ \t\n]+", " "));
  89.607 +    }
  89.608 +
  89.609 +    public void testChangeFieldType2() throws Exception {
  89.610 +        performFixTest("test/Test.java",
  89.611 +                       "|package test;\n" +
  89.612 +                       "public class Test {\n" +
  89.613 +                       "     String name = null;\n" +
  89.614 +                       "}\n",
  89.615 +                       "2:12-2:16:verifier:HINT",
  89.616 +                       "FixImpl",
  89.617 +                       ("package test;\n" +
  89.618 +                       "public class Test {\n" +
  89.619 +                       "     CharSequence name = null;\n" +
  89.620 +                       "}\n").replaceAll("[ \t\n]+", " "));
  89.621 +    }
  89.622 +
  89.623 +    public void testChangeFieldType3() throws Exception {
  89.624 +        performFixTest("test/Test.java",
  89.625 +                       "|package test;\n" +
  89.626 +                       "public class Test {\n" +
  89.627 +                       "     private static final String name = \"test\".substring(0, 4);\n" +
  89.628 +                       "}\n",
  89.629 +                       "2:33-2:37:verifier:HINT",
  89.630 +                       "FixImpl",
  89.631 +                       ("package test;\n" +
  89.632 +                       "public class Test {\n" +
  89.633 +                       "     private static final CharSequence name = \"test\".substring(0, 4);\n" +
  89.634 +                       "}\n").replaceAll("[ \t\n]+", " "));
  89.635 +    }
  89.636 +
  89.637 +    public void testIdentifier() throws Exception {
  89.638 +        performFixTest("test/Test.java",
  89.639 +                       "|package test;\n" +
  89.640 +                       "public class Test {\n" +
  89.641 +                       "     private int l;" +
  89.642 +                       "     {System.err.println(l);}\n" +
  89.643 +                       "}\n",
  89.644 +                       "2:44-2:45:verifier:HINT",
  89.645 +                       "FixImpl",
  89.646 +                       ("package test;\n" +
  89.647 +                       "public class Test {\n" +
  89.648 +                       "     private int l;" +
  89.649 +                       "     {System.err.println(2);}\n" +
  89.650 +                       "}\n").replaceAll("[ \t\n]+", " "));
  89.651 +    }
  89.652 +
  89.653 +    public void testLambda() throws Exception {
  89.654 +        performAnalysisTest("test/Test.java",
  89.655 +                       "|package test;\n" +
  89.656 +                       "public class Test {\n" +
  89.657 +                       "     { new java.io.FileFilter() {public boolean accept(java.io.File f) { return true; } } }\n" +
  89.658 +                       "}\n",
  89.659 +                       "2:7-2:89:verifier:HINT");
  89.660 +    }
  89.661 +
  89.662 +    public void testAddCasesToSwitch() throws Exception {
  89.663 +        performFixTest("test/Test.java",
  89.664 +                       "|package test;\n" +
  89.665 +                       "public class Test {\n" +
  89.666 +                       "     {\n" +
  89.667 +                       "         E e = null;\n" +
  89.668 +                       "         switch (e) {\n" +
  89.669 +                       "             case A: System.err.println(1); break;\n" +
  89.670 +                       "             case D: System.err.println(2); break;\n" +
  89.671 +                       "             case E: System.err.println(3); break;\n" +
  89.672 +                       "         }\n" +
  89.673 +                       "     }\n" +
  89.674 +                       "     public enum E {A, B, C, D, E, F;}\n" +
  89.675 +                       "}\n",
  89.676 +                       "4:9-4:15:verifier:HINT",
  89.677 +                       "FixImpl",
  89.678 +                       ("package test;\n" +
  89.679 +                       "public class Test {\n" +
  89.680 +                       "     {\n" +
  89.681 +                       "         E e = null;\n" +
  89.682 +                       "         switch (e) {\n" +
  89.683 +                       "             case A: System.err.println(1); break;\n" +
  89.684 +                       "             case B:case C:\n" +
  89.685 +//                       "             case C:\n" +
  89.686 +                       "             case D: System.err.println(2); break;\n" +
  89.687 +                       "             case E: System.err.println(3); break;\n" +
  89.688 +                       "         }\n" +
  89.689 +                       "     }\n" +
  89.690 +                       "     public enum E {A, B, C, D, E, F;}\n" +
  89.691 +                       "}\n").replaceAll("[ \t\n]+", " "));
  89.692 +    }
  89.693 +
  89.694 +    private static final Map<String, HintDescription> test2Hint;
  89.695 +
  89.696 +    static {
  89.697 +        test2Hint = new HashMap<String, HintDescription>();
  89.698 +        test2Hint.put("testPattern1", HintDescriptionFactory.create().setTrigger(PatternDescription.create("$1.toURL()", Collections.singletonMap("$1", "java.io.File"))).setWorker(new WorkerImpl()).produce());
  89.699 +        test2Hint.put("testPattern2", test2Hint.get("testPattern1"));
  89.700 +        test2Hint.put("testKind1", HintDescriptionFactory.create().setTrigger(new Kinds(EnumSet.of(Kind.METHOD_INVOCATION))).setWorker(new WorkerImpl()).produce());
  89.701 +        test2Hint.put("testPatternVariable1", HintDescriptionFactory.create().setTrigger(PatternDescription.create("{ $1 $2; $2 = $3; }", Collections.<String, String>emptyMap())).setWorker(new WorkerImpl("{ $1 $2 = $3; }")).produce());
  89.702 +        Map<String, String> constraints = new HashMap<String, String>();
  89.703 +
  89.704 +        constraints.put("$1", "boolean");
  89.705 +        constraints.put("$2", "java.lang.Object");
  89.706 +
  89.707 +        test2Hint.put("testPatternAssert1", HintDescriptionFactory.create().setTrigger(PatternDescription.create("assert $1 : $2;", constraints)).setWorker(new WorkerImpl()).produce());
  89.708 +        test2Hint.put("testPatternStatementAndSingleStatementBlockAreSame", HintDescriptionFactory.create().setTrigger(PatternDescription.create("if ($1) return $2;", Collections.<String, String>emptyMap())).setWorker(new WorkerImpl()).produce());
  89.709 +        test2Hint.put("testPatternFalseOccurrence", HintDescriptionFactory.create().setTrigger(PatternDescription.create("$1.toURL()", Collections.singletonMap("$1", "java.io.File"))).setWorker(new WorkerImpl()).produce());
  89.710 +        test2Hint.put("testStatementVariables1", HintDescriptionFactory.create().setTrigger(PatternDescription.create("if ($1) $2; else $3;", constraints)).setWorker(new WorkerImpl("if (!$1) $3; else $2;")).produce());
  89.711 +        test2Hint.put("testStatementVariables2", test2Hint.get("testStatementVariables1"));
  89.712 +        test2Hint.put("testMultiStatementVariables1", HintDescriptionFactory.create().setTrigger(PatternDescription.create("{ $pref$; int $i = 3; $inf$; return $i; }", Collections.<String, String>emptyMap())).setWorker(new WorkerImpl("{ $pref$; float $i = 3; $inf$; return $i; }")).produce());
  89.713 +        test2Hint.put("testMultiStatementVariables2", test2Hint.get("testMultiStatementVariables1"));
  89.714 +        test2Hint.put("testMultiStatementVariables3", test2Hint.get("testMultiStatementVariables1"));
  89.715 +        test2Hint.put("testMultiStatementVariablesAndBlocks", HintDescriptionFactory.create().setTrigger(PatternDescription.create("if ($c) {$s1$; System.err.println(); $s2$; }", Collections.<String, String>emptyMap())).setWorker(new WorkerImpl("if (!$c) {$s1$; System.err.println(); $s2$; }")).produce());
  89.716 +        test2Hint.put("testOneStatement2MultipleBlock", HintDescriptionFactory.create().setTrigger(PatternDescription.create("System.err.println($1);", Collections.<String, String>emptyMap())).setWorker(new WorkerImpl("System.err.println($1); System.err.println($1);")).produce());
  89.717 +        test2Hint.put("testOneStatement2MultipleStatement", test2Hint.get("testOneStatement2MultipleBlock"));
  89.718 +        test2Hint.put("testMultiple2OneStatement1", HintDescriptionFactory.create().setTrigger(PatternDescription.create("System.err.println($1); System.err.println($2);", Collections.<String, String>emptyMap())).setWorker(new WorkerImpl("System.err.println($1);")).produce());
  89.719 +        test2Hint.put("testMultiple2OneStatement2", test2Hint.get("testMultiple2OneStatement1"));
  89.720 +        test2Hint.put("testMemberSelectInsideMemberSelect", HintDescriptionFactory.create().setTrigger(PatternDescription.create("$Test.test", Collections.<String, String>singletonMap("$Test", "test.Test"))).setWorker(new WorkerImpl("$Test.getTest()")).produce());
  89.721 +        test2Hint.put("testPackageInfo", HintDescriptionFactory.create().setTrigger(PatternDescription.create("$Test.test", Collections.<String, String>singletonMap("$Test", "test.Test"))).setWorker(new WorkerImpl("$Test.getTest()")).produce());
  89.722 +        HintMetadata metadata = HintMetadata.Builder.create("no-id").addOptions(Options.NON_GUI).addSuppressWarnings("test").build();
  89.723 +        test2Hint.put("testSuppressWarnings", HintDescriptionFactory.create().setTrigger(PatternDescription.create("$Test.test", Collections.<String, String>singletonMap("$Test", "test.Test"))).setWorker(new WorkerImpl("$Test.getTest()")).setMetadata(metadata).produce());
  89.724 +        test2Hint.put("testRewriteOneToMultipleClassMembers", HintDescriptionFactory.create().setTrigger(PatternDescription.create("private int i;", Collections.<String, String>emptyMap())).setWorker(new WorkerImpl("private int i; public int getI() { return i; }")).produce());
  89.725 +//        test2Hint.put("testImports1", HintDescriptionFactory.create().setTrigger(PatternDescription.create("new LinkedList()", Collections.<String, String>emptyMap(), "import java.util.LinkedList;")).setWorker(new WorkerImpl("new ArrayList()", "import java.util.ArrayList;\n")).produce());
  89.726 +//        test2Hint.put("testImports2", HintDescriptionFactory.create().setTrigger(PatternDescription.create("LinkedList $0;", Collections.<String, String>emptyMap(), "import java.util.LinkedList;")).setWorker(new WorkerImpl("ArrayList $0;", "import java.util.ArrayList;\n")).produce());
  89.727 +        test2Hint.put("testImports1", HintDescriptionFactory.create().setTrigger(PatternDescription.create("new LinkedList()", Collections.<String, String>emptyMap(), "import java.util.LinkedList;")).setWorker(new WorkerImpl("new java.util.ArrayList()")).produce());
  89.728 +        test2Hint.put("testImports2", HintDescriptionFactory.create().setTrigger(PatternDescription.create("LinkedList $0;", Collections.<String, String>emptyMap(), "import java.util.LinkedList;")).setWorker(new WorkerImpl("java.util.ArrayList $0;")).produce());
  89.729 +        test2Hint.put("testMultiParameters", HintDescriptionFactory.create().setTrigger(PatternDescription.create("java.util.Arrays.asList($1$)", Collections.<String,String>emptyMap())).setWorker(new WorkerImpl("java.util.Arrays.asList(\"d\", $1$)")).produce());
  89.730 +        test2Hint.put("testTypeParametersMethod", HintDescriptionFactory.create().setTrigger(PatternDescription.create("java.util.Arrays.<$T>asList($1$)", Collections.<String,String>emptyMap())).setWorker(new WorkerImpl("java.util.Arrays.<$T>asList(\"d\", $1$)")).produce());
  89.731 +        test2Hint.put("testTypeParametersNewClass", HintDescriptionFactory.create().setTrigger(PatternDescription.create("new java.util.HashSet<$T1$>(java.util.Arrays.<$T$>asList($1$))", Collections.<String,String>emptyMap())).setWorker(new WorkerImpl("new java.util.HashSet<$T1$>(java.util.Arrays.<$T$>asList(\"d\", $1$))")).produce());
  89.732 +        test2Hint.put("testChangeFieldType1", HintDescriptionFactory.create().setTrigger(PatternDescription.create("$modifiers$ java.lang.String $name = $initializer;", Collections.<String, String>emptyMap())).setWorker(new WorkerImpl("$modifiers$ java.lang.CharSequence $name = $initializer;")).produce());
  89.733 +        test2Hint.put("testChangeFieldType2", test2Hint.get("testChangeFieldType1"));
  89.734 +        test2Hint.put("testChangeFieldType3", test2Hint.get("testChangeFieldType1"));
  89.735 +        test2Hint.put("testIdentifier", HintDescriptionFactory.create().setTrigger(PatternDescription.create("$i", Collections.<String, String>singletonMap("$i", "int"))).setWorker(new WorkerImpl("2")).produce());
  89.736 +        test2Hint.put("testLambda", HintDescriptionFactory.create().setTrigger(PatternDescription.create("new $type() { $mods$ $retType $name($params$) { $body$; } }", Collections.<String, String>emptyMap())).setWorker(new WorkerImpl()).produce());
  89.737 +        test2Hint.put("testAddCasesToSwitch", HintDescriptionFactory.create().setTrigger(PatternDescription.create("switch ($var) { case $c1$; case D: $stmts$; case $c2$; }", Collections.<String,String>singletonMap("$var", "test.Test.E"))).setWorker(new WorkerImpl("switch ($var) { case $c1$ case B: case C: case D: $stmts$; case $c2$ }")).produce());
  89.738 +    }
  89.739 +
  89.740 +//    @Override
  89.741 +    protected List<ErrorDescription> computeErrors(CompilationInfo info, TreePath path, int pos) {
  89.742 +        HintDescription hd = test2Hint.get(getName());
  89.743 +
  89.744 +        assertNotNull(hd);
  89.745 +
  89.746 +        return new HintsInvoker(HintsSettings.getGlobalSettings(), new AtomicBoolean()).computeHints(info, Collections.singletonList(hd));
  89.747 +    }
  89.748 +
  89.749 +//    @Override
  89.750 +    protected String toDebugString(CompilationInfo info, Fix f) {
  89.751 +        return "FixImpl";
  89.752 +    }
  89.753 +
  89.754 +//    @Override
  89.755 +//    public void testIssue105979() throws Exception {}
  89.756 +//
  89.757 +//    @Override
  89.758 +//    public void testIssue108246() throws Exception {}
  89.759 +//
  89.760 +//    @Override
  89.761 +//    public void testIssue113933() throws Exception {}
  89.762 +//
  89.763 +//    @Override
  89.764 +//    public void testNoHintsForSimpleInitialize() throws Exception {}
  89.765 +
  89.766 +    private static final class WorkerImpl implements Worker {
  89.767 +
  89.768 +        private final String fix;
  89.769 +
  89.770 +        public WorkerImpl() {
  89.771 +            this(null);
  89.772 +        }
  89.773 +
  89.774 +        public WorkerImpl(String fix) {
  89.775 +            this.fix = fix;
  89.776 +        }
  89.777 +
  89.778 +        public Collection<? extends ErrorDescription> createErrors(HintContext ctx) {
  89.779 +            if (ctx.getInfo().getTreeUtilities().isSynthetic(ctx.getPath())) {
  89.780 +                return null;
  89.781 +            }
  89.782 +
  89.783 +            List<Fix> fixes = new LinkedList<Fix>();
  89.784 +
  89.785 +            if (fix != null) {
  89.786 +                fixes.add(JavaFixUtilities.rewriteFix(ctx, "Rewrite", ctx.getPath(), fix));
  89.787 +            }
  89.788 +            
  89.789 +            return Collections.singletonList(ErrorDescriptionFactory.forName(ctx, ctx.getPath(), "HINT", fixes.toArray(new Fix[0])));
  89.790 +        }
  89.791 +    }
  89.792 +
  89.793 +
  89.794 +    //XXX:copied from TreeRuleTestBase:
  89.795 +
  89.796 +    protected void performAnalysisTest(String fileName, String code, String... golden) throws Exception {
  89.797 +        int[] offset = new int[1];
  89.798 +
  89.799 +        code = org.netbeans.modules.java.hints.spiimpl.TestUtilities.detectOffsets(code, offset);
  89.800 +
  89.801 +        performAnalysisTest(fileName, code, offset[0], golden);
  89.802 +    }
  89.803 +
  89.804 +    protected void performAnalysisTest(String fileName, String code, int pos, String... golden) throws Exception {
  89.805 +        prepareTest(fileName, code);
  89.806 +
  89.807 +        TreePath path = info.getTreeUtilities().pathFor(pos);
  89.808 +
  89.809 +        List<ErrorDescription> errors = computeErrors(info, path, pos);
  89.810 +        List<String> errorsNames = new LinkedList<String>();
  89.811 +
  89.812 +        errors = errors != null ? errors : Collections.<ErrorDescription>emptyList();
  89.813 +
  89.814 +        for (ErrorDescription e : errors) {
  89.815 +            errorsNames.add(e.toString());
  89.816 +        }
  89.817 +
  89.818 +        assertTrue("The warnings provided by the hint do not match expected warnings. Provided warnings: " + errorsNames.toString(), Arrays.equals(golden, errorsNames.toArray(new String[0])));
  89.819 +    }
  89.820 +
  89.821 +    protected String performFixTest(String fileName, String code, String errorDescriptionToString, String fixDebugString, String golden) throws Exception {
  89.822 +        int[] offset = new int[1];
  89.823 +
  89.824 +        code = org.netbeans.modules.java.hints.spiimpl.TestUtilities.detectOffsets(code, offset);
  89.825 +
  89.826 +        return performFixTest(fileName, code, offset[0], errorDescriptionToString, fixDebugString, golden);
  89.827 +    }
  89.828 +
  89.829 +    protected String performFixTest(String fileName, String code, int pos, String errorDescriptionToString, String fixDebugString, String golden) throws Exception {
  89.830 +        return performFixTest(fileName, code, pos, errorDescriptionToString, fixDebugString, fileName, golden);
  89.831 +    }
  89.832 +
  89.833 +    protected String performFixTest(String fileName, String code, String errorDescriptionToString, String fixDebugString, String goldenFileName, String golden) throws Exception {
  89.834 +        int[] offset = new int[1];
  89.835 +
  89.836 +        code = org.netbeans.modules.java.hints.spiimpl.TestUtilities.detectOffsets(code, offset);
  89.837 +
  89.838 +        return performFixTest(fileName, code, offset[0], errorDescriptionToString, fixDebugString, goldenFileName, golden);
  89.839 +    }
  89.840 +
  89.841 +    protected String performFixTest(String fileName, String code, int pos, String errorDescriptionToString, String fixDebugString, String goldenFileName, String golden) throws Exception {
  89.842 +        prepareTest(fileName, code);
  89.843 +
  89.844 +        TreePath path = info.getTreeUtilities().pathFor(pos);
  89.845 +
  89.846 +        List<ErrorDescription> errors = computeErrors(info, path, pos);
  89.847 +
  89.848 +        ErrorDescription toFix = null;
  89.849 +
  89.850 +        for (ErrorDescription d : errors) {
  89.851 +            if (errorDescriptionToString.equals(d.toString())) {
  89.852 +                toFix = d;
  89.853 +                break;
  89.854 +            }
  89.855 +        }
  89.856 +
  89.857 +        assertNotNull("Error: \"" + errorDescriptionToString + "\" not found. All ErrorDescriptions: " + errors.toString(), toFix);
  89.858 +
  89.859 +        assertTrue("Must be computed", toFix.getFixes().isComputed());
  89.860 +
  89.861 +        List<Fix> fixes = toFix.getFixes().getFixes();
  89.862 +        List<String> fixNames = new LinkedList<String>();
  89.863 +        Fix toApply = null;
  89.864 +
  89.865 +        for (Fix f : fixes) {
  89.866 +            if (fixDebugString.equals(toDebugString(info, f))) {
  89.867 +                toApply = f;
  89.868 +            }
  89.869 +
  89.870 +            fixNames.add(toDebugString(info, f));
  89.871 +        }
  89.872 +
  89.873 +        assertNotNull("Cannot find fix to invoke: " + fixNames.toString(), toApply);
  89.874 +
  89.875 +        toApply.implement();
  89.876 +
  89.877 +        FileObject toCheck = sourceRoot.getFileObject(goldenFileName);
  89.878 +
  89.879 +        assertNotNull(toCheck);
  89.880 +
  89.881 +        DataObject toCheckDO = DataObject.find(toCheck);
  89.882 +        EditorCookie ec = toCheckDO.getLookup().lookup(EditorCookie.class);
  89.883 +        Document toCheckDocument = ec.openDocument();
  89.884 +
  89.885 +        String realCode = toCheckDocument.getText(0, toCheckDocument.getLength());
  89.886 +
  89.887 +        //ignore whitespaces:
  89.888 +        realCode = realCode.replaceAll("[ \t\n]+", " ");
  89.889 +
  89.890 +        if (golden != null) {
  89.891 +            assertEquals("The output code does not match the expected code.", golden, realCode);
  89.892 +        }
  89.893 +
  89.894 +        LifecycleManager.getDefault().saveAll();
  89.895 +
  89.896 +        return realCode;
  89.897 +    }
  89.898 +}
  89.899 \ No newline at end of file
    90.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    90.2 +++ b/java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/pm/BulkSearchTestPerformer.java	Wed May 08 21:47:42 2013 +0200
    90.3 @@ -0,0 +1,694 @@
    90.4 +/*
    90.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    90.6 + *
    90.7 + * Copyright 2010 Oracle and/or its affiliates. All rights reserved.
    90.8 + *
    90.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   90.10 + * Other names may be trademarks of their respective owners.
   90.11 + *
   90.12 + * The contents of this file are subject to the terms of either the GNU
   90.13 + * General Public License Version 2 only ("GPL") or the Common
   90.14 + * Development and Distribution License("CDDL") (collectively, the
   90.15 + * "License"). You may not use this file except in compliance with the
   90.16 + * License. You can obtain a copy of the License at
   90.17 + * http://www.netbeans.org/cddl-gplv2.html
   90.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   90.19 + * specific language governing permissions and limitations under the
   90.20 + * License.  When distributing the software, include this License Header
   90.21 + * Notice in each file and include the License file at
   90.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   90.23 + * particular file as subject to the "Classpath" exception as provided
   90.24 + * by Oracle in the GPL Version 2 section of the License file that
   90.25 + * accompanied this code. If applicable, add the following below the
   90.26 + * License Header, with the fields enclosed by brackets [] replaced by
   90.27 + * your own identifying information:
   90.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   90.29 + *
   90.30 + * If you wish your version of this file to be governed by only the CDDL
   90.31 + * or only the GPL Version 2, indicate your decision by adding
   90.32 + * "[Contributor] elects to include this software in this distribution
   90.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   90.34 + * single choice of license, a recipient has the option to distribute
   90.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   90.36 + * to extend the choice of license to its licensees as provided above.
   90.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   90.38 + * Version 2 license, then the option applies only if the new code is
   90.39 + * made subject to such option by the copyright holder.
   90.40 + *
   90.41 + * Contributor(s):
   90.42 + *
   90.43 + * Portions Copyrighted 2009 Sun Microsystems, Inc.
   90.44 + */
   90.45 +
   90.46 +package org.netbeans.modules.java.hints.spiimpl.pm;
   90.47 +
   90.48 +import org.netbeans.modules.java.hints.spiimpl.pm.BulkSearch.BulkPattern;
   90.49 +import org.netbeans.modules.java.hints.spiimpl.pm.BulkSearch.EncodingContext;
   90.50 +import com.sun.source.util.TreePath;
   90.51 +import java.io.ByteArrayInputStream;
   90.52 +import java.io.ByteArrayOutputStream;
   90.53 +import java.io.File;
   90.54 +import java.util.Arrays;
   90.55 +import java.util.Collection;
   90.56 +import java.util.Collections;
   90.57 +import java.util.HashMap;
   90.58 +import java.util.HashSet;
   90.59 +import java.util.LinkedList;
   90.60 +import java.util.List;
   90.61 +import java.util.Map;
   90.62 +import java.util.Map.Entry;
   90.63 +import java.util.Set;
   90.64 +import java.util.concurrent.atomic.AtomicBoolean;
   90.65 +import java.util.regex.Pattern;
   90.66 +import javax.swing.text.Document;
   90.67 +import org.netbeans.api.java.lexer.JavaTokenId;
   90.68 +import org.netbeans.api.java.source.CompilationInfo;
   90.69 +import org.netbeans.api.java.source.JavaSource;
   90.70 +import org.netbeans.api.java.source.JavaSource.Phase;
   90.71 +import org.netbeans.api.java.source.SourceUtilsTestUtil;
   90.72 +import org.netbeans.api.java.source.TestUtilities;
   90.73 +import org.netbeans.api.java.source.TreePathHandle;
   90.74 +import org.netbeans.api.lexer.Language;
   90.75 +import org.netbeans.junit.NbTestCase;
   90.76 +import org.netbeans.modules.java.source.TreeLoader;
   90.77 +import org.openide.cookies.EditorCookie;
   90.78 +import org.openide.filesystems.FileObject;
   90.79 +import org.openide.filesystems.FileUtil;
   90.80 +import org.openide.loaders.DataObject;
   90.81 +import static org.junit.Assert.*;
   90.82 +import org.netbeans.junit.RandomlyFails;
   90.83 +
   90.84 +/**
   90.85 + *
   90.86 + * @author lahvac
   90.87 + */
   90.88 +public abstract class BulkSearchTestPerformer extends NbTestCase {
   90.89 +
   90.90 +    public BulkSearchTestPerformer(String name) {
   90.91 +        super(name);
   90.92 +    }
   90.93 +
   90.94 +    @Override
   90.95 +    protected void setUp() throws Exception {
   90.96 +        super.setUp();
   90.97 +        SourceUtilsTestUtil.prepareTest(new String[] {"org/netbeans/modules/java/editor/resources/layer.xml"}, new Object[0]);
   90.98 +        TreeLoader.DISABLE_CONFINEMENT_TEST = true;
   90.99 +    }
  90.100 +
  90.101 +//    public static TestSuite suite() {
  90.102 +//        NbTestSuite s = new NbTestSuite();
  90.103 +//
  90.104 +//        s.addTestSuite(NFABasedBulkSearchTest.class);
  90.105 +//
  90.106 +//        return s;
  90.107 +//    }
  90.108 +
  90.109 +    public void testSimple1() throws Exception {
  90.110 +        performTest("package test; public class Test { private void test() { System.err./**/println(\"\");}}",
  90.111 +                    Collections.singletonMap("System.err.println(\"\")", Arrays.asList("System.err./**/println(\"\")")),
  90.112 +                    Arrays.asList("System.err.println(\"\" + \"\")"));
  90.113 +    }
  90.114 +
  90.115 +    public void testDontCare() throws Exception {
  90.116 +        performTest("package test; public class Test { private void test() { System.err./**/println(\"\" + \"\");}}",
  90.117 +                    Collections.singletonMap("System.err.println($1)", Arrays.asList("System.err./**/println(\"\" + \"\")")),
  90.118 +                    Collections.<String>emptyList());
  90.119 +    }
  90.120 +
  90.121 +    public void testMemberSelectAndIdentifier() throws Exception {
  90.122 +        performTest("package test; public class Test { private static void test() { test();}}",
  90.123 +                    Collections.singletonMap("test.Test.test()", Arrays.asList("test()")),
  90.124 +                    Collections.<String>emptyList());
  90.125 +    }
  90.126 +
  90.127 +    public void testUnpureMemberSelect() throws Exception {
  90.128 +        performTest("package test; public class Test { private static void test() { new StringBuilder().append(\"\");}}",
  90.129 +                    Collections.<String, List<String>>emptyMap(),
  90.130 +                    Arrays.asList("test.append(\"\")"));
  90.131 +    }
  90.132 +
  90.133 +    public void testMemberSelectWithVariables1() throws Exception {
  90.134 +        performTest("package test; public class Test { private static void test() { new StringBuilder().append(\"\");}}",
  90.135 +                    Collections.singletonMap("$0.append(\"\")", Arrays.asList("new StringBuilder().append(\"\")")),
  90.136 +                    Collections.<String>emptyList());
  90.137 +    }
  90.138 +
  90.139 +    public void testMemberSelectWithVariables2() throws Exception {
  90.140 +        performTest("package test; public class Test { private void append(char c) { append(\"\");}}",
  90.141 +                    Collections.singletonMap("$0.append(\"\")", Arrays.asList("append(\"\")")),
  90.142 +                    Collections.<String>emptyList());
  90.143 +    }
  90.144 +
  90.145 +    public void testLocalVariables() throws Exception {
  90.146 +        performTest("package test; public class Test { private void test() { { int y; y = 1; } }}",
  90.147 +                    Collections.singletonMap("{ int $1; $1 = 1; }", Arrays.asList("{ int y; y = 1; }")),
  90.148 +                    Collections.<String>emptyList());
  90.149 +    }
  90.150 +
  90.151 +    public void testAssert() throws Exception {
  90.152 +        performTest("package test; public class Test { private void test() { assert true : \"\"; }}",
  90.153 +                    Collections.singletonMap("assert $1 : $2;", Arrays.asList("assert true : \"\";")),
  90.154 +                    Collections.<String>emptyList());
  90.155 +    }
  90.156 +
  90.157 +    public void testStatementAndSingleBlockStatementAreSame1() throws Exception {
  90.158 +        performTest("package test; public class Test { private void test() { { int y; { y = 1; } } }}",
  90.159 +                    Collections.singletonMap("{ int $1; $1 = 1; }", Arrays.asList("{ int y; { y = 1; } }")),
  90.160 +                    Collections.<String>emptyList());
  90.161 +    }
  90.162 +
  90.163 +    public void testStatementAndSingleBlockStatementAreSame2() throws Exception {
  90.164 +        performTest("package test; public class Test { private void test() { { int y; y = 1; } }}",
  90.165 +                    Collections.singletonMap("{ int $1; { $1 = 1; } }", Arrays.asList("{ int y; y = 1; }")),
  90.166 +                    Collections.<String>emptyList());
  90.167 +    }
  90.168 +
  90.169 +    public void testStatementVariables1() throws Exception {
  90.170 +        performTest("package test; public class Test { public int test1() { if (true) return 1; else return 2; } }",
  90.171 +                    Collections.singletonMap("if ($1) $2; else $3;", Arrays.asList("if (true) return 1; else return 2;")),
  90.172 +                    Collections.<String>emptyList());
  90.173 +    }
  90.174 +
  90.175 +    public void testMultiStatementVariables1() throws Exception {
  90.176 +        performTest("package test; public class Test { public int test1(int i) { System.err.println(i); System.err.println(i); i = 3; System.err.println(i); System.err.println(i); return i; } }",
  90.177 +                    Collections.singletonMap("{ $s1$; i = 3; $s2$; return i; }", Arrays.asList("{ System.err.println(i); System.err.println(i); i = 3; System.err.println(i); System.err.println(i); return i; }")),
  90.178 +                    Collections.<String>emptyList());
  90.179 +    }
  90.180 +
  90.181 +    public void testMultiStatementVariables2() throws Exception {
  90.182 +        performTest("package test; public class Test { public int test1(int i) { i = 3; return i; } }",
  90.183 +                    Collections.singletonMap("{ $s1$; i = 3; $s2$; return i; }", Arrays.asList("{ i = 3; return i; }")),
  90.184 +                    Collections.<String>emptyList());
  90.185 +    }
  90.186 +
  90.187 +    public void testMultiStatementVariablesAndBlocks1() throws Exception {
  90.188 +        performTest("package test; public class Test { public void test1() { if (true) System.err.println(); } }",
  90.189 +                    Collections.singletonMap("if ($c) {$s1$; System.err.println(); $s2$; }", Arrays.asList("if (true) System.err.println();")),
  90.190 +                    Collections.<String>emptyList());
  90.191 +    }
  90.192 +
  90.193 +    public void testMultiStatementVariablesAndBlocks2() throws Exception {
  90.194 +        performTest("package test; public class Test { public void test1() { if (true) System.err.println(); } }",
  90.195 +                    Collections.singletonMap("if ($c) {$s1$; System.err.println(); }", Arrays.asList("if (true) System.err.println();")),
  90.196 +                    Collections.<String>emptyList());
  90.197 +    }
  90.198 +
  90.199 +    public void testMultiStatementVariablesAndBlocks3() throws Exception {
  90.200 +        performTest("package test; public class Test { public void test1() { if (true) System.err.println(); } }",
  90.201 +                    Collections.singletonMap("if ($c) {System.err.println(); $s2$; }", Arrays.asList("if (true) System.err.println();")),
  90.202 +                    Collections.<String>emptyList());
  90.203 +    }
  90.204 +
  90.205 +    public void testMultiStatementVariablesAndBlocks4() throws Exception {
  90.206 +        performTest("package test; public class Test { public void test1() { if (true) System.err.println(); } }",
  90.207 +                    Collections.singletonMap("{ $s1$; System.err.println(); $s2$; }", Arrays.asList("System.err.println();")),
  90.208 +                    Collections.<String>emptyList());
  90.209 +    }
  90.210 +
  90.211 +    public void testTwoPatterns() throws Exception {
  90.212 +        Map<String, List<String>> contained = new HashMap<String, List<String>>();
  90.213 +
  90.214 +        contained.put("if ($a) $ret = $b; else $ret = $c;", Arrays.asList("if (b) q = 2; else q = 3;"));
  90.215 +        contained.put("{ $p$; $T $v; if($a) $v = $b; else $v = $c; $q$; }", Arrays.asList("{ int q; if (b) q = 2; else q = 3; }"));
  90.216 +
  90.217 +        performTest("package test; public class Test { public void test1(boolean b) { int q; if (b) q = 2; else q = 3; } }",
  90.218 +                    contained,
  90.219 +                    Collections.<String>emptyList());
  90.220 +    }
  90.221 +
  90.222 +    public void testEffectiveNewClass() throws Exception {
  90.223 +        performTest("package test; import javax.swing.ImageIcon; public class Test { public void test1(java.awt.Image i) { new ImageIcon(i); new String(i); } }",
  90.224 +                    Collections.singletonMap("new javax.swing.ImageIcon($1)", Arrays.asList("new ImageIcon(i)")),
  90.225 +                    Collections.<String>emptyList());
  90.226 +    }
  90.227 +
  90.228 +    public void testSynchronizedAndMultiStatementVariables() throws Exception {
  90.229 +        performTest("package test; public class Test {public void test() { Object o = null; int i = 0; synchronized (o) {} } }",
  90.230 +                    Collections.singletonMap("synchronized($var) {$stmts$;}", Arrays.asList("synchronized (o) {}")),
  90.231 +                    Collections.<String>emptyList());
  90.232 +    }
  90.233 +
  90.234 +    public void testJackpot30_2() throws Exception {
  90.235 +        String code = "package test;\n" +
  90.236 +                      "public class Test {\n" +
  90.237 +                      "    private void m() {\n" +
  90.238 +                      "        a(c.i().getFileObject());\n" +
  90.239 +                      "        if (span != null && span[0] != (-1) && span[1] != (-1));\n" +
  90.240 +                      "    }\n" +
  90.241 +                      "}\n";
  90.242 +
  90.243 +        performTest(code,
  90.244 +                    Collections.<String, List<String>>emptyMap(),
  90.245 +                    Arrays.asList("$0.getFileObject($1)"));
  90.246 +    }
  90.247 +
  90.248 +    public void testIdentifierInPureMemberSelect() throws Exception {
  90.249 +        String code = "package test;\n" +
  90.250 +                       "public class Test {\n" +
  90.251 +                       "     public Test test;\n" +
  90.252 +                       "     public String name;\n" +
  90.253 +                       "     private void test() {\n" +
  90.254 +                       "         Test t = null;\n" +
  90.255 +                       "         String s = t.test.name;\n" +
  90.256 +                       "     }\n" +
  90.257 +                       "}\n";
  90.258 +
  90.259 +        performTest(code,
  90.260 +                    Collections.singletonMap("$Test.test", Arrays.asList("test", "t.test")),
  90.261 +                    Collections.<String>emptyList());
  90.262 +    }
  90.263 +
  90.264 +    @RandomlyFails
  90.265 +    public void testNoExponentialTimeComplexity() throws Exception {
  90.266 +        try {
  90.267 +        String code = "package test;\n" +
  90.268 +                      "public class Test {\n" +
  90.269 +                      "    private void test() {\n" +
  90.270 +                      "        Object o;\n" +
  90.271 +                      "        if(o == null) {\n" +
  90.272 +                      "            f(\"\");\n" +
  90.273 +                      "        }|\n" +
  90.274 +                      "    }\n" +
  90.275 +                      "}";
  90.276 +        String pattern = "{ $p$; $T $v; if($a) $v = $b; else $v = $c; }";
  90.277 +
  90.278 +        measure(code, "\na(\"\");", 5, pattern); //to load needed classes, etc.
  90.279 +
  90.280 +        int rep = 1;
  90.281 +        long baseline;
  90.282 +
  90.283 +        while (true) {
  90.284 +            baseline = measure(code, "\na(\"\");", rep, pattern);
  90.285 +
  90.286 +            if (baseline >= 2000) {
  90.287 +                break;
  90.288 +            }
  90.289 +
  90.290 +            rep *= 2;
  90.291 +        }
  90.292 +
  90.293 +        long doubleSize = measure(code, "\na(\"\");", 2 * rep, pattern);
  90.294 +
  90.295 +        assertTrue("baseline=" + baseline + ", actual=" + String.valueOf(doubleSize), doubleSize <= 4 * baseline);
  90.296 +        } catch (OutOfMemoryError oome) {
  90.297 +            //OK
  90.298 +        }
  90.299 +    }
  90.300 +
  90.301 +    public void testMultiParameter1() throws Exception {
  90.302 +        performTest("package test; public class Test { { java.util.Arrays.asList(\"a\", \"b\", \"c\"); } }",
  90.303 +                    Collections.singletonMap("java.util.Arrays.asList($params$)", Arrays.asList("java.util.Arrays.asList(\"a\", \"b\", \"c\")")),
  90.304 +                    Collections.<String>emptyList());
  90.305 +    }
  90.306 +
  90.307 +    public void testMultiParameter2() throws Exception {
  90.308 +        performTest("package test; public class Test { { java.util.Arrays.asList(); } }",
  90.309 +                    Collections.singletonMap("java.util.Arrays.asList($params$)", Arrays.asList("java.util.Arrays.asList()")),
  90.310 +                    Collections.<String>emptyList());
  90.311 +    }
  90.312 +
  90.313 +    public void testTypeParameter() throws Exception {
  90.314 +        performTest("package test; public class Test { { java.util.Arrays.<String>asList(); } }",
  90.315 +                    Collections.singletonMap("java.util.Arrays.<$1>asList($params$)", Arrays.asList("java.util.Arrays.<String>asList()")),
  90.316 +                    Collections.<String>emptyList());
  90.317 +    }
  90.318 +
  90.319 +    public void testField1() throws Exception {
  90.320 +        String code = "package test;\n" +
  90.321 +                       "public class Test {\n" +
  90.322 +                       "     String name = null;\n" +
  90.323 +                       "}\n";
  90.324 +
  90.325 +        performTest(code,
  90.326 +                    Collections.singletonMap("$modifiers$ java.lang.String $name = $initializer;", Arrays.asList("String name = null;")),
  90.327 +                    Collections.<String>emptyList());
  90.328 +    }
  90.329 +
  90.330 +    public void testField2() throws Exception {
  90.331 +        String code = "package test;\n" +
  90.332 +                       "public class Test {\n" +
  90.333 +                       "     private String name = null;\n" +
  90.334 +                       "}\n";
  90.335 +
  90.336 +        performTest(code,
  90.337 +                    Collections.singletonMap("$modifiers$ java.lang.String $name = $initializer;", Arrays.asList("private String name = null;")),
  90.338 +                    Collections.<String>emptyList());
  90.339 +    }
  90.340 +
  90.341 +    public void testMemberSelectWithVariable() throws Exception {
  90.342 +        String code = "package test;\n" +
  90.343 +                      "import java.util.Arrays;\n" +
  90.344 +                      "public class Test {" +
  90.345 +                      "     {\n" +
  90.346 +                      "          foo.bar(0, 3, 4);\n" +
  90.347 +                      "     }\n" +
  90.348 +                      "}\n";
  90.349 +
  90.350 +        performTest(code,
  90.351 +                    Collections.singletonMap("$foo.$bar($p1, $p2$)", Arrays.asList("foo.bar(0, 3, 4)")),
  90.352 +                    Collections.<String>emptyList());
  90.353 +    }
  90.354 +
  90.355 +    public void testCheckIdentifiers1() throws Exception {
  90.356 +        String code = "package test;\n" +
  90.357 +                      "import static java.util.Arrays.*;\n" +
  90.358 +                      "public class Test {" +
  90.359 +                      "     {\n" +
  90.360 +                      "          toString(new int[] {0, 3, 4});\n" +
  90.361 +                      "     }\n" +
  90.362 +                      "}\n";
  90.363 +
  90.364 +        performTest(code,
  90.365 +                    Collections.singletonMap("java.util.Arrays.toString($x)", Arrays.asList("toString(new int[] {0, 3, 4})")),
  90.366 +                    Collections.<String>emptyList());
  90.367 +    }
  90.368 +
  90.369 +    public void testCheckIdentifiers2() throws Exception {
  90.370 +        String code = "package test;\n" +
  90.371 +                      "public class Test {" +
  90.372 +                      "     {\n" +
  90.373 +                      "          toString(new int[] {0, 3, 4});\n" +
  90.374 +                      "     }\n" +
  90.375 +                      "}\n";
  90.376 +
  90.377 +        performTest(code,
  90.378 +                    Collections.<String, List<String>>emptyMap(),
  90.379 +                    Collections.singletonList("java.util.Arrays.toString($x)"));
  90.380 +    }
  90.381 +
  90.382 +    public void testCheckIdentifiers3() throws Exception {
  90.383 +        String code = "package test;\n" +
  90.384 +                      "import static java.util.Arrays.*;\n" +
  90.385 +                      "public class Test {" +
  90.386 +                      "     {\n" +
  90.387 +                      "          Foo.toString(new int[] {0, 3, 4});\n" +
  90.388 +                      "     }\n" +
  90.389 +                      "}\n";
  90.390 +
  90.391 +        performTest(code,
  90.392 +                    Collections.<String, List<String>>emptyMap(),
  90.393 +                    Collections.singletonList("java.util.Arrays.toString($x)"));
  90.394 +    }
  90.395 +
  90.396 +    public void testCheckIdentifiers4() throws Exception {
  90.397 +        String code = "package test;\n" +
  90.398 +                      "public class Test {" +
  90.399 +                      "     {\n" +
  90.400 +                      "          java.util.Arrays.toString(new int[] {0, 3, 4});\n" +
  90.401 +                      "     }\n" +
  90.402 +                      "}\n";
  90.403 +
  90.404 +        performTest(code,
  90.405 +                    Collections.singletonMap("Arrays", Arrays.asList("java.util.Arrays")), //could be imported in the input pattern
  90.406 +                    Collections.<String>emptyList());
  90.407 +    }
  90.408 +
  90.409 +    public void testLambdaInput() throws Exception {
  90.410 +        String code = "package test; public class Test {public void test() { new java.io.FilenameFilter() { public boolean accept(java.io.File dir, String name) { return true; } }; } }";
  90.411 +
  90.412 +        performTest(code,
  90.413 +                    Collections.singletonMap("new $type() {public $retType $name($params$) { $body$; } }", Arrays.asList("new java.io.FilenameFilter() { public boolean accept(java.io.File dir, String name) { return true; } }")),
  90.414 +
  90.415 +                    Collections.<String>emptyList());
  90.416 +    }
  90.417 +
  90.418 +    public void testDoubleCheckedLockingWithVariable() throws Exception {
  90.419 +        String dcl =  "if (o == null) {\n" +
  90.420 +                      "              Object o1 = new Object();\n" +
  90.421 +                      "              synchronized (Test.class) {\n" +
  90.422 +                      "                  if (o == null) {\n" +
  90.423 +                      "                      o = o1;\n" +
  90.424 +                      "                  }\n" +
  90.425 +                      "              }\n" +
  90.426 +                      "          }";
  90.427 +        String code = "package test;\n" +
  90.428 +                      "public class Test {\n" +
  90.429 +                      "     private Object o;\n" +
  90.430 +                      "     private void t() {\n" +
  90.431 +                      "          " + dcl + "\n" +
  90.432 +                      "     }\n" +
  90.433 +                      "}\n";
  90.434 +
  90.435 +        performTest(code,
  90.436 +                    Collections.singletonMap("if ($var == null) {$pref$; synchronized ($lock) { if ($var == null) { $init$; } } }", Arrays.asList(dcl)),
  90.437 +                    Collections.<String>emptyList());
  90.438 +    }
  90.439 +
  90.440 +    public void testMethodName1() throws Exception {
  90.441 +        String code = "package test; public class Test {public void test() { clone(); } }";
  90.442 +
  90.443 +        performTest(code,
  90.444 +                    Collections.<String, List<String>>emptyMap(),
  90.445 +                    Collections.<String>singletonList("public void clone() {$stmts$;}"));
  90.446 +    }
  90.447 +
  90.448 +    public void testMethodName2() throws Exception {
  90.449 +        String code = "package test; public class Test {public void test() { clone(); } }";
  90.450 +
  90.451 +        performTest(code,
  90.452 +                    Collections.singletonMap("public void test() {$stmts$;}", Arrays.asList("public void test() { clone(); }")),
  90.453 +                    Collections.<String>emptyList());
  90.454 +    }
  90.455 +    
  90.456 +    public void testBooleanLiterals() throws Exception {
  90.457 +        String code = "package test; public class Test { public void test() { if (false) { System.err.println(\"false\"); } if (true) { System.err.println(\"true\"); } } }";
  90.458 +
  90.459 +        performTest(code,
  90.460 +                    Collections.singletonMap("if (true) $then; else $else$;", Arrays.asList("if (true) { System.err.println(\"true\"); }")),
  90.461 +                    Collections.<String>emptyList());
  90.462 +    }
  90.463 +    
  90.464 +    public void testEfficientMultiMatching() throws Exception {
  90.465 +        String code = "package test; public class Test { private void m() {} }";
  90.466 +
  90.467 +        performTest(code,
  90.468 +                    Collections.<String, List<String>>emptyMap(),
  90.469 +                    Collections.singletonList("$mods$ class $name implements $i$ { }"));
  90.470 +    }
  90.471 +
  90.472 +    private long measure(String baseCode, String toInsert, int repetitions, String pattern) throws Exception {
  90.473 +        int pos = baseCode.indexOf('|');
  90.474 +
  90.475 +        assertTrue(pos != (-1));
  90.476 +
  90.477 +        baseCode = baseCode.replaceAll(Pattern.quote("|"), "");
  90.478 +        
  90.479 +        StringBuilder code = new StringBuilder(baseCode.length() + repetitions * toInsert.length());
  90.480 +
  90.481 +        code.append(baseCode);
  90.482 +        
  90.483 +        while (repetitions-- > 0) {
  90.484 +            code.insert(pos, toInsert);
  90.485 +        }
  90.486 +
  90.487 +        long startTime = System.currentTimeMillis();
  90.488 +
  90.489 +        performTest(code.toString(),
  90.490 +                    Collections.<String, List<String>>emptyMap(),
  90.491 +                    Arrays.asList(pattern));
  90.492 +
  90.493 +        long endTime = System.currentTimeMillis();
  90.494 +
  90.495 +        return endTime - startTime;
  90.496 +    }
  90.497 +
  90.498 +    public void XtestMeasureTime() throws Exception {
  90.499 +        String code = TestUtilities.copyFileToString(new File("/usr/local/home/lahvac/src/nb//outgoing/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionProvider.java"));
  90.500 +        List<String> patterns = new LinkedList<String>();
  90.501 +
  90.502 +        for (int cntr = 0; cntr < 1000; cntr++) {
  90.503 +            patterns.add("System.err.println($1)");
  90.504 +        }
  90.505 +
  90.506 +        performTest(code,
  90.507 +                    Collections.<String, List<String>>emptyMap(),
  90.508 +                    patterns);
  90.509 +    }
  90.510 +
  90.511 +    public void testMatches1() throws Exception {
  90.512 +        performMatchesTest("package test; public class Test { private void test() { f.isDirectory(); } }", Arrays.asList("$1.isDirectory()", "new ImageIcon($1)"), true);
  90.513 +    }
  90.514 +
  90.515 +    public void testSerialization() throws Exception {
  90.516 +        String text = "package test; public class Test { public void test1(boolean b) { int q; if (b) q = 2; else q = 3; } }";
  90.517 +
  90.518 +        prepareTest("test/Test.java", text);
  90.519 +
  90.520 +        ByteArrayOutputStream out = new ByteArrayOutputStream();
  90.521 +        EncodingContext ec = new EncodingContext(out, false);
  90.522 +
  90.523 +        createSearch().encode(info.getCompilationUnit(), ec, new AtomicBoolean());
  90.524 +        
  90.525 +        boolean matches = createSearch().matches(new ByteArrayInputStream(out.toByteArray()), new AtomicBoolean(), createSearch().create(info, new AtomicBoolean(), "{ $p$; $T $v; if($a) $v = $b; else $v = $c; $q$; }"));
  90.526 +
  90.527 +        assertTrue(matches);
  90.528 +    }
  90.529 +
  90.530 +    public void testFrequencies() throws Exception {
  90.531 +        String text = "package test; public class Test { public void test1(boolean b) { java.io.File f = null; f.isDirectory(); f.isDirectory(); new javax.swing.ImageIcon(null); } }";
  90.532 +
  90.533 +        prepareTest("test/Test.java", text);
  90.534 +
  90.535 +        ByteArrayOutputStream out = new ByteArrayOutputStream();
  90.536 +        EncodingContext ec = new EncodingContext(out, false);
  90.537 +
  90.538 +        createSearch().encode(info.getCompilationUnit(), ec, new AtomicBoolean());
  90.539 +        
  90.540 +        Map<String, Integer> actual = createSearch().matchesWithFrequencies(new ByteArrayInputStream(out.toByteArray()), createSearch().create(info, new AtomicBoolean(), "$1.isDirectory()", "new ImageIcon($1)"), new AtomicBoolean());
  90.541 +        Map<String, Integer> golden = new HashMap<String, Integer>();
  90.542 +
  90.543 +        golden.put("$1.isDirectory()", 2);
  90.544 +        golden.put("new ImageIcon($1)", 1);
  90.545 +
  90.546 +        assertEquals(golden, actual);
  90.547 +    }
  90.548 +
  90.549 +    public void testPatternEncodingAndIdentifiers() throws Exception {
  90.550 +        String text = "package test; public class Test { }";
  90.551 +
  90.552 +        prepareTest("test/Test.java", text);
  90.553 +
  90.554 +        BulkPattern bp = createSearch().create(info, new AtomicBoolean(), "$0.isDirectory()");
  90.555 +
  90.556 +        assertEquals(Arrays.asList(new HashSet<String>(Arrays.asList("isDirectory"))), bp.getIdentifiers());
  90.557 +        //TODO: the actual code for kinds differs for NFABased search and REBased search:
  90.558 +//        assertEquals(Arrays.asList(new HashSet<String>(Arrays.asList(Kind.METHOD_INVOCATION.name()))), bp.getKinds());
  90.559 +    }
  90.560 +    
  90.561 +    public void testModifiersMultiVariable() throws Exception {
  90.562 +        String code = "package test;\n" +
  90.563 +                       "public class Test {\n" +
  90.564 +                       "     @Deprecated @Override public Test test;\n" +
  90.565 +                       "}\n";
  90.566 +
  90.567 +        performTest(code,
  90.568 +                    Collections.singletonMap("$mods$ @Deprecated public $type $name = $init$;", Arrays.asList("@Deprecated @Override public Test test;")),
  90.569 +                    Collections.<String>emptyList());
  90.570 +    }
  90.571 +
  90.572 +    protected abstract BulkSearch createSearch();
  90.573 +    
  90.574 +    private void performMatchesTest(String text, List<String> patterns, boolean golden) throws Exception {
  90.575 +        prepareTest("test/Test.java", text);
  90.576 +
  90.577 +        BulkPattern p = createSearch().create(info, new AtomicBoolean(), patterns);
  90.578 +
  90.579 +        boolean result = createSearch().matches(info, new AtomicBoolean(), new TreePath(info.getCompilationUnit()), p);
  90.580 +
  90.581 +        assertEquals(golden, result);
  90.582 +    }
  90.583 +    
  90.584 +    private void performTest(String text, Map<String, List<String>> containedPatterns, Collection<String> notContainedPatterns) throws Exception {
  90.585 +        prepareTest("test/Test.java", text);
  90.586 +
  90.587 +        List<String> patterns = new LinkedList<String>();
  90.588 +
  90.589 +        patterns.addAll(containedPatterns.keySet());
  90.590 +        patterns.addAll(notContainedPatterns);
  90.591 +
  90.592 +        long s1 = System.currentTimeMillis();
  90.593 +        BulkPattern p = createSearch().create(info, new AtomicBoolean(), patterns);
  90.594 +        long e1 = System.currentTimeMillis();
  90.595 +
  90.596 +//        System.err.println("create: " + (e1 - s1));
  90.597 +
  90.598 +        long s2 = System.currentTimeMillis();
  90.599 +        Map<String, Collection<TreePath>> result = createSearch().match(info, new AtomicBoolean(), new TreePath(info.getCompilationUnit()), p);
  90.600 +        long e2 = System.currentTimeMillis();
  90.601 +
  90.602 +//        System.err.println("match: " + (e2 - s2));
  90.603 +
  90.604 +        assertTrue(result.toString(), result.keySet().containsAll(containedPatterns.keySet()));
  90.605 +
  90.606 +        for (Entry<String, Collection<TreePath>> e : result.entrySet()) {
  90.607 +            List<String> actual = new LinkedList<String>();
  90.608 +
  90.609 +            for (TreePath tp : e.getValue()) {
  90.610 +                assertNotNull(TreePathHandle.create(tp, info).resolve(info));
  90.611 +                
  90.612 +                int start = (int) info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), tp.getLeaf());
  90.613 +                int end   = (int) info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), tp.getLeaf());
  90.614 +
  90.615 +                actual.add(info.getText().substring(start, end));
  90.616 +            }
  90.617 +
  90.618 +            assertEquals(e.getKey(), containedPatterns.get(e.getKey()), actual);
  90.619 +        }
  90.620 +
  90.621 +
  90.622 +        Set<String> none = new HashSet<String>(result.keySet());
  90.623 +
  90.624 +        none.retainAll(notContainedPatterns);
  90.625 +
  90.626 +        assertTrue(none.isEmpty());
  90.627 +
  90.628 +        if (!verifyIndexingData())
  90.629 +            return ;
  90.630 +        
  90.631 +        //ensure the returned identifiers/treeKinds are correct:
  90.632 +        ByteArrayOutputStream data = new ByteArrayOutputStream();
  90.633 +        EncodingContext ec = new EncodingContext(data, false);
  90.634 +        
  90.635 +        createSearch().encode(info.getCompilationUnit(), ec, new AtomicBoolean());
  90.636 +
  90.637 +        for (int i = 0; i < containedPatterns.size(); i++) {
  90.638 +            assertTrue("expected: " + p.getIdentifiers().get(i) + ", but exist only: " + ec.getIdentifiers(), ec.getIdentifiers().containsAll(p.getIdentifiers().get(i)));
  90.639 +            
  90.640 +            for (List<String> phrase : p.getRequiredContent().get(i)) {
  90.641 +                assertTrue("expected: " + phrase + ", but exist only: " + ec.getContent() + "(all phrases: " + p.getRequiredContent().get(i) + ")", Collections.indexOfSubList(ec.getContent(), phrase) != (-1));
  90.642 +            }
  90.643 +        }
  90.644 +
  90.645 +        data.close();
  90.646 +        assertEquals(!containedPatterns.isEmpty(), createSearch().matches(new ByteArrayInputStream(data.toByteArray()), new AtomicBoolean(), p));
  90.647 +    }
  90.648 +    
  90.649 +    private void prepareTest(String fileName, String code) throws Exception {
  90.650 +        clearWorkDir();
  90.651 +
  90.652 +        FileUtil.refreshFor(File.listRoots());
  90.653 +
  90.654 +        FileObject workFO = FileUtil.toFileObject(getWorkDir());
  90.655 +
  90.656 +        assertNotNull(workFO);
  90.657 +
  90.658 +        workFO.refresh();
  90.659 +
  90.660 +        sourceRoot = workFO.createFolder("src");
  90.661 +        FileObject buildRoot  = workFO.createFolder("build");
  90.662 +        FileObject cache = workFO.createFolder("cache");
  90.663 +
  90.664 +        FileObject data = FileUtil.createData(sourceRoot, fileName);
  90.665 +        File dataFile = FileUtil.toFile(data);
  90.666 +
  90.667 +        assertNotNull(dataFile);
  90.668 +
  90.669 +        TestUtilities.copyStringToFile(dataFile, code);
  90.670 +
  90.671 +        SourceUtilsTestUtil.prepareTest(sourceRoot, buildRoot, cache);
  90.672 +
  90.673 +        DataObject od = DataObject.find(data);
  90.674 +        EditorCookie ec = od.getLookup().lookup(EditorCookie.class);
  90.675 +
  90.676 +        assertNotNull(ec);
  90.677 +
  90.678 +        doc = ec.openDocument();
  90.679 +        doc.putProperty(Language.class, JavaTokenId.language());
  90.680 +
  90.681 +        JavaSource js = JavaSource.forFileObject(data);
  90.682 +
  90.683 +        assertNotNull(js);
  90.684 +
  90.685 +        info = SourceUtilsTestUtil.getCompilationInfo(js, Phase.RESOLVED);
  90.686 +
  90.687 +        assertNotNull(info);
  90.688 +    }
  90.689 +
  90.690 +    private FileObject sourceRoot;
  90.691 +    private CompilationInfo info;
  90.692 +    private Document doc;
  90.693 +
  90.694 +    protected boolean verifyIndexingData() {
  90.695 +        return true;
  90.696 +    }
  90.697 +}
    91.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    91.2 +++ b/java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/pm/CopyFinderBasedBulkSearchTest.java	Wed May 08 21:47:42 2013 +0200
    91.3 @@ -0,0 +1,99 @@
    91.4 +/*
    91.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    91.6 + *
    91.7 + * Copyright 2010 Oracle and/or its affiliates. All rights reserved.
    91.8 + *
    91.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   91.10 + * Other names may be trademarks of their respective owners.
   91.11 + *
   91.12 + * The contents of this file are subject to the terms of either the GNU
   91.13 + * General Public License Version 2 only ("GPL") or the Common
   91.14 + * Development and Distribution License("CDDL") (collectively, the
   91.15 + * "License"). You may not use this file except in compliance with the
   91.16 + * License. You can obtain a copy of the License at
   91.17 + * http://www.netbeans.org/cddl-gplv2.html
   91.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   91.19 + * specific language governing permissions and limitations under the
   91.20 + * License.  When distributing the software, include this License Header
   91.21 + * Notice in each file and include the License file at
   91.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   91.23 + * particular file as subject to the "Classpath" exception as provided
   91.24 + * by Oracle in the GPL Version 2 section of the License file that
   91.25 + * accompanied this code. If applicable, add the following below the
   91.26 + * License Header, with the fields enclosed by brackets [] replaced by
   91.27 + * your own identifying information:
   91.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   91.29 + *
   91.30 + * If you wish your version of this file to be governed by only the CDDL
   91.31 + * or only the GPL Version 2, indicate your decision by adding
   91.32 + * "[Contributor] elects to include this software in this distribution
   91.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   91.34 + * single choice of license, a recipient has the option to distribute
   91.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   91.36 + * to extend the choice of license to its licensees as provided above.
   91.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   91.38 + * Version 2 license, then the option applies only if the new code is
   91.39 + * made subject to such option by the copyright holder.
   91.40 + *
   91.41 + * Contributor(s):
   91.42 + *
   91.43 + * Portions Copyrighted 2009 Sun Microsystems, Inc.
   91.44 + */
   91.45 +
   91.46 +package org.netbeans.modules.java.hints.spiimpl.pm;
   91.47 +
   91.48 +/**
   91.49 + *
   91.50 + * @author lahvac
   91.51 + */
   91.52 +public class CopyFinderBasedBulkSearchTest extends BulkSearchTestPerformer {
   91.53 +
   91.54 +    public CopyFinderBasedBulkSearchTest(String name) {
   91.55 +        super(name);
   91.56 +    }
   91.57 +
   91.58 +    @Override
   91.59 +    protected BulkSearch createSearch() {
   91.60 +        return new CopyFinderBasedBulkSearch();
   91.61 +    }
   91.62 +
   91.63 +    @Override
   91.64 +    protected boolean verifyIndexingData() {
   91.65 +        return false;
   91.66 +    }
   91.67 +
   91.68 +    @Override
   91.69 +    public void testSerialization() throws Exception {
   91.70 +        //XXX
   91.71 +    }
   91.72 +
   91.73 +    @Override
   91.74 +    public void testFrequencies() throws Exception {
   91.75 +        //XXX: serialization is a prerequisite
   91.76 +    }
   91.77 +
   91.78 +    @Override
   91.79 +    public void testPatternEncodingAndIdentifiers() throws Exception {
   91.80 +        //XXX
   91.81 +    }
   91.82 +
   91.83 +    @Override
   91.84 +    public void testNoExponentialTimeComplexity() throws Exception {
   91.85 +        //XXX
   91.86 +    }
   91.87 +
   91.88 +    @Override
   91.89 +    public void testCheckIdentifiers2() throws Exception {
   91.90 +        //not critical, only improves performance on vast amounts of sources,
   91.91 +        //and NFA based search is used in such case anyway.
   91.92 +        //XXX
   91.93 +    }
   91.94 +
   91.95 +    @Override
   91.96 +    public void testCheckIdentifiers3() throws Exception {
   91.97 +        //not critical, only improves performance on vast amounts of sources,
   91.98 +        //and NFA based search is used in such case anyway.
   91.99 +        //XXX
  91.100 +    }
  91.101 +
  91.102 +}
  91.103 \ No newline at end of file
    92.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    92.2 +++ b/java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/pm/NFABasedBulkSearchTest.java	Wed May 08 21:47:42 2013 +0200
    92.3 @@ -0,0 +1,69 @@
    92.4 +/*
    92.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    92.6 + *
    92.7 + * Copyright 2009-2010 Oracle and/or its affiliates. All rights reserved.
    92.8 + *
    92.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   92.10 + * Other names may be trademarks of their respective owners.
   92.11 + *
   92.12 + * The contents of this file are subject to the terms of either the GNU
   92.13 + * General Public License Version 2 only ("GPL") or the Common
   92.14 + * Development and Distribution License("CDDL") (collectively, the
   92.15 + * "License"). You may not use this file except in compliance with the
   92.16 + * License. You can obtain a copy of the License at
   92.17 + * http://www.netbeans.org/cddl-gplv2.html
   92.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   92.19 + * specific language governing permissions and limitations under the
   92.20 + * License.  When distributing the software, include this License Header
   92.21 + * Notice in each file and include the License file at
   92.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   92.23 + * particular file as subject to the "Classpath" exception as provided
   92.24 + * by Oracle in the GPL Version 2 section of the License file that
   92.25 + * accompanied this code. If applicable, add the following below the
   92.26 + * License Header, with the fields enclosed by brackets [] replaced by
   92.27 + * your own identifying information:
   92.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   92.29 + *
   92.30 + * If you wish your version of this file to be governed by only the CDDL
   92.31 + * or only the GPL Version 2, indicate your decision by adding
   92.32 + * "[Contributor] elects to include this software in this distribution
   92.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   92.34 + * single choice of license, a recipient has the option to distribute
   92.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   92.36 + * to extend the choice of license to its licensees as provided above.
   92.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   92.38 + * Version 2 license, then the option applies only if the new code is
   92.39 + * made subject to such option by the copyright holder.
   92.40 + *
   92.41 + * Contributor(s):
   92.42 + *
   92.43 + * Portions Copyrighted 2009-2010 Sun Microsystems, Inc.
   92.44 + */
   92.45 +
   92.46 +package org.netbeans.modules.java.hints.spiimpl.pm;
   92.47 +
   92.48 +/**
   92.49 + *
   92.50 + * @author lahvac
   92.51 + */
   92.52 +public class NFABasedBulkSearchTest extends BulkSearchTestPerformer {
   92.53 +
   92.54 +    public NFABasedBulkSearchTest(String name) {
   92.55 +        super(name);
   92.56 +    }
   92.57 +
   92.58 +//    public static TestSuite suite() {
   92.59 +//        NbTestSuite r = new NbTestSuite();
   92.60 +//
   92.61 +//        r.addTest(new NFABasedBulkSearchTest("testField1"));
   92.62 +//        r.addTest(new NFABasedBulkSearchTest("testField2"));
   92.63 +//
   92.64 +//        return r;
   92.65 +//    }
   92.66 +
   92.67 +    @Override
   92.68 +    protected BulkSearch createSearch() {
   92.69 +        return new NFABasedBulkSearch();
   92.70 +    }
   92.71 +
   92.72 +}
    93.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    93.2 +++ b/java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/pm/PatternCompilerTest.java	Wed May 08 21:47:42 2013 +0200
    93.3 @@ -0,0 +1,203 @@
    93.4 +/*
    93.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    93.6 + *
    93.7 + * Copyright 2008-2010 Oracle and/or its affiliates. All rights reserved.
    93.8 + *
    93.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   93.10 + * Other names may be trademarks of their respective owners.
   93.11 + *
   93.12 + * The contents of this file are subject to the terms of either the GNU
   93.13 + * General Public License Version 2 only ("GPL") or the Common
   93.14 + * Development and Distribution License("CDDL") (collectively, the
   93.15 + * "License"). You may not use this file except in compliance with the
   93.16 + * License. You can obtain a copy of the License at
   93.17 + * http://www.netbeans.org/cddl-gplv2.html
   93.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   93.19 + * specific language governing permissions and limitations under the
   93.20 + * License.  When distributing the software, include this License Header
   93.21 + * Notice in each file and include the License file at
   93.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   93.23 + * particular file as subject to the "Classpath" exception as provided
   93.24 + * by Oracle in the GPL Version 2 section of the License file that
   93.25 + * accompanied this code. If applicable, add the following below the
   93.26 + * License Header, with the fields enclosed by brackets [] replaced by
   93.27 + * your own identifying information:
   93.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   93.29 + *
   93.30 + * If you wish your version of this file to be governed by only the CDDL
   93.31 + * or only the GPL Version 2, indicate your decision by adding
   93.32 + * "[Contributor] elects to include this software in this distribution
   93.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   93.34 + * single choice of license, a recipient has the option to distribute
   93.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   93.36 + * to extend the choice of license to its licensees as provided above.
   93.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   93.38 + * Version 2 license, then the option applies only if the new code is
   93.39 + * made subject to such option by the copyright holder.
   93.40 + *
   93.41 + * Contributor(s):
   93.42 + *
   93.43 + * Portions Copyrighted 2008-2009 Sun Microsystems, Inc.
   93.44 + */
   93.45 +
   93.46 +package org.netbeans.modules.java.hints.spiimpl.pm;
   93.47 +
   93.48 +import com.sun.source.tree.Tree;
   93.49 +import com.sun.source.util.SourcePositions;
   93.50 +import com.sun.source.util.TreePath;
   93.51 +import java.util.Arrays;
   93.52 +import java.util.HashMap;
   93.53 +import java.util.Iterator;
   93.54 +import java.util.Map;
   93.55 +import java.util.Map.Entry;
   93.56 +import java.util.concurrent.atomic.AtomicBoolean;
   93.57 +import org.netbeans.modules.java.hints.spiimpl.TestBase;
   93.58 +import org.netbeans.api.java.source.matching.Matcher;
   93.59 +import org.netbeans.api.java.source.matching.Occurrence;
   93.60 +import org.openide.util.Pair;
   93.61 +
   93.62 +/**
   93.63 + *
   93.64 + * @author Jan Lahoda
   93.65 + */
   93.66 +public class PatternCompilerTest extends TestBase {
   93.67 +
   93.68 +    public PatternCompilerTest(String name) {
   93.69 +        super(name);
   93.70 +    }
   93.71 +
   93.72 +    public void testSimple1() throws Exception {
   93.73 +        performVariablesTest("package test; public class Test {public void test() {int i = |1 + 2|;}}", "$1+$2",
   93.74 +                             Pair.<String, String>of("$1", "1"),
   93.75 +                             Pair.<String, String>of("$2", "2"));
   93.76 +    }
   93.77 +
   93.78 +    public void testTyped1() throws Exception {
   93.79 +        performVariablesTest("package test; public class Test {public void test() {|String.valueOf(\"t\")|;}}", "String.valueOf($1{String})",
   93.80 +                             Pair.<String, String>of("$1", "\"t\""));
   93.81 +    }
   93.82 +
   93.83 +//    public void testTyped2() throws Exception {
   93.84 +//        performVariablesTest("package test; public class Test {public void test() {|String.valueOf(\"t\")|;}}", "$2{java.lang.String}.valueOf($1{String})",
   93.85 +//                             new Pair<String, String>("$1", "\"t\""),
   93.86 +//                             new Pair<String, String>("$2", "String"));
   93.87 +//    }
   93.88 +
   93.89 +    public void testTyped3() throws Exception {
   93.90 +        performVariablesTest("package test; public class Test {public void test(String str) {|str.valueOf(\"t\")|;}}", "String.valueOf($1{String})",
   93.91 +                             Pair.<String, String>of("$1", "\"t\""));
   93.92 +    }
   93.93 +
   93.94 +    public void testTyped4() throws Exception {
   93.95 +        performVariablesTest("package test; public class Test {public void test() {|Integer.bitCount(1)|;}}", "$2{java.lang.String}.valueOf($1{String})",
   93.96 +                             (Pair[]) null);
   93.97 +    }
   93.98 +
   93.99 +    public void testTyped5() throws Exception {
  93.100 +        performVariablesTest("package test; public class Test {public void test() {java.io.File f = null; |f.toURI().toURL()|;}}", "$1{java.io.File}.toURL()",
  93.101 +                             (Pair[]) null);
  93.102 +    }
  93.103 +
  93.104 +    public void testTypedPrimitiveType() throws Exception {
  93.105 +        performVariablesTest("package test; public class Test {public void test(int i) {|test(1)|;}}", "$0{test.Test}.test($1{int})",
  93.106 +                             Pair.<String, String>of("$1", "1"));
  93.107 +    }
  93.108 +
  93.109 +    public void testMemberSelectVSIdentifier() throws Exception {
  93.110 +        performVariablesTest("package test; public class Test {void test1() {} void test2() {|test1()|;}}", "$1{test.Test}.test1()",
  93.111 +                             new Pair[0]);
  93.112 +    }
  93.113 +
  93.114 +    public void testSubClass() throws Exception {
  93.115 +        performVariablesTest("package test; public class Test {void test() {String s = null; |s.toString()|;}}", "$1{java.lang.CharSequence}.toString()",
  93.116 +                             Pair.<String, String>of("$1", "s"));
  93.117 +    }
  93.118 +
  93.119 +    public void testEquality1() throws Exception {
  93.120 +        performVariablesTest("package test; public class Test {void test() {|test()|;}}", "$1{test.Test}.test()",
  93.121 +                             new Pair[0]);
  93.122 +    }
  93.123 +
  93.124 +    public void testEquality2() throws Exception {
  93.125 +        performVariablesTest("package test; public class Test {void test() {String s = null; |String.valueOf(1).charAt(0)|;}}", "$1{java.lang.String}.charAt(0)",
  93.126 +                             Pair.<String, String>of("$1", "String.valueOf(1)"));
  93.127 +    }
  93.128 +
  93.129 +    public void testEquality3() throws Exception {
  93.130 +        performVariablesTest("package test; public class Test {void test() {String s = null; |s.charAt(0)|;}}", "java.lang.String.valueOf(1).charAt(0)",
  93.131 +                             (Pair[]) null);
  93.132 +    }
  93.133 +
  93.134 +    public void testType1() throws Exception {
  93.135 +        performVariablesTest("package test; public class Test {void test() {|String| s;}}", "java.lang.String",
  93.136 +                             new Pair[0]);
  93.137 +    }
  93.138 +
  93.139 +    public void testStatements1() throws Exception {
  93.140 +        performVariablesTest("package test; public class Test {void test() {|assert true : \"\";|}}", "assert $1{boolean} : $2{java.lang.Object};",
  93.141 +                             new Pair[0]);
  93.142 +    }
  93.143 +
  93.144 +    protected void performVariablesTest(String code, String pattern, Pair<String, String>... duplicates) throws Exception {
  93.145 +        String[] split = code.split("\\|");
  93.146 +
  93.147 +        assertEquals(Arrays.toString(split), 3, split.length);
  93.148 +
  93.149 +        int      start = split[0].length();
  93.150 +        int      end   = start + split[1].length();
  93.151 +
  93.152 +        code = split[0] + split[1] + split[2];
  93.153 +
  93.154 +        prepareTest("test/Test.java", code);
  93.155 +
  93.156 +        TreePath tp = info.getTreeUtilities().pathFor((start + end) / 2);
  93.157 +
  93.158 +        while (tp != null) {
  93.159 +            Tree t = tp.getLeaf();
  93.160 +            SourcePositions sp = info.getTrees().getSourcePositions();
  93.161 +
  93.162 +            if (   start == sp.getStartPosition(info.getCompilationUnit(), t)
  93.163 +                && end   == sp.getEndPosition(info.getCompilationUnit(), t)) {
  93.164 +                break;
  93.165 +            }
  93.166 +
  93.167 +            tp = tp.getParentPath();
  93.168 +        }
  93.169 +
  93.170 +        assertNotNull(tp);
  93.171 +
  93.172 +        //XXX:
  93.173 +        Iterator<? extends Occurrence> vars = Matcher.create(info).setCancel(new AtomicBoolean()).setSearchRoot(tp).setTreeTopSearch().match(PatternCompilerUtilities.compile(info, pattern)).iterator();
  93.174 +
  93.175 +        if (duplicates == null) {
  93.176 +            assertFalse(vars.hasNext());
  93.177 +            return ;
  93.178 +        }
  93.179 +
  93.180 +        assertNotNull(vars);
  93.181 +        assertTrue(vars.hasNext());
  93.182 +
  93.183 +        Map<String, String> actual = new HashMap<String, String>();
  93.184 +
  93.185 +        for (Entry<String, TreePath> e : vars.next().getVariables().entrySet()) {
  93.186 +            int[] span = new int[] {
  93.187 +                (int) info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), e.getValue().getLeaf()),
  93.188 +                (int) info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), e.getValue().getLeaf())
  93.189 +            };
  93.190 +
  93.191 +            actual.put(e.getKey(), info.getText().substring(span[0], span[1]));
  93.192 +        }
  93.193 +
  93.194 +        assertFalse(vars.hasNext());
  93.195 +
  93.196 +        for (Pair<String, String> dup : duplicates) {
  93.197 +            String span = actual.remove(dup.first());
  93.198 +
  93.199 +            if (span == null) {
  93.200 +                fail(dup.first());
  93.201 +            }
  93.202 +            assertEquals(dup.first()+ ":" + span, span, dup.second());
  93.203 +        }
  93.204 +    }
  93.205 +
  93.206 +}
    94.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    94.2 +++ b/java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/pm/PatternCompilerUtilities.java	Wed May 08 21:47:42 2013 +0200
    94.3 @@ -0,0 +1,88 @@
    94.4 +/*
    94.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    94.6 + *
    94.7 + * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
    94.8 + *
    94.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   94.10 + * Other names may be trademarks of their respective owners.
   94.11 + *
   94.12 + * The contents of this file are subject to the terms of either the GNU
   94.13 + * General Public License Version 2 only ("GPL") or the Common
   94.14 + * Development and Distribution License("CDDL") (collectively, the
   94.15 + * "License"). You may not use this file except in compliance with the
   94.16 + * License. You can obtain a copy of the License at
   94.17 + * http://www.netbeans.org/cddl-gplv2.html
   94.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   94.19 + * specific language governing permissions and limitations under the
   94.20 + * License.  When distributing the software, include this License Header
   94.21 + * Notice in each file and include the License file at
   94.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   94.23 + * particular file as subject to the "Classpath" exception as provided
   94.24 + * by Oracle in the GPL Version 2 section of the License file that
   94.25 + * accompanied this code. If applicable, add the following below the
   94.26 + * License Header, with the fields enclosed by brackets [] replaced by
   94.27 + * your own identifying information:
   94.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   94.29 + *
   94.30 + * If you wish your version of this file to be governed by only the CDDL
   94.31 + * or only the GPL Version 2, indicate your decision by adding
   94.32 + * "[Contributor] elects to include this software in this distribution
   94.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   94.34 + * single choice of license, a recipient has the option to distribute
   94.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   94.36 + * to extend the choice of license to its licensees as provided above.
   94.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   94.38 + * Version 2 license, then the option applies only if the new code is
   94.39 + * made subject to such option by the copyright holder.
   94.40 + *
   94.41 + * Contributor(s):
   94.42 + *
   94.43 + * Portions Copyrighted 2011 Sun Microsystems, Inc.
   94.44 + */
   94.45 +package org.netbeans.modules.java.hints.spiimpl.pm;
   94.46 +
   94.47 +import java.util.Collections;
   94.48 +import java.util.HashMap;
   94.49 +import java.util.Map;
   94.50 +import java.util.regex.Matcher;
   94.51 +import javax.lang.model.type.TypeMirror;
   94.52 +import org.netbeans.api.java.source.CompilationInfo;
   94.53 +import org.netbeans.modules.java.hints.spiimpl.pm.PatternCompiler;
   94.54 +import org.netbeans.api.java.source.matching.Pattern;
   94.55 +import org.netbeans.modules.java.hints.spiimpl.Hacks;
   94.56 +
   94.57 +/**
   94.58 + *
   94.59 + * @author lahvac
   94.60 + */
   94.61 +public class PatternCompilerUtilities {
   94.62 +
   94.63 +    public static Pattern compile(CompilationInfo info, String pattern) {
   94.64 +        Map<String, TypeMirror> constraints = new HashMap<String, TypeMirror>();
   94.65 +        pattern = parseOutTypesFromPattern(info, pattern, constraints);
   94.66 +
   94.67 +        return PatternCompiler.compile(info, pattern, constraints, Collections.<String>emptyList());
   94.68 +    }
   94.69 +
   94.70 +    public static String parseOutTypesFromPattern(CompilationInfo info, String pattern, Map<String, TypeMirror> variablesToTypes) {
   94.71 +        java.util.regex.Pattern p = java.util.regex.Pattern.compile("(\\$[0-9])(\\{([^}]*)\\})?");
   94.72 +        StringBuilder filtered = new StringBuilder();
   94.73 +        Matcher m = p.matcher(pattern);
   94.74 +        int i = 0;
   94.75 +
   94.76 +        while (m.find()) {
   94.77 +            filtered.append(pattern.substring(i, m.start()));
   94.78 +            i = m.end();
   94.79 +
   94.80 +            String var  = m.group(1);
   94.81 +            String type = m.group(3);
   94.82 +
   94.83 +            filtered.append(var);
   94.84 +            variablesToTypes.put(var, type != null ? Hacks.parseFQNType(info, type) : null);
   94.85 +        }
   94.86 +
   94.87 +        filtered.append(pattern.substring(i));
   94.88 +
   94.89 +        return filtered.toString();
   94.90 +    }
   94.91 +}
    95.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    95.2 +++ b/java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/processor/JavaHintsAnnotationProcessorTest.java	Wed May 08 21:47:42 2013 +0200
    95.3 @@ -0,0 +1,149 @@
    95.4 +/*
    95.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    95.6 + *
    95.7 + * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
    95.8 + *
    95.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   95.10 + * Other names may be trademarks of their respective owners.
   95.11 + *
   95.12 + * The contents of this file are subject to the terms of either the GNU
   95.13 + * General Public License Version 2 only ("GPL") or the Common
   95.14 + * Development and Distribution License("CDDL") (collectively, the
   95.15 + * "License"). You may not use this file except in compliance with the
   95.16 + * License. You can obtain a copy of the License at
   95.17 + * http://www.netbeans.org/cddl-gplv2.html
   95.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   95.19 + * specific language governing permissions and limitations under the
   95.20 + * License.  When distributing the software, include this License Header
   95.21 + * Notice in each file and include the License file at
   95.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   95.23 + * particular file as subject to the "Classpath" exception as provided
   95.24 + * by Oracle in the GPL Version 2 section of the License file that
   95.25 + * accompanied this code. If applicable, add the following below the
   95.26 + * License Header, with the fields enclosed by brackets [] replaced by
   95.27 + * your own identifying information:
   95.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   95.29 + *
   95.30 + * If you wish your version of this file to be governed by only the CDDL
   95.31 + * or only the GPL Version 2, indicate your decision by adding
   95.32 + * "[Contributor] elects to include this software in this distribution
   95.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   95.34 + * single choice of license, a recipient has the option to distribute
   95.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   95.36 + * to extend the choice of license to its licensees as provided above.
   95.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   95.38 + * Version 2 license, then the option applies only if the new code is
   95.39 + * made subject to such option by the copyright holder.
   95.40 + *
   95.41 + * Contributor(s):
   95.42 + *
   95.43 + * Portions Copyrighted 2012 Sun Microsystems, Inc.
   95.44 + */
   95.45 +package org.netbeans.modules.java.hints.spiimpl.processor;
   95.46 +
   95.47 +import java.io.ByteArrayOutputStream;
   95.48 +import java.io.File;
   95.49 +import org.netbeans.junit.NbTestCase;
   95.50 +import org.openide.util.test.AnnotationProcessorTestUtils;
   95.51 +import org.openide.util.test.TestFileUtils;
   95.52 +
   95.53 +/**
   95.54 + *
   95.55 + * @author lahvac
   95.56 + */
   95.57 +public class JavaHintsAnnotationProcessorTest extends NbTestCase {
   95.58 +
   95.59 +    public JavaHintsAnnotationProcessorTest(String name) {
   95.60 +        super(name);
   95.61 +    }
   95.62 +
   95.63 +    public void testErrors1() throws Exception {
   95.64 +        File src = new File(getWorkDir(), "src");
   95.65 +        File dest = new File(getWorkDir(), "classes");
   95.66 +        AnnotationProcessorTestUtils.makeSource(src, "p.H",
   95.67 +                "import org.netbeans.spi.java.hints.*;\n",
   95.68 +                "import org.netbeans.spi.editor.hints.*;\n",
   95.69 +                "@Hint(category=\"general\")\n",
   95.70 +                "public class H {\n",
   95.71 +                "    @TriggerPattern(\"$1.$2\")\n",
   95.72 +                "    public static String h1(HintContext ctx) { return null;}\n",
   95.73 +                "    @TriggerPattern(\"$1.$2.$3\")\n",
   95.74 +                "    public static ErrorDescription h2() { return null;}\n",
   95.75 +                "    @TriggerPatterns({@TriggerPattern(\"$1.$2.$3.$4\")})\n",
   95.76 +                "    private ErrorDescription h3(HintContext ctx) { return null;}\n",
   95.77 +                "    @TriggerPattern(value=\"$1.isEmpty()\", constraints=@ConstraintVariableType(variable=\"$unknown\", type=\"java.lang.String\"))\n",
   95.78 +                "    public static ErrorDescription h4(HintContext ctx) { return null;}\n",
   95.79 +                "}\n");
   95.80 +        TestFileUtils.writeFile(new File(src, "p/Bundle.properties"), "");
   95.81 +        ByteArrayOutputStream err = new ByteArrayOutputStream();
   95.82 +        assertFalse(AnnotationProcessorTestUtils.runJavac(src, null, dest, null, err));
   95.83 +        String errors = err.toString();
   95.84 +        assertTrue(errors.contains("error: The return type must be either org.netbeans.spi.editor.hints.ErrorDescription or java.util.List<org.netbeans.spi.editor.hints.ErrorDescription>"));
   95.85 +        assertTrue(errors.contains("error: The method must have exactly one parameter of type org.netbeans.spi.java.hints.HintContext"));
   95.86 +        assertTrue(errors.contains("error: The method must be static"));
   95.87 +        assertTrue(errors.contains("warning: Variable $unknown not used in the pattern"));
   95.88 +    }
   95.89 +
   95.90 +    public void testErrors2() throws Exception {
   95.91 +        File src = new File(getWorkDir(), "src");
   95.92 +        File dest = new File(getWorkDir(), "classes");
   95.93 +        AnnotationProcessorTestUtils.makeSource(src, "p.H",
   95.94 +                "import org.netbeans.spi.java.hints.*;\n",
   95.95 +                "import org.netbeans.spi.editor.hints.*;\n",
   95.96 +                "import java.util.*;\n",
   95.97 +                "@Hint(displayName=\"#DN_p.H\", description=\"#DESC_p.H\", category=\"general\")\n",
   95.98 +                "public class H {\n",
   95.99 +                "    @TriggerPattern(\"$1.$2.$3\")\n",
  95.100 +                "    public static List<ErrorDescription> hint(HintContext ctx) { return null;}\n",
  95.101 +                "}\n");
  95.102 +        TestFileUtils.writeFile(new File(src, "p/Bundle.properties"), "DN_p.H=DN_p.H\nDESC_p.H=DESC_p.H\n");
  95.103 +        ByteArrayOutputStream err = new ByteArrayOutputStream();
  95.104 +        assertTrue(AnnotationProcessorTestUtils.runJavac(src, null, dest, null, err));
  95.105 +    }
  95.106 +
  95.107 +    public void testCustomizerProvider() throws Exception {
  95.108 +        File src = new File(getWorkDir(), "src");
  95.109 +        File dest = new File(getWorkDir(), "classes");
  95.110 +        AnnotationProcessorTestUtils.makeSource(src, "p.H",
  95.111 +                "import org.netbeans.spi.java.hints.*;\n",
  95.112 +                "import org.netbeans.spi.editor.hints.*;\n",
  95.113 +                "import java.util.*;\n",
  95.114 +                "import java.util.prefs.*;\n",
  95.115 +                "import javax.swing.*;\n",
  95.116 +                "@Hint(displayName=\"dn\", description=\"desc\", category=\"general\", customizerProvider=H.Customizer.class)\n",
  95.117 +                "public class H {\n",
  95.118 +                "    @TriggerPattern(\"$1.$2.$3\")\n",
  95.119 +                "    public static List<ErrorDescription> hint(HintContext ctx) { return null;}\n",
  95.120 +                "    static final class Customizer implements CustomizerProvider {\n",
  95.121 +                "        @Override public JComponent getCustomizer(Preferences prefs) {\n",
  95.122 +                "            return new JPanel();\n",
  95.123 +                "        }\n",
  95.124 +                "    }\n",
  95.125 +                "}\n");
  95.126 +        TestFileUtils.writeFile(new File(src, "p/Bundle.properties"), "DN_p.H=DN_p.H\nDESC_p.H=DESC_p.H\n");
  95.127 +        ByteArrayOutputStream err = new ByteArrayOutputStream();
  95.128 +        assertFalse(AnnotationProcessorTestUtils.runJavac(src, null, dest, null, err));
  95.129 +        String errors = err.toString();
  95.130 +        assertTrue(errors.contains("error: Customizer provider must be public"));
  95.131 +        assertTrue(errors.contains("error: Customizer provider must provide a public default constructor"));
  95.132 +    }
  95.133 +
  95.134 +    public void testErrorsMessagesOnMethod() throws Exception {
  95.135 +        File src = new File(getWorkDir(), "src");
  95.136 +        File dest = new File(getWorkDir(), "classes");
  95.137 +        AnnotationProcessorTestUtils.makeSource(src, "p.H",
  95.138 +                "import org.netbeans.spi.java.hints.*;\n",
  95.139 +                "import org.netbeans.spi.editor.hints.*;\n",
  95.140 +                "import org.openide.util.NbBundle.Messages;\n",
  95.141 +                "import java.util.*;\n",
  95.142 +                "public class H {\n",
  95.143 +                "    @Hint(displayName=\"#DN_p.H\", description=\"#DESC_p.H\", category=\"general\")\n",
  95.144 +                "    @TriggerPattern(\"$1.$2.$3\")\n",
  95.145 +                "    @Messages({\"DN_p.H=1\", \"DESC_p.H=2\"})\n",
  95.146 +                "    public static List<ErrorDescription> hint(HintContext ctx) { return null;}\n",
  95.147 +                "}\n");
  95.148 +        ByteArrayOutputStream err = new ByteArrayOutputStream();
  95.149 +        boolean result = AnnotationProcessorTestUtils.runJavac(src, null, dest, null, err);
  95.150 +        assertTrue(err.toString(), result);
  95.151 +    }
  95.152 +}
    96.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    96.2 +++ b/java.hints/spi.java.hints/test/unit/src/org/netbeans/spi/java/hints/JavaFixUtilitiesTest.java	Wed May 08 21:47:42 2013 +0200
    96.3 @@ -0,0 +1,1161 @@
    96.4 +/*
    96.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    96.6 + *
    96.7 + * Copyright 2008-2010 Oracle and/or its affiliates. All rights reserved.
    96.8 + *
    96.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   96.10 + * Other names may be trademarks of their respective owners.
   96.11 + *
   96.12 + * The contents of this file are subject to the terms of either the GNU
   96.13 + * General Public License Version 2 only ("GPL") or the Common
   96.14 + * Development and Distribution License("CDDL") (collectively, the
   96.15 + * "License"). You may not use this file except in compliance with the
   96.16 + * License. You can obtain a copy of the License at
   96.17 + * http://www.netbeans.org/cddl-gplv2.html
   96.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   96.19 + * specific language governing permissions and limitations under the
   96.20 + * License.  When distributing the software, include this License Header
   96.21 + * Notice in each file and include the License file at
   96.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   96.23 + * particular file as subject to the "Classpath" exception as provided
   96.24 + * by Oracle in the GPL Version 2 section of the License file that
   96.25 + * accompanied this code. If applicable, add the following below the
   96.26 + * License Header, with the fields enclosed by brackets [] replaced by
   96.27 + * your own identifying information:
   96.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   96.29 + *
   96.30 + * If you wish your version of this file to be governed by only the CDDL
   96.31 + * or only the GPL Version 2, indicate your decision by adding
   96.32 + * "[Contributor] elects to include this software in this distribution
   96.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   96.34 + * single choice of license, a recipient has the option to distribute
   96.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   96.36 + * to extend the choice of license to its licensees as provided above.
   96.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   96.38 + * Version 2 license, then the option applies only if the new code is
   96.39 + * made subject to such option by the copyright holder.
   96.40 + *
   96.41 + * Contributor(s):
   96.42 + *
   96.43 + * Portions Copyrighted 2008-2010 Sun Microsystems, Inc.
   96.44 + */
   96.45 +
   96.46 +package org.netbeans.spi.java.hints;
   96.47 +
   96.48 +import org.netbeans.modules.java.hints.providers.spi.HintDescriptionFactory;
   96.49 +import org.netbeans.modules.java.hints.providers.spi.HintDescription;
   96.50 +import com.sun.source.tree.ClassTree;
   96.51 +import com.sun.source.tree.ExpressionTree;
   96.52 +import com.sun.source.tree.VariableTree;
   96.53 +import com.sun.source.util.TreePath;
   96.54 +import java.util.Collection;
   96.55 +import java.util.Collections;
   96.56 +import java.util.HashMap;
   96.57 +import java.util.List;
   96.58 +import java.util.Map;
   96.59 +import java.util.Map.Entry;
   96.60 +import java.util.concurrent.atomic.AtomicBoolean;
   96.61 +import javax.lang.model.element.ExecutableElement;
   96.62 +import javax.lang.model.element.TypeElement;
   96.63 +import javax.lang.model.type.TypeMirror;
   96.64 +import javax.lang.model.util.ElementFilter;
   96.65 +import org.netbeans.modules.java.hints.spiimpl.TestBase;
   96.66 +import org.netbeans.modules.java.hints.spiimpl.hints.HintsInvoker;
   96.67 +import org.netbeans.modules.java.hints.providers.spi.Trigger.PatternDescription;
   96.68 +import org.netbeans.modules.java.hints.spiimpl.options.HintsSettings;
   96.69 +import org.netbeans.modules.java.hints.spiimpl.pm.PatternCompilerUtilities;
   96.70 +import org.netbeans.spi.editor.hints.ErrorDescription;
   96.71 +import org.netbeans.spi.editor.hints.Fix;
   96.72 +import org.openide.LifecycleManager;
   96.73 +import org.openide.modules.SpecificationVersion;
   96.74 +import org.openide.util.MapFormat;
   96.75 +
   96.76 +/**
   96.77 + *
   96.78 + * @author Jan Lahoda
   96.79 + */
   96.80 +public class JavaFixUtilitiesTest extends TestBase {
   96.81 +
   96.82 +    public JavaFixUtilitiesTest(String name) {
   96.83 +        super(name);
   96.84 +    }
   96.85 +
   96.86 +    public void testSimple() throws Exception {
   96.87 +        SpecificationVersion v = computeSpecVersion("/**\n" +
   96.88 +                                                    " * @since 1.5\n" +
   96.89 +                                                    " */\n");
   96.90 +
   96.91 +        assertEquals(0, v.compareTo(new SpecificationVersion("1.5")));
   96.92 +    }
   96.93 +
   96.94 +    public void testSimpleDate() throws Exception {
   96.95 +        SpecificationVersion v = computeSpecVersion("/**\n" +
   96.96 +                                                    " * @since 1.5 (16 May 2005)\n" +
   96.97 +                                                    " */\n");
   96.98 +
   96.99 +        assertEquals(0, v.compareTo(new SpecificationVersion("1.5")));
  96.100 +    }
  96.101 +
  96.102 +    public void testLongText() throws Exception {
  96.103 +        SpecificationVersion v = computeSpecVersion("/**\n" +
  96.104 +                                                    " * @since 1.123.2.1 - branch propsheet_issue_29447\n" +
  96.105 +                                                    " */\n");
  96.106 +
  96.107 +        assertEquals(0, v.compareTo(new SpecificationVersion("1.123.2.1")));
  96.108 +    }
  96.109 +
  96.110 +    public void testModuleName() throws Exception {
  96.111 +        SpecificationVersion v = computeSpecVersion("/**\n" +
  96.112 +                                                    " * @since org.openide.filesystems 7.15\n" +
  96.113 +                                                    " */\n");
  96.114 +
  96.115 +        assertEquals(0, v.compareTo(new SpecificationVersion("7.15")));
  96.116 +    }
  96.117 +
  96.118 +    public void testModuleNameMajor() throws Exception {
  96.119 +        SpecificationVersion v = computeSpecVersion("/**\n" +
  96.120 +                                                    " * @since org.openide/1 4.42\n" +
  96.121 +                                                    " */\n");
  96.122 +
  96.123 +        assertEquals(0, v.compareTo(new SpecificationVersion("4.42")));
  96.124 +    }
  96.125 +
  96.126 +    public void testEnd() throws Exception {
  96.127 +        SpecificationVersion v = computeSpecVersion("/**\n" +
  96.128 +                                                    " * @since 1.5 */\n");
  96.129 +
  96.130 +        assertEquals(0, v.compareTo(new SpecificationVersion("1.5")));
  96.131 +    }
  96.132 +
  96.133 +    public void testOpenAPI() throws Exception {
  96.134 +        SpecificationVersion v = computeSpecVersion("/**\n" +
  96.135 +                                                    " * @since OpenAPI version 2.12" +
  96.136 +                                                    " */\n");
  96.137 +
  96.138 +        assertEquals(0, v.compareTo(new SpecificationVersion("2.12")));
  96.139 +
  96.140 +    }
  96.141 +
  96.142 +    private SpecificationVersion computeSpecVersion(String javadoc) throws Exception {
  96.143 +        prepareTest("test/Test.java",
  96.144 +                    "package test;\n" +
  96.145 +                    "public class Test {\n" +
  96.146 +                    javadoc +
  96.147 +                    "     public void test() {\n" +
  96.148 +                    "     }\n" +
  96.149 +                    "}\n");
  96.150 +
  96.151 +        TypeElement te = info.getElements().getTypeElement("test.Test");
  96.152 +        ExecutableElement method = ElementFilter.methodsIn(te.getEnclosedElements()).iterator().next();
  96.153 +
  96.154 +        return JavaFixUtilities.computeSpecVersion(info, method);
  96.155 +    }
  96.156 +
  96.157 +    public void testArithmetic1() throws Exception {
  96.158 +        performArithmeticTest("1 + 2", "3");
  96.159 +        performArithmeticTest("1f + 2", "3.0F");
  96.160 +        performArithmeticTest("1 + 2f", "3.0F");
  96.161 +        performArithmeticTest("1.0 + 2f", "3.0");
  96.162 +        performArithmeticTest("1 + 2.0", "3.0");
  96.163 +        performArithmeticTest("1L + 2", "3L");
  96.164 +    }
  96.165 +
  96.166 +    public void testArithmetic2() throws Exception {
  96.167 +        performArithmeticTest("1 * 2", "2");
  96.168 +        performArithmeticTest("1f * 2", "2.0F");
  96.169 +        performArithmeticTest("1 * 2f", "2.0F");
  96.170 +        performArithmeticTest("1.0 * 2f", "2.0");
  96.171 +        performArithmeticTest("1 * 2.0", "2.0");
  96.172 +        performArithmeticTest("1L * 2", "2L");
  96.173 +    }
  96.174 +
  96.175 +    public void testArithmetic3() throws Exception {
  96.176 +        performArithmeticTest("4 / 2", "2");
  96.177 +        performArithmeticTest("4f / 2", "2.0F");
  96.178 +        performArithmeticTest("4 / 2f", "2.0F");
  96.179 +        performArithmeticTest("4.0 / 2f", "2.0");
  96.180 +        performArithmeticTest("4 / 2.0", "2.0");
  96.181 +        performArithmeticTest("4L / 2", "2L");
  96.182 +    }
  96.183 +
  96.184 +    public void testArithmetic4() throws Exception {
  96.185 +        performArithmeticTest("5 % 2", "1");
  96.186 +        performArithmeticTest("5f % 2", "1.0F");
  96.187 +        performArithmeticTest("5 % 2f", "1.0F");
  96.188 +        performArithmeticTest("5.0 % 2f", "1.0");
  96.189 +        performArithmeticTest("5 % 2.0", "1.0");
  96.190 +        performArithmeticTest("5L % 2", "1L");
  96.191 +    }
  96.192 +
  96.193 +    public void testArithmetic5() throws Exception {
  96.194 +        performArithmeticTest("5 - 2", "3");
  96.195 +        performArithmeticTest("5f - 2", "3.0F");
  96.196 +        performArithmeticTest("5 - 2f", "3.0F");
  96.197 +        performArithmeticTest("5.0 - 2f", "3.0");
  96.198 +        performArithmeticTest("5 - 2.0", "3.0");
  96.199 +        performArithmeticTest("5L - 2", "3L");
  96.200 +    }
  96.201 +
  96.202 +    public void testArithmetic6() throws Exception {
  96.203 +        performArithmeticTest("5 | 2", "7");
  96.204 +        performArithmeticTest("5L | 2", "7L");
  96.205 +        performArithmeticTest("5 | 2L", "7L");
  96.206 +    }
  96.207 +
  96.208 +    public void testArithmetic7() throws Exception {
  96.209 +        performArithmeticTest("5 & 4", "4");
  96.210 +        performArithmeticTest("5L & 4", "4L");
  96.211 +        performArithmeticTest("5 & 4L", "4L");
  96.212 +    }
  96.213 +
  96.214 +    public void testArithmetic8() throws Exception {
  96.215 +        performArithmeticTest("5 ^ 4", "1");
  96.216 +        performArithmeticTest("5L ^ 4", "1L");
  96.217 +        performArithmeticTest("5 ^ 4L", "1L");
  96.218 +    }
  96.219 +
  96.220 +    public void testArithmetic9() throws Exception {
  96.221 +        performArithmeticTest("5 << 2", "20");
  96.222 +        performArithmeticTest("5L << 2", "20L");
  96.223 +        performArithmeticTest("5 << 2L", "20L");
  96.224 +    }
  96.225 +
  96.226 +    public void testArithmeticA() throws Exception {
  96.227 +        performArithmeticTest("-20 >> 2", "-5");
  96.228 +        performArithmeticTest("-20L >> 2", "-5L");
  96.229 +        performArithmeticTest("-20 >> 2L", "-5L");
  96.230 +    }
  96.231 +
  96.232 +    public void testArithmeticB() throws Exception {
  96.233 +        performArithmeticTest("-20 >>> 2", "1073741819");
  96.234 +    }
  96.235 +
  96.236 +    public void testArithmeticC() throws Exception {
  96.237 +        performArithmeticTest("0 + -20", "-20");
  96.238 +        performArithmeticTest("0 + +20", "20");
  96.239 +    }
  96.240 +
  96.241 +    public void testArithmeticComplex() throws Exception {
  96.242 +        performArithmeticTest("1 + 2 * 4 - 5", "4");
  96.243 +        performArithmeticTest("1f + 2 * 4.0 - 5", "4.0");
  96.244 +        performArithmeticTest("1L + 2 * 4 - 5", "4L");
  96.245 +    }
  96.246 +
  96.247 +    private static final String ARITHMETIC = "public class Test { private Object o = __VAL__; }";
  96.248 +    private void performArithmeticTest(String orig, String nue) throws Exception {
  96.249 +        String code = replace("0");
  96.250 +
  96.251 +        prepareTest("Test.java", code);
  96.252 +        ClassTree clazz = (ClassTree) info.getCompilationUnit().getTypeDecls().get(0);
  96.253 +        VariableTree variable = (VariableTree) clazz.getMembers().get(1);
  96.254 +        ExpressionTree init = variable.getInitializer();
  96.255 +        TreePath tp = new TreePath(new TreePath(new TreePath(new TreePath(info.getCompilationUnit()), clazz), variable), init);
  96.256 +        Fix fix = JavaFixUtilities.rewriteFix(info, "A", tp, orig, Collections.<String, TreePath>emptyMap(), Collections.<String, Collection<? extends TreePath>>emptyMap(), Collections.<String, String>emptyMap(), Collections.<String, TypeMirror>emptyMap(), Collections.<String, String>emptyMap());
  96.257 +        fix.implement();
  96.258 +
  96.259 +        String golden = replace(nue);
  96.260 +        String out = doc.getText(0, doc.getLength());
  96.261 +
  96.262 +        assertEquals(golden, out);
  96.263 +
  96.264 +        LifecycleManager.getDefault().saveAll();
  96.265 +    }
  96.266 +
  96.267 +    private static String replace(String val) {
  96.268 +        MapFormat f = new MapFormat(Collections.singletonMap("VAL", val));
  96.269 +
  96.270 +        f.setLeftBrace("__");
  96.271 +        f.setRightBrace("__");
  96.272 +
  96.273 +        return f.format(ARITHMETIC);
  96.274 +    }
  96.275 +
  96.276 +    public void testRewriteWithParenthesis1() throws Exception {
  96.277 +        performRewriteTest("package test;\n" +
  96.278 +                           "public class Test {\n" +
  96.279 +                           "    int i = new String(\"a\" + \"b\").length();\n" +
  96.280 +                           "}\n",
  96.281 +                           "new String($1)=>$1",
  96.282 +                           "package test;\n" +
  96.283 +                           "public class Test {\n" +
  96.284 +		           "    int i = (\"a\" + \"b\").length();\n" +
  96.285 +		           "}\n");
  96.286 +    }
  96.287 +
  96.288 +    public void testRewriteWithParenthesis2() throws Exception {
  96.289 +        performRewriteTest("package test;\n" +
  96.290 +                           "public class Test {\n" +
  96.291 +                           "    int i = Integer.valueOf(1 + 2) * 3;\n" +
  96.292 +                           "}\n",
  96.293 +                           "Integer.valueOf($1)=>$1",
  96.294 +                           "package test;\n" +
  96.295 +                           "public class Test {\n" +
  96.296 +		           "    int i = (1 + 2) * 3;\n" +
  96.297 +		           "}\n");
  96.298 +    }
  96.299 +
  96.300 +    public void testRewriteWithoutParenthesis1() throws Exception {
  96.301 +        performRewriteTest("package test;\n" +
  96.302 +                           "public class Test {\n" +
  96.303 +                           "    int i = new String(\"a\" + \"b\").length();\n" +
  96.304 +                           "}\n",
  96.305 +                           "new String($1)=>java.lang.String.format(\"%s%s\", $1, \"\")",
  96.306 +                           "package test;\n" +
  96.307 +                           "public class Test {\n" +
  96.308 +		           "    int i = String.format(\"%s%s\", \"a\" + \"b\", \"\").length();\n" +
  96.309 +		           "}\n");
  96.310 +    }
  96.311 +
  96.312 +    public void testRewriteWithoutParenthesis2() throws Exception {
  96.313 +        performRewriteTest("package test;\n" +
  96.314 +                           "public class Test {\n" +
  96.315 +                           "    String s = (\"a\" + \"b\").intern();\n" +
  96.316 +                           "}\n",
  96.317 +                           "($1).intern()=>$1",
  96.318 +                           "package test;\n" +
  96.319 +                           "public class Test {\n" +
  96.320 +		           "    String s = \"a\" + \"b\";\n" +
  96.321 +		           "}\n");
  96.322 +    }
  96.323 +
  96.324 +    public void testRewriteWithoutParenthesis3() throws Exception {
  96.325 +        performRewriteTest("package test;\n" +
  96.326 +                           "public class Test {\n" +
  96.327 +                           "    int i = Integer.valueOf(1 + 2) + 3;\n" +
  96.328 +                           "}\n",
  96.329 +                           "Integer.valueOf($1)=>$1",
  96.330 +                           "package test;\n" +
  96.331 +                           "public class Test {\n" +
  96.332 +		           "    int i = 1 + 2 + 3;\n" +
  96.333 +		           "}\n");
  96.334 +    }
  96.335 +
  96.336 +    public void testRewriteWithoutParenthesis4() throws Exception {
  96.337 +        performRewriteTest("package test;\n" +
  96.338 +                           "public class Test {\n" +
  96.339 +                           "    int i = Integer.valueOf(1 * 2) + 3;\n" +
  96.340 +                           "}\n",
  96.341 +                           "Integer.valueOf($1)=>$1",
  96.342 +                           "package test;\n" +
  96.343 +                           "public class Test {\n" +
  96.344 +		           "    int i = 1 * 2 + 3;\n" +
  96.345 +		           "}\n");
  96.346 +    }
  96.347 +
  96.348 +    public void testRewriteWithoutParenthesis5() throws Exception {
  96.349 +        performRewriteTest("package test;\n" +
  96.350 +                           "public class Test {\n" +
  96.351 +                           "    int i = new Integer(1 * 2).hashCode();\n" +
  96.352 +                           "}\n",
  96.353 +                           "$1.hashCode()=>$1.hashCode()",
  96.354 +                           "package test;\n" +
  96.355 +                           "public class Test {\n" +
  96.356 +		           "    int i = new Integer(1 * 2).hashCode();\n" +
  96.357 +		           "}\n");
  96.358 +    }
  96.359 +
  96.360 +    public void testRewriteWithoutParenthesis6() throws Exception {
  96.361 +        performRewriteTest("package test;\n" +
  96.362 +                           "public class Test {\n" +
  96.363 +                           "    {\n" +
  96.364 +                           "        System.err.println(\"a\" + 1);\n" +
  96.365 +                           "    }\n" +
  96.366 +                           "}\n",
  96.367 +                           "System.err.println($t)=>D.println($t)",
  96.368 +                           "package test;\n" +
  96.369 +                           "public class Test {\n" +
  96.370 +                           "    {\n" +
  96.371 +                           "        D.println(\"a\" + 1);\n" +
  96.372 +                           "    }\n" +
  96.373 +		           "}\n");
  96.374 +    }
  96.375 +
  96.376 +    public void testRewriteWithoutParenthesis7() throws Exception {
  96.377 +        performRewriteTest("package test;\n" +
  96.378 +                           "public class Test {\n" +
  96.379 +                           "    {\n" +
  96.380 +                           "        new String(\"a\" + 1);\n" +
  96.381 +                           "    }\n" +
  96.382 +                           "}\n",
  96.383 +                           "new String($t)=>new D($t)",
  96.384 +                           "package test;\n" +
  96.385 +                           "public class Test {\n" +
  96.386 +                           "    {\n" +
  96.387 +                           "        new D(\"a\" + 1);\n" +
  96.388 +                           "    }\n" +
  96.389 +		           "}\n");
  96.390 +    }
  96.391 +
  96.392 +    public void testTopLevelRewriteWithoutParenthesis1() throws Exception {
  96.393 +        performRewriteTest("package test;\n" +
  96.394 +                           "public class Test {\n" +
  96.395 +                           "    int i = (1 + 2) * 2;\n" +
  96.396 +                           "}\n",
  96.397 +                           "$1 + $2=>3",
  96.398 +                           "package test;\n" +
  96.399 +                           "public class Test {\n" +
  96.400 +		           "    int i = 3 * 2;\n" +
  96.401 +		           "}\n");
  96.402 +    }
  96.403 +
  96.404 +    public void testTopLevelRewriteKeepParenthesis1() throws Exception {
  96.405 +        performRewriteTest("package test;\n" +
  96.406 +                           "public class Test {\n" +
  96.407 +                           "    int i = (1 * 2) + 2;\n" +
  96.408 +                           "}\n",
  96.409 +                           "$1 * $2=>2",
  96.410 +                           "package test;\n" +
  96.411 +                           "public class Test {\n" +
  96.412 +		           "    int i = (2) + 2;\n" +
  96.413 +		           "}\n");
  96.414 +    }
  96.415 +
  96.416 +    public void testTopLevelRewriteKeepParenthesis2() throws Exception {
  96.417 +        performRewriteTest("package test;\n" +
  96.418 +                           "public class Test {\n" +
  96.419 +                           "    { if (1 > 2) ; }\n" +
  96.420 +                           "}\n",
  96.421 +                           "$1 > $2=>false",
  96.422 +                           "package test;\n" +
  96.423 +                           "public class Test {\n" +
  96.424 +                           "    { if (false) ; }\n" +
  96.425 +		           "}\n");
  96.426 +    }
  96.427 +    
  96.428 +    public void testRewriteCatchMultiVariable() throws Exception {
  96.429 +        performRewriteTest("package test;\n" +
  96.430 +                           "public class Test {\n" +
  96.431 +                           "    { try { } catch {NullPointerException ex} { } }\n" +
  96.432 +                           "}\n",
  96.433 +                           "try { } catch $catches$ => try { new Object(); } catch $catches$",
  96.434 +                           "package test;\n" +
  96.435 +                           "public class Test {\n" +
  96.436 +                           "    { try {      new Object();\n } catch {NullPointerException ex} { } }\n" +
  96.437 +		           "}\n");
  96.438 +    }
  96.439 +
  96.440 +    public void testRewriteCaseMultiVariable() throws Exception {
  96.441 +        performRewriteTest("package test;\n" +
  96.442 +                           "public class Test {\n" +
  96.443 +                           "    { int i = 0; switch (i) {case 0: System.err.println(1); break; case 1: System.err.println(2); break; case 2: System.err.println(3); break; }\n" +
  96.444 +                           "}\n",
  96.445 +                           "switch ($v) { case $p$ case 2: $stmts$; } => switch ($v) { case $p$ case 3: $stmts$; }",
  96.446 +                           "package test;\n" +
  96.447 +                           "public class Test {\n" +
  96.448 +                           //XXX: whitespaces:
  96.449 +//                           "    { int i = 0; switch (i) {case 0: System.err.println(1); break; case 1: System.err.println(2); break; case 3: System.err.println(3); break; }\n" +
  96.450 +                           "    { int i = 0; switch (i) {case 0: System.err.println(1); break; case 1: System.err.println(2); break; case   3: System.err.println(3); break; }\n" +
  96.451 +		           "}\n");
  96.452 +    }
  96.453 +
  96.454 +    public void testRewriteMemberSelectVariable() throws Exception {
  96.455 +        performRewriteTest("package test;\n" +
  96.456 +                           "public class Test {\n" +
  96.457 +                           "    { java.io.File f = null; boolean b = f.isDirectory(); }\n" +
  96.458 +                           "}\n",
  96.459 +                           "$file.$m() => foo.Bar.$m($file)",
  96.460 +                           "package test;\n" +
  96.461 +                           "public class Test {\n" +
  96.462 +                           "    { java.io.File f = null; boolean b = foo.Bar.isDirectory(f); }\n" +
  96.463 +		           "}\n");
  96.464 +    }
  96.465 +    
  96.466 +    public void testRewriteIdent2IdentMemberSelectPattern() throws Exception {
  96.467 +        performRewriteTest("package test;\n" +
  96.468 +                           "public class Test {\n" +
  96.469 +                           "    private boolean b; private void t() { boolean c = b; }\n" +
  96.470 +                           "}\n",
  96.471 +                           "$0{test.Test}.b => !$0.b",
  96.472 +                           "package test;\n" +
  96.473 +                           "public class Test {\n" +
  96.474 +                           "    private boolean b; private void t() { boolean c = !b; }\n" +
  96.475 +		           "}\n");
  96.476 +    }
  96.477 +
  96.478 +    public void testCarefulRewriteInImports() throws Exception {
  96.479 +        performRewriteTest("package test;\n" +
  96.480 +                           "import javax.swing.text.AbstractDocument;\n" +
  96.481 +                           "public class Test {\n" +
  96.482 +                           "}\n",
  96.483 +                           "javax.swing.text.AbstractDocument => javax.swing.text.Document",
  96.484 +                           "package test;\n" +
  96.485 +                           "import javax.swing.text.Document;\n" +
  96.486 +                           "public class Test {\n" +
  96.487 +		           "}\n");
  96.488 +    }
  96.489 +
  96.490 +    public void testRemoveFromParent1() throws Exception {
  96.491 +        performRemoveFromParentTest("package test;\n" +
  96.492 +                                    "public class Test {\n" +
  96.493 +                                    "    private int I;" +
  96.494 +                                    "}\n",
  96.495 +                                    "$mods$ int $f;",
  96.496 +                                    "package test;\n" +
  96.497 +                                    "public class Test {\n" +
  96.498 +                                    "}\n");
  96.499 +    }
  96.500 +
  96.501 +    public void testRemoveFromParent2() throws Exception {
  96.502 +        performRemoveFromParentTest("package test;\n" +
  96.503 +                                    "public class Test extends java.util.ArrayList {\n" +
  96.504 +                                    "}\n",
  96.505 +                                    "java.util.ArrayList",
  96.506 +                                    "package test;\n" +
  96.507 +                                    "public class Test {\n" +
  96.508 +                                    "}\n");
  96.509 +    }
  96.510 +    
  96.511 +    public void testRemoveFromParentExpressionStatement206116() throws Exception {
  96.512 +        performRemoveFromParentTest("package test;\n" +
  96.513 +                           "import java.io.InputStream;\n" +
  96.514 +                           "public class Test {\n" +
  96.515 +                           "    private void t() throws Exception {\n" +
  96.516 +                           "        System.err.println();\n" +
  96.517 +                           "        System.err.println(\"a\");\n" +
  96.518 +                           "    }\n" +
  96.519 +                           "}\n",
  96.520 +                           "System.err.println()",
  96.521 +                           "package test;\n" +
  96.522 +                           "import java.io.InputStream;\n" +
  96.523 +                           "public class Test {\n" +
  96.524 +                           "    private void t() throws Exception {\n" +
  96.525 +                           "        System.err.println(\"a\");\n" +
  96.526 +                           "    }\n" +
  96.527 +		           "}\n");
  96.528 +    }
  96.529 +
  96.530 +    public void testUnresolvableTarget() throws Exception {
  96.531 +        performRewriteTest("package test;\n" +
  96.532 +                           "public class Test extends java.util.ArrayList {\n" +
  96.533 +                           "}\n",
  96.534 +                           "java.util.ArrayList => Test",
  96.535 +                           "package test;\n" +
  96.536 +                           "public class Test extends Test {\n" +
  96.537 +                           "}\n");
  96.538 +    }
  96.539 +
  96.540 +    public void testTryWithResourceTarget() throws Exception {
  96.541 +        performRewriteTest("package test;\n" +
  96.542 +                           "import java.io.InputStream;\n" +
  96.543 +                           "public class Test {\n" +
  96.544 +                           "    private void t() throws Exception {\n" +
  96.545 +                           "        InputStream in = null;\n" +
  96.546 +                           "        try {\n" +
  96.547 +                           "        } finally {\n" +
  96.548 +                           "            in.close()\n" +
  96.549 +                           "        }\n" +
  96.550 +                           "    }\n" +
  96.551 +                           "}\n",
  96.552 +                           "$type $var = $init; try {} finally {$var.close();} => try ($type $var = $init) {} finally {$var.close();}",
  96.553 +                           "package test;\n" +
  96.554 +                           "import java.io.InputStream;\n" +
  96.555 +                           "public class Test {\n" +
  96.556 +                           "    private void t() throws Exception {\n" +
  96.557 +//                           "        try (InputStream in = null) {\n" +
  96.558 +                           //XXX:
  96.559 +                           "        try (final InputStream in = null) {\n" +
  96.560 +                           "        } finally {\n" +
  96.561 +                           "            in.close()\n" +
  96.562 +                           "        }\n" +
  96.563 +                           "    }\n" +
  96.564 +		           "}\n");
  96.565 +    }
  96.566 +
  96.567 +    public void testSingle2MultipleStatements() throws Exception {
  96.568 +        performRewriteTest("package test;\n" +
  96.569 +                           "import java.io.InputStream;\n" +
  96.570 +                           "public class Test {\n" +
  96.571 +                           "    private void t() throws Exception {\n" +
  96.572 +                           "        int i = 0;\n" +
  96.573 +                           "    }\n" +
  96.574 +                           "}\n",
  96.575 +                           "$type $var = $init; => $type $var; $var = $init;",
  96.576 +                           "package test;\n" +
  96.577 +                           "import java.io.InputStream;\n" +
  96.578 +                           "public class Test {\n" +
  96.579 +                           "    private void t() throws Exception {\n" +
  96.580 +                           "        int i;\n" +
  96.581 +                           "        i = 0;\n" +
  96.582 +                           "    }\n" +
  96.583 +		           "}\n");
  96.584 +    }
  96.585 +    
  96.586 +    public void testSingle2MultipleStatements2() throws Exception {
  96.587 +        performRewriteTest("package test;\n" +
  96.588 +                           "import java.io.InputStream;\n" +
  96.589 +                           "public class Test {\n" +
  96.590 +                           "    private void t() throws Exception {\n" +
  96.591 +                           "        while (true)\n" +
  96.592 +                           "            if (true) {\n" +
  96.593 +                           "                System.err.println();\n" +
  96.594 +                           "            }\n" +
  96.595 +                           "    }\n" +
  96.596 +                           "}\n",
  96.597 +                           "if (true) $then; => if (true) $then; System.err.println();",
  96.598 +                           "package test;\n" +
  96.599 +                           "import java.io.InputStream;\n" +
  96.600 +                           "public class Test {\n" +
  96.601 +                           "    private void t() throws Exception {\n" +
  96.602 +                           "        while (true) {\n" +
  96.603 +                           "            if (true) {\n" +
  96.604 +                           "                System.err.println();\n" +
  96.605 +                           "            }\n" +
  96.606 +                           "            System.err.println();\n" +
  96.607 +                           "        }\n" +
  96.608 +                           "    }\n" +
  96.609 +		           "}\n");
  96.610 +    }
  96.611 +    
  96.612 +    public void testMultipleStatementsWrapComments1() throws Exception {
  96.613 +        performRewriteTest("package test;\n" +
  96.614 +                           "import java.io.InputStream;\n" +
  96.615 +                           "public class Test {\n" +
  96.616 +                           "    private void t() throws Exception {\n" +
  96.617 +                           "        if (1 == 1) {\n" +
  96.618 +                           "            System.err.println();\n" +
  96.619 +                           "            System.err.println(\"a\");\n" +
  96.620 +                           "            \n" +
  96.621 +                           "            \n" +
  96.622 +                           "            //C\n" +
  96.623 +                           "            System.err.println(\"b\");\n" +
  96.624 +                           "        }\n" +
  96.625 +                           "    }\n" +
  96.626 +                           "}\n",
  96.627 +                           "if ($cond) { System.err.println(); $stmts$;} => while ($cond) { $stmts$;}",
  96.628 +                           "package test;\n" +
  96.629 +                           "import java.io.InputStream;\n" +
  96.630 +                           "public class Test {\n" +
  96.631 +                           "    private void t() throws Exception {\n" +
  96.632 +                           "        while (1 == 1) {\n" +
  96.633 +                           "            System.err.println(\"a\");\n" +
  96.634 +                           "            \n" +
  96.635 +                           "            \n" +
  96.636 +                           "            //C\n" +
  96.637 +                           "            System.err.println(\"b\");\n" +
  96.638 +                           "        }\n" +
  96.639 +                           "    }\n" +
  96.640 +		           "}\n");
  96.641 +    }
  96.642 +    
  96.643 +    public void testMultipleStatementsWrapComments2() throws Exception {
  96.644 +        performRewriteTest("package test;\n" +
  96.645 +                           "import java.io.InputStream;\n" +
  96.646 +                           "public class Test {\n" +
  96.647 +                           "    private void t() throws Exception {\n" +
  96.648 +                           "        if (1 == 1) {\n" +
  96.649 +                           "            System.err.println();\n" +
  96.650 +                           "            System.err.println(\"a\");\n" +
  96.651 +                           "            \n" +
  96.652 +                           "            \n" +
  96.653 +                           "            //C\n" +
  96.654 +                           "            System.err.println(\"b\");\n" +
  96.655 +                           "        }\n" +
  96.656 +                           "    }\n" +
  96.657 +                           "}\n",
  96.658 +                           "if ($cond) { $stmts$;} => while ($cond) { $stmts$;}",
  96.659 +                           "package test;\n" +
  96.660 +                           "import java.io.InputStream;\n" +
  96.661 +                           "public class Test {\n" +
  96.662 +                           "    private void t() throws Exception {\n" +
  96.663 +                           "        while (1 == 1) {\n" +
  96.664 +                           "            System.err.println();\n" +
  96.665 +                           "            System.err.println(\"a\");\n" +
  96.666 +                           "            \n" +
  96.667 +                           "            \n" +
  96.668 +                           "            //C\n" +
  96.669 +                           "            System.err.println(\"b\");\n" +
  96.670 +                           "        }\n" +
  96.671 +                           "    }\n" +
  96.672 +		           "}\n");
  96.673 +    }
  96.674 +    
  96.675 +    public void testReplaceTypeParameters1() throws Exception {
  96.676 +        performRewriteTest("package test;\n" +
  96.677 +                           "import java.io.InputStream;\n" +
  96.678 +                           "public class Test {\n" +
  96.679 +                           "    private <A, B> void t() {\n" +
  96.680 +                           "    }\n" +
  96.681 +                           "}\n",
  96.682 +                           "$mods$ <$O, $T> $ret $name() { $body$; } => $mods$ <$T, $O> $ret $name() { $body$; }",
  96.683 +                           "package test;\n" +
  96.684 +                           "import java.io.InputStream;\n" +
  96.685 +                           "public class Test {\n" +
  96.686 +                           "    private <B, A> void t() {\n" +
  96.687 +                           "    }\n" +
  96.688 +		           "}\n");
  96.689 +    }
  96.690 +    
  96.691 +    public void testReplaceTypeParameters2() throws Exception {
  96.692 +        performRewriteTest("package test;\n" +
  96.693 +                           "import java.io.InputStream;\n" +
  96.694 +                           "public class Test {\n" +
  96.695 +                           "    private <A, B> void t() {\n" +
  96.696 +                           "    }\n" +
  96.697 +                           "}\n",
  96.698 +                           "$mods$ <$T$> $ret $name() { $body$; } => $mods$ <C, $T$> $ret $name() { $body$; }",
  96.699 +                           "package test;\n" +
  96.700 +                           "import java.io.InputStream;\n" +
  96.701 +                           "public class Test {\n" +
  96.702 +                           "    private <C, A, B> void t() {\n" +
  96.703 +                           "    }\n" +
  96.704 +		           "}\n");
  96.705 +    }
  96.706 +    
  96.707 +    public void testAdd2Modifiers() throws Exception {
  96.708 +        performRewriteTest("package test;\n" +
  96.709 +                           "import java.io.InputStream;\n" +
  96.710 +                           "public class Test {\n" +
  96.711 +                           "    void t() {\n" +
  96.712 +                           "    }\n" +
  96.713 +                           "}\n",
  96.714 +                           "$mods$ $ret $name() { $body$; } => $mods$ @java.lang.Deprecated private $ret $name() { $body$; }",
  96.715 +                           "package test;\n" +
  96.716 +                           "import java.io.InputStream;\n" +
  96.717 +                           "public class Test {\n" +
  96.718 +                           "    @Deprecated\n" +
  96.719 +                           "    private void t() {\n" +
  96.720 +                           "    }\n" +
  96.721 +		           "}\n");
  96.722 +    }
  96.723 +    
  96.724 +    public void testReplaceInModifiers() throws Exception {
  96.725 +        performRewriteTest("package test;\n" +
  96.726 +                           "import java.io.InputStream;\n" +
  96.727 +                           "public class Test {\n" +
  96.728 +                           "    public @Override void t() {\n" +
  96.729 +                           "    }\n" +
  96.730 +                           "}\n",
  96.731 +                           "$mods$ public @Override $ret $name() { $body$; } => $mods$ private @Deprecated $ret $name() { $body$; }",
  96.732 +                           "package test;\n" +
  96.733 +                           "import java.io.InputStream;\n" +
  96.734 +                           "public class Test {\n" +
  96.735 +                           "    private @Deprecated void t() {\n" +
  96.736 +                           "    }\n" +
  96.737 +		           "}\n");
  96.738 +    }
  96.739 +    
  96.740 +    public void testKeepInModifiers() throws Exception {
  96.741 +        performRewriteTest("package test;\n" +
  96.742 +                           "import java.io.InputStream;\n" +
  96.743 +                           "public class Test {\n" +
  96.744 +                           "    public @Override void t() {\n" +
  96.745 +                           "    }\n" +
  96.746 +                           "}\n",
  96.747 +                           "$mods$ public @Override $ret $name() { $body$; } => $mods$ public @Override $ret $name() { $body$; }",
  96.748 +                           "package test;\n" +
  96.749 +                           "import java.io.InputStream;\n" +
  96.750 +                           "public class Test {\n" +
  96.751 +                           "    public @Override void t() {\n" +
  96.752 +                           "    }\n" +
  96.753 +		           "}\n");
  96.754 +    }
  96.755 +    
  96.756 +    public void testRemoveInModifiers() throws Exception {
  96.757 +        performRewriteTest("package test;\n" +
  96.758 +                           "import java.io.InputStream;\n" +
  96.759 +                           "public class Test {\n" +
  96.760 +                           "    public static @Deprecated @Override void t() {\n" +
  96.761 +                           "    }\n" +
  96.762 +                           "}\n",
  96.763 +                           "$mods$ public @Override $ret $name() { $body$; } => $mods$ $ret $name() { $body$; }",
  96.764 +                           "package test;\n" +
  96.765 +                           "import java.io.InputStream;\n" +
  96.766 +                           "public class Test {\n" +
  96.767 +                           "    static @Deprecated void t() {\n" +
  96.768 +                           "    }\n" +
  96.769 +		           "}\n");
  96.770 +    }
  96.771 +    
  96.772 +    public void testRewriteMethodParametersWildcard() throws Exception {
  96.773 +        performRewriteTest("package test;\n" +
  96.774 +                           "import java.io.InputStream;\n" +
  96.775 +                           "public class Test {\n" +
  96.776 +                           "    public static void t() {\n" +
  96.777 +                           "    }\n" +
  96.778 +                           "}\n",
  96.779 +                           "$mods$ void $name($args$) { $body$; } => $mods$ int $name($args$) { $body$; }",
  96.780 +                           "package test;\n" +
  96.781 +                           "import java.io.InputStream;\n" +
  96.782 +                           "public class Test {\n" +
  96.783 +                           "    public static int t() {\n" +
  96.784 +                           "    }\n" +
  96.785 +		           "}\n");
  96.786 +    }
  96.787 +    
  96.788 +    public void testRewriteClass() throws Exception {
  96.789 +        performRewriteTest("package test;\n" +
  96.790 +                           "public class Test {\n" +
  96.791 +                           "}\n",
  96.792 +                           "$mods$ class $name<$tp$> extends $e$ implements $i$ { $members$; } => $mods$ @java.lang.Deprecated class $name<$tp$> extends $e$ implements $i$ { $members$; }",
  96.793 +                           "package test;\n" +
  96.794 +                           "@Deprecated\n" +
  96.795 +                           "public class Test {\n" +
  96.796 +		           "}\n");
  96.797 +    }
  96.798 +    
  96.799 +    public void testOptionalVariableInitializer1() throws Exception {
  96.800 +        performRewriteTest("package test;\n" +
  96.801 +                           "public class Test {\n" +
  96.802 +                           "    private int I;\n" +
  96.803 +                           "}\n",
  96.804 +                           "$mods$ int $name = $init$; => $mods$ long $name = $init$;",
  96.805 +                           "package test;\n" +
  96.806 +                           "public class Test {\n" +
  96.807 +                           "    private long I;\n" +
  96.808 +		           "}\n");
  96.809 +    }
  96.810 +    
  96.811 +    public void testOptionalVariableInitializer2() throws Exception {
  96.812 +        performRewriteTest("package test;\n" +
  96.813 +                           "public class Test {\n" +
  96.814 +                           "    private int I = 1;\n" +
  96.815 +                           "}\n",
  96.816 +                           "$mods$ int $name = $init$; => $mods$ long $name = $init$;",
  96.817 +                           "package test;\n" +
  96.818 +                           "public class Test {\n" +
  96.819 +                           "    private long I = 1;\n" +
  96.820 +		           "}\n");
  96.821 +    }
  96.822 +    
  96.823 +    public void testOptionalElse1() throws Exception {
  96.824 +        performRewriteTest("package test;\n" +
  96.825 +                           "public class Test {\n" +
  96.826 +                           "    {\n" +
  96.827 +                           "        if (true) System.err.println(\"a\");\n" +
  96.828 +                           "    }\n" +
  96.829 +                           "}\n",
  96.830 +                           "if (true) $then else $else$; => if (false) $then else $else$;",
  96.831 +                           "package test;\n" +
  96.832 +                           "public class Test {\n" +
  96.833 +                           "    {\n" +
  96.834 +                           "        if (false) System.err.println(\"a\");\n" +
  96.835 +                           "    }\n" +
  96.836 +		           "}\n");
  96.837 +    }
  96.838 +    
  96.839 +    public void testOptionalElse2() throws Exception {
  96.840 +        performRewriteTest("package test;\n" +
  96.841 +                           "public class Test {\n" +
  96.842 +                           "    {\n" +
  96.843 +                           "        if (true) System.err.println(\"a\");\n" +
  96.844 +                           "        else System.err.println(\"b\");\n" +
  96.845 +                           "    }\n" +
  96.846 +                           "}\n",
  96.847 +                           "if (true) $then else $else$; => if (false) $then else $else$;",
  96.848 +                           "package test;\n" +
  96.849 +                           "public class Test {\n" +
  96.850 +                           "    {\n" +
  96.851 +                           "        if (false) System.err.println(\"a\");\n" +
  96.852 +                           "        else System.err.println(\"b\");\n" +
  96.853 +                           "    }\n" +
  96.854 +		           "}\n");
  96.855 +    }
  96.856 +    
  96.857 +    public void testMultiNewArray() throws Exception {
  96.858 +        performRewriteTest("package test;\n" +
  96.859 +                           "public class Test {\n" +
  96.860 +                           "    private static void t(Object... obj) {\n" +
  96.861 +                           "        Test.t(1);\n" +
  96.862 +                           "    }\n" +
  96.863 +                           "}\n",
  96.864 +                           "test.Test.t($args$) => test.Test.t(new Object[] {$args$})",
  96.865 +                           "package test;\n" +
  96.866 +                           "public class Test {\n" +
  96.867 +                           "    private static void t(Object... obj) {\n" +
  96.868 +                           "        Test.t(new Object[]{1});\n" +
  96.869 +                           "    }\n" +
  96.870 +		           "}\n");
  96.871 +    }
  96.872 +
  96.873 +    public void testFakeBlock2FakeBlock191283() throws Exception {
  96.874 +        performRewriteTest("package test;\n" +
  96.875 +                           "import java.io.InputStream;\n" +
  96.876 +                           "public class Test {\n" +
  96.877 +                           "    private void t() throws Exception {\n" +
  96.878 +                           "        System.err.println(1);\n" +
  96.879 +                           "        lock();\n" +
  96.880 +                           "        System.err.println(2);\n" +
  96.881 +                           "        unlock();\n" +
  96.882 +                           "        System.err.println(3);\n" +
  96.883 +                           "    }\n" +
  96.884 +                           "    private static void lock() {}\n" +
  96.885 +                           "    private static void unlock() {}\n" +
  96.886 +                           "}\n",
  96.887 +                           "test.Test.lock(); $i$; test.Test.unlock(); => lock(); try { $i$; } finally { unlock(); }",
  96.888 +                           "package test;\n" +
  96.889 +                           "import java.io.InputStream;\n" +
  96.890 +                           "public class Test {\n" +
  96.891 +                           "    private void t() throws Exception {\n" +
  96.892 +                           "        System.err.println(1);\n" +
  96.893 +                           "        lock();\n" +
  96.894 +                           "        try {\n" +
  96.895 +                           "            System.err.println(2);\n" +
  96.896 +                           "        } finally {\n" +
  96.897 +                           "            unlock();\n" +
  96.898 +                           "        }\n" +
  96.899 +                           "        System.err.println(3);\n" +
  96.900 +                           "    }\n" +
  96.901 +                           "    private static void lock() {}\n" +
  96.902 +                           "    private static void unlock() {}\n" +
  96.903 +		           "}\n");
  96.904 +    }
  96.905 +    
  96.906 +    public void testOptimizeNegExpression() throws Exception {
  96.907 +        performRewriteTest("package test;\n" +
  96.908 +                           "public class Test {\n" +
  96.909 +                           "    private static void t(int i) {\n" +
  96.910 +                           "        if (i == 0) {\n" +
  96.911 +                           "            System.err.println(1);\n" +
  96.912 +                           "        } else {\n" +
  96.913 +                           "            System.err.println(2);\n" +
  96.914 +                           "        }\n" +
  96.915 +                           "    }\n" +
  96.916 +                           "}\n",
  96.917 +                           "if ($cond) $then; else $else; => if (!$cond) $else; else $then;",
  96.918 +                           "package test;\n" +
  96.919 +                           "public class Test {\n" +
  96.920 +                           "    private static void t(int i) {\n" +
  96.921 +                           "        if (i != 0) {\n" +
  96.922 +                           "            System.err.println(2);\n" +
  96.923 +                           "        } else {\n" +
  96.924 +                           "            System.err.println(1);\n" +
  96.925 +                           "        }\n" +
  96.926 +                           "    }\n" +
  96.927 +		           "}\n");
  96.928 +    }
  96.929 +    
  96.930 +    public void testDontOptimizeNegExpression() throws Exception {
  96.931 +        performRewriteTest("package test;\n" +
  96.932 +                           "public class Test {\n" +
  96.933 +                           "    private static void t(int i) {\n" +
  96.934 +                           "        if (!(i == 0)) {\n" +
  96.935 +                           "            System.err.println(1);\n" +
  96.936 +                           "        } else {\n" +
  96.937 +                           "            System.err.println(2);\n" +
  96.938 +                           "        }\n" +
  96.939 +                           "    }\n" +
  96.940 +                           "}\n",
  96.941 +                           "if (!$cond) $then; else $else; => if (!$cond) $else; else $then;",
  96.942 +                           "package test;\n" +
  96.943 +                           "public class Test {\n" +
  96.944 +                           "    private static void t(int i) {\n" +
  96.945 +                           "        if (!(i == 0)) {\n" +
  96.946 +                           "            System.err.println(2);\n" +
  96.947 +                           "        } else {\n" +
  96.948 +                           "            System.err.println(1);\n" +
  96.949 +                           "        }\n" +
  96.950 +                           "    }\n" +
  96.951 +		           "}\n");
  96.952 +    }
  96.953 +    
  96.954 +    public void testCannotOptimizeNegExpression() throws Exception {
  96.955 +        performRewriteTest("package test;\n" +
  96.956 +                           "public class Test {\n" +
  96.957 +                           "    private static void t(String str) {\n" +
  96.958 +                           "        if (str.isEmpty()) {\n" +
  96.959 +                           "            System.err.println(1);\n" +
  96.960 +                           "        } else {\n" +
  96.961 +                           "            System.err.println(2);\n" +
  96.962 +                           "        }\n" +
  96.963 +                           "    }\n" +
  96.964 +                           "}\n",
  96.965 +                           "if ($cond) $then; else $else; => if (!$cond) $else; else $then;",
  96.966 +                           "package test;\n" +
  96.967 +                           "public class Test {\n" +
  96.968 +                           "    private static void t(String str) {\n" +
  96.969 +                           "        if (!str.isEmpty()) {\n" +
  96.970 +                           "            System.err.println(2);\n" +
  96.971 +                           "        } else {\n" +
  96.972 +                           "            System.err.println(1);\n" +
  96.973 +                           "        }\n" +
  96.974 +                           "    }\n" +
  96.975 +		           "}\n");
  96.976 +    }
  96.977 +    
  96.978 +    public void testOptimizeNegExpressionNeg() throws Exception {
  96.979 +        performOptimizeNegExpressionTest("!s.isEmpty()", "s.isEmpty()");
  96.980 +    }
  96.981 +    
  96.982 +    public void testOptimizeNegExpressionParens() throws Exception {
  96.983 +        performOptimizeNegExpressionTest("(!(a.length == 0))", "a.length == 0");
  96.984 +    }
  96.985 +    
  96.986 +    public void testOptimizeNegExpressionEquals() throws Exception {
  96.987 +        performOptimizeNegExpressionTest("i == 0", "i != 0");
  96.988 +    }
  96.989 +    
  96.990 +    public void testOptimizeNegExpressionNotEquals() throws Exception {
  96.991 +        performOptimizeNegExpressionTest("i != 0", "i == 0");
  96.992 +    }
  96.993 +    
  96.994 +    public void testOptimizeNegExpressionTrue() throws Exception {
  96.995 +        performOptimizeNegExpressionTest("true", "false");
  96.996 +    }
  96.997 +    
  96.998 +    public void testOptimizeNegExpressionFalse() throws Exception {
  96.999 +        performOptimizeNegExpressionTest("false", "true");
 96.1000 +    }
 96.1001 +    
 96.1002 +    public void testOptimizeNegExpressionDeMorganAnd() throws Exception {
 96.1003 +        performOptimizeNegExpressionTest("a.length != 0 && true", "a.length == 0 || false");
 96.1004 +    }
 96.1005 +    
 96.1006 +    public void testOptimizeNegExpressionDeMorganOr() throws Exception {
 96.1007 +        performOptimizeNegExpressionTest("args.length != 0 || false", "args.length == 0 && true");
 96.1008 +    }
 96.1009 +    
 96.1010 +    public void testOptimizeNegExpressionLess() throws Exception {
 96.1011 +        performOptimizeNegExpressionTest("i < 0", "i >= 0");
 96.1012 +    }
 96.1013 +    
 96.1014 +    public void testOptimizeNegExpressionLessEq() throws Exception {
 96.1015 +        performOptimizeNegExpressionTest("i <= 0", "i > 0");
 96.1016 +    }
 96.1017 +    
 96.1018 +    public void testOptimizeNegExpressionGreater() throws Exception {
 96.1019 +        performOptimizeNegExpressionTest("i > 0", "i <= 0");
 96.1020 +    }
 96.1021 +    
 96.1022 +    public void testOptimizeNegExpressionGreaterEq() throws Exception {
 96.1023 +        performOptimizeNegExpressionTest("i >= 0", "i < 0");
 96.1024 +    }
 96.1025 +    
 96.1026 +    public void testOptimizeNegExpressionAnd() throws Exception {
 96.1027 +        performOptimizeNegExpressionTest("b1 && b2", "!b1 || !b2");
 96.1028 +    }
 96.1029 +    
 96.1030 +    private void performOptimizeNegExpressionTest(String origExpr, String newExpr) throws Exception {
 96.1031 +        performRewriteTest("package test;\n" +
 96.1032 +                           "public class Test {\n" +
 96.1033 +                           "    private static void t(String s, int i, boolean b1, boolean b2, String... a) {\n" +
 96.1034 +                           "        if (" + origExpr + ") {\n" +
 96.1035 +                           "            System.err.println(1);\n" +
 96.1036 +                           "        } else {\n" +
 96.1037 +                           "            System.err.println(2);\n" +
 96.1038 +                           "        }\n" +
 96.1039 +                           "    }\n" +
 96.1040 +                           "}\n",
 96.1041 +                           "if ($cond) $then; else $else; => if (!$cond) $else; else $then;",
 96.1042 +                           "package test;\n" +
 96.1043 +                           "public class Test {\n" +
 96.1044 +                           "    private static void t(String s, int i, boolean b1, boolean b2, String... a) {\n" +
 96.1045 +                           "        if (" + newExpr + ") {\n" +
 96.1046 +                           "            System.err.println(2);\n" +
 96.1047 +                           "        } else {\n" +
 96.1048 +                           "            System.err.println(1);\n" +
 96.1049 +                           "        }\n" +
 96.1050 +                           "    }\n" +
 96.1051 +		           "}\n");
 96.1052 +    }
 96.1053 +    
 96.1054 +    public void testExpression2ExpressionStatementTolerance227429() throws Exception {
 96.1055 +        performRewriteTest("package test;\n" +
 96.1056 +                           "public class Test {\n" +
 96.1057 +                           "    private static void t() {\n" +
 96.1058 +                           "        System.err.println(1);\n" +
 96.1059 +                           "    }\n" +
 96.1060 +                           "}\n",
 96.1061 +                           "java.lang.System.err.println($args$) => java.lang.System.out.println($args$);",
 96.1062 +                           "package test;\n" +
 96.1063 +                           "public class Test {\n" +
 96.1064 +                           "    private static void t() {\n" +
 96.1065 +                           "        System.out.println(1);\n" +
 96.1066 +                           "    }\n" +
 96.1067 +		           "}\n");
 96.1068 +    }
 96.1069 +    
 96.1070 +    public void testSplitIfOr() throws Exception {
 96.1071 +        performRewriteTest("package test;\n" +
 96.1072 +                           "public class Test {\n" +
 96.1073 +                           "    private static void t(int i) {\n" +
 96.1074 +                           "        if (i == 0 || i == 1) {\n" +
 96.1075 +                           "            System.err.println();\n" +
 96.1076 +                           "        }\n" +
 96.1077 +                           "    }\n" +
 96.1078 +                           "}\n",
 96.1079 +                           "if ($cond1 || $cond2) $then; => if ($cond1) $then; else if ($cond2) $then;",
 96.1080 +                           "package test;\n" +
 96.1081 +                           "public class Test {\n" +
 96.1082 +                           "    private static void t(int i) {\n" +
 96.1083 +                           "        if (i == 0) {\n" +
 96.1084 +                           "            System.err.println();\n" +
 96.1085 +                           "        } else if (i == 1) {\n" +
 96.1086 +                           "            System.err.println();\n" +
 96.1087 +                           "        }\n" +
 96.1088 +                           "    }\n" +
 96.1089 +		           "}\n");
 96.1090 +    }
 96.1091 +    
 96.1092 +    public void testLambdaExpr2Block() throws Exception {
 96.1093 +        performRewriteTest("package test;\n" +
 96.1094 +                           "import java.util.*;\n" +
 96.1095 +                           "public class Test {\n" +
 96.1096 +                           "    public void main(List<String> list) {\n" +
 96.1097 +                           "        Collections.sort(list, (l, r) -> l.compareTo(r));\n" +
 96.1098 +                           "    }\n" +
 96.1099 +                           "}\n",
 96.1100 +                           "($args$) -> $expr => ($args$) -> { return $expr; }",
 96.1101 +                           "package test;\n" +
 96.1102 +                           "import java.util.*;\n" +
 96.1103 +                           "public class Test {\n" +
 96.1104 +                           "    public void main(List<String> list) {\n" +
 96.1105 +                           "        Collections.sort(list, (l, r) -> {\n" +
 96.1106 +                           "            return l.compareTo(r);\n" +
 96.1107 +                           "        });\n" +
 96.1108 +                           "    }\n" +
 96.1109 +		           "}\n");
 96.1110 +    }
 96.1111 +    
 96.1112 +    public void performRewriteTest(String code, String rule, String golden) throws Exception {
 96.1113 +	prepareTest("test/Test.java", code);
 96.1114 +
 96.1115 +        final String[] split = rule.split("=>");
 96.1116 +        assertEquals(2, split.length);
 96.1117 +        Map<String, TypeMirror> variablesToTypesTM = new HashMap<String, TypeMirror>();
 96.1118 +        String plainRule = PatternCompilerUtilities.parseOutTypesFromPattern(info, split[0], variablesToTypesTM);
 96.1119 +        Map<String, String> variablesToTypes = new HashMap<String, String>();
 96.1120 +        for (Entry<String, TypeMirror> e : variablesToTypesTM.entrySet()) {
 96.1121 +            if (e.getValue() == null) continue;
 96.1122 +            variablesToTypes.put(e.getKey(), e.getValue().toString());
 96.1123 +        }
 96.1124 +        HintDescription hd = HintDescriptionFactory.create()
 96.1125 +                                                   .setTrigger(PatternDescription.create(plainRule, variablesToTypes))
 96.1126 +                                                   .setWorker(new HintDescription.Worker() {
 96.1127 +            @Override public Collection<? extends ErrorDescription> createErrors(HintContext ctx) {
 96.1128 +                return Collections.singletonList(ErrorDescriptionFactory.forName(ctx, ctx.getPath(), "", JavaFixUtilities.rewriteFix(ctx, "", ctx.getPath(), split[1])));
 96.1129 +            }
 96.1130 +        }).produce();
 96.1131 +
 96.1132 +        List<ErrorDescription> computeHints = new HintsInvoker(HintsSettings.getGlobalSettings(), new AtomicBoolean()).computeHints(info, Collections.singleton(hd));
 96.1133 +
 96.1134 +        assertEquals(computeHints.toString(), 1, computeHints.size());
 96.1135 +
 96.1136 +        Fix fix = computeHints.get(0).getFixes().getFixes().get(0);
 96.1137 +
 96.1138 +	fix.implement();
 96.1139 +
 96.1140 +        assertEquals(golden, doc.getText(0, doc.getLength()));
 96.1141 +    }
 96.1142 +
 96.1143 +    public void performRemoveFromParentTest(String code, String rule, String golden) throws Exception {
 96.1144 +	prepareTest("test/Test.java", code);
 96.1145 +
 96.1146 +        HintDescription hd = HintDescriptionFactory.create()
 96.1147 +                                                   .setTrigger(PatternDescription.create(rule, Collections.<String, String>emptyMap()))
 96.1148 +                                                   .setWorker(new HintDescription.Worker() {
 96.1149 +            @Override public Collection<? extends ErrorDescription> createErrors(HintContext ctx) {
 96.1150 +                return Collections.singletonList(ErrorDescriptionFactory.forName(ctx, ctx.getPath(), "", JavaFixUtilities.removeFromParent(ctx, "", ctx.getPath())));
 96.1151 +            }
 96.1152 +        }).produce();
 96.1153 +
 96.1154 +        List<ErrorDescription> computeHints = new HintsInvoker(HintsSettings.getGlobalSettings(), new AtomicBoolean()).computeHints(info, Collections.singleton(hd));
 96.1155 +
 96.1156 +        assertEquals(computeHints.toString(), 1, computeHints.size());
 96.1157 +
 96.1158 +        Fix fix = computeHints.get(0).getFixes().getFixes().get(0);
 96.1159 +
 96.1160 +	fix.implement();
 96.1161 +
 96.1162 +        assertEquals(golden, doc.getText(0, doc.getLength()));
 96.1163 +    }
 96.1164 +}
    97.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    97.2 +++ b/java.hints/spi.java.hints/test/unit/src/org/netbeans/spi/java/hints/MatcherUtilitiesTest.java	Wed May 08 21:47:42 2013 +0200
    97.3 @@ -0,0 +1,113 @@
    97.4 +/*
    97.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    97.6 + *
    97.7 + * Copyright 2009-2010 Oracle and/or its affiliates. All rights reserved.
    97.8 + *
    97.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   97.10 + * Other names may be trademarks of their respective owners.
   97.11 + *
   97.12 + * The contents of this file are subject to the terms of either the GNU
   97.13 + * General Public License Version 2 only ("GPL") or the Common
   97.14 + * Development and Distribution License("CDDL") (collectively, the
   97.15 + * "License"). You may not use this file except in compliance with the
   97.16 + * License. You can obtain a copy of the License at
   97.17 + * http://www.netbeans.org/cddl-gplv2.html
   97.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   97.19 + * specific language governing permissions and limitations under the
   97.20 + * License.  When distributing the software, include this License Header
   97.21 + * Notice in each file and include the License file at
   97.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   97.23 + * particular file as subject to the "Classpath" exception as provided
   97.24 + * by Oracle in the GPL Version 2 section of the License file that
   97.25 + * accompanied this code. If applicable, add the following below the
   97.26 + * License Header, with the fields enclosed by brackets [] replaced by
   97.27 + * your own identifying information:
   97.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   97.29 + *
   97.30 + * If you wish your version of this file to be governed by only the CDDL
   97.31 + * or only the GPL Version 2, indicate your decision by adding
   97.32 + * "[Contributor] elects to include this software in this distribution
   97.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   97.34 + * single choice of license, a recipient has the option to distribute
   97.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   97.36 + * to extend the choice of license to its licensees as provided above.
   97.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   97.38 + * Version 2 license, then the option applies only if the new code is
   97.39 + * made subject to such option by the copyright holder.
   97.40 + *
   97.41 + * Contributor(s):
   97.42 + *
   97.43 + * Portions Copyrighted 2009-2010 Sun Microsystems, Inc.
   97.44 + */
   97.45 +
   97.46 +package org.netbeans.spi.java.hints;
   97.47 +
   97.48 +import com.sun.source.util.TreePath;
   97.49 +import java.util.Collection;
   97.50 +import java.util.Collections;
   97.51 +import java.util.HashMap;
   97.52 +import java.util.Map;
   97.53 +import java.util.regex.Pattern;
   97.54 +import org.netbeans.modules.java.hints.spiimpl.SPIAccessor;
   97.55 +import org.netbeans.modules.java.hints.spiimpl.TestBase;
   97.56 +import org.netbeans.modules.java.hints.spiimpl.options.HintsSettings;
   97.57 +
   97.58 +/**
   97.59 + *
   97.60 + * @author lahvac
   97.61 + */
   97.62 +public class MatcherUtilitiesTest extends TestBase {
   97.63 +
   97.64 +    public MatcherUtilitiesTest(String name) {
   97.65 +        super(name);
   97.66 +    }
   97.67 +
   97.68 +    public void testParentMatches1() throws Exception {
   97.69 +        String code = "package test; public class Test { private int test() { int i = 0; i = test(|); } }";
   97.70 +        int pos = code.indexOf("|");
   97.71 +
   97.72 +        code = code.replaceAll(Pattern.quote("|"), "");
   97.73 +
   97.74 +        prepareTest("test/Test.java", code);
   97.75 +
   97.76 +        TreePath tp = info.getTreeUtilities().pathFor(pos);
   97.77 +        HintContext ctx = SPIAccessor.getINSTANCE().createHintContext(info, HintsSettings.getGlobalSettings(), null, tp, Collections.<String, TreePath>emptyMap(), Collections.<String, Collection<? extends TreePath>>emptyMap(), Collections.<String, String>emptyMap());
   97.78 +
   97.79 +        assertTrue(MatcherUtilities.matches(ctx, ctx.getPath().getParentPath(), "$0 = $_"));
   97.80 +    }
   97.81 +
   97.82 +    public void testParentMatches2() throws Exception {
   97.83 +        String code = "package test; public class Test { private int test() { int i = test(|); } }";
   97.84 +        int pos = code.indexOf("|");
   97.85 +
   97.86 +        code = code.replaceAll(Pattern.quote("|"), "");
   97.87 +
   97.88 +        prepareTest("test/Test.java", code);
   97.89 +
   97.90 +        TreePath tp = info.getTreeUtilities().pathFor(pos);
   97.91 +        HintContext ctx = SPIAccessor.getINSTANCE().createHintContext(info, HintsSettings.getGlobalSettings(), null, tp, Collections.<String, TreePath>emptyMap(), Collections.<String, Collection<? extends TreePath>>emptyMap(), Collections.<String, String>emptyMap());
   97.92 +
   97.93 +        assertTrue(MatcherUtilities.matches(ctx, ctx.getPath().getParentPath(), "$1 $0 = $_;"));
   97.94 +    }
   97.95 +
   97.96 +    public void testOutVariables1() throws Exception {
   97.97 +        String code = "package test; public class Test { private int test() { int i = test(|); } }";
   97.98 +        int pos = code.indexOf("|");
   97.99 +
  97.100 +        code = code.replaceAll(Pattern.quote("|"), "");
  97.101 +
  97.102 +        prepareTest("test/Test.java", code);
  97.103 +
  97.104 +        TreePath tp = info.getTreeUtilities().pathFor(pos);
  97.105 +        HintContext ctx = SPIAccessor.getINSTANCE().createHintContext(info, HintsSettings.getGlobalSettings(), null, tp, Collections.<String, TreePath>emptyMap(), Collections.<String, Collection<? extends TreePath>>emptyMap(), Collections.<String, String>emptyMap());
  97.106 +
  97.107 +        Map<String, TreePath> outVariables = new HashMap<String, TreePath>();
  97.108 +        Map<String, Collection<? extends TreePath>> outMultiVariables = new HashMap<String, Collection<? extends TreePath>>();
  97.109 +        Map<String, String> outVariables2Names = new HashMap<String, String>();
  97.110 +
  97.111 +        assertTrue(MatcherUtilities.matches(ctx, ctx.getPath().getParentPath(), "$1 $0 = $_;", outVariables, outMultiVariables, outVariables2Names));
  97.112 +        assertEquals("int", outVariables.get("$1").getLeaf().toString());
  97.113 +        assertEquals("i", outVariables2Names.get("$0"));
  97.114 +    }
  97.115 +
  97.116 +}
  97.117 \ No newline at end of file
    98.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    98.2 +++ b/java.hints/spi.java.hints/test/unit/src/org/netbeans/spi/java/hints/matching/CopyFinderTest.java	Wed May 08 21:47:42 2013 +0200
    98.3 @@ -0,0 +1,1583 @@
    98.4 +/*
    98.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    98.6 + *
    98.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    98.8 + *
    98.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   98.10 + * Other names may be trademarks of their respective owners.
   98.11 + *
   98.12 + * The contents of this file are subject to the terms of either the GNU
   98.13 + * General Public License Version 2 only ("GPL") or the Common
   98.14 + * Development and Distribution License("CDDL") (collectively, the
   98.15 + * "License"). You may not use this file except in compliance with the
   98.16 + * License. You can obtain a copy of the License at
   98.17 + * http://www.netbeans.org/cddl-gplv2.html
   98.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   98.19 + * specific language governing permissions and limitations under the
   98.20 + * License.  When distributing the software, include this License Header
   98.21 + * Notice in each file and include the License file at
   98.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   98.23 + * particular file as subject to the "Classpath" exception as provided
   98.24 + * by Oracle in the GPL Version 2 section of the License file that
   98.25 + * accompanied this code. If applicable, add the following below the
   98.26 + * License Header, with the fields enclosed by brackets [] replaced by
   98.27 + * your own identifying information:
   98.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   98.29 + *
   98.30 + * Contributor(s):
   98.31 + *
   98.32 + * Portions Copyrighted 2007-2010 Sun Microsystems, Inc.
   98.33 + */
   98.34 +package org.netbeans.spi.java.hints.matching;
   98.35 +
   98.36 +import com.sun.source.tree.BlockTree;
   98.37 +import com.sun.source.tree.StatementTree;
   98.38 +import com.sun.source.tree.Tree;
   98.39 +import com.sun.source.tree.VariableTree;
   98.40 +import com.sun.source.util.SourcePositions;
   98.41 +import com.sun.source.util.TreePath;
   98.42 +import com.sun.source.util.TreePathScanner;
   98.43 +import java.io.File;
   98.44 +import java.util.Arrays;
   98.45 +import java.util.Collection;
   98.46 +import java.util.Collections;
   98.47 +import java.util.EnumSet;
   98.48 +import java.util.HashMap;
   98.49 +import java.util.HashSet;
   98.50 +import java.util.LinkedList;
   98.51 +import java.util.List;
   98.52 +import java.util.Map;
   98.53 +import java.util.Map.Entry;
   98.54 +import java.util.Set;
   98.55 +import java.util.concurrent.atomic.AtomicBoolean;
   98.56 +import javax.lang.model.element.VariableElement;
   98.57 +import javax.lang.model.type.TypeMirror;
   98.58 +import javax.swing.text.Document;
   98.59 +import org.netbeans.api.java.lexer.JavaTokenId;
   98.60 +import org.netbeans.api.java.source.CompilationInfo;
   98.61 +import org.netbeans.api.java.source.JavaSource;
   98.62 +import org.netbeans.api.java.source.JavaSource.Phase;
   98.63 +import org.netbeans.api.java.source.SourceUtilsTestUtil;
   98.64 +import org.netbeans.api.java.source.TestUtilities;
   98.65 +import org.netbeans.api.java.source.TreePathHandle;
   98.66 +import org.netbeans.api.java.source.matching.MatchingTestAccessor;
   98.67 +import org.netbeans.api.java.source.matching.Pattern;
   98.68 +import org.netbeans.api.lexer.Language;
   98.69 +import org.netbeans.junit.NbTestCase;
   98.70 +import org.netbeans.modules.java.hints.introduce.IntroduceHint;
   98.71 +import org.netbeans.modules.java.hints.spiimpl.pm.BulkSearch;
   98.72 +import org.netbeans.modules.java.hints.spiimpl.pm.BulkSearch.BulkPattern;
   98.73 +import org.netbeans.modules.java.hints.spiimpl.pm.PatternCompiler;
   98.74 +import org.netbeans.modules.java.hints.spiimpl.pm.PatternCompilerUtilities;
   98.75 +import org.netbeans.modules.java.source.matching.CopyFinder;
   98.76 +import org.netbeans.modules.java.source.matching.CopyFinder.Cancel;
   98.77 +import org.netbeans.modules.java.source.matching.CopyFinder.Options;
   98.78 +import org.netbeans.modules.java.source.matching.CopyFinder.VariableAssignments;
   98.79 +import org.openide.cookies.EditorCookie;
   98.80 +import org.openide.filesystems.FileObject;
   98.81 +import org.openide.filesystems.FileUtil;
   98.82 +import org.openide.loaders.DataObject;
   98.83 +
   98.84 +/**
   98.85 + *
   98.86 + * @author Jan Lahoda
   98.87 + */
   98.88 +public class CopyFinderTest extends NbTestCase {
   98.89 +
   98.90 +    public CopyFinderTest(String testName) {
   98.91 +        super(testName);
   98.92 +    }
   98.93 +
   98.94 +//    public static TestSuite suite() {
   98.95 +//        NbTestSuite nb = new NbTestSuite();
   98.96 +//
   98.97 +//        nb.addTest(new CopyFinderTest("testCorrectSite3"));
   98.98 +//
   98.99 +//        return nb;
  98.100 +//    }
  98.101 +
  98.102 +    @Override
  98.103 +    protected void setUp() throws Exception {
  98.104 +        SourceUtilsTestUtil.prepareTest(new String[0], new Object[0]);
  98.105 +        super.setUp();
  98.106 +    }
  98.107 +
  98.108 +    public void testSimple1() throws Exception {
  98.109 +        performTest("package test; public class Test {public void test() {int i = 0; y = i + i; y = i + i;}}", 90 - 22, 95 - 22, 101 - 22, 106 - 22);
  98.110 +    }
  98.111 +
  98.112 +//    public void testSimple2() throws Exception {
  98.113 +//        performTest("package test; public class Test {public void test() {int i = 0; y = i + i; y = i + i + i;}}", 90 - 22, 95 - 22, 101 - 22, 106 - 22);
  98.114 +//    }
  98.115 +
  98.116 +    public void testSimple3() throws Exception {
  98.117 +        performTest("package test; public class Test {public void test() {int i = System.currentTimeMillis(); y = System.currentTimeMillis();}}", 83 - 22, 109 - 22, 115 - 22, 141 - 22);
  98.118 +    }
  98.119 +
  98.120 +    public void testSimple4() throws Exception {
  98.121 +        performTest("package test; import java.util.ArrayList; public class Test {public void test() {Object o = new ArrayList<String>();o = new ArrayList<String>();}}", 114 - 22, 137- 22, 142 - 22, 165 - 22);
  98.122 +    }
  98.123 +
  98.124 +    public void testSimple5() throws Exception {
  98.125 +        performTest("package test; public class Test {public void test() {Object o = null; String s = (String) o; s = (String) o; s = (String) null; o = (Object) o;}}", 103 - 22, 113 - 22, 119 - 22, 129 - 22);
  98.126 +    }
  98.127 +
  98.128 +    public void testSimple6() throws Exception {
  98.129 +        performTest("package test; public class Test {public void test() {int i = 0; y = i + i; y = i + i;} public void test2() {int i = 0; y = i + i; y = i + i;}}", 90 - 22, 95 - 22, 101 - 22, 106 - 22);
  98.130 +    }
  98.131 +
  98.132 +    public void testSimple7() throws Exception {
  98.133 +        performTest("package test; public class Test {public void test() {int i = 0; y = i != 0 ? i + i : i * i; y = i != 0 ? i + i : i * i; y = i != 1 ? i + i : i * i; y = i == 0 ? i + i : i * i; y = i != 0 ? i * i : i * i; y = i != 0 ? i + i : i + i; y = i != 0 ? i + i : i * 1;}}", 90 - 22, 112 - 22, 118 - 22, 140 - 22);
  98.134 +    }
  98.135 +
  98.136 +    public void testSimple8() throws Exception {
  98.137 +        performTest("package test; public class Test {public void test() {int i = 0; int y = -i; y = -i; y = +i; y = +y;}}", 94 - 22, 96 - 22, 102 - 22, 104 - 22);
  98.138 +    }
  98.139 +
  98.140 +    public void testSimple9() throws Exception {
  98.141 +        performTest("package test; public class Test {public void test() {int i = 0; int y = i *= 9; y = i *= 9; y = i /= 9; y = i *= 8; y = y *= 9;}}", 94 - 22, 100 - 22, 106 - 22, 112 - 22);
  98.142 +    }
  98.143 +
  98.144 +    public void testSimple10() throws Exception {
  98.145 +        performTest("package test; public class Test {public void test() {int[] i = null; int y = i[1]; y = i[1]; y = i[y]; y = i[0];}}", 99 - 22, 103 - 22, 109 - 22, 113 - 22);
  98.146 +    }
  98.147 +
  98.148 +    public void testSimple11() throws Exception {
  98.149 +        performTest("package test; public class Test {public void test() {int[] i = new int[0]; i = new int[0]; i = new int[1];}}", 85 - 22, 95 - 22, 101 - 22, 111 - 22);
  98.150 +    }
  98.151 +
  98.152 +    public void testSimple12() throws Exception {
  98.153 +        performTest("package test; public class Test {public void test() {int[] i = new int[1]; i = new int[1]; i = new int[0];}}", 85 - 22, 95 - 22, 101 - 22, 111 - 22);
  98.154 +    }
  98.155 +
  98.156 +    public void testSimple13() throws Exception {
  98.157 +        performTest("package test; public class Test {public void test() {int i = 0; int y = (i); y = (i); y = i;}}", 94 - 22, 97 - 22, 103 - 22, 106 - 22);
  98.158 +    }
  98.159 +
  98.160 +    public void testSimple14() throws Exception {
  98.161 +        performTest("package test; public class Test {public void test() {Object o = null; boolean b = o instanceof String; b = o instanceof String; b = o instanceof Object;}}", 104 - 22, 123 - 22, 129 - 22, 148 - 22);
  98.162 +    }
  98.163 +
  98.164 +    public void testSimple15() throws Exception {
  98.165 +        performTest("package test; public class Test {private int x = 1; private int y = 1; public void test() {int x = 1; int y = 1;}}", 90 - 22, 91 - 22, 71 - 22, 72 - 22, 121 - 22, 122 - 22, 132 - 22, 133 - 22);
  98.166 +    }
  98.167 +
  98.168 +    public void testSimple16() throws Exception {
  98.169 +        performTest("package test; public class Test {public void test(int i) {int y = \"\".length(); test(\"\".length());} }", 88 - 22, 99 - 22, 106 - 22, 117 - 22);
  98.170 +    }
  98.171 +
  98.172 +    public void testSimple17() throws Exception {
  98.173 +        performTest("package test; public class Test {public void test2() {int a = test(test(test(1))); a = test(test(test(1))); a = test(test(test(1)));} public int test(int i) {return 0;} }", 94 - 22, 101 - 22, 119 - 22, 126 - 22, 144 - 22, 151 - 22);
  98.174 +    }
  98.175 +
  98.176 +    public void testMemberSelectAndIdentifierAreSame() throws Exception {
  98.177 +        performTest("package test; import static java.lang.String.*; public class Test {public void test1() {|String.valueOf(2)|; |valueOf(2)|;} }");
  98.178 +    }
  98.179 +
  98.180 +    public void testVariables1() throws Exception {
  98.181 +        performVariablesTest("package test; import static java.lang.String.*; public class Test {public void test1() {String.valueOf(2+4);} }",
  98.182 +                             "java.lang.String.valueOf($1)",
  98.183 +                             new Pair[] {new Pair<String, int[]>("$1", new int[] {134 - 31, 137 - 31})},
  98.184 +                             new Pair[0]);
  98.185 +    }
  98.186 +
  98.187 +    public void testAssert1() throws Exception {
  98.188 +        performTest("package test; public class Test {public void test() {int i = 0; |assert i == 1;| |assert i == 1;|}}");
  98.189 +    }
  98.190 +
  98.191 +    public void testReturn1() throws Exception {
  98.192 +        performTest("package test; public class Test {public int test1() {|return 1;|} public int test2() {|return 1;|}}");
  98.193 +    }
  98.194 +
  98.195 +    public void testIf1() throws Exception {
  98.196 +        performTest("package test; public class Test {public void test() { int i = 0; int j; |if (i == 0) {j = 1;} else {j = 2;}| |if (i == 0) {j = 1;} else {j = 2;}| } }");
  98.197 +    }
  98.198 +
  98.199 +    public void testExpressionStatement1() throws Exception {
  98.200 +        performTest("package test; public class Test {public void test() { int i = 0; |i = 1;| |i = 1;| } }");
  98.201 +    }
  98.202 +
  98.203 +    public void testBlock1() throws Exception {
  98.204 +        performTest("package test; public class Test {public void test() { int i = 0; |{i = 1;}| |{i = 1;}| } }");
  98.205 +    }
  98.206 +
  98.207 +    public void testSynchronized1() throws Exception {
  98.208 +        performTest("package test; public class Test {public void test() { Object o = null; int i = 0; |synchronized (o) {i = 1;}| |synchronized (o) {i = 1;}| } }");
  98.209 +    }
  98.210 +
  98.211 +//    public void testEnhancedForLoop() throws Exception {
  98.212 +//        performTest("package test; public class Test {public void test(Iterable<String> i) { |for (String s : i) { System.err.println(); }| |for (String s : i) { System.err.println(); }| }");
  98.213 +//    }
  98.214 +
  98.215 +//    public void testConstants() throws Exception {
  98.216 +//        performTest("package test; public class Test {public static final int A = 3; public void test() { int i = |3|; i = |test.Test.A|; } }");
  98.217 +//    }
  98.218 +
  98.219 +    public void testOverridingImplementing1() throws Exception {
  98.220 +        performVariablesTest("package test; public class Test implements Runnable { { this.run(); } public void run() { } } }",
  98.221 +                             "$0{java.lang.Runnable}.run()",
  98.222 +                             new Pair[] {new Pair<String, int[]>("$0", new int[] {56, 60})},
  98.223 +                             new Pair[0]);
  98.224 +    }
  98.225 +
  98.226 +    public void testMemberSelectCCE() throws Exception {
  98.227 +        //should not throw a CCE
  98.228 +        //(selected regions are not duplicates)
  98.229 +        performTest("package test; public class Test {public static class T extends Test { public void test() { |Test.test|(); |System.err.println|(); } } }", false);
  98.230 +    }
  98.231 +
  98.232 +    public void testLocalVariable() throws Exception {
  98.233 +        performVariablesTest("package test; public class Test {public void test1() { { int y; y = 1; } int z; { int y; z = 1; } } }",
  98.234 +                             "{ int $1; $1 = 1; }",
  98.235 +                             new Pair[0],
  98.236 +                             new Pair[] {new Pair<String, String>("$1", "y")});
  98.237 +    }
  98.238 +
  98.239 +    public void testStatementAndSingleBlockStatementAreSame1() throws Exception {
  98.240 +        performVariablesTest("package test; public class Test {public void test1() { { int x; { x = 1; } } } }",
  98.241 +                             "{ int $1; $1 = 1; }",
  98.242 +                             new Pair[0],
  98.243 +                             new Pair[] {new Pair<String, String>("$1", "x")});
  98.244 +    }
  98.245 +
  98.246 +    public void testStatementAndSingleBlockStatementAreSame2() throws Exception {
  98.247 +        performVariablesTest("package test; public class Test {public void test1() { { int x; x = 1; } } }",
  98.248 +                             "{ int $1; { $1 = 1; } }",
  98.249 +                             new Pair[0],
  98.250 +                             new Pair[] {new Pair<String, String>("$1", "x")});
  98.251 +    }
  98.252 +
  98.253 +    public void testStatementVariables() throws Exception {
  98.254 +        performVariablesTest("package test; public class Test {public int test1() { if (true) return 1; else return 2; } }",
  98.255 +                             "if ($1) $2; else $3;",
  98.256 +                             new Pair[] {
  98.257 +                                  new Pair<String, int[]>("$1", new int[] {89 - 31, 93 - 31}),
  98.258 +                                  new Pair<String, int[]>("$2", new int[] {95 - 31, 104 - 31}),
  98.259 +                                  new Pair<String, int[]>("$3", new int[] {110 - 31, 119 - 31})
  98.260 +                             },
  98.261 +                             new Pair[0]);
  98.262 +    }
  98.263 +
  98.264 +    public void testThrowStatement() throws Exception {
  98.265 +        performVariablesTest("package test; public class Test {public void test() { throw new NullPointerException(); throw new IllegalStateException();} }",
  98.266 +                             "throw new NullPointerException()",
  98.267 +                             new Pair[0],
  98.268 +                             new Pair[0]);
  98.269 +    }
  98.270 +
  98.271 +    public void testMultiStatementVariables1() throws Exception {
  98.272 +        performVariablesTest("package test; public class Test { public int test1() { System.err.println(); System.err.println(); int i = 3; System.err.println(i); System.err.println(i); return i; } }",
  98.273 +                             "{ $s1$; int $i = 3; $s2$; return $i; }",
  98.274 +                             new Pair[0],
  98.275 +                             new Pair[] {
  98.276 +                                  new Pair<String, int[]>("$s1$", new int[] {55, 76, 77, 98}),
  98.277 +                                  new Pair<String, int[]>("$s2$", new int[] {110, 132, 133, 155})
  98.278 +                             },
  98.279 +                             new Pair[] {new Pair<String, String>("$i", "i")});
  98.280 +    }
  98.281 +
  98.282 +    public void testMultiStatementVariables2() throws Exception {
  98.283 +        performVariablesTest("package test; public class Test { public int test1() { int i = 3; return i; } }",
  98.284 +                             "{ $s1$; int $i = 3; $s2$; return $i; }",
  98.285 +                             new Pair[0],
  98.286 +                             new Pair[] {
  98.287 +                                  new Pair<String, int[]>("$s1$", new int[] {}),
  98.288 +                                  new Pair<String, int[]>("$s2$", new int[] {}),
  98.289 +                             },
  98.290 +                             new Pair[] {new Pair<String, String>("$i", "i")});
  98.291 +    }
  98.292 +
  98.293 +    public void testMultiStatementVariablesAndBlocks1() throws Exception {
  98.294 +        performVariablesTest("package test; public class Test { public void test1() { if (true) System.err.println(); } }",
  98.295 +                             "if ($c) {$s1$; System.err.println(); $s2$; }",
  98.296 +                             new Pair[] {new Pair<String, int[]>("$c", new int[] {60, 64})},
  98.297 +                             new Pair[] {
  98.298 +                                  new Pair<String, int[]>("$s1$", new int[] {}),
  98.299 +                                  new Pair<String, int[]>("$s2$", new int[] {}),
  98.300 +                             },
  98.301 +                             new Pair[0]);
  98.302 +    }
  98.303 +
  98.304 +    public void testMultiStatementVariablesAndBlocks2() throws Exception {
  98.305 +        performVariablesTest("package test; public class Test { public void test1() { if (true) System.err.println(); } }",
  98.306 +                             "if ($c) {$s1$; System.err.println(); }",
  98.307 +                             new Pair[] {new Pair<String, int[]>("$c", new int[] {60, 64})},
  98.308 +                             new Pair[] {
  98.309 +                                  new Pair<String, int[]>("$s1$", new int[] {}),
  98.310 +                             },
  98.311 +                             new Pair[0]);
  98.312 +    }
  98.313 +
  98.314 +    public void testMultiStatementVariablesAndBlocks3() throws Exception {
  98.315 +        performVariablesTest("package test; public class Test { public void test1() { if (true) System.err.println(); } }",
  98.316 +                             "if ($c) {System.err.println(); $s2$; }",
  98.317 +                             new Pair[] {new Pair<String, int[]>("$c", new int[] {60, 64})},
  98.318 +                             new Pair[] {
  98.319 +                                  new Pair<String, int[]>("$s2$", new int[] {}),
  98.320 +                             },
  98.321 +                             new Pair[0]);
  98.322 +    }
  98.323 +
  98.324 +    public void testMultiStatementVariablesAndBlocks4() throws Exception {
  98.325 +        performVariablesTest("package test; public class Test { public void test1() { if (true) System.err.println(); } }",
  98.326 +                             "if ($c) { $s$; }",
  98.327 +                             new Pair[] {new Pair<String, int[]>("$c", new int[] {60, 64})},
  98.328 +                             new Pair[] {
  98.329 +                                  new Pair<String, int[]>("$s$", new int[] {66, 87}),
  98.330 +                             },
  98.331 +                             new Pair[0]);
  98.332 +    }
  98.333 +
  98.334 +    public void testVariableVerification() throws Exception {
  98.335 +        performVariablesTest("package test; public class Test { public void test1(String[] a, String[] b) { for (int c = 0; c < a.length; c++) { String s = b[c]; System.err.println(s); } } }",
  98.336 +                             "for(int $i = 0; $i < $array.length; $i++) { $T $var = $array[$i]; $stmts$; }",
  98.337 +                             new Pair[0],
  98.338 +                             new Pair[0],
  98.339 +                             new Pair[0],
  98.340 +                             true);
  98.341 +    }
  98.342 +
  98.343 +    public void testFor() throws Exception {
  98.344 +        performVariablesTest("package test; public class Test { public void test1(String[] a) { for (int c = 0; c < a.length; c++) { String s = a[c]; System.err.println(s); } } }",
  98.345 +                             "for(int $i = 0; $i < $array.length; $i++) { $T $var = $array[$i]; $stmts$; }",
  98.346 +                             new Pair[] {
  98.347 +                                  new Pair<String, int[]>("$array", new int[] {117 - 31, 118 - 31}),
  98.348 +                                  new Pair<String, int[]>("$T", new int[] {134 - 31, 140 - 31}),
  98.349 +                             },
  98.350 +                             new Pair[] {
  98.351 +                                  new Pair<String, int[]>("$stmts$", new int[] {151 - 31, 173 - 31}),
  98.352 +                             },
  98.353 +                             new Pair[] {
  98.354 +                                  new Pair<String, String>("$i", "c"),
  98.355 +                                  new Pair<String, String>("$var", "s"),
  98.356 +                             });
  98.357 +    }
  98.358 +
  98.359 +    public void testEnhancedFor() throws Exception {
  98.360 +        performVariablesTest("package test; public class Test { public void test1(String[] a) { for (String s : a) { System.err.println(s); } } }",
  98.361 +                             "for($T $var : $array) { $stmts$; }",
  98.362 +                             new Pair[] {
  98.363 +                                  new Pair<String, int[]>("$array", new int[] {113 - 31, 114 - 31}),
  98.364 +                                  new Pair<String, int[]>("$T", new int[] {102 - 31, 108 - 31}),
  98.365 +                             },
  98.366 +                             new Pair[] {
  98.367 +                                  new Pair<String, int[]>("$stmts$", new int[] {118 - 31, 140 - 31}),
  98.368 +                             },
  98.369 +                             new Pair[] {
  98.370 +                                  new Pair<String, String>("$var", "s"),
  98.371 +                             });
  98.372 +    }
  98.373 +
  98.374 +    public void testWhile() throws Exception {
  98.375 +        performVariablesTest("package test; public class Test { public void test1(String[] a) { int c = 0; while  (c < a.length) { String s = a[c]; System.err.println(s); c++; } } }",
  98.376 +                             "while ($i < $array.length) { $T $var = $array[$i]; $stmts$; $i++; }",
  98.377 +                             new Pair[] {
  98.378 +                                  new Pair<String, int[]>("$array", new int[] {120 - 31, 121 - 31}),
  98.379 +                                  new Pair<String, int[]>("$T", new int[] {132 - 31, 138 - 31}),
  98.380 +                                  new Pair<String, int[]>("$i", new int[] {116 - 31, 117 - 31}),
  98.381 +                             },
  98.382 +                             new Pair[] {
  98.383 +                                  new Pair<String, int[]>("$stmts$", new int[] {149 - 31, 171 - 31}),
  98.384 +                             },
  98.385 +                             new Pair[] {
  98.386 +                                  new Pair<String, String>("$var", "s"),
  98.387 +                             });
  98.388 +    }
  98.389 +
  98.390 +    public void testDoWhile() throws Exception {
  98.391 +        performVariablesTest("package test; public class Test { public void test1(String[] a) { int c = 0; do { String s = a[c]; System.err.println(s); c++; } while  (c < a.length); } }",
  98.392 +                             "do { $T $var = $array[$i]; $stmts$; $i++; } while ($i < $array.length);",
  98.393 +                             new Pair[] {
  98.394 +                                  new Pair<String, int[]>("$array", new int[] {124 - 31, 125 - 31}),
  98.395 +                                  new Pair<String, int[]>("$T", new int[] {113 - 31, 119 - 31}),
  98.396 +                                  new Pair<String, int[]>("$i", new int[] {126 - 31, 127 - 31}),
  98.397 +                             },
  98.398 +                             new Pair[] {
  98.399 +                                  new Pair<String, int[]>("$stmts$", new int[] {130 - 31, 152 - 31}),
  98.400 +                             },
  98.401 +                             new Pair[] {
  98.402 +                                  new Pair<String, String>("$var", "s"),
  98.403 +                             });
  98.404 +    }
  98.405 +
  98.406 +    public void testArrayType() throws Exception {
  98.407 +        performVariablesTest("package test; public class Test { public void test1() { int[][] a; } }",
  98.408 +                             "$T[]",
  98.409 +                             new Pair[] {
  98.410 +                                  new Pair<String, int[]>("$T", new int[] {87 - 31, /*92*//*XXX:*/94 - 31}),
  98.411 +                             },
  98.412 +                             new Pair[0],
  98.413 +                             new Pair[0]);
  98.414 +    }
  98.415 +
  98.416 +    public void testSemiMatchPackage() throws Exception {
  98.417 +        performVariablesTest("package test; import javax.lang.model.type.TypeMirror; public class Test { }",
  98.418 +                             "$T{java.lang.Object}.type",
  98.419 +                             new Pair[0],
  98.420 +                             new Pair[0],
  98.421 +                             new Pair[0],
  98.422 +                             true);
  98.423 +    }
  98.424 +
  98.425 +    public void testNullType() throws Exception {
  98.426 +        performVariablesTest("package javax.lang.model.type; public class Test { }",
  98.427 +                             "$T{java.lang.Object}.type",
  98.428 +                             new Pair[0],
  98.429 +                             new Pair[0],
  98.430 +                             new Pair[0],
  98.431 +                             true);
  98.432 +    }
  98.433 +
  98.434 +    public void testTryCatch() throws Exception {
  98.435 +        performVariablesTest("package test; import java.io.*; public class Test { public void test() { InputStream ins = null; try { ins = new FileInputStream(\"\"); } catch (IOException e) { e.printStackTrace(); } finally {ins.close();} } }",
  98.436 +                             "try {$stmts$;} catch (java.io.IOException $e) {$e.printStackTrace();} finally {$finally$;}",
  98.437 +                             new Pair[] {
  98.438 +                                   new Pair<String, int[]>("$e", new int[] {176 - 31 - 2, 189 - 31 - 2}),
  98.439 +                             },
  98.440 +                             new Pair[] {
  98.441 +                                  new Pair<String, int[]>("$stmts$", new int[] {134 - 31, 166 - 31 - 2}),
  98.442 +                                  new Pair<String, int[]>("$finally$", new int[] {225 - 31 - 2, 237 - 31 - 2}),
  98.443 +                             },
  98.444 +                             new Pair[] {
  98.445 +                                  new Pair<String, String>("$e", "e"),
  98.446 +                             });
  98.447 +    }
  98.448 +
  98.449 +    public void testMultiParameters1() throws Exception {
  98.450 +        performVariablesTest("package test; public class Test { { java.util.Arrays.asList(\"a\", \"b\", \"c\"); }",
  98.451 +                             "java.util.Arrays.asList($1$)",
  98.452 +                             new Pair[] {
  98.453 +                             },
  98.454 +                             new Pair[] {
  98.455 +                                new Pair<String, int[]>("$1$", new int[] {60, 63, 65, 68, 70, 73}),
  98.456 +                             },
  98.457 +                             new Pair[] {
  98.458 +                             });
  98.459 +    }
  98.460 +
  98.461 +    public void testMultiParameters2() throws Exception {
  98.462 +        performVariablesTest("package test; public class Test { { java.util.Arrays.asList(new String(\"a\"), \"b\", \"c\"); }",
  98.463 +                             "java.util.Arrays.asList(new String(\"a\"), $1$)",
  98.464 +                             new Pair[] {
  98.465 +                             },
  98.466 +                             new Pair[] {
  98.467 +                                new Pair<String, int[]>("$1$", new int[] {77, 80, 82, 85}),
  98.468 +                             },
  98.469 +                             new Pair[] {
  98.470 +                             });
  98.471 +    }
  98.472 +
  98.473 +    public void testMultiParameters3() throws Exception {
  98.474 +        performVariablesTest("package test; public class Test { { java.util.Arrays.asList(); }",
  98.475 +                             "java.util.Arrays.asList($1$)",
  98.476 +                             new Pair[] {
  98.477 +                             },
  98.478 +                             new Pair[] {
  98.479 +                                new Pair<String, int[]>("$1$", new int[] {}),
  98.480 +                             },
  98.481 +                             new Pair[] {
  98.482 +                             });
  98.483 +    }
  98.484 +
  98.485 +    public void testTypeParameters() throws Exception {
  98.486 +        performVariablesTest("package test; public class Test { { java.util.Arrays.<String>asList(\"a\", \"b\"); }",
  98.487 +                             "java.util.Arrays.<$1>asList($1$)",
  98.488 +                             new Pair[] {
  98.489 +                                   new Pair<String, int[]>("$1", new int[] {85 - 31, 91 - 31}),
  98.490 +                             },
  98.491 +                             new Pair[] {
  98.492 +                             },
  98.493 +                             new Pair[] {
  98.494 +                             });
  98.495 +    }
  98.496 +
  98.497 +    public void testModifiers() throws Exception {
  98.498 +        performVariablesTest("package test; public class Test { private String s; }",
  98.499 +                             "$mods$ java.lang.String $name;",
  98.500 +                             new Pair[] {
  98.501 +                                 new Pair<String, int[]>("$name", new int[] {65 - 31, 82 - 31}),
  98.502 +                                 new Pair<String, int[]>("$mods$", new int[] {65 - 31, 72 - 31}), //XXX: shouldn't this be a multi-variable?
  98.503 +                             },
  98.504 +                             new Pair[] {
  98.505 +                             },
  98.506 +                             new Pair[] {
  98.507 +                                  new Pair<String, String>("$name", "s"),
  98.508 +                             });
  98.509 +    }
  98.510 +
  98.511 +    public void testVariableIsFullPattern1() throws Exception {
  98.512 +        performVariablesTest("package test; public class Test { private int a; {System.err.println(a);} }",
  98.513 +                             "$0{int}",
  98.514 +                             new Pair[] {
  98.515 +                                 new Pair<String, int[]>("$0", new int[] {100 - 31, 101 - 31}),
  98.516 +                             },
  98.517 +                             new Pair[] {
  98.518 +                             },
  98.519 +                             new Pair[] {
  98.520 +                             });
  98.521 +    }
  98.522 +
  98.523 +    public void testVariableIsFullPattern2() throws Exception {
  98.524 +        performVariablesTest("package test; public class Test { private int a; {System.err.println(a);} }",
  98.525 +                             "$0{int}",
  98.526 +                             new Pair[] {
  98.527 +                                 new Pair<String, int[]>("$0", new int[] {100 - 31, 101 - 31}),
  98.528 +                             },
  98.529 +                             new Pair[] {
  98.530 +                             },
  98.531 +                             new Pair[] {
  98.532 +                             },
  98.533 +                             false,
  98.534 +                             true);
  98.535 +    }
  98.536 +
  98.537 +    public void testNoCCEForVariableName() throws Exception {
  98.538 +        performVariablesTest("package test; public class Test { { int[] arr = null; int a; arr[a] = 0;} }",
  98.539 +                             "int $a; $a = 0;",
  98.540 +                             new Pair[] {
  98.541 +                             },
  98.542 +                             new Pair[] {
  98.543 +                             },
  98.544 +                             new Pair[] {
  98.545 +                             },
  98.546 +                             true,
  98.547 +                             true);
  98.548 +    }
  98.549 +
  98.550 +    public void testVerifySameTrees1() throws Exception {
  98.551 +        performVariablesTest("package test; public class Test { { if (true) { System.err.println(); } else { System.err.println(); System.err.println(); } } }",
  98.552 +                             "if ($c) $s; else $s;",
  98.553 +                             new Pair[] {
  98.554 +                             },
  98.555 +                             new Pair[] {
  98.556 +                             },
  98.557 +                             new Pair[] {
  98.558 +                             },
  98.559 +                             true,
  98.560 +                             true);
  98.561 +    }
  98.562 +
  98.563 +    public void testVerifySameTreesMultiVariables1() throws Exception {
  98.564 +        performVariablesTest("package test; public class Test { { if (true) { System.err.println(); System.err.println(); } else { System.err.println(); System.err.println(); System.err.println(); } } }",
  98.565 +                             "if ($c) { $s$;} else { $s$; }",
  98.566 +                             new Pair[] {
  98.567 +                             },
  98.568 +                             new Pair[] {
  98.569 +                             },
  98.570 +                             new Pair[] {
  98.571 +                             },
  98.572 +                             true,
  98.573 +                             true);
  98.574 +    }
  98.575 +
  98.576 +    public void testVerifySameTreesMultiVariables2() throws Exception {
  98.577 +        performVariablesTest("package test; public class Test { { if (true) { System.err.println(1); System.err.println(); } else System.err.println(1); } }",
  98.578 +                             "if ($c) { System.err.println(1); $s2$; } else { System.err.println(1); $s2$; }",
  98.579 +                             new Pair[] {
  98.580 +                             },
  98.581 +                             new Pair[] {
  98.582 +                             },
  98.583 +                             new Pair[] {
  98.584 +                             },
  98.585 +                             true,
  98.586 +                             true);
  98.587 +    }
  98.588 +
  98.589 +    public void testVerifySameTreesMultiVariables3() throws Exception {
  98.590 +        performVariablesTest("package test; public class Test { { if (true) { System.err.println(); System.err.println(1); } else System.err.println(1); } }",
  98.591 +                             "if ($c) { $s1$; System.err.println(1); } else { $s1$; System.err.println(1); }",
  98.592 +                             new Pair[] {
  98.593 +                             },
  98.594 +                             new Pair[] {
  98.595 +                             },
  98.596 +                             new Pair[] {
  98.597 +                             },
  98.598 +                             true,
  98.599 +                             true);
  98.600 +    }
  98.601 +
  98.602 +    public void XtestVerifySameTreesMultiVariables4() throws Exception {
  98.603 +        performVariablesTest("package test; public class Test { { if (true) { System.err.println(); System.err.println(1); System.err.println(); } else System.err.println(1); } }",
  98.604 +                             "if ($c) { $s1$; System.err.println(1); $s2$; } else { $s1$; System.err.println(1); $s2$; }",
  98.605 +                             new Pair[] {
  98.606 +                             },
  98.607 +                             new Pair[] {
  98.608 +                             },
  98.609 +                             new Pair[] {
  98.610 +                             },
  98.611 +                             true,
  98.612 +                             true);
  98.613 +    }
  98.614 +
  98.615 +    public void testVerifySameTreesMultiVariables5() throws Exception {
  98.616 +        performVariablesTest("package test; public class Test { { if (true) { System.err.println(1); } else System.err.println(2); } }",
  98.617 +                             "if ($c) { $s$; } else { $s$; }",
  98.618 +                             new Pair[] {
  98.619 +                             },
  98.620 +                             new Pair[] {
  98.621 +                             },
  98.622 +                             new Pair[] {
  98.623 +                             },
  98.624 +                             true,
  98.625 +                             true);
  98.626 +    }
  98.627 +
  98.628 +    public void testSimpleRemapping1() throws Exception {
  98.629 +        performRemappingTest("package test;\n" +
  98.630 +                             "public class Test {\n" +
  98.631 +                             "    void t1() {\n" +
  98.632 +                             "        int i = 0;\n" +
  98.633 +                             "        |System.err.println(i);|\n" +
  98.634 +                             "    }\n" +
  98.635 +                             "    void t2() {\n" +
  98.636 +                             "        int a = 0;\n" +
  98.637 +                             "        |System.err.println(a);|\n" +
  98.638 +                             "    }\n" +
  98.639 +                             "}\n",
  98.640 +                             "i",
  98.641 +                             Options.ALLOW_REMAP_VARIABLE_TO_EXPRESSION);
  98.642 +    }
  98.643 +
  98.644 +    public void testSimpleRemapping2() throws Exception {
  98.645 +        performRemappingTest("package test;\n" +
  98.646 +                             "public class Test {\n" +
  98.647 +                             "    void t1() {\n" +
  98.648 +                             "        int i = 0;\n" +
  98.649 +                             "        |System.err.println(i);\n" +
  98.650 +                             "         int i2 = 0;\n" +
  98.651 +                             "         System.err.println(i2);|\n" +
  98.652 +                             "    }\n" +
  98.653 +                             "    void t2() {\n" +
  98.654 +                             "        int a = 0;\n" +
  98.655 +                             "        |System.err.println(a);\n" +
  98.656 +                             "         int a2 = 0;\n" +
  98.657 +                             "         System.err.println(a2);|\n" +
  98.658 +                             "    }\n" +
  98.659 +                             "}\n",
  98.660 +                             "i",
  98.661 +                             Options.ALLOW_REMAP_VARIABLE_TO_EXPRESSION);
  98.662 +    }
  98.663 +
  98.664 +    public void testSimpleRemapping3() throws Exception {
  98.665 +        performRemappingTest("package test;\n" +
  98.666 +                             "public class Test {\n" +
  98.667 +                             "    void t1() {\n" +
  98.668 +                             "        |int i = 0;\n" +
  98.669 +                             "         System.err.println(i);\n" +
  98.670 +                             "         int i2 = 0;\n" +
  98.671 +                             "         System.err.println(i2);|\n" +
  98.672 +                             "    }\n" +
  98.673 +                             "    void t2() {\n" +
  98.674 +                             "        |int a = 0;\n" +
  98.675 +                             "         System.err.println(a);\n" +
  98.676 +                             "         int a2 = 0;\n" +
  98.677 +                             "         System.err.println(a2);|\n" +
  98.678 +                             "    }\n" +
  98.679 +                             "}\n",
  98.680 +                             "",
  98.681 +                             Options.ALLOW_REMAP_VARIABLE_TO_EXPRESSION);
  98.682 +    }
  98.683 +
  98.684 +    public void testSimpleRemapping4() throws Exception {
  98.685 +        performRemappingTest("package test;\n" +
  98.686 +                             "public class Test {\n" +
  98.687 +                             "    void t1() {\n" +
  98.688 +                             "        int i = 0;\n" +
  98.689 +                             "        |System.err.println(i);|\n" +
  98.690 +                             "    }\n" +
  98.691 +                             "    void t2() {\n" +
  98.692 +                             "        int[] a = {0};\n" +
  98.693 +                             "        |System.err.println(a[0]);|\n" +
  98.694 +                             "    }\n" +
  98.695 +                             "}\n",
  98.696 +                             "i",
  98.697 +                             Options.ALLOW_REMAP_VARIABLE_TO_EXPRESSION);
  98.698 +    }
  98.699 +
  98.700 +    public void testPreventRemapOnExpressions1() throws Exception {
  98.701 +        performRemappingTest("package test;\n" +
  98.702 +                             "public class Test {\n" +
  98.703 +                             "    void t1() {\n" +
  98.704 +                             "        Throwable t = null;\n" +
  98.705 +                             "        |System.err.println(t);|\n" +
  98.706 +                             "    }\n" +
  98.707 +                             "    void t2() {\n" +
  98.708 +                             "        Throwable t = null;\n" +
  98.709 +                             "        |System.err.println(t.getCause());|\n" +
  98.710 +                             "    }\n" +
  98.711 +                             "}\n",
  98.712 +                             "t",
  98.713 +                             Options.ALLOW_REMAP_VARIABLE_TO_EXPRESSION);
  98.714 +    }
  98.715 +
  98.716 +    public void testPreventRemapOnExpressions2() throws Exception {
  98.717 +        performRemappingTest("package test;\n" +
  98.718 +                             "public class Test {\n" +
  98.719 +                             "    void t1() {\n" +
  98.720 +                             "        Throwable t = null;\n" +
  98.721 +                             "        |System.err.println(t);|\n" +
  98.722 +                             "    }\n" +
  98.723 +                             "    void t2() {\n" +
  98.724 +                             "        Throwable t = null;\n" +
  98.725 +                             "        System.err.println(t.getCause());\n" +
  98.726 +                             "    }\n" +
  98.727 +                             "}\n",
  98.728 +                             "t");
  98.729 +    }
  98.730 +
  98.731 +    public void testVariableMemberSelect() throws Exception {
  98.732 +        performVariablesTest("package test; public class Test {public void test(String str) { str.length(); str.length(); } public void test1(String str) { str.length(); str.isEmpty(); } }",
  98.733 +                             "{ $str.$method(); $str.$method(); }",
  98.734 +                             new Pair[0],
  98.735 +                             new Pair[] {new Pair<String, String>("$method", "length")});
  98.736 +    }
  98.737 +
  98.738 +    public void testCorrectSite1() throws Exception {
  98.739 +        performVariablesTest("package test; public class Test { public void test(Object o) { o.wait(); } }",
  98.740 +                             "$s{java.util.concurrent.locks.Condition}.wait()",
  98.741 +                             new Pair[0],
  98.742 +                             new Pair[0],
  98.743 +                             new Pair[0],
  98.744 +                             true);
  98.745 +    }
  98.746 +
  98.747 +    public void testCorrectSite2() throws Exception {
  98.748 +        performVariablesTest("package test; public class Test { public void test(Object o) { wait(); } }",
  98.749 +                             "$s{java.util.concurrent.locks.Condition}.wait()",
  98.750 +                             new Pair[0],
  98.751 +                             new Pair[0],
  98.752 +                             new Pair[0],
  98.753 +                             true);
  98.754 +    }
  98.755 +
  98.756 +    public void testCorrectSite3() throws Exception {
  98.757 +        performVariablesTest("package test; public abstract class Test implements java.util.concurrent.locks.Condition { public void test() { new Runnable() { public void run() { wait(); } } } }",
  98.758 +                             "$0{java.util.concurrent.locks.Condition}.wait()",
  98.759 +                             new Pair[0],// {new Pair<String, int[]>("$s", new int[] {-1, -1})},
  98.760 +                             new Pair[0],
  98.761 +                             new Pair[0]);
  98.762 +    }
  98.763 +
  98.764 +    public void testCorrectSite4() throws Exception {
  98.765 +        performVariablesTest("package test; public class Test { public void test() { foo.stop(); } }",
  98.766 +                             "$0{java.lang.Thread}.stop()",
  98.767 +                             new Pair[0],
  98.768 +                             new Pair[0],
  98.769 +                             new Pair[0],
  98.770 +                             true);
  98.771 +    }
  98.772 +
  98.773 +    public void testDotClassForSameClass() throws Exception {
  98.774 +        performTest("package test; public class Test { {Class c = |Test.class|; c = |Test.class|; c = String.class; } }");
  98.775 +    }
  98.776 +
  98.777 +    public void testTryCatchVariable() throws Exception {
  98.778 +        performVariablesTest("package test; public class Test { { try { throw new java.io.IOException(); } catch (java.io.IOException ex) { } } }",
  98.779 +                             "try { $stmts$; } catch $catches$",
  98.780 +                             new Pair[] {
  98.781 +                             },
  98.782 +                             new Pair[] {
  98.783 +                                new Pair<String, int[]>("$stmts$", new int[] {42, 74}),
  98.784 +                                new Pair<String, int[]>("$catches$", new int[] {77, 111}),
  98.785 +                             },
  98.786 +                             new Pair[] {
  98.787 +                             },
  98.788 +                             false,
  98.789 +                             true);
  98.790 +    }
  98.791 +
  98.792 +    public void testMatchInterfaceNoFQN() throws Exception {
  98.793 +        performTest("package test; import java.util.*; public class Test { public void test() { |List| l1; |java.util.List| l2;} }");
  98.794 +    }
  98.795 +
  98.796 +    public void testUnresolvableNonMatchingConstraint() throws Exception {
  98.797 +        performVariablesTest("package test; public class Test { private Object a; {System.err.println(a);} }",
  98.798 +                             "System.err.println($v{does.not.Exist}",
  98.799 +                             new Pair[0],
  98.800 +                             new Pair[0],
  98.801 +                             new Pair[0],
  98.802 +                             true);
  98.803 +    }
  98.804 +
  98.805 +    public void testIndexOutOfBoundsInMultiList() throws Exception {
  98.806 +        performVariablesTest("package test;" +
  98.807 +                             "public class Test {" +
  98.808 +                             "    public void test() {" +
  98.809 +                             "        int i = 0;" +
  98.810 +                             "        int j = 0;" +
  98.811 +                             "        i++;" +
  98.812 +                             "        j++;" +
  98.813 +                             "    }" +
  98.814 +                             "}",
  98.815 +                             "{$type $i = $init; $stms$; $i++;}",
  98.816 +                             new Pair[0],
  98.817 +                             new Pair[0],
  98.818 +                             new Pair[0],
  98.819 +                             true,
  98.820 +                             false);
  98.821 +    }
  98.822 +
  98.823 +    public void testCorrectSite192812() throws Exception {
  98.824 +        performVariablesTest("package test; public class Test { private int i; public void test(Test t) { t.i = i - 10; } }",
  98.825 +                             "$t = $t - $v",
  98.826 +                             new Pair[0],
  98.827 +                             new Pair[0],
  98.828 +                             new Pair[0],
  98.829 +                             true,
  98.830 +                             true);
  98.831 +    }
  98.832 +
  98.833 +    public void testCorrectSite183367() throws Exception {
  98.834 +        performVariablesTest("package test; public class Test { public void test(java.util.List l) { l.subList(0, 0).remove(0); } }",
  98.835 +                             "$l{java.util.Collection}.remove($o{java.lang.Object})",
  98.836 +                             new Pair[0],
  98.837 +                             new Pair[0],
  98.838 +                             new Pair[0],
  98.839 +                             true,
  98.840 +                             true);
  98.841 +    }
  98.842 +
  98.843 +    public void testDisableVariablesWhenVerifyingDuplicates1() throws Exception {
  98.844 +        performVariablesTest("package test; public class Test { public void test() { int $i = 1, $j = 2; int k = $i + $i; } }",
  98.845 +                             "$i + $i",
  98.846 +                             new Pair[] {new Pair<String, int[]>("$i", new int[] {83, 85})},
  98.847 +                             new Pair[0],
  98.848 +                             new Pair[0],
  98.849 +                             false,
  98.850 +                             true);
  98.851 +    }
  98.852 +
  98.853 +    public void testDisableVariablesWhenVerifyingDuplicates2() throws Exception {
  98.854 +        performVariablesTest("package test; public class Test { public void test() { int $i = 1, $j = 2; int k = $i + $i; } }",
  98.855 +                             "$i + $i",
  98.856 +                             new Pair[] {new Pair<String, int[]>("$i", new int[] {83, 85})},
  98.857 +                             new Pair[0],
  98.858 +                             new Pair[0],
  98.859 +                             false,
  98.860 +                             false);
  98.861 +    }
  98.862 +
  98.863 +    public void testMethodMatchingMoreParams() throws Exception {
  98.864 +        performVariablesTest("package test; public class Test {public void test(String s1, String s2) { } }",
  98.865 +                             "public void test($params$) { }",
  98.866 +                             new Pair[0],
  98.867 +                             new Pair[] {new Pair<String, int[]>("$params$", new int[] {50, 59, 61, 70})},
  98.868 +                             new Pair[0],
  98.869 +                             false,
  98.870 +                             true);
  98.871 +    }
  98.872 +
  98.873 +    public void testLambdaInput1() throws Exception {
  98.874 +        performVariablesTest("package test; public class Test {public void test() { new java.io.FilenameFilter() { public boolean accept(File dir, String name) { } }; } }",
  98.875 +                             "new $type() {public $retType $name($params$) { $body$; } }",
  98.876 +                             new Pair[0],
  98.877 +                             new Pair[] {new Pair<String, int[]>("$params$", new int[] { 107, 115, 117, 128 })},
  98.878 +                             new Pair[] {new Pair<String, String>("$name", "accept")},
  98.879 +                             false,
  98.880 +                             false);
  98.881 +    }
  98.882 +
  98.883 +    public void testLambdaInput2() throws Exception {
  98.884 +        performVariablesTest("package test; public class Test {public void test() { new java.io.FilenameFilter() { public boolean accept(File dir, String name) { } }; } }",
  98.885 +                             "new $type() { $mods$ $retType $name($params$) { $body$; } }",
  98.886 +                             new Pair[0],
  98.887 +                             new Pair[] {new Pair<String, int[]>("$params$", new int[] { 107, 115, 117, 128 })},
  98.888 +                             new Pair[] {new Pair<String, String>("$name", "accept")},
  98.889 +                             false,
  98.890 +                             true);
  98.891 +    }
  98.892 +
  98.893 +    public void testSwitch1() throws Exception {
  98.894 +        performVariablesTest("package test;\n" +
  98.895 +                             "public class Test {\n" +
  98.896 +                             "     {\n" +
  98.897 +                             "         E e = null;\n" +
  98.898 +                             "         switch (e) {\n" +
  98.899 +                             "             case A: System.err.println(1); break;\n" +
  98.900 +                             "             case D: System.err.println(2); break;\n" +
  98.901 +                             "             case E: System.err.println(3); break;\n" +
  98.902 +                             "         }\n" +
  98.903 +                             "     }\n" +
  98.904 +                             "     public enum E {A, B, C, D, E, F;}\n" +
  98.905 +                             "}\n",
  98.906 +                             "switch ($0{test.Test.E}) { case $c1$ case D: $stmts$; case $c2$ }",
  98.907 +                             new Pair[] {new Pair<String, int[]>("$0", new int[] {79, 80})},
  98.908 +                             new Pair[] {
  98.909 +                                new Pair<String, int[]>("$stmts$", new int[] { 156, 178, 179, 185 }),
  98.910 +                                new Pair<String, int[]>("$c1$", new int[] { 97, 134 }),
  98.911 +                                new Pair<String, int[]>("$c2$", new int[] { 199, 236 }),
  98.912 +                             },
  98.913 +                             new Pair[0],
  98.914 +                             false,
  98.915 +                             false);
  98.916 +    }
  98.917 +
  98.918 +    public void testWildcard1() throws Exception {
  98.919 +        performTest("package test; import java.util.*; public class Test { public void test() { |List<?>| l1; |List<?>| l2;} }");
  98.920 +    }
  98.921 +
  98.922 +    public void testWildcard2() throws Exception {
  98.923 +        performTest("package test; import java.util.*; public class Test { public void test() { |List<? extends String>| l1; |List<? extends String>| l2;} }");
  98.924 +    }
  98.925 +
  98.926 +    public void testWildcard3() throws Exception {
  98.927 +        performTest("package test; import java.util.*; public class Test { public void test() { |List<? super String>| l1; |List<? super String>| l2;} }");
  98.928 +    }
  98.929 +
  98.930 +    public void testSingleVariableStrict() throws Exception {
  98.931 +        performVariablesTest("package test; public class Test { public void test() { if (true) System.err.println(1); } }",
  98.932 +                             "if ($c) $then; else $else;",
  98.933 +                             new Pair[0],
  98.934 +                             new Pair[0],
  98.935 +                             new Pair[0],
  98.936 +                             true,
  98.937 +                             true);
  98.938 +    }
  98.939 +
  98.940 +    public void testMultiVariableZeroOrOne1() throws Exception {
  98.941 +        performVariablesTest("package test; public class Test { public void test() { if (true) System.err.println(1); } }",
  98.942 +                             "if ($c) $then; else $else$;",
  98.943 +                             new Pair[] {new Pair<String, int[]>("$c", new int[] {59, 63}),
  98.944 +                                         new Pair<String, int[]>("$then", new int[] {65, 87})},
  98.945 +                             new Pair[0],
  98.946 +                             new Pair[0],
  98.947 +                             false,
  98.948 +                             true);
  98.949 +    }
  98.950 +
  98.951 +    public void testMultiVariableZeroOrOne2() throws Exception {
  98.952 +        performVariablesTest("package test; public class Test { public void test() { if (true) System.err.println(1); else System.err.println(2); } }",
  98.953 +                             "if ($c) $then; else $else$;",
  98.954 +                             new Pair[] {new Pair<String, int[]>("$c", new int[] {59, 63}),
  98.955 +                                         new Pair<String, int[]>("$then", new int[] {65, 87}),
  98.956 +                                         new Pair<String, int[]>("$else$", new int[] {93, 115})},
  98.957 +                             new Pair[0],
  98.958 +                             new Pair[0],
  98.959 +                             false,
  98.960 +                             true);
  98.961 +    }
  98.962 +
  98.963 +    public void testNonResolvableType() throws Exception {
  98.964 +        performVariablesTest("package test; public class Test { { java.io.File f = null; boolean b = f.isDirectory(); } }",
  98.965 +                             "$1{can.not.Resolve}.$m($args$)",
  98.966 +                             new Pair[0],
  98.967 +                             new Pair[0],
  98.968 +                             new Pair[0],
  98.969 +                             true,
  98.970 +                             true);
  98.971 +    }
  98.972 +
  98.973 +    public void testTryWithResources() throws Exception {
  98.974 +        performVariablesTest("package test; public class Test { { try (java.io.InputStream in = null) { System.err.println(1); } } }",
  98.975 +                             "try ($resources$) {$body$;}",
  98.976 +                             new Pair[] {
  98.977 +                             },
  98.978 +                             new Pair[] {
  98.979 +                                new Pair<String, int[]>("$resources$", new int[] {41, 70}),
  98.980 +                                new Pair<String, int[]>("$body$", new int[] {74, 96}),
  98.981 +                             },
  98.982 +                             new Pair[] {
  98.983 +                             },
  98.984 +                             false,
  98.985 +                             true);
  98.986 +    }
  98.987 +
  98.988 +    public void testIgnoreOtherKind() throws Exception {
  98.989 +        performVariablesTest("package test; public class Test { private java.util.Collection<String> x() { return java.util.Collections.emptySet(); } } }",
  98.990 +                             "$i{java.lang.Class}",
  98.991 +                             new Pair[] {
  98.992 +                             },
  98.993 +                             new Pair[] {
  98.994 +                             },
  98.995 +                             new Pair[] {
  98.996 +                             },
  98.997 +                             true,
  98.998 +                             true);
  98.999 +    }
 98.1000 +
 98.1001 +    public void testSearchPackageClause() throws Exception {
 98.1002 +        performVariablesTest("package test.a; public class Test { }",
 98.1003 +                             "test.$1",
 98.1004 +                             new Pair[] {
 98.1005 +                             },
 98.1006 +                             new Pair[] {
 98.1007 +                             },
 98.1008 +                             new Pair[] {
 98.1009 +                                 new Pair<String, String>("$1", "a"),
 98.1010 +                             },
 98.1011 +                             false,
 98.1012 +                             true);
 98.1013 +    }
 98.1014 +
 98.1015 +    public void testPackageImport() throws Exception {
 98.1016 +        performVariablesTest("package test; import java.util.*; public class Test { }",
 98.1017 +                             "java.$1",
 98.1018 +                             new Pair[] {
 98.1019 +                             },
 98.1020 +                             new Pair[] {
 98.1021 +                             },
 98.1022 +                             new Pair[] {
 98.1023 +                                 new Pair<String, String>("$1", "util"),
 98.1024 +                             },
 98.1025 +                             false,
 98.1026 +                             true);
 98.1027 +    }
 98.1028 +    
 98.1029 +    public void testSubclassMatching() throws Exception {
 98.1030 +        performVariablesTest("package test; import java.util.*; public abstract class Test { Map.Entry e; }",
 98.1031 +                             "java.util.Map.$1",
 98.1032 +                             new Pair[] {
 98.1033 +                             },
 98.1034 +                             new Pair[] {
 98.1035 +                             },
 98.1036 +                             new Pair[] {
 98.1037 +                                 new Pair<String, String>("$1", "Entry"),
 98.1038 +                             },
 98.1039 +                             false,
 98.1040 +                             true);
 98.1041 +    }
 98.1042 +    
 98.1043 +    public void testMethodTypeParameters1() throws Exception {
 98.1044 +        performVariablesTest("package test; public class Test { private void t() { } }",
 98.1045 +                             "$mods$ <$tp$> $ret $name($args$) { $body$; }",
 98.1046 +                             new Pair[] {
 98.1047 +                                new Pair<String, int[]>("$ret", new int[] {42, 46}),
 98.1048 +                                new Pair<String, int[]>("$mods$", new int[] {34, 41}),
 98.1049 +                             },
 98.1050 +                             new Pair[] {
 98.1051 +                                new Pair<String, int[]>("$tp$", new int[] {}),
 98.1052 +                                new Pair<String, int[]>("$args$", new int[] {}),
 98.1053 +                                new Pair<String, int[]>("$body$", new int[] {}),
 98.1054 +                             },
 98.1055 +                             new Pair[] {
 98.1056 +                                 new Pair<String, String>("$name", "t")
 98.1057 +                             },
 98.1058 +                             false,
 98.1059 +                             false);
 98.1060 +    }
 98.1061 +    
 98.1062 +    public void testMethodTypeParameters2() throws Exception {
 98.1063 +        performVariablesTest("package test; public class Test { private <A, B> String aa(int a, int b) { a = b; b = a;} }",
 98.1064 +                             "$mods$ <$tp$> $ret $name($args$) { $body$; }",
 98.1065 +                             new Pair[] {
 98.1066 +                                new Pair<String, int[]>("$ret", new int[] {49, 55}),
 98.1067 +                                new Pair<String, int[]>("$mods$", new int[] {34, 41}),
 98.1068 +                             },
 98.1069 +                             new Pair[] {
 98.1070 +                                new Pair<String, int[]>("$tp$", new int[] {43, 44, 46, 47}),
 98.1071 +                                new Pair<String, int[]>("$args$", new int[] {59, 64, 66, 71}),
 98.1072 +                                new Pair<String, int[]>("$body$", new int[] {75, 81, 82, 88}),
 98.1073 +                             },
 98.1074 +                             new Pair[] {
 98.1075 +                                 new Pair<String, String>("$name", "aa")
 98.1076 +                             },
 98.1077 +                             false,
 98.1078 +                             true);
 98.1079 +    }
 98.1080 +    
 98.1081 +    public void testMethodTypeParameters3() throws Exception {
 98.1082 +        performVariablesTest("package test; public class Test { private <A> String aa(int a, int b) { a = b; b = a;} }",
 98.1083 +                             "$mods$ <$tp> $ret $name($args$) { $body$; }",
 98.1084 +                             new Pair[] {
 98.1085 +                                new Pair<String, int[]>("$ret", new int[] {46, 52}),
 98.1086 +                                new Pair<String, int[]>("$mods$", new int[] {34, 41}),
 98.1087 +                                new Pair<String, int[]>("$tp", new int[] {43, 44}),
 98.1088 +                             },
 98.1089 +                             new Pair[] {
 98.1090 +                                new Pair<String, int[]>("$args$", new int[] {56, 61, 63, 68}),
 98.1091 +                                new Pair<String, int[]>("$body$", new int[] {72, 78, 79, 85}),
 98.1092 +                             },
 98.1093 +                             new Pair[] {
 98.1094 +                                 new Pair<String, String>("$name", "aa")
 98.1095 +                             },
 98.1096 +                             false,
 98.1097 +                             true);
 98.1098 +    }
 98.1099 +    
 98.1100 +    public void testTypeParameters1() throws Exception {
 98.1101 +        performVariablesTest("package test; public class Test { private <A extends String> void aa() { } }",
 98.1102 +                             "$mods$ <$tp extends $bound&$obounds$> $ret $name($args$) { $body$; }",
 98.1103 +                             new Pair[] {
 98.1104 +                                new Pair<String, int[]>("$ret", new int[] {61, 65}),
 98.1105 +                                new Pair<String, int[]>("$mods$", new int[] {34, 41}),
 98.1106 +                                new Pair<String, int[]>("$tp", new int[] {43, 59}),
 98.1107 +                                new Pair<String, int[]>("$bound", new int[] {53, 59}),
 98.1108 +                             },
 98.1109 +                             new Pair[] {
 98.1110 +                                new Pair<String, int[]>("$obounds$", new int[] {}),
 98.1111 +                             },
 98.1112 +                             new Pair[] {
 98.1113 +                                 new Pair<String, String>("$name", "aa"),
 98.1114 +                                 new Pair<String, String>("$tp", "A")
 98.1115 +                             },
 98.1116 +                             false,
 98.1117 +                             true);
 98.1118 +    }
 98.1119 +    
 98.1120 +    public void testPartialModifiers1() throws Exception {
 98.1121 +        performVariablesTest("package test; public class Test { @Deprecated @Override private void aa() { } }",
 98.1122 +                             "$mods$ @Deprecated private $ret $name() { $body$; }",
 98.1123 +                             new Pair[] {
 98.1124 +                                new Pair<String, int[]>("$ret", new int[] {64, 68}),
 98.1125 +                                new Pair<String, int[]>("$mods$", new int[] {34, 63}),
 98.1126 +                             },
 98.1127 +                             new Pair[] {
 98.1128 +                             },
 98.1129 +                             new Pair[] {
 98.1130 +                                 new Pair<String, String>("$name", "aa"),
 98.1131 +                             },
 98.1132 +                             false,
 98.1133 +                             true);
 98.1134 +    }
 98.1135 +    
 98.1136 +    public void testPartialModifiers2() throws Exception {
 98.1137 +        performVariablesTest("package test; public class Test { @Override private void aa() { } }",
 98.1138 +                             "$mods$ @Deprecated private $ret $name() { $body$; }",
 98.1139 +                             new Pair[0],
 98.1140 +                             new Pair[0],
 98.1141 +                             new Pair[0],
 98.1142 +                             true,
 98.1143 +                             true);
 98.1144 +    }
 98.1145 +    
 98.1146 +    public void testNonStaticInnerClassesMatch() throws Exception {
 98.1147 +        performVariablesTest("package test; import test.Test.Inner; public class Test { public class Inner { } } class Other { { Inner i = null; } }",
 98.1148 +                             "test.Test.Inner $i = $init$;",
 98.1149 +                             new Pair[] {
 98.1150 +                                 new Pair<String, int[]>("$i", new int[] {99, 114}),
 98.1151 +                                 new Pair<String, int[]>("$init$", new int[] {109, 113})
 98.1152 +                             },
 98.1153 +                             new Pair[0],
 98.1154 +                             new Pair[] {
 98.1155 +                                 new Pair<String, String>("$i", "i")
 98.1156 +                             },
 98.1157 +                             false,
 98.1158 +                             true);
 98.1159 +    }
 98.1160 +    
 98.1161 +    public void testNewClassTypeParams222066a() throws Exception {
 98.1162 +        performVariablesTest("package test; public class Test { private Object aa() { return new java.util.ArrayList(1); } }",
 98.1163 +                             "new java.util.ArrayList<$whatever$>($param)",
 98.1164 +                             new Pair[] {
 98.1165 +                                 new Pair<String, int[]>("$param", new int[] {87, 88})
 98.1166 +                             },
 98.1167 +                             new Pair[] {
 98.1168 +                                 new Pair<String, int[]>("$whatever$", new int[0])
 98.1169 +                             },
 98.1170 +                             new Pair[0],
 98.1171 +                             false,
 98.1172 +                             false);
 98.1173 +    }
 98.1174 +    
 98.1175 +    public void testNewClassTypeParams222066b() throws Exception {
 98.1176 +        performVariablesTest("package test; import java.util.ArrayList; public class Test { private Object aa() { return new ArrayList(1); } }",
 98.1177 +                             "new java.util.ArrayList<$whatever$>($param)",
 98.1178 +                             new Pair[] {
 98.1179 +                                 new Pair<String, int[]>("$param", new int[] {105, 106})
 98.1180 +                             },
 98.1181 +                             new Pair[] {
 98.1182 +                                 new Pair<String, int[]>("$whatever$", new int[0])
 98.1183 +                             },
 98.1184 +                             new Pair[0],
 98.1185 +                             false,
 98.1186 +                             false);
 98.1187 +    }
 98.1188 +    
 98.1189 +    public void testFindLambda() throws Exception {
 98.1190 +        performVariablesTest("package test; import java.util.Comparator; public class Test { private void aa() { Comparator<String> c = (l, r) -> l.compareTo(r); } }",
 98.1191 +                             "($args$) -> $expression",
 98.1192 +                             new Pair[] {
 98.1193 +                                 new Pair<String, int[]>("$expression", new int[] {116, 130})
 98.1194 +                             },
 98.1195 +                             new Pair[] {
 98.1196 +                                 new Pair<String, int[]>("$args$", new int[] {107, 108, 110, 111})
 98.1197 +                             },
 98.1198 +                             new Pair[0],
 98.1199 +                             false,
 98.1200 +                             false);
 98.1201 +    }
 98.1202 +    
 98.1203 +    protected void prepareTest(String code) throws Exception {
 98.1204 +        prepareTest(code, -1);
 98.1205 +    }
 98.1206 +
 98.1207 +    protected void prepareTest(String code, int testIndex) throws Exception {
 98.1208 +        File workDirWithIndexFile = testIndex != (-1) ? new File(getWorkDir(), Integer.toString(testIndex)) : getWorkDir();
 98.1209 +        FileObject workDirWithIndex = FileUtil.toFileObject(workDirWithIndexFile);
 98.1210 +
 98.1211 +        if (workDirWithIndex != null) {
 98.1212 +            workDirWithIndex.delete();
 98.1213 +        }
 98.1214 +
 98.1215 +        workDirWithIndex = FileUtil.createFolder(workDirWithIndexFile);
 98.1216 +
 98.1217 +        assertNotNull(workDirWithIndexFile);
 98.1218 +
 98.1219 +        FileObject sourceRoot = workDirWithIndex.createFolder("src");
 98.1220 +        FileObject buildRoot  = workDirWithIndex.createFolder("build");
 98.1221 +        FileObject cache = workDirWithIndex.createFolder("cache");
 98.1222 +
 98.1223 +        FileObject data = FileUtil.createData(sourceRoot, "test/Test.java");
 98.1224 +
 98.1225 +        TestUtilities.copyStringToFile(data, code);
 98.1226 +
 98.1227 +        data.refresh();
 98.1228 +
 98.1229 +        SourceUtilsTestUtil.prepareTest(sourceRoot, buildRoot, cache);
 98.1230 +
 98.1231 +        DataObject od = DataObject.find(data);
 98.1232 +        EditorCookie ec = od.getLookup().lookup(EditorCookie.class);
 98.1233 +
 98.1234 +        assertNotNull(ec);
 98.1235 +
 98.1236 +        doc = ec.openDocument();
 98.1237 +
 98.1238 +        doc.putProperty(Language.class, JavaTokenId.language());
 98.1239 +        doc.putProperty("mimeType", "text/x-java");
 98.1240 +
 98.1241 +        JavaSource js = JavaSource.forFileObject(data);
 98.1242 +
 98.1243 +        assertNotNull(js);
 98.1244 +
 98.1245 +        info = SourceUtilsTestUtil.getCompilationInfo(js, Phase.RESOLVED);
 98.1246 +
 98.1247 +        assertNotNull(info);
 98.1248 +    }
 98.1249 +
 98.1250 +    private static String findRegions(String code, List<int[]> regions) {
 98.1251 +        String[] split = code.split("\\|");
 98.1252 +        StringBuilder filtered = new StringBuilder();
 98.1253 +
 98.1254 +        filtered.append(split[0]);
 98.1255 +
 98.1256 +        int offset = split[0].length();
 98.1257 +
 98.1258 +        for (int cntr = 1; cntr < split.length; cntr += 2) {
 98.1259 +            int[] i = new int[] {
 98.1260 +                offset,
 98.1261 +                offset + split[cntr].length()
 98.1262 +            };
 98.1263 +
 98.1264 +            regions.add(i);
 98.1265 +
 98.1266 +            filtered.append(split[cntr]);
 98.1267 +            filtered.append(split[cntr + 1]);
 98.1268 +
 98.1269 +            offset += split[cntr].length();
 98.1270 +            offset += split[cntr + 1].length();
 98.1271 +        }
 98.1272 +
 98.1273 +        return filtered.toString();
 98.1274 +    }
 98.1275 +
 98.1276 +    protected CompilationInfo info;
 98.1277 +    private Document doc;
 98.1278 +
 98.1279 +    private void performTest(String code) throws Exception {
 98.1280 +        performTest(code, true);
 98.1281 +    }
 98.1282 +
 98.1283 +    private void performTest(String code, boolean verify) throws Exception {
 98.1284 +        List<int[]> result = new LinkedList<int[]>();
 98.1285 +
 98.1286 +        code = findRegions(code, result);
 98.1287 +
 98.1288 +        int testIndex = 0;
 98.1289 +
 98.1290 +        for (int[] i : result) {
 98.1291 +            int[] duplicates = new int[2 * (result.size() - 1)];
 98.1292 +            int cntr = 0;
 98.1293 +            List<int[]> l = new LinkedList<int[]>(result);
 98.1294 +
 98.1295 +            l.remove(i);
 98.1296 +
 98.1297 +            for (int[] span : l) {
 98.1298 +                duplicates[cntr++] = span[0];
 98.1299 +                duplicates[cntr++] = span[1];
 98.1300 +            }
 98.1301 +
 98.1302 +            doPerformTest(code, i[0], i[1], testIndex++, verify, duplicates);
 98.1303 +        }
 98.1304 +    }
 98.1305 +
 98.1306 +    protected void performTest(String code, int start, int end, int... duplicates) throws Exception {
 98.1307 +        doPerformTest(code, start, end, -1, true, duplicates);
 98.1308 +    }
 98.1309 +
 98.1310 +    protected void doPerformTest(String code, int start, int end, int testIndex, int... duplicates) throws Exception {
 98.1311 +        doPerformTest(code, start, end, testIndex, true, duplicates);
 98.1312 +    }
 98.1313 +
 98.1314 +    protected void doPerformTest(String code, int start, int end, int testIndex, boolean verify, int... duplicates) throws Exception {
 98.1315 +        prepareTest(code, testIndex);
 98.1316 +
 98.1317 +        TreePath path = info.getTreeUtilities().pathFor((start + end) / 2 + 1);
 98.1318 +
 98.1319 +        while (path != null) {
 98.1320 +            Tree t = path.getLeaf();
 98.1321 +            SourcePositions sp = info.getTrees().getSourcePositions();
 98.1322 +
 98.1323 +            if (   start == sp.getStartPosition(info.getCompilationUnit(), t)
 98.1324 +                && end   == sp.getEndPosition(info.getCompilationUnit(), t)) {
 98.1325 +                break;
 98.1326 +            }
 98.1327 +
 98.1328 +            path = path.getParentPath();
 98.1329 +        }
 98.1330 +
 98.1331 +        assertNotNull(path);
 98.1332 +
 98.1333 +        Collection<TreePath> result = computeDuplicates(path);
 98.1334 +
 98.1335 +        //        assertEquals(f.result.toString(), duplicates.length / 2, f.result.size());
 98.1336 +
 98.1337 +        if (verify) {
 98.1338 +            int[] dupes = new int[result.size() * 2];
 98.1339 +            int   index = 0;
 98.1340 +
 98.1341 +            for (TreePath tp : result) {
 98.1342 +                dupes[index++] = (int) info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), tp.getLeaf());
 98.1343 +                dupes[index++] = (int) info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), tp.getLeaf());
 98.1344 +            }
 98.1345 +
 98.1346 +            assertTrue("Was: " + Arrays.toString(dupes) + " should have been: " + Arrays.toString(duplicates), Arrays.equals(duplicates, dupes));
 98.1347 +        }
 98.1348 +    }
 98.1349 +
 98.1350 +    protected void performVariablesTest(String code, String pattern, Pair<String, int[]>[] duplicatesPos, Pair<String, String>[] duplicatesNames) throws Exception {
 98.1351 +        performVariablesTest(code, pattern, duplicatesPos, new Pair[0], duplicatesNames);
 98.1352 +    }
 98.1353 +
 98.1354 +    protected void performVariablesTest(String code, String pattern, Pair<String, int[]>[] duplicatesPos, Pair<String, int[]>[] multiStatementPos, Pair<String, String>[] duplicatesNames) throws Exception {
 98.1355 +        performVariablesTest(code, pattern, duplicatesPos, multiStatementPos, duplicatesNames, false);
 98.1356 +    }
 98.1357 +
 98.1358 +    protected void performVariablesTest(String code, String pattern, Pair<String, int[]>[] duplicatesPos, Pair<String, int[]>[] multiStatementPos, Pair<String, String>[] duplicatesNames, boolean noOccurrences) throws Exception {
 98.1359 +        performVariablesTest(code, pattern, duplicatesPos, multiStatementPos, duplicatesNames, noOccurrences, false);
 98.1360 +    }
 98.1361 +
 98.1362 +    protected void performVariablesTest(String code, String pattern, Pair<String, int[]>[] duplicatesPos, Pair<String, int[]>[] multiStatementPos, Pair<String, String>[] duplicatesNames, boolean noOccurrences, boolean useBulkSearch) throws Exception {
 98.1363 +        prepareTest(code, -1);
 98.1364 +
 98.1365 +        Map<String, TypeMirror> constraints = new HashMap<String, TypeMirror>();
 98.1366 +        String patternCode = PatternCompilerUtilities.parseOutTypesFromPattern(info, pattern, constraints);
 98.1367 +
 98.1368 +        Pattern patternObj = PatternCompiler.compile(info, patternCode, constraints, Collections.<String>emptyList());
 98.1369 +        TreePath patternPath = MatchingTestAccessor.getPattern(patternObj).iterator().next();
 98.1370 +        Map<TreePath, VariableAssignments> result;
 98.1371 +
 98.1372 +        if (useBulkSearch) {
 98.1373 +            result = new HashMap<TreePath, VariableAssignments>();
 98.1374 +
 98.1375 +            BulkPattern bulkPattern = BulkSearch.getDefault().create(info, new AtomicBoolean(), patternCode);
 98.1376 +
 98.1377 +            for (Entry<String, Collection<TreePath>> e : BulkSearch.getDefault().match(info, new AtomicBoolean(), new TreePath(info.getCompilationUnit()), bulkPattern).entrySet()) {
 98.1378 +                for (TreePath tp : e.getValue()) {
 98.1379 +                    VariableAssignments vars = computeVariables(info, patternPath, tp, new AtomicBoolean(), MatchingTestAccessor.getVariable2Type(patternObj));
 98.1380 +
 98.1381 +                    if (vars != null) {
 98.1382 +                        result.put(tp, vars);
 98.1383 +                    }
 98.1384 +                }
 98.1385 +            }
 98.1386 +        } else {
 98.1387 +            result = computeDuplicates(info, patternPath, new TreePath( info.getCompilationUnit()), new AtomicBoolean(), MatchingTestAccessor.getVariable2Type(patternObj));
 98.1388 +        }
 98.1389 +
 98.1390 +        if (noOccurrences) {
 98.1391 +            assertEquals(0, result.size());
 98.1392 +            return ;
 98.1393 +        }
 98.1394 +
 98.1395 +        assertSame(1, result.size());
 98.1396 +
 98.1397 +        Map<String, int[]> actual = new HashMap<String, int[]>();
 98.1398 +
 98.1399 +        for (Entry<String, TreePath> e : result.values().iterator().next().variables.entrySet()) {
 98.1400 +            int[] span = new int[] {
 98.1401 +                (int) info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), e.getValue().getLeaf()),
 98.1402 +                (int) info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), e.getValue().getLeaf())
 98.1403 +            };
 98.1404 +
 98.1405 +            actual.put(e.getKey(), span);
 98.1406 +        }
 98.1407 +
 98.1408 +        for (Pair<String, int[]> dup : duplicatesPos) {
 98.1409 +            int[] span = actual.remove(dup.getA());
 98.1410 +
 98.1411 +            if (span == null) {
 98.1412 +                fail(dup.getA());
 98.1413 +            }
 98.1414 +            assertTrue(dup.getA() + ":" + Arrays.toString(span), Arrays.equals(span, dup.getB()));
 98.1415 +        }
 98.1416 +
 98.1417 +        Map<String, int[]> actualMulti = new HashMap<String, int[]>();
 98.1418 +
 98.1419 +        for (Entry<String, Collection<? extends TreePath>> e : result.values().iterator().next().multiVariables.entrySet()) {
 98.1420 +            int[] span = new int[2 * e.getValue().size()];
 98.1421 +            int i = 0;
 98.1422 +
 98.1423 +            for (TreePath tp : e.getValue()) {
 98.1424 +                span[i++] = (int) info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), tp.getLeaf());
 98.1425 +                span[i++] = (int) info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), tp.getLeaf());
 98.1426 +            }
 98.1427 +
 98.1428 +            actualMulti.put(e.getKey(), span);
 98.1429 +        }
 98.1430 +
 98.1431 +        for (Pair<String, int[]> dup : multiStatementPos) {
 98.1432 +            int[] span = actualMulti.remove(dup.getA());
 98.1433 +
 98.1434 +            if (span == null) {
 98.1435 +                fail(dup.getA());
 98.1436 +            }
 98.1437 +            assertTrue(dup.getA() + ":" + Arrays.toString(span), Arrays.equals(span, dup.getB()));
 98.1438 +        }
 98.1439 +
 98.1440 +        Map<String, String> golden = new HashMap<String, String>();
 98.1441 +
 98.1442 +        for ( Pair<String, String> e : duplicatesNames) {
 98.1443 +            golden.put(e.getA(), e.getB());
 98.1444 +        }
 98.1445 +
 98.1446 +        assertEquals(golden, result.values().iterator().next().variables2Names);
 98.1447 +    }
 98.1448 +
 98.1449 +    protected VariableAssignments computeVariables(CompilationInfo info, TreePath searchingFor, TreePath scope, AtomicBoolean cancel, Map<String, TypeMirror> designedTypeHack) {
 98.1450 +        Collection<VariableAssignments> values = CopyFinder.internalComputeDuplicates(info, Collections.singletonList(searchingFor), scope, null, null, new AtomicBooleanCancel(cancel), designedTypeHack, Options.ALLOW_VARIABLES_IN_PATTERN).values();
 98.1451 +
 98.1452 +        if (values.iterator().hasNext()) {
 98.1453 +            return values.iterator().next();
 98.1454 +        } else {
 98.1455 +            return null;
 98.1456 +        }
 98.1457 +    }
 98.1458 +
 98.1459 +    protected Map<TreePath, VariableAssignments> computeDuplicates(CompilationInfo info, TreePath searchingFor, TreePath scope, AtomicBoolean cancel, Map<String, TypeMirror> designedTypeHack) {
 98.1460 +        return CopyFinder.internalComputeDuplicates(info, Collections.singletonList(searchingFor), scope, null, null, new AtomicBooleanCancel(cancel), designedTypeHack, Options.ALLOW_VARIABLES_IN_PATTERN, Options.ALLOW_GO_DEEPER);
 98.1461 +    }
 98.1462 +
 98.1463 +    private void performRemappingTest(String code, String remappableVariables, Options... options) throws Exception {
 98.1464 +        List<int[]> regions = new LinkedList<int[]>();
 98.1465 +
 98.1466 +        code = findRegions(code, regions);
 98.1467 +
 98.1468 +        prepareTest(code, -1);
 98.1469 +
 98.1470 +        int[] statements = new int[2];
 98.1471 +
 98.1472 +        int[] currentRegion = regions.get(0);
 98.1473 +        TreePathHandle tph = IntroduceHint.validateSelectionForIntroduceMethod(info, currentRegion[0], currentRegion[1], statements);
 98.1474 +
 98.1475 +        assertNotNull(tph);
 98.1476 +
 98.1477 +        TreePath tp = tph.resolve(info);
 98.1478 +
 98.1479 +        assertNotNull(tp);
 98.1480 +
 98.1481 +        BlockTree bt = (BlockTree) tp.getParentPath().getLeaf();
 98.1482 +        List<TreePath> searchFor = new LinkedList<TreePath>();
 98.1483 +
 98.1484 +        for (StatementTree t : bt.getStatements().subList(statements[0], statements[1] + 1)) {
 98.1485 +            searchFor.add(new TreePath(tp, t));
 98.1486 +        }
 98.1487 +
 98.1488 +        final Set<VariableElement> vars = new HashSet<VariableElement>();
 98.1489 +
 98.1490 +        for (final String name : remappableVariables.split(",")) {
 98.1491 +            if (name.isEmpty()) continue;
 98.1492 +            new TreePathScanner<Object, Object>() {
 98.1493 +                @Override
 98.1494 +                public Object visitVariable(VariableTree node, Object p) {
 98.1495 +                    if (node.getName().contentEquals(name)) {
 98.1496 +                        vars.add((VariableElement) info.getTrees().getElement(getCurrentPath()));
 98.1497 +                    }
 98.1498 +
 98.1499 +                    return super.visitVariable(node, p);
 98.1500 +                }
 98.1501 +            }.scan(info.getCompilationUnit(), null);
 98.1502 +        }
 98.1503 +
 98.1504 +        Set<Options> opts = EnumSet.of(Options.ALLOW_GO_DEEPER);
 98.1505 +
 98.1506 +        opts.addAll(Arrays.asList(options));
 98.1507 +
 98.1508 +        Map<TreePath, VariableAssignments> result = CopyFinder.internalComputeDuplicates(info, searchFor, new TreePath(info.getCompilationUnit()), null, vars, new AtomicBooleanCancel(), Collections.<String, TypeMirror>emptyMap(), opts.toArray(new Options[0]));
 98.1509 +        Set<List<Integer>> realSpans = new HashSet<List<Integer>>();
 98.1510 +
 98.1511 +        for (Entry<TreePath, VariableAssignments> e : result.entrySet()) {
 98.1512 +            List<? extends StatementTree> parentStatements = CopyFinder.getStatements(e.getKey());
 98.1513 +            int dupeStart = parentStatements.indexOf(e.getKey().getLeaf());
 98.1514 +            int startPos = (int) info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), parentStatements.get(dupeStart));
 98.1515 +            int endPos = (int) info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), parentStatements.get(dupeStart + searchFor.size() - 1));
 98.1516 +
 98.1517 +            realSpans.add(Arrays.asList(startPos, endPos));
 98.1518 +        }
 98.1519 +
 98.1520 +        Set<List<Integer>> goldenSpans = new HashSet<List<Integer>>();
 98.1521 +
 98.1522 +        for (int[] region : regions) {
 98.1523 +            if (region == currentRegion) continue;
 98.1524 +
 98.1525 +            int[] stmts = new int[2];
 98.1526 +            TreePathHandle gtph = IntroduceHint.validateSelectionForIntroduceMethod(info, region[0], region[1], stmts);
 98.1527 +
 98.1528 +            assertNotNull(gtph);
 98.1529 +
 98.1530 +            TreePath gtp = gtph.resolve(info);
 98.1531 +
 98.1532 +            assertNotNull(gtp);
 98.1533 +
 98.1534 +            BlockTree b = (BlockTree) gtp.getParentPath().getLeaf();
 98.1535 +
 98.1536 +            int startPos = (int) info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), b.getStatements().get(stmts[0]));
 98.1537 +            int endPos = (int) info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), b.getStatements().get(stmts[1]));
 98.1538 +
 98.1539 +            goldenSpans.add(Arrays.asList(startPos, endPos));
 98.1540 +        }
 98.1541 +
 98.1542 +        assertEquals(goldenSpans, realSpans);
 98.1543 +    }
 98.1544 +
 98.1545 +    protected Collection<TreePath> computeDuplicates(TreePath path) {
 98.1546 +        return CopyFinder.internalComputeDuplicates(info, Collections.singletonList(path), new TreePath(info.getCompilationUnit()), null, null, new AtomicBooleanCancel(), null, Options.ALLOW_GO_DEEPER).keySet();
 98.1547 +    }
 98.1548 +
 98.1549 +    public static final class Pair<A, B> {
 98.1550 +        private final A a;
 98.1551 +        private final B b;
 98.1552 +
 98.1553 +        public Pair(A a, B b) {
 98.1554 +            this.a = a;
 98.1555 +            this.b = b;
 98.1556 +        }
 98.1557 +
 98.1558 +        public A getA() {
 98.1559 +            return a;
 98.1560 +        }
 98.1561 +
 98.1562 +        public B getB() {
 98.1563 +            return b;
 98.1564 +        }
 98.1565 +
 98.1566 +    }
 98.1567 +
 98.1568 +    private static final class AtomicBooleanCancel implements Cancel {
 98.1569 +
 98.1570 +        private final AtomicBoolean cancel;
 98.1571 +
 98.1572 +        public AtomicBooleanCancel() {
 98.1573 +            this(new AtomicBoolean());
 98.1574 +        }
 98.1575 +
 98.1576 +        public AtomicBooleanCancel(AtomicBoolean cancel) {
 98.1577 +            this.cancel = cancel;
 98.1578 +        }
 98.1579 +
 98.1580 +        @Override
 98.1581 +        public boolean isCancelled() {
 98.1582 +            return cancel.get();
 98.1583 +        }
 98.1584 +
 98.1585 +    }
 98.1586 +}
    99.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    99.2 +++ b/java.hints/spi.java.hints/test/unit/src/org/netbeans/spi/java/hints/support/FixFactoryTest.java	Wed May 08 21:47:42 2013 +0200
    99.3 @@ -0,0 +1,79 @@
    99.4 +/*
    99.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    99.6 + *
    99.7 + * Copyright 2013 Oracle and/or its affiliates. All rights reserved.
    99.8 + *
    99.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   99.10 + * Other names may be trademarks of their respective owners.
   99.11 + *
   99.12 + * The contents of this file are subject to the terms of either the GNU
   99.13 + * General Public License Version 2 only ("GPL") or the Common
   99.14 + * Development and Distribution License("CDDL") (collectively, the
   99.15 + * "License"). You may not use this file except in compliance with the
   99.16 + * License. You can obtain a copy of the License at
   99.17 + * http://www.netbeans.org/cddl-gplv2.html
   99.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   99.19 + * specific language governing permissions and limitations under the
   99.20 + * License.  When distributing the software, include this License Header
   99.21 + * Notice in each file and include the License file at
   99.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   99.23 + * particular file as subject to the "Classpath" exception as provided
   99.24 + * by Oracle in the GPL Version 2 section of the License file that
   99.25 + * accompanied this code. If applicable, add the following below the
   99.26 + * License Header, with the fields enclosed by brackets [] replaced by
   99.27 + * your own identifying information:
   99.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   99.29 + *
   99.30 + * If you wish your version of this file to be governed by only the CDDL
   99.31 + * or only the GPL Version 2, indicate your decision by adding
   99.32 + * "[Contributor] elects to include this software in this distribution
   99.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   99.34 + * single choice of license, a recipient has the option to distribute
   99.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   99.36 + * to extend the choice of license to its licensees as provided above.
   99.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   99.38 + * Version 2 license, then the option applies only if the new code is
   99.39 + * made subject to such option by the copyright holder.
   99.40 + *
   99.41 + * Contributor(s):
   99.42 + *
   99.43 + * Portions Copyrighted 2013 Sun Microsystems, Inc.
   99.44 + */
   99.45 +package org.netbeans.spi.java.hints.support;
   99.46 +
   99.47 +import com.sun.source.tree.ClassTree;
   99.48 +import com.sun.source.util.TreePath;
   99.49 +import java.util.EnumSet;
   99.50 +import javax.lang.model.element.Modifier;
   99.51 +import org.netbeans.api.java.source.SourceUtilsTestUtil;
   99.52 +import org.netbeans.modules.java.hints.spiimpl.TestBase;
   99.53 +import org.openide.LifecycleManager;
   99.54 +
   99.55 +/**
   99.56 + *
   99.57 + * @author lahvac
   99.58 + */
   99.59 +public class FixFactoryTest extends TestBase {
   99.60 +    
   99.61 +    public FixFactoryTest(String name) {
   99.62 +        super(name);
   99.63 +    }
   99.64 +
   99.65 +    @Override
   99.66 +    protected void setUp() throws Exception {
   99.67 +        super.setUp();
   99.68 +        SourceUtilsTestUtil.makeScratchDir(this);
   99.69 +    }
   99.70 +    
   99.71 +    public void testInterfaceModifiers() throws Exception {
   99.72 +        prepareTest("test/Test.java", "package test; public interface I { }");
   99.73 +        
   99.74 +        ClassTree i = (ClassTree) info.getCompilationUnit().getTypeDecls().get(0);
   99.75 +        
   99.76 +        FixFactory.removeModifiersFix(info, TreePath.getPath(info.getCompilationUnit(), i.getModifiers()), EnumSet.of(Modifier.PUBLIC), "").implement();
   99.77 +        
   99.78 +        LifecycleManager.getDefault().saveAll();
   99.79 +        
   99.80 +        assertEquals("package test; interface I { }", info.getFileObject().asText());
   99.81 +    }
   99.82 +}
   99.83 \ No newline at end of file
   100.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   100.2 +++ b/remoting/common/borrowedtests/src/org/netbeans/api/java/source/matching/MatchingTestAccessor.java	Wed May 08 21:47:42 2013 +0200
   100.3 @@ -0,0 +1,62 @@
   100.4 +/*
   100.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   100.6 + *
   100.7 + * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
   100.8 + *
   100.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  100.10 + * Other names may be trademarks of their respective owners.
  100.11 + *
  100.12 + * The contents of this file are subject to the terms of either the GNU
  100.13 + * General Public License Version 2 only ("GPL") or the Common
  100.14 + * Development and Distribution License("CDDL") (collectively, the
  100.15 + * "License"). You may not use this file except in compliance with the
  100.16 + * License. You can obtain a copy of the License at
  100.17 + * http://www.netbeans.org/cddl-gplv2.html
  100.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  100.19 + * specific language governing permissions and limitations under the
  100.20 + * License.  When distributing the software, include this License Header
  100.21 + * Notice in each file and include the License file at
  100.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  100.23 + * particular file as subject to the "Classpath" exception as provided
  100.24 + * by Oracle in the GPL Version 2 section of the License file that
  100.25 + * accompanied this code. If applicable, add the following below the
  100.26 + * License Header, with the fields enclosed by brackets [] replaced by
  100.27 + * your own identifying information:
  100.28 + * "Portions Copyrighted [year] [name of copyright owner]"
  100.29 + *
  100.30 + * If you wish your version of this file to be governed by only the CDDL
  100.31 + * or only the GPL Version 2, indicate your decision by adding
  100.32 + * "[Contributor] elects to include this software in this distribution
  100.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
  100.34 + * single choice of license, a recipient has the option to distribute
  100.35 + * your version of this file under either the CDDL, the GPL Version 2 or
  100.36 + * to extend the choice of license to its licensees as provided above.
  100.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
  100.38 + * Version 2 license, then the option applies only if the new code is
  100.39 + * made subject to such option by the copyright holder.
  100.40 + *
  100.41 + * Contributor(s):
  100.42 + *
  100.43 + * Portions Copyrighted 2012 Sun Microsystems, Inc.
  100.44 + */
  100.45 +package org.netbeans.api.java.source.matching;
  100.46 +
  100.47 +import com.sun.source.util.TreePath;
  100.48 +import java.util.Collection;
  100.49 +import java.util.Map;
  100.50 +import javax.lang.model.type.TypeMirror;
  100.51 +
  100.52 +/**
  100.53 + *
  100.54 + * @author lahvac
  100.55 + */
  100.56 +public class MatchingTestAccessor {
  100.57 +
  100.58 +    public static Collection<? extends TreePath> getPattern(Pattern p) {
  100.59 +        return p.pattern;
  100.60 +    }
  100.61 +
  100.62 +    public static Map<String, TypeMirror> getVariable2Type(Pattern p) {
  100.63 +        return p.variable2Type;
  100.64 +    }
  100.65 +}
   101.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   101.2 +++ b/remoting/common/borrowedtests/src/org/openide/util/test/TestFileUtils.java	Wed May 08 21:47:42 2013 +0200
   101.3 @@ -0,0 +1,271 @@
   101.4 +/*
   101.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   101.6 + *
   101.7 + * Copyright 2010 Oracle and/or its affiliates. All rights reserved.
   101.8 + *
   101.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  101.10 + * Other names may be trademarks of their respective owners.
  101.11 + *
  101.12 + * The contents of this file are subject to the terms of either the GNU
  101.13 + * General Public License Version 2 only ("GPL") or the Common
  101.14 + * Development and Distribution License("CDDL") (collectively, the
  101.15 + * "License"). You may not use this file except in compliance with the
  101.16 + * License. You can obtain a copy of the License at
  101.17 + * http://www.netbeans.org/cddl-gplv2.html
  101.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  101.19 + * specific language governing permissions and limitations under the
  101.20 + * License.  When distributing the software, include this License Header
  101.21 + * Notice in each file and include the License file at
  101.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  101.23 + * particular file as subject to the "Classpath" exception as provided
  101.24 + * by Oracle in the GPL Version 2 section of the License file that
  101.25 + * accompanied this code. If applicable, add the following below the
  101.26 + * License Header, with the fields enclosed by brackets [] replaced by
  101.27 + * your own identifying information:
  101.28 + * "Portions Copyrighted [year] [name of copyright owner]"
  101.29 + *
  101.30 + * If you wish your version of this file to be governed by only the CDDL
  101.31 + * or only the GPL Version 2, indicate your decision by adding
  101.32 + * "[Contributor] elects to include this software in this distribution
  101.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
  101.34 + * single choice of license, a recipient has the option to distribute
  101.35 + * your version of this file under either the CDDL, the GPL Version 2 or
  101.36 + * to extend the choice of license to its licensees as provided above.
  101.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
  101.38 + * Version 2 license, then the option applies only if the new code is
  101.39 + * made subject to such option by the copyright holder.
  101.40 + *
  101.41 + * Contributor(s):
  101.42 + *
  101.43 + * Portions Copyrighted 2008 Sun Microsystems, Inc.
  101.44 + */
  101.45 +
  101.46 +package org.openide.util.test;
  101.47 +
  101.48 +import java.io.ByteArrayOutputStream;
  101.49 +import java.io.File;
  101.50 +import java.io.FileInputStream;
  101.51 +import java.io.FileOutputStream;
  101.52 +import java.io.IOException;
  101.53 +import java.io.InputStream;
  101.54 +import java.io.OutputStream;
  101.55 +import java.io.OutputStreamWriter;
  101.56 +import java.io.PrintWriter;
  101.57 +import java.util.Collections;
  101.58 +import java.util.HashSet;
  101.59 +import java.util.LinkedHashMap;
  101.60 +import java.util.Map;
  101.61 +import java.util.Set;
  101.62 +import java.util.zip.CRC32;
  101.63 +import java.util.zip.ZipEntry;
  101.64 +import java.util.zip.ZipInputStream;
  101.65 +import java.util.zip.ZipOutputStream;
  101.66 +import junit.framework.Assert;
  101.67 +
  101.68 +/**
  101.69 + * Common utility methods for massaging and inspecting files from tests.
  101.70 + */
  101.71 +public class TestFileUtils {
  101.72 +
  101.73 +    private TestFileUtils() {}
  101.74 +
  101.75 +    /**
  101.76 +     * Create a new data file with specified initial contents.
  101.77 +     * @param f a file to create (parents will be created automatically)
  101.78 +     * @param body the complete contents of the new file (in UTF-8 encoding)
  101.79 +     */
  101.80 +    public static File writeFile(File f, String body) throws IOException {
  101.81 +        f.getParentFile().mkdirs();
  101.82 +        OutputStream os = new FileOutputStream(f);
  101.83 +        PrintWriter pw = new PrintWriter(new OutputStreamWriter(os, "UTF-8"));
  101.84 +        pw.print(body);
  101.85 +        pw.flush();
  101.86 +        os.close();
  101.87 +        return f;
  101.88 +    }
  101.89 +
  101.90 +    /**
  101.91 +     * Read the contents of a file as a single string.
  101.92 +     * @param a data file
  101.93 +     * @return its contents (in UTF-8 encoding)
  101.94 +     */
  101.95 +    public static String readFile(File file) throws IOException {
  101.96 +        InputStream is = new FileInputStream(file);
  101.97 +        ByteArrayOutputStream baos = new ByteArrayOutputStream();
  101.98 +        byte[] buf = new byte[4096];
  101.99 +        int read;
 101.100 +        while ((read = is.read(buf)) != -1) {
 101.101 +            baos.write(buf, 0, read);
 101.102 +        }
 101.103 +        is.close();
 101.104 +        return baos.toString("UTF-8");
 101.105 +    }
 101.106 +
 101.107 +    /**
 101.108 +     * Read the contents of a file as a byte array.
 101.109 +     * @param a data file
 101.110 +     * @return its raw binary contents
 101.111 +     */
 101.112 +    public static byte[] readFileBin(File file) throws IOException {
 101.113 +        InputStream is = new FileInputStream(file);
 101.114 +        ByteArrayOutputStream baos = new ByteArrayOutputStream();
 101.115 +        byte[] buf = new byte[4096];
 101.116 +        int read;
 101.117 +        while ((read = is.read(buf)) != -1) {
 101.118 +            baos.write(buf, 0, read);
 101.119 +        }
 101.120 +        is.close();
 101.121 +        return baos.toByteArray();
 101.122 +    }
 101.123 +
 101.124 +    /**
 101.125 +     * Create a new ZIP file.
 101.126 +     * @param jar the ZIP file to create
 101.127 +     * @param entries a list of entries in the form of "filename:UTF8-contents"; parent dirs created automatically
 101.128 +     * @return the {@code jar} parameter, for convenience
 101.129 +     * @throws IOException for the usual reasons
 101.130 +     */
 101.131 +    public static File writeZipFile(File jar, String... entries) throws IOException {
 101.132 +        jar.getParentFile().mkdirs();
 101.133 +        writeZipFile(new FileOutputStream(jar), entries);
 101.134 +        return jar;
 101.135 +    }
 101.136 +
 101.137 +    /**
 101.138 +     * Create a new ZIP file.
 101.139 +     * @param os a stream to which the ZIP will be written
 101.140 +     * @param entries a list of entries in the form of "filename:UTF8-contents"; parent dirs created automatically
 101.141 +     * @throws IOException for the usual reasons
 101.142 +     */
 101.143 +    public static void writeZipFile(OutputStream os, String... entries) throws IOException {
 101.144 +        Map<String,byte[]> binary = new LinkedHashMap<String,byte[]>();
 101.145 +        for (String entry : entries) {
 101.146 +            int colon = entry.indexOf(':');
 101.147 +            assert colon != -1 : entry;
 101.148 +            binary.put(entry.substring(0, colon), entry.substring(colon + 1).getBytes("UTF-8"));
 101.149 +        }
 101.150 +        writeZipFile(os, binary);
 101.151 +    }
 101.152 +
 101.153 +    /**
 101.154 +     * Create a new ZIP file.
 101.155 +     * @param os a stream to which the ZIP will be written
 101.156 +     * @param entries entries as maps from filename to binary contents;; parent dirs created automatically
 101.157 +     * @throws IOException for the usual reasons
 101.158 +     */
 101.159 +    public static void writeZipFile(OutputStream os, Map<String,byte[]> entries) throws IOException {
 101.160 +        ZipOutputStream zos = new ZipOutputStream(os);
 101.161 +        Set<String> parents = new HashSet<String>();
 101.162 +        if (entries.isEmpty()) {
 101.163 +            entries = Collections.singletonMap("PLACEHOLDER", new byte[0]);
 101.164 +        }
 101.165 +        for (Map.Entry<String,byte[]> entry : entries.entrySet()) {
 101.166 +            String name = entry.getKey();
 101.167 +            assert name.length() > 0 && !name.endsWith("/") && !name.startsWith("/") && name.indexOf("//") == -1 : name;
 101.168 +            for (int i = 0; i < name.length(); i++) {
 101.169 +                if (name.charAt(i) == '/') {
 101.170 +                    String parent = name.substring(0, i + 1);
 101.171 +                    if (parents.add(parent)) {
 101.172 +                        ZipEntry ze = new ZipEntry(parent);
 101.173 +                        ze.setMethod(ZipEntry.STORED);
 101.174 +                        ze.setSize(0);
 101.175 +                        ze.setCrc(0);
 101.176 +                        ze.setTime(0);
 101.177 +                        zos.putNextEntry(ze);
 101.178 +                        zos.closeEntry();
 101.179 +                    }
 101.180 +                }
 101.181 +            }
 101.182 +            byte[] data = entry.getValue();
 101.183 +            ZipEntry ze = new ZipEntry(name);
 101.184 +            ze.setMethod(ZipEntry.STORED);
 101.185 +            ze.setSize(data.length);
 101.186 +            CRC32 crc = new CRC32();
 101.187 +            crc.update(data);
 101.188 +            ze.setCrc(crc.getValue());
 101.189 +            ze.setTime(0);
 101.190 +            zos.putNextEntry(ze);
 101.191 +            zos.write(data, 0, data.length);
 101.192 +            zos.closeEntry();
 101.193 +        }
 101.194 +        zos.finish();
 101.195 +        zos.close();
 101.196 +        os.close();
 101.197 +    }
 101.198 +
 101.199 +    /**
 101.200 +     * Unpacks a ZIP file to disk.
 101.201 +     * All entries are unpacked, even {@code META-INF/MANIFEST.MF} if present.
 101.202 +     * Parent directories are created as needed (even if not mentioned in the ZIP);
 101.203 +     * empty ZIP directories are created too.
 101.204 +     * Existing files are overwritten.
 101.205 +     * @param zip a ZIP file
 101.206 +     * @param dir the base directory in which to unpack (need not yet exist)
 101.207 +     * @throws IOException in case of problems
 101.208 +     */
 101.209 +    public static void unpackZipFile(File zip, File dir) throws IOException {
 101.210 +        byte[] buf = new byte[8192];
 101.211 +        InputStream is = new FileInputStream(zip);
 101.212 +        try {
 101.213 +            ZipInputStream zis = new ZipInputStream(is);
 101.214 +            ZipEntry entry;
 101.215 +            while ((entry = zis.getNextEntry()) != null) {
 101.216 +                String name = entry.getName();
 101.217 +                int slash = name.lastIndexOf('/');
 101.218 +                File d = new File(dir, name.substring(0, slash).replace('/', File.separatorChar));
 101.219 +                if (!d.isDirectory() && !d.mkdirs()) {
 101.220 +                    throw new IOException("could not make " + d);
 101.221 +                }
 101.222 +                if (slash != name.length() - 1) {
 101.223 +                    File f = new File(dir, name.replace('/', File.separatorChar));
 101.224 +                    OutputStream os = new FileOutputStream(f);
 101.225 +                    try {
 101.226 +                        int read;
 101.227 +                        while ((read = zis.read(buf)) != -1) {
 101.228 +                            os.write(buf, 0, read);
 101.229 +                        }
 101.230 +                    } finally {
 101.231 +                        os.close();
 101.232 +                    }
 101.233 +                }
 101.234 +            }
 101.235 +        } finally {
 101.236 +            is.close();
 101.237 +        }
 101.238 +    }
 101.239 +
 101.240 +    /**
 101.241 +     * Make sure the timestamp on a file changes.
 101.242 +     * @param f a file to touch (make newer)
 101.243 +     * @param ref if not null, make f newer than this file; else make f newer than it was before
 101.244 +     */
 101.245 +    @SuppressWarnings("SleepWhileInLoop")
 101.246 +    public static void touch(File f, File ref) throws IOException, InterruptedException {
 101.247 +        long older = f.lastModified();
 101.248 +        if (ref != null) {
 101.249 +            older = Math.max(older, ref.lastModified());
 101.250 +        } else {
 101.251 +            older = Math.max(older, System.currentTimeMillis());
 101.252 +        }
 101.253 +        int maxPause = 9999;
 101.254 +        /* XXX consider this (as yet untested):
 101.255 +        long curr = System.currentTimeMillis();
 101.256 +        if (older > curr + maxPause) {
 101.257 +            throw new IllegalArgumentException("reference too far into the future, by " + (older - curr) + "msec");
 101.258 +        }
 101.259 +         */
 101.260 +        for (long pause = 1; pause < maxPause; pause *= 2) {
 101.261 +            Thread.sleep(pause);
 101.262 +            f.setLastModified(System.currentTimeMillis() + 1);  // plus 1 needed for FileObject tests (initially FO lastModified is set to currentTimeMillis)
 101.263 +            if (f.lastModified() > older) {
 101.264 +                while (f.lastModified() >= System.currentTimeMillis()) {
 101.265 +//                    LOG.log(Level.INFO, "Modification time is in future {0}", System.currentTimeMillis());
 101.266 +                    Thread.sleep(10);
 101.267 +                }
 101.268 +                return;
 101.269 +            }
 101.270 +        }
 101.271 +        Assert.fail("Did not manage to touch " + f);
 101.272 +    }
 101.273 +
 101.274 +}