Commits

Jan Lahoda committed 738e0ec

Porting a lot of code from the lang project.

Comments (0)

Files changed (18)

hints/nbproject/project.xml

                     </run-dependency>
                 </dependency>
                 <dependency>
+                    <code-name-base>org.netbeans.modules.apisupport.project</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <implementation-version/>
+                    </run-dependency>
+                </dependency>
+                <dependency>
                     <code-name-base>org.netbeans.modules.editor</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
                     </run-dependency>
                 </dependency>
                 <dependency>
+                    <code-name-base>org.openide.modules</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>7.10</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
                     <code-name-base>org.openide.nodes</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>

hints/src/org/netbeans/modules/jackpot30/hints/Utilities.java

 
 package org.netbeans.modules.jackpot30.hints;
 
+import com.sun.source.tree.AnnotationTree;
+import com.sun.source.tree.AssignmentTree;
+import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.IdentifierTree;
+import com.sun.source.tree.LiteralTree;
+import com.sun.source.tree.MemberSelectTree;
+import com.sun.source.tree.NewArrayTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.Tree.Kind;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+import org.netbeans.api.java.source.TreeMaker;
 import org.netbeans.api.java.source.WorkingCopy;
-import org.netbeans.modules.java.editor.semantic.SemanticHighlighter;
+import org.openide.util.NbCollections;
 
 /**
  *
  */
 public class Utilities {
 
-    /**
-     * single-class imports only!
-     */
-    public static void removeImportsIfNotUsed(WorkingCopy wc, String... fqns) {
-//        new SemanticHighlighter()
+    private Utilities() {}
+
+    public static <E> Iterable<E> checkedIterableByFilter(final Iterable raw, final Class<E> type, final boolean strict) {
+        return new Iterable<E>() {
+            public Iterator<E> iterator() {
+                return NbCollections.checkedIteratorByFilter(raw.iterator(), type, strict);
+            }
+        };
     }
+    
+//    public static AnnotationTree constructConstraint(WorkingCopy wc, String name, TypeMirror tm) {
+//        TreeMaker make = wc.getTreeMaker();
+//        ExpressionTree variable = prepareAssignment(make, "variable", make.Literal(name));
+//        ExpressionTree type     = prepareAssignment(make, "type", make.MemberSelect((ExpressionTree) make.Type(wc.getTypes().erasure(tm)), "class"));
+//        TypeElement constraint  = wc.getElements().getTypeElement(Annotations.CONSTRAINT.toFQN());
+//
+//        return make.Annotation(make.QualIdent(constraint), Arrays.asList(variable, type));
+//    }
+
+    public static ExpressionTree prepareAssignment(TreeMaker make, String name, ExpressionTree value) {
+        return make.Assignment(make.Identifier(name), value);
+    }
+
+    public static ExpressionTree findValue(AnnotationTree m, String name) {
+        for (ExpressionTree et : m.getArguments()) {
+            if (et.getKind() == Kind.ASSIGNMENT) {
+                AssignmentTree at = (AssignmentTree) et;
+                String varName = ((IdentifierTree) at.getVariable()).getName().toString();
+
+                if (varName.equals(name)) {
+                    return at.getExpression();
+                }
+            }
+
+            if (et instanceof LiteralTree/*XXX*/ && "value".equals(name)) {
+                return et;
+            }
+        }
+
+        return null;
+    }
+
+    public static List<AnnotationTree> findArrayValue(AnnotationTree at, String name) {
+        ExpressionTree fixesArray = findValue(at, name);
+        List<AnnotationTree> fixes = new LinkedList<AnnotationTree>();
+
+        if (fixesArray != null && fixesArray.getKind() == Kind.NEW_ARRAY) {
+            NewArrayTree trees = (NewArrayTree) fixesArray;
+
+            for (ExpressionTree fix : trees.getInitializers()) {
+                if (fix.getKind() == Kind.ANNOTATION) {
+                    fixes.add((AnnotationTree) fix);
+                }
+            }
+        }
+
+        if (fixesArray != null && fixesArray.getKind() == Kind.ANNOTATION) {
+            fixes.add((AnnotationTree) fixesArray);
+        }
+        
+        return fixes;
+    }
+
+    public static boolean isPureMemberSelect(Tree mst, boolean allowVariables) {
+        switch (mst.getKind()) {
+            case IDENTIFIER: return allowVariables || ((IdentifierTree) mst).getName().charAt(0) != '$';
+            case MEMBER_SELECT: return isPureMemberSelect(((MemberSelectTree) mst).getExpression(), allowVariables);
+            default: return false;
+        }
+    }
+
 }

hints/src/org/netbeans/modules/jackpot30/hints/batch/BatchApply.java

 
 package org.netbeans.modules.jackpot30.hints.batch;
 
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.tree.ImportTree;
+import com.sun.source.util.TreePath;
 import java.awt.Dialog;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.util.prefs.AbstractPreferences;
 import java.util.prefs.BackingStoreException;
 import java.util.prefs.Preferences;
+import java.util.regex.Pattern;
 import javax.swing.SwingUtilities;
 import javax.swing.text.Document;
 import org.netbeans.api.java.classpath.ClassPath;
 import org.netbeans.api.java.source.JavaSource.Phase;
 import org.netbeans.api.java.source.ModificationResult;
 import org.netbeans.api.java.source.Task;
+import org.netbeans.api.java.source.TreePathHandle;
 import org.netbeans.api.java.source.WorkingCopy;
 import org.netbeans.api.progress.ProgressHandle;
 import org.netbeans.api.progress.ProgressHandleFactory;
 import org.netbeans.api.project.ProjectUtils;
 import org.netbeans.api.project.SourceGroup;
 import org.netbeans.api.project.Sources;
+import org.netbeans.modules.jackpot30.hints.epi.JavaFix;
+import org.netbeans.modules.jackpot30.hints.pm.AnnotationBasedHintsRunner;
+import org.netbeans.modules.java.editor.semantic.SemanticHighlighter;
 import org.netbeans.modules.java.hints.errors.SuppressWarningsFixer;
 import org.netbeans.modules.java.hints.infrastructure.HintsTask;
 import org.netbeans.modules.java.hints.infrastructure.RulesManager;
 import org.netbeans.modules.java.hints.spi.AbstractHint;
 import org.netbeans.modules.java.hints.spi.AbstractHint.HintSeverity;
 import org.netbeans.modules.java.hints.spi.TreeRule;
-import org.netbeans.modules.jackpot30.hints.epi.JavaFix;
 import org.netbeans.spi.editor.hints.ErrorDescription;
 import org.netbeans.spi.editor.hints.Fix;
 import org.openide.DialogDescriptor;
 import org.openide.DialogDisplayer;
+import org.openide.LifecycleManager;
 import org.openide.cookies.EditorCookie;
 import org.openide.cookies.SaveCookie;
 import org.openide.filesystems.FileObject;
 
     private static final RequestProcessor WORKER = new RequestProcessor("Batch Hint Apply");
     
-    public static String applyFixes(final Lookup context, final Set<String> enabledHints, boolean progress) {
+    public static String applyFixes(final Lookup context, final String enabledHints, boolean progress) {
         assert !progress || SwingUtilities.isEventDispatchThread();
 
         if (progress) {
         }
     }
 
-    private static String applyFixesImpl(Lookup context, Set<String> enabledHints, ProgressHandle h, AtomicBoolean cancel) {
+    private static String applyFixesImpl(Lookup context, String enabledHints, ProgressHandle h, AtomicBoolean cancel) {
         ProgressHandleWrapper handle = new ProgressHandleWrapper(h, new int[] {20, 40, 40});
-        
-        Map<String, Preferences> overlay = prepareOverlay(enabledHints);
+
+        Pattern hints = Pattern.compile(enabledHints);
         List<ErrorDescription> eds = new LinkedList<ErrorDescription>();
         Collection<FileObject> toProcess = toProcess(context);
 
         for (Entry<ClasspathInfo, Collection<FileObject>> e: sortedFiles.entrySet()) {
             if (cancel.get()) return null;
             
-            eds.addAll(processFiles(e.getKey(), e.getValue(), overlay, handle, cancel));
+            eds.addAll(processFiles(e.getKey(), e.getValue(), hints, handle, cancel));
         }
 
         Map<ErrorDescription, Fix> fixes = new IdentityHashMap<ErrorDescription, Fix>();
 
             if (cancel.get()) return null;
 
+            List<FileObject> fastFiles = new LinkedList<FileObject>();
+
             for (ModificationResult r : results) {
                 r.commit();
+                fastFiles.addAll(r.getModifiedFileObjects());
             }
+
+            Map<ClasspathInfo, Collection<FileObject>> sortedFastFiles = sortFiles(fastFiles);
+
+            for (Entry<ClasspathInfo, Collection<FileObject>> e : sortedFastFiles.entrySet()) {
+                JavaSource.create(e.getKey(), e.getValue()).runModificationTask(new RemoveUnusedImports()).commit();
+            }
+
+            LifecycleManager.getDefault().saveAll();
         } catch (Exception ex) {
             Exceptions.printStackTrace(ex);
             return ex.getLocalizedMessage();
         return null;
     }
 
-    public static List<TreeRule> listHints() {
-        List<TreeRule> hints = new LinkedList<TreeRule>();
+    private static List<ErrorDescription> processFiles(ClasspathInfo cpInfo, Collection<FileObject> toProcess, final Pattern hints, final ProgressHandleWrapper handle, final AtomicBoolean cancel) {
+        final List<ErrorDescription> eds = new LinkedList<ErrorDescription>();
+        //XXX: workarounding NB issues #154252 and #152534:
+        for (FileObject file : toProcess) {
+//        JavaSource js = JavaSource.create(cpInfo, toProcess);
+        try {
+            DataObject d = DataObject.find(file);
+            EditorCookie ec = d.getLookup().lookup(EditorCookie.class);
+            Document doc = ec.openDocument();
+            JavaSource js = JavaSource.create(cpInfo, file);
 
-        for (List<TreeRule> rules : RulesManager.getInstance().getHints().values()) {
-            for (TreeRule r : rules) {
-                if (r instanceof AbstractHint) {
-                    try {
-                        r.getId();
-                        r.getDisplayName();
-                        
-                        hints.add(r);
-                    } catch (Exception e) {
-                        Logger.getLogger(BatchApply.class.getName()).log(Level.FINE, null, e);
-                    }
-                }
-            }
-        }
-
-        Collections.sort(hints, new Comparator<TreeRule>() {
-            public int compare(TreeRule o1, TreeRule o2) {
-                return o1.getDisplayName().compareTo(o2.getDisplayName());
-            }
-        });
-        
-        return hints;
-    }
-
-    private static List<ErrorDescription> processFiles(ClasspathInfo cpInfo, Collection<FileObject> toProcess, final Map<String, Preferences> preferencesOverlay, final ProgressHandleWrapper handle, final AtomicBoolean cancel) {
-        final List<ErrorDescription> eds = new LinkedList<ErrorDescription>();
-        JavaSource js = JavaSource.create(cpInfo, toProcess);
-
-        try {
             js.runUserActionTask(new Task<CompilationController>() {
                 public void run(CompilationController cc) throws Exception {
                     if (cancel.get()) return ;
                     
-                    HintsSettings.setPreferencesOverride(preferencesOverlay);
-
-                    DataObject d = DataObject.find(cc.getFileObject());
-                    EditorCookie ec = d.getLookup().lookup(EditorCookie.class);
-                    Document doc = ec.openDocument();
+//                    DataObject d = DataObject.find(cc.getFileObject());
+//                    EditorCookie ec = d.getLookup().lookup(EditorCookie.class);
+//                    Document doc = ec.openDocument();
 
                     try {
                         if (cc.toPhase(JavaSource.Phase.RESOLVED).compareTo(JavaSource.Phase.RESOLVED) < 0) {
                             return;
                         }
 
-                        eds.addAll(new HintsTask().computeHints(cc));
+                        //XXX:
+//                        eds.addAll(new AnnotationBasedHintsRunner().findWarnings(cc, hints));
                     } finally {
                         HintsSettings.setPreferencesOverride(null);
                     }
         } catch (IOException ex) {
             Exceptions.printStackTrace(ex);
         }
+        }
 
         return eds;
     }
 
                 fixes.get(ed).implement();
 
+                JavaSource.forFileObject(ed.getFile()).runModificationTask(new RemoveUnusedImports()).commit();
+                
                 SaveCookie sc = d.getLookup().lookup(SaveCookie.class);
 
                 if (sc != null) {
         return null;
     }
 
+    private static final class RemoveUnusedImports implements Task<WorkingCopy> {
+        public void run(WorkingCopy wc) throws IOException {
+            if (wc.toPhase(Phase.RESOLVED).compareTo(Phase.RESOLVED) < 0) {
+                return;
+            }
+
+            //compute imports to remove:
+            List<TreePathHandle> unusedImports = SemanticHighlighter.computeUnusedImports(wc);
+            CompilationUnitTree cut = wc.getCompilationUnit();
+            // make the changes to the source
+            for (TreePathHandle handle : unusedImports) {
+                TreePath path = handle.resolve(wc);
+                assert path != null;
+                cut = wc.getTreeMaker().removeCompUnitImport(cut,
+                        (ImportTree) path.getLeaf());
+            }
+
+            if (!unusedImports.isEmpty()) {
+                wc.rewrite(wc.getCompilationUnit(), cut);
+            }
+        }
+    }
+
     private static List<ModificationResult> performFastFixes(Map<FileObject, List<JavaFix>> fastFixes, ProgressHandleWrapper handle, AtomicBoolean cancel) {
         Map<ClasspathInfo, Collection<FileObject>> sortedFilesForFixes = sortFiles(fastFixes.keySet());
         List<ModificationResult> results = new LinkedList<ModificationResult>();
                     for (JavaFix f : toProcess.get(wc.getFileObject())) {
                         if (cancel.get()) return ;
                         
-                        JavaFixImpl.Accessor.INSTANCE.process(f, wc);
+                        JavaFixImpl.Accessor.INSTANCE.process(f, wc, new JavaFix.UpgradeUICallback() {
+                            public boolean shouldUpgrade(String comment) {
+                                return true;
+                            }
+                        });
                     }
 
                     handle.tick();

hints/src/org/netbeans/modules/jackpot30/hints/batch/BatchApplyAction.java

         this(prepareDefaultMap());
     }
 
-    public BatchApplyAction(Map attributes) {
+    private BatchApplyAction(Map attributes) {
         this(Utilities.actionsGlobalContext(), attributes);
     }
 
         String hintToExecute = (String) getValue(HINT);
 
         if (hintToExecute == null) {
-            SelectHint p = new SelectHint();
-            DialogDescriptor dd = new DialogDescriptor(p, "Select Hint", true, DialogDescriptor.OK_CANCEL_OPTION, DialogDescriptor.OK_OPTION, null);
+            NotifyDescriptor.InputLine nd = new NotifyDescriptor.InputLine("Select Hint (regexp)", "Select Hint");
 
-            if (DialogDisplayer.getDefault().notify(dd) != DialogDescriptor.OK_OPTION) {
+            if (DialogDisplayer.getDefault().notify(nd) != DialogDescriptor.OK_OPTION) {
                 return ;
             }
             
-            hintToExecute = p.getSelectedHint().getId();
+            hintToExecute = nd.getInputText();
         }
 
-        String error = BatchApply.applyFixes(context, Collections.singleton(hintToExecute), true);
+        String error = BatchApply.applyFixes(context, hintToExecute, true);
 
         if (error != null) {
             DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Message(error, NotifyDescriptor.ERROR_MESSAGE));
     private static Map prepareDefaultMap() {
         Map<String, Object> m = new HashMap<String, Object>();
 
-        m.put(NAME, NbBundle.getMessage(BatchApplyAction.class, "CTL_BatchApplyAction"));
+        m.put("displayName", NbBundle.getMessage(BatchApplyAction.class, "CTL_BatchApplyAction"));
         m.put("noIconInMenu", Boolean.TRUE);
 
         return m;

hints/src/org/netbeans/modules/jackpot30/hints/batch/Bundle.properties

 # made subject to such option by the copyright holder.
 
 CTL_BatchApplyAction=Batch Apply Hint
+SD_ApplyTransformations=applies specified transformation(s) on specified project or all opened projects
+SD_ApplyTransformationsProject=projects on which the transformations should be applied
 SelectHint.jLabel1.text=Select Hint:

hints/src/org/netbeans/modules/jackpot30/hints/batch/JavaFixImpl.java

 import org.netbeans.api.java.source.Task;
 import org.netbeans.api.java.source.WorkingCopy;
 import org.netbeans.modules.jackpot30.hints.epi.JavaFix;
+import org.netbeans.modules.jackpot30.hints.epi.JavaFix.UpgradeUICallback;
 import org.netbeans.spi.editor.hints.ChangeInfo;
 import org.netbeans.spi.editor.hints.Fix;
+import org.openide.DialogDisplayer;
+import org.openide.NotifyDescriptor;
 import org.openide.filesystems.FileObject;
 
 /**TODO: move to better package
                     return;
                 }
 
-                Accessor.INSTANCE.process(jf, wc);
+                Accessor.INSTANCE.process(jf, wc, new JavaFix.UpgradeUICallback() {
+                    public boolean shouldUpgrade(String comment) {
+                        NotifyDescriptor nd = new NotifyDescriptor.Confirmation(comment, "Update spec version.", NotifyDescriptor.YES_NO_OPTION);
+
+                        return DialogDisplayer.getDefault().notify(nd) == NotifyDescriptor.YES_OPTION;
+                    }
+                });
             }
         }).commit();
 
         public static Accessor INSTANCE;
 
         public abstract String getText(JavaFix jf);
-        public abstract ChangeInfo process(JavaFix jf, WorkingCopy wc) throws Exception;
+        public abstract ChangeInfo process(JavaFix jf, WorkingCopy wc, UpgradeUICallback callback) throws Exception;
         public abstract FileObject getFile(JavaFix jf);
         
     }

hints/src/org/netbeans/modules/jackpot30/hints/batch/OptionProcessorImpl.java

 
 package org.netbeans.modules.jackpot30.hints.batch;
 
+import java.io.File;
+import java.io.IOException;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.netbeans.api.java.classpath.ClassPath;
+import org.netbeans.api.java.classpath.GlobalPathRegistry;
+import org.netbeans.api.java.source.SourceUtils;
+import org.netbeans.api.project.Project;
+import org.netbeans.api.project.ProjectManager;
+import org.netbeans.api.project.ProjectUtils;
+import org.netbeans.api.project.SourceGroup;
 import org.netbeans.api.project.ui.OpenProjects;
 import org.netbeans.api.sendopts.CommandException;
-import org.netbeans.modules.java.hints.infrastructure.RulesManager;
-import org.netbeans.modules.java.hints.spi.AbstractHint;
-import org.netbeans.modules.java.hints.spi.TreeRule;
+import org.netbeans.spi.java.classpath.support.ClassPathSupport;
 import org.netbeans.spi.sendopts.Env;
 import org.netbeans.spi.sendopts.Option;
 import org.netbeans.spi.sendopts.OptionProcessor;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.util.Exceptions;
 import org.openide.util.Lookup;
 import org.openide.util.lookup.Lookups;
+import org.openide.util.lookup.ServiceProvider;
 
 /**
  *
  * @author Jan Lahoda
  */
+@ServiceProvider(service=OptionProcessor.class)
 public class OptionProcessorImpl extends OptionProcessor {
 
-    private static final Option LIST = Option.withoutArgument(Option.NO_SHORT_NAME, "list-hints");
-    private static final Option APPLY_HINTS = Option.requiredArgument(Option.NO_SHORT_NAME, "apply-hints");
+    private static final Logger LOG = Logger.getLogger(OptionProcessorImpl.class.getName());
     
-    private static final Set<Option> OPTIONS = new HashSet<Option>(Arrays.asList(LIST, APPLY_HINTS));
+    private static final String APPLY_TRANSFORMATIONS_PROJECT_OPTION = "apply-transformations-project";
+
+//    private static final Option LIST = Option.withoutArgument(Option.NO_SHORT_NAME, "list-hints-transformation");
+    private static final Option APPLY_TRANSFORMATIONS = Option.shortDescription(
+                                                            Option.requiredArgument(Option.NO_SHORT_NAME, "apply-transformations"),
+                                                            "org.netbeans.modules.jackpot30.hints.batch.Bundle",
+                                                            "SD_ApplyTransformations");
+    private static final Option APPLY_TRANSFORMATIONS_PROJECT = Option.shortDescription(
+                                                            Option.additionalArguments(Option.NO_SHORT_NAME, APPLY_TRANSFORMATIONS_PROJECT_OPTION),
+                                                            "org.netbeans.modules.jackpot30.hints.batch.Bundle",
+                                                            "SD_ApplyTransformationsProject");
+
+    private static final Set<Option> OPTIONS = new HashSet<Option>(Arrays.asList(/*LIST, */APPLY_TRANSFORMATIONS, APPLY_TRANSFORMATIONS_PROJECT));
     
     @Override
     protected Set<Option> getOptions() {
 
     @Override
     protected void process(Env env, Map<Option, String[]> optionValues) throws CommandException {
-        if (optionValues.containsKey(LIST)) {
-            env.getOutputStream().println("Supported Hints:");
-            for (TreeRule r : BatchApply.listHints()) {
-                env.getOutputStream().println(r.getDisplayName() + " - " + r.getId());
+//        if (optionValues.containsKey(LIST)) {
+//            env.getOutputStream().println("Supported Hints:");
+//            for (TreeRule r : BatchApply.listHints()) {
+//                env.getOutputStream().println(r.getDisplayName() + " - " + r.getId());
+//            }
+//        }
+
+        List<Project> projects = new LinkedList<Project>();
+        Map<String, List<ClassPath>> classPaths = new HashMap<String, List<ClassPath>>();
+        
+        if (optionValues.containsKey(APPLY_TRANSFORMATIONS_PROJECT)) {
+            String[] projectNames = optionValues.get(APPLY_TRANSFORMATIONS_PROJECT);
+
+            if (projectNames.length == 0) {
+                env.getErrorStream().println("At least one parameter needed for " + APPLY_TRANSFORMATIONS_PROJECT_OPTION);
+                throw new CommandException(1);
             }
+
+            OUTER: for (String p : projectNames) {
+                File loc = new File(env.getCurrentDirectory(), p);
+                FileObject projectFile = FileUtil.toFileObject(loc);
+
+                if (projectFile == null) {
+                    env.getErrorStream().println("Ignoring file " + p + " - cannot be found.");
+                    continue;
+                }
+
+                if (!projectFile.isFolder()) {
+                    env.getErrorStream().println("Ignoring file " + p + " - not a folder.");
+                    continue;
+                }
+
+                Project project = null;
+                String  error   = null;
+
+                try {
+                    project = ProjectManager.getDefault().findProject(projectFile);
+                } catch (IOException ex) {
+                    error = ex.getLocalizedMessage();
+                } catch (IllegalArgumentException ex) {
+                    error = ex.getLocalizedMessage();
+                }
+
+                if (project == null) {
+                    if (error == null) {
+                        env.getErrorStream().println("Ignoring file " + p + " - not a project.");
+                    } else {
+                        env.getErrorStream().println("Ignoring file " + p + " - not a project (" + error + ").");
+                    }
+
+                    continue;
+                }
+
+                for (SourceGroup sg : ProjectUtils.getSources(project).getSourceGroups("java")) {
+                    FileObject root = sg.getRootFolder();
+
+                    for (String type : Arrays.asList(ClassPath.BOOT, ClassPath.COMPILE, ClassPath.SOURCE)) {
+                        if (!handleClassPath(root, type, env, p, classPaths)) {
+                            continue OUTER;
+                        }
+                    }
+                }
+
+                projects.add(project);
+            }
+
+            for (Entry<String, List<ClassPath>> cps : classPaths.entrySet()) {
+                LOG.log(Level.INFO, "registering classpaths: type={0}, classpaths={1}", new Object[] {cps.getKey(), cps.getValue()});
+                GlobalPathRegistry.getDefault().register(cps.getKey(), cps.getValue().toArray(new ClassPath[0]));
+            }
+        } else {
+            projects.addAll(Arrays.asList(OpenProjects.getDefault().getOpenProjects()));
         }
+        
+        try {
+            waitScanFinished();
+        } catch (InterruptedException ex) {
+            Exceptions.printStackTrace(ex);
+        }
+        
+        if (optionValues.containsKey(APPLY_TRANSFORMATIONS)) {
+            String hintsArg = optionValues.get(APPLY_TRANSFORMATIONS)[0];
+//            String[] hints = hintsArg.split(":");
 
-        if (optionValues.containsKey(APPLY_HINTS)) {
-            String hintsArg = optionValues.get(APPLY_HINTS)[0];
-            String[] hints = hintsArg.split(":");
-
-            Lookup context = Lookups.fixed((Object[]) OpenProjects.getDefault().getOpenProjects());
-            String error = BatchApply.applyFixes(context, new HashSet<String>(Arrays.asList(hints)), false);
+            Lookup context = Lookups.fixed((Object[]) projects.toArray(new Project[0]));
+            String error = BatchApply.applyFixes(context, hintsArg, false);
 
             if (error != null) {
                 env.getErrorStream().println("Cannot apply hints because of: " + error);
             }
         }
+
+        for (Entry<String, List<ClassPath>> cps : classPaths.entrySet()) {
+            GlobalPathRegistry.getDefault().unregister(cps.toString(), cps.getValue().toArray(new ClassPath[0]));
+        }
+    }
+
+    private boolean handleClassPath(FileObject root, String type, Env env, String p, Map<String, List<ClassPath>> classPaths) {
+        ClassPath cp = ClassPath.getClassPath(root, type);
+
+        if (cp == null) {
+            env.getErrorStream().println("Ignoring file " + p + " - no " + type + " classpath for source group: " + FileUtil.getFileDisplayName(root));
+            return false;
+        }
+
+        List<ClassPath> cps = classPaths.get(type);
+
+        if (cps == null) {
+            classPaths.put(type, cps = new LinkedList<ClassPath>());
+        }
+
+        cp = ClassPathSupport.createProxyClassPath(cp);
+        
+        cps.add(cp);
+        
+        return true;
+    }
+
+    @SuppressWarnings("deprecation")
+    private void waitScanFinished() throws InterruptedException {
+        SourceUtils.waitScanFinished();
     }
 
 }

hints/src/org/netbeans/modules/jackpot30/hints/batch/SelectHint.java

     public SelectHint() {
         initComponents();
         DefaultComboBoxModel model = new DefaultComboBoxModel();
-        for (TreeRule r : BatchApply.listHints()) {
-            model.addElement(new HintDescriptor(r.getId(), r.getDisplayName()));
-        }
+        //XXX:
+//        for (TreeRule r : BatchApply.listHints()) {
+//            model.addElement(new HintDescriptor(r.getId(), r.getDisplayName()));
+//        }
         jComboBox1.setModel(model);
     }
 

hints/src/org/netbeans/modules/jackpot30/hints/epi/Bundle.properties

+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+#
+# Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved.
+#
+# The contents of this file are subject to the terms of either the GNU
+# General Public License Version 2 only ("GPL") or the Common
+# Development and Distribution License("CDDL") (collectively, the
+# "License"). You may not use this file except in compliance with the
+# License. You can obtain a copy of the License at
+# http://www.netbeans.org/cddl-gplv2.html
+# or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+# specific language governing permissions and limitations under the
+# License.  When distributing the software, include this License Header
+# Notice in each file and include the License file at
+# nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Sun in the GPL Version 2 section of the License file that
+# accompanied this code. If applicable, add the following below the
+# License Header, with the fields enclosed by brackets [] replaced by
+# your own identifying information:
+# "Portions Copyrighted [year] [name of copyright owner]"
+#
+# Contributor(s):
+#
+# The Original Software is NetBeans. The Initial Developer of the Original
+# Software is Sun Microsystems, Inc. Portions Copyright 2008-2009 Sun
+# Microsystems, Inc. All Rights Reserved.
+#
+# If you wish your version of this file to be governed by only the CDDL
+# or only the GPL Version 2, indicate your decision by adding
+# "[Contributor] elects to include this software in this distribution
+# under the [CDDL or GPL Version 2] license." If you do not indicate a
+# single choice of license, a recipient has the option to distribute
+# your version of this file under either the CDDL, the GPL Version 2 or
+# to extend the choice of license to its licensees as provided above.
+# However, if you add GPL Version 2 code and therefore, elected the GPL
+# Version 2 license, then the option applies only if the new code is
+# made subject to such option by the copyright holder.
+LBL_UpdateDependencyQuestion=Update dependency on module {0} to specification version {1}?

hints/src/org/netbeans/modules/jackpot30/hints/epi/JavaFix.java

 
 package org.netbeans.modules.jackpot30.hints.epi;
 
+import com.sun.javadoc.Tag;
+import java.io.IOException;
+import java.util.regex.Matcher;
 import com.sun.source.tree.IdentifierTree;
 import com.sun.source.tree.MemberSelectTree;
 import com.sun.source.tree.Scope;
 import com.sun.source.tree.Tree;
 import com.sun.source.tree.Tree.Kind;
-import com.sun.source.util.SourcePositions;
 import com.sun.source.util.TreePath;
 import com.sun.source.util.TreePathScanner;
 import java.util.HashMap;
 import javax.lang.model.element.ElementKind;
 import javax.lang.model.element.TypeElement;
 import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
 import org.netbeans.api.java.source.CompilationInfo;
+import org.netbeans.api.java.source.SourceUtils;
 import org.netbeans.api.java.source.TreePathHandle;
+import org.netbeans.api.java.source.TypeMirrorHandle;
 import org.netbeans.api.java.source.WorkingCopy;
+import org.netbeans.api.project.FileOwnerQuery;
+import org.netbeans.api.project.Project;
+import org.netbeans.api.project.ProjectManager;
+import org.netbeans.api.project.ProjectUtils;
+import org.netbeans.modules.apisupport.project.NbModuleProject;
+import org.netbeans.modules.apisupport.project.ProjectXMLManager;
+import org.netbeans.modules.apisupport.project.spi.NbModuleProvider;
+import org.netbeans.modules.apisupport.project.ui.customizer.ModuleDependency;
+import org.netbeans.modules.jackpot30.hints.Utilities;
 import org.netbeans.modules.jackpot30.hints.batch.JavaFixImpl;
 import org.netbeans.spi.editor.hints.ChangeInfo;
 import org.netbeans.spi.editor.hints.Fix;
 import org.openide.filesystems.FileObject;
+import org.openide.modules.SpecificationVersion;
+import org.openide.util.Exceptions;
+import org.openide.util.NbBundle;
 
 /**
  *
 
     protected abstract String getText();
 
-    protected abstract void performRewrite(WorkingCopy wc, TreePath tp);
+    protected abstract void performRewrite(WorkingCopy wc, TreePath tp, UpgradeUICallback callback);
 
-    final ChangeInfo process(WorkingCopy wc) throws Exception {
+    final ChangeInfo process(WorkingCopy wc, UpgradeUICallback callback) throws Exception {
         TreePath tp = handle.resolve(wc);
 
         if (tp == null) {
             return null;
         }
 
-        performRewrite(wc, tp);
+        performRewrite(wc, tp, callback);
 
         return null;
     }
         return handle.getFileObject();
     }
 
-    public static Fix rewriteFix(CompilationInfo info, final String displayName, TreePath what, final String to, TreePath... parameters) {
-        Map<String, TreePath> params = new HashMap<String, TreePath>();
-        int c = 1;
-
-        for (TreePath t : parameters) {
-            params.put("$" + c, t);
-            c++;
-        }
-
-        return rewriteFix(info, displayName, what, to, params);
-    }
-
-    public static Fix rewriteFix(CompilationInfo info, final String displayName, TreePath what, final String to, Map<String, TreePath> parameters) {
+    public static Fix rewriteFix(CompilationInfo info, final String displayName, TreePath what, final String to, Map<String, TreePath> parameters, Map<String, TypeMirror> constraints) {
         final Map<String, TreePathHandle> params = new HashMap<String, TreePathHandle>();
 
         for (Entry<String, TreePath> e : parameters.entrySet()) {
             params.put(e.getKey(), TreePathHandle.create(e.getValue(), info));
         }
 
+        final Map<String, TypeMirrorHandle> constraintsHandles = new HashMap<String, TypeMirrorHandle>();
+
+        for (Entry<String, TypeMirror> c : constraints.entrySet()) {
+            constraintsHandles.put(c.getKey(), TypeMirrorHandle.create(c.getValue()));
+        }
+
         return toEditorFix(new JavaFix(info, what) {
             @Override
             protected String getText() {
                 return displayName;
             }
             @Override
-            protected void performRewrite(final WorkingCopy wc, TreePath tp) {
+            protected void performRewrite(final WorkingCopy wc, TreePath tp, final UpgradeUICallback callback) {
                 final Map<String, TreePath> parameters = new HashMap<String, TreePath>();
 
                 for (Entry<String, TreePathHandle> e : params.entrySet()) {
                     parameters.put(e.getKey(), p);
                 }
 
-                Tree parsed = wc.getTreeUtilities().parseExpression(to, new SourcePositions[1]);
-                Scope s = wc.getTrees().getScope(tp);
-                
-                wc.getTreeUtilities().attributeTree(parsed, s);
+                Map<String, TypeMirror> constraints = new HashMap<String, TypeMirror>();
+
+                for (Entry<String, TypeMirrorHandle> c : constraintsHandles.entrySet()) {
+                    constraints.put(c.getKey(), c.getValue().resolve(wc));
+                }
+
+                Tree parsed = Pattern.parseAndAttribute(wc, to, constraints, new Scope[1]);
 
                 new TreePathScanner<Void, Void>() {
                     @Override
                             return super.visitMemberSelect(node, p);
                         }
 
-                        wc.rewrite(node, wc.getTreeMaker().QualIdent(e));
+                        //check correct dependency:
+                        checkDependency(wc, e, callback);
+                        
+                        if (Utilities.isPureMemberSelect(node, false)) {
+                            wc.rewrite(node, wc.getTreeMaker().QualIdent(e));
 
-                        return null;
+                            return null;
+                        } else {
+                            return super.visitMemberSelect(node, p);
+                        }
                     }
+
                 }.scan(new TreePath(new TreePath(tp.getCompilationUnit()), parsed), null);
 
                 wc.rewrite(tp.getLeaf(), parsed);
             }
         });
     }
+
+    private static void checkDependency(WorkingCopy copy, Element e, UpgradeUICallback callback) {
+        SpecificationVersion sv = computeSpecVersion(copy, e);
+
+        if (sv == null) {
+            return ;
+        }
+
+        Project currentProject = FileOwnerQuery.getOwner(copy.getFileObject());
+
+        if (currentProject == null) {
+            return ;
+        }
+
+        FileObject file = getFile(copy, e);
+
+        if (file == null) {
+            return ;
+        }
+
+        Project referedProject = FileOwnerQuery.getOwner(file);
+
+        if (referedProject == null || currentProject.getProjectDirectory().equals(referedProject.getProjectDirectory())) {
+            return ;
+        }
+
+        resolveNbModuleDependencies(currentProject, referedProject, sv, callback);
+    }
+
+    private static java.util.regex.Pattern SPEC_VERSION = java.util.regex.Pattern.compile("[0-9]+(\\.[0-9]+)+");
+    
+    static SpecificationVersion computeSpecVersion(CompilationInfo info, Element el) {
+        for (Tag since : info.getElementUtilities().javaDocFor(el).tags("@since")) {
+            String text = since.text();
+
+            Matcher m = SPEC_VERSION.matcher(text);
+
+            if (!m.find()) {
+                continue;
+            }
+
+            return new SpecificationVersion(m.group()/*ver.toString()*/);
+        }
+
+        return null;
+    }
     
     public static Fix toEditorFix(final JavaFix jf) {
         return new JavaFixImpl(jf);
     }
 
+    private static void resolveNbModuleDependencies(Project currentProject, Project referedProject, SpecificationVersion sv, UpgradeUICallback callback) throws IllegalArgumentException {
+        NbModuleProvider currentNbModule = currentProject.getLookup().lookup(NbModuleProvider.class);
+
+        if (currentNbModule == null) {
+            return ;
+        }
+
+        NbModuleProvider referedNbModule = referedProject.getLookup().lookup(NbModuleProvider.class);
+
+        if (referedNbModule == null) {
+            return ;
+        }
+
+        try {
+            NbModuleProject currentNbModuleProject = currentProject.getLookup().lookup(NbModuleProject.class);
+
+            if (currentNbModuleProject == null) {
+                return ;
+            }
+            
+            ProjectXMLManager m = new ProjectXMLManager(currentNbModuleProject);
+            ModuleDependency dep = null;
+
+            for (ModuleDependency md : m.getDirectDependencies()) {
+                if (referedNbModule.getCodeNameBase().equals(md.getModuleEntry().getCodeNameBase())) {
+                    dep = md;
+                    break;
+                }
+            }
+
+            if (dep == null) {
+                return ;
+            }
+
+            SpecificationVersion currentDep = new SpecificationVersion(dep.getSpecificationVersion());
+
+            if (currentDep == null || currentDep.compareTo(sv) < 0) {
+                String upgradeText = NbBundle.getMessage(JavaFix.class,
+                                                         "LBL_UpdateDependencyQuestion",
+                                                         new Object[] {
+                                                            ProjectUtils.getInformation(referedProject).getDisplayName(),
+                                                            currentDep.toString()
+                                                         });
+
+                if (callback.shouldUpgrade(upgradeText)) {
+                    ModuleDependency nue = new ModuleDependency(dep.getModuleEntry(),
+                                                                dep.getReleaseVersion(),
+                                                                sv.toString(),
+                                                                dep.hasCompileDependency(),
+                                                                dep.hasImplementationDepedendency());
+                    
+                    m.editDependency(dep, nue);
+                    ProjectManager.getDefault().saveProject(currentProject);
+                }
+            }
+        } catch (IOException ex) {
+            Exceptions.printStackTrace(ex);
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+    private static FileObject getFile(WorkingCopy copy, Element e) {
+        return SourceUtils.getFile(e, copy.getClasspathInfo());
+    }
+
+    public interface UpgradeUICallback {
+        public boolean shouldUpgrade(String comment);
+    }
+
     static {
         JavaFixImpl.Accessor.INSTANCE = new JavaFixImpl.Accessor() {
             @Override
                 return jf.getText();
             }
             @Override
-            public ChangeInfo process(JavaFix jf, WorkingCopy wc) throws Exception {
-                return jf.process(wc);
+            public ChangeInfo process(JavaFix jf, WorkingCopy wc, UpgradeUICallback callback) throws Exception {
+                return jf.process(wc, callback);
             }
             @Override
             public FileObject getFile(JavaFix jf) {

hints/src/org/netbeans/modules/jackpot30/hints/epi/Pattern.java

 
 import com.sun.source.tree.BlockTree;
 import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.tree.MemberSelectTree;
 import com.sun.source.tree.MethodTree;
 import com.sun.source.tree.Scope;
 import com.sun.source.tree.Tree;
 import com.sun.source.util.SourcePositions;
 import com.sun.source.util.TreePath;
 import com.sun.source.util.TreePathScanner;
+import com.sun.tools.javac.api.JavacScope;
 import com.sun.tools.javac.api.JavacTaskImpl;
+import com.sun.tools.javac.comp.AttrContext;
+import com.sun.tools.javac.comp.Env;
 import com.sun.tools.javac.util.Context;
 import com.sun.tools.javac.util.Log;
 import java.io.File;
 import java.io.IOException;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.regex.Matcher;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeKind;
 import javax.lang.model.type.TypeMirror;
 import javax.tools.JavaFileObject;
 import org.netbeans.api.java.source.CompilationInfo;
+import org.netbeans.modules.jackpot30.hints.Utilities;
+import org.netbeans.modules.jackpot30.hints.pm.CopyFinder;
 import org.netbeans.modules.java.source.JavaSourceAccessor;
 import org.netbeans.modules.java.source.parsing.FileObjects;
-import org.netbeans.modules.jackpot30.hints.pm.CopyFinder;
 import org.openide.util.Exceptions;
 
-/**
+/**XXX: cancelability!
  *
  * @author Jan Lahoda
  */
 public class Pattern {
 
-    private Pattern() {}
+    private final CompilationInfo info;
+    private final Tree patternTree;
+    private final Iterable<Tree> antipatterns;
 
-    public static Map<String, TreePath> matchesPattern(CompilationInfo info, String pattern, TreePath toCheck, AtomicBoolean cancel) {
-        Map<String, String> designedTypeHack = new HashMap<String, String>();
-        pattern = parseOutTypesFromPattern(pattern, designedTypeHack);
-        Tree patternTree = parseExpressionPattern(info, pattern, designedTypeHack);
+    private final Map<String, TypeMirror> constraintsHack;
 
-        return CopyFinder.computeVariables(info, new TreePath(new TreePath(info.getCompilationUnit()), patternTree), toCheck, cancel, designedTypeHack);
+    public Pattern(CompilationInfo info, Tree patternTree, Iterable<Tree> antipatterns, Map<String, TypeMirror> constraintsHack) {
+        this.info = info;
+        this.patternTree = patternTree;
+        this.antipatterns = antipatterns;
+        this.constraintsHack = constraintsHack;
     }
 
-    public static Map<String, TreePath> matchesPattern(CompilationInfo info, String pattern, Map<String, TypeMirror> constraints, TreePath toCheck, AtomicBoolean cancel) {
-        Map<String, String> designedTypeHack = new HashMap<String, String>();
-        for (Entry<String, TypeMirror> e : constraints.entrySet()) {
-            designedTypeHack.put(e.getKey(), e.getValue().toString());
+    public static Pattern compile(CompilationInfo info, String pattern) {
+        Map<String, TypeMirror> constraints = new HashMap<String, TypeMirror>();
+        pattern = parseOutTypesFromPattern(info, pattern, constraints);
+
+        return compile(info, pattern, constraints);
+    }
+
+    public static Pattern compile(CompilationInfo info, String pattern, Map<String, TypeMirror> constraints) {
+        return compile(info, pattern, Collections.<String>emptyList(), constraints);
+    }
+
+    public static Pattern compile(CompilationInfo info, String pattern, Iterable<String> antipatterns, Map<String, TypeMirror> constraints) {
+        Scope[] scope = new Scope[1];
+        Tree patternTree = parseAndAttribute(info, pattern, constraints, scope);
+
+        List<Tree> antipatternsTrees = new LinkedList<Tree>();
+
+        for (String ap : antipatterns) {
+            Tree p = info.getTreeUtilities().parseExpression(ap, new SourcePositions[1]);
+
+            info.getTreeUtilities().attributeTree(p, scope[0]);
+
+            antipatternsTrees.add(p);
         }
-        pattern = parseOutTypesFromPattern(pattern, designedTypeHack);
-        Tree patternTree = parseExpressionPattern(info, pattern, designedTypeHack);
+        
+        return new Pattern(info, patternTree, antipatternsTrees, constraints);
+    }
 
-        return CopyFinder.computeVariables(info, new TreePath(new TreePath(info.getCompilationUnit()), patternTree), toCheck, cancel, designedTypeHack);
+    public Map<String, TreePath> match(TreePath toCheck) {
+        return CopyFinder.computeVariables(info, new TreePath(new TreePath(info.getCompilationUnit()), patternTree), toCheck, new AtomicBoolean(), constraintsHack);
+    }
+
+    public boolean checkAntipatterns(TreePath tp) {
+        for (Tree ap : antipatterns) {
+            if (CopyFinder.computeVariables(info, new TreePath(new TreePath(info.getCompilationUnit()), ap), tp, new AtomicBoolean(), constraintsHack) != null) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    public Map<String, TypeMirror> getConstraints() {
+        return constraintsHack;
     }
     
-    private static String parseOutTypesFromPattern(String pattern, Map<String, String> variablesToTypes) {
+    private static String parseOutTypesFromPattern(CompilationInfo info, String pattern, Map<String, TypeMirror> variablesToTypes) {
+        //XXX:
+        TypeElement scope = (TypeElement) info.getTrees().getElement(new TreePath(new TreePath(info.getCompilationUnit()), info.getCompilationUnit().getTypeDecls().get(0)));
         java.util.regex.Pattern p = java.util.regex.Pattern.compile("(\\$.)(\\{([^}]*)\\})?");
         StringBuffer filtered = new StringBuffer();
         Matcher m = p.matcher(pattern);
             String type = m.group(3);
 
             filtered.append(var);
-            variablesToTypes.put(var, type);
+            variablesToTypes.put(var, type != null ? info.getTreeUtilities().parseType(type, scope) : null);
         }
 
         filtered.append(pattern.substring(i));
 
     private static long inc;
 
-    private static Tree parseExpressionPattern(CompilationInfo info, String pattern, Map<String, String> designedTypeHack) {
+    private static Scope constructScope(CompilationInfo info, Map<String, TypeMirror> constraints) {
         StringBuilder clazz = new StringBuilder();
 
         clazz.append("package $; public class $" + (inc++) + "{");
 
-        for (Entry<String, String> e : designedTypeHack.entrySet()) {
+        for (Entry<String, TypeMirror> e : constraints.entrySet()) {
             if (e.getValue() != null) {
                 clazz.append("private ");
-                clazz.append(e.getValue());
+                clazz.append(e.getValue().toString()); //XXX
                 clazz.append(" ");
                 clazz.append(e.getKey());
                 clazz.append(";\n");
         Context context = jti.getContext();
 
         Log.instance(context).nerrors = 0;
-        
+
         JavaFileObject jfo = FileObjects.memoryFileObject("$", "$", new File("/tmp/t.java").toURI(), System.currentTimeMillis(), clazz.toString());
 
         try {
             Iterable<? extends CompilationUnitTree> parsed = jti.parse(jfo);
             CompilationUnitTree cut = parsed.iterator().next();
-            
+
             jti.analyze(jti.enter(parsed));
 
-            Scope scope = new ScannerImpl().scan(cut, info);
-
-            Tree patternTree = info.getTreeUtilities().parseExpression(pattern, new SourcePositions[1]);
-
-            info.getTreeUtilities().attributeTree(patternTree, scope);
-
-            return patternTree;
+            return new ScannerImpl().scan(cut, info);
         } catch (IOException ex) {
             Exceptions.printStackTrace(ex);
             return null;
         }
     }
+    
+//    private static Scope constructScope2(CompilationInfo info, Map<String, TypeMirror> constraints) {
+//        JavacScope s = (JavacScope) info.getTrees().getScope(new TreePath(info.getCompilationUnit()));
+//        Env<AttrContext> env = s.getEnv();
+//
+//        env = env.dup(env.tree);
+//
+//        env.info.
+//    }
+    
+    public static Tree parseAndAttribute(CompilationInfo info, String pattern, Map<String, TypeMirror> constraints, Scope[] scope) {
+        scope[0] = constructScope(info, constraints);
 
+        if (scope == null) {
+            return null;
+        }
+
+        Tree patternTree = info.getTreeUtilities().parseExpression(pattern, new SourcePositions[1]);
+        TypeMirror type = info.getTreeUtilities().attributeTree(patternTree, scope[0]);
+
+        if (isError(type)) {
+            //maybe type?
+            if (Utilities.isPureMemberSelect(patternTree, false) && info.getElements().getTypeElement(pattern) != null) {
+                Tree var = info.getTreeUtilities().parseExpression(pattern + ".class;", new SourcePositions[1]);
+
+                info.getTreeUtilities().attributeTree(var, scope[0]);
+
+                Tree typeTree = ((MemberSelectTree) var).getExpression();
+
+                if (!isError(info.getTrees().getElement(new TreePath(new TreePath(info.getCompilationUnit()), typeTree)))) {
+                    patternTree = typeTree;
+                }
+            }
+        }
+
+        return patternTree;
+    }
+
+    private static boolean isError(Element el) {
+        return (el == null || (el.getKind() == ElementKind.CLASS) && isError(((TypeElement) el).asType()));
+    }
+    
+    private static boolean isError(TypeMirror type) {
+        return type == null || type.getKind() == TypeKind.ERROR;
+    }
+    
     private static final class ScannerImpl extends TreePathScanner<Scope, CompilationInfo> {
 
         @Override

hints/src/org/netbeans/modules/jackpot30/hints/file/DeclarativeHintsRunner.java

 
 import com.sun.source.tree.Tree.Kind;
 import com.sun.source.util.TreePath;
+import java.util.Collections;
 import java.util.EnumSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
+import javax.lang.model.type.TypeMirror;
 import org.netbeans.api.java.source.CompilationInfo;
 import org.netbeans.modules.java.hints.spi.AbstractHint;
 import org.netbeans.modules.jackpot30.hints.epi.ErrorDescriptionFactory;
         List<ErrorDescription> result = new LinkedList<ErrorDescription>();
         
         for (DeclarativeHint h : DeclarativeHintRegistry.getAllHints()) {
-            Map<String, TreePath> vars = Pattern.matchesPattern(compilationInfo, h.getPattern(), treePath, cancel);
+            Map<String, TreePath> vars = Pattern.compile(compilationInfo, h.getPattern()).match(treePath); //XXX: cancellability
 
             if (vars == null)
                 continue;
             Fix[] fixes = new Fix[h.getFixes().size()];
 
             for (int cntr = 0; cntr < h.getFixes().size(); cntr++) {
-                fixes[cntr] = JavaFix.rewriteFix(compilationInfo, h.getFixes().get(cntr).getDisplayName(), treePath, h.getFixes().get(cntr).getPattern(), vars);
+                fixes[cntr] = JavaFix.rewriteFix(compilationInfo, h.getFixes().get(cntr).getDisplayName(), treePath, h.getFixes().get(cntr).getPattern(), vars, Collections.<String, TypeMirror>emptyMap()/*XXX*/);
             }
 
             ErrorDescription ed = ErrorDescriptionFactory.forName(HintContext.create(compilationInfo, getSeverity(), treePath), treePath, h.getDisplayName(), fixes);

hints/src/org/netbeans/modules/jackpot30/hints/pm/AnnotationBasedHintsRunner.java

 import com.sun.source.tree.Tree.Kind;
 import com.sun.source.util.TreePath;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.LinkedList;
             variableTypes.put(var, tm);
         }
 
-        Map<String, TreePath> variables = Pattern.matchesPattern(compilationInfo, patternString, variableTypes, treePath, cancel);
+        Map<String, TreePath> variables = Pattern.compile(compilationInfo, patternString, Collections.<String, TypeMirror>emptyMap()/*XXX*/).match(treePath);
 
         if (variables == null) {
             return null;
                 dn = "Rewrite to " + to;
             }
             
-            fixes.add(JavaFix.rewriteFix(compilationInfo, dn, treePath, to, variables));
+            fixes.add(JavaFix.rewriteFix(compilationInfo, dn, treePath, to, variables, Collections.<String, TypeMirror>emptyMap()/*XXX*/));
         }
 
         return ErrorDescriptionFactory.forName(HintContext.create(compilationInfo, getSeverity(), treePath), treePath, displayName, fixes.toArray(new Fix[0]));

hints/src/org/netbeans/modules/jackpot30/hints/pm/CopyFinder.java

 package org.netbeans.modules.jackpot30.hints.pm;
 
 import com.sun.source.tree.ArrayAccessTree;
+import com.sun.source.tree.AssertTree;
 import com.sun.source.tree.AssignmentTree;
 import com.sun.source.tree.BinaryTree;
+import com.sun.source.tree.BlockTree;
 import com.sun.source.tree.CompoundAssignmentTree;
 import com.sun.source.tree.ConditionalExpressionTree;
+import com.sun.source.tree.EnhancedForLoopTree;
+import com.sun.source.tree.ExpressionStatementTree;
 import com.sun.source.tree.IdentifierTree;
+import com.sun.source.tree.IfTree;
 import com.sun.source.tree.InstanceOfTree;
 import com.sun.source.tree.LiteralTree;
 import com.sun.source.tree.MemberSelectTree;
 import com.sun.source.tree.ParameterizedTypeTree;
 import com.sun.source.tree.ParenthesizedTree;
 import com.sun.source.tree.PrimitiveTypeTree;
+import com.sun.source.tree.ReturnTree;
+import com.sun.source.tree.SynchronizedTree;
 import com.sun.source.tree.Tree;
 import com.sun.source.tree.Tree.Kind;
 import com.sun.source.tree.TypeCastTree;
 import java.util.concurrent.atomic.AtomicBoolean;
 import javax.lang.model.element.Element;
 import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.TypeElement;
 import javax.lang.model.type.TypeKind;
 import javax.lang.model.type.TypeMirror;
 import org.netbeans.api.java.source.CompilationInfo;
+import org.netbeans.modules.jackpot30.hints.Utilities;
 
 /**
  *
     private AtomicBoolean cancel;
 
 
-    private Map<String, String> designedTypeHack;
+    private Map<String, TypeMirror> designedTypeHack;
 
     private CopyFinder(TreePath searchingFor, CompilationInfo info, AtomicBoolean cancel) {
         this.searchingFor = searchingFor;
         return f.result;
     }
 
-    public static Map<String, TreePath> computeVariables(CompilationInfo info, TreePath searchingFor, TreePath scope, AtomicBoolean cancel, Map<String, String> designedTypeHack) {
-        if (searchingFor.getLeaf().getKind() != scope.getLeaf().getKind()) {
+    public static Map<String, TreePath> computeVariables(CompilationInfo info, TreePath searchingFor, TreePath scope, AtomicBoolean cancel, Map<String, TypeMirror> designedTypeHack) {
+        if (!sameKind(searchingFor.getLeaf(), scope.getLeaf())) {
             return null;
         }
 
         return f.scan(second, one);
     }
 
-    private boolean sameKind(Kind k1, Kind k2) {
-        return    k1 == k2
-               || (k1 == Kind.MEMBER_SELECT && k2 == Kind.IDENTIFIER)
-               || (k1 == Kind.IDENTIFIER && k2 == Kind.MEMBER_SELECT);
+    private static boolean sameKind(Tree t1, Tree t2) {
+        Kind k1 = t1.getKind();
+        Kind k2 = t2.getKind();
+        
+        if (k1 == k2) {
+            return true;
+        }
+        
+        if (    (k1 != Kind.MEMBER_SELECT && k1 != Kind.IDENTIFIER)
+             || (k2 != Kind.MEMBER_SELECT && k2 != Kind.IDENTIFIER)) {
+            return false;
+        }
+
+        return Utilities.isPureMemberSelect(t1, true) && Utilities.isPureMemberSelect(t2, true);
     }
     
     @Override
 
             if (ident.startsWith("$")) {
                 TreePath currentPath = new TreePath(getCurrentPath(), node);
-                String dTypeHack = designedTypeHack.get(ident);
-                TypeMirror designed = dTypeHack != null ? info.getTreeUtilities().parseType(dTypeHack,info.getTrees().getScope(currentPath).getEnclosingClass()) : null;//info.getTrees().getTypeMirror(p);
+                TypeMirror designed = designedTypeHack != null ? designedTypeHack.get(ident) : null;//info.getTrees().getTypeMirror(p);
 
                 boolean bind = true;
 
             }
         }
 
-        if (p != null && sameKind(node.getKind(), p.getLeaf().getKind())) {
+        if (p != null && sameKind(node, p.getLeaf())) {
             //maybe equivalent:
             boolean result = super.scan(node, p) == Boolean.TRUE;
 
         if (!allowGoDeeper)
             return false;
         
-        if ((p != null && p.getLeaf() == searchingFor.getLeaf()) || !sameKind(node.getKind(), searchingFor.getLeaf().getKind())) {
+        if ((p != null && p.getLeaf() == searchingFor.getLeaf()) || !sameKind(node, searchingFor.getLeaf())) {
             super.scan(node, null);
             return false;
         } else {
         return true;
     }
 
-//    public Boolean visitAssert(AssertTree node, TreePath p) {
-//        throw new UnsupportedOperationException("Not supported yet.");
-//    }
+    public Boolean visitAssert(AssertTree node, TreePath p) {
+        if (p == null) {
+            super.visitAssert(node, p);
+            return false;
+        }
+
+        AssertTree at = (AssertTree) p.getLeaf();
+
+        if (!scan(node.getCondition(), at.getCondition(), p)) {
+            return false;
+        }
+
+        return scan(node.getDetail(), at.getDetail(), p);
+    }
 
     public Boolean visitAssignment(AssignmentTree node, TreePath p) {
         if (p == null)
         return result && scan(node.getRightOperand(), bt.getRightOperand(), p);
     }
 
-//    public Boolean visitBlock(BlockTree node, TreePath p) {
-//        throw new UnsupportedOperationException("Not supported yet.");
-//    }
-//
+    public Boolean visitBlock(BlockTree node, TreePath p) {
+        if (p == null) {
+            super.visitBlock(node, p);
+            return false;
+        }
+
+        BlockTree at = (BlockTree) p.getLeaf();
+
+        if (node.isStatic() != at.isStatic()) {
+            return false;
+        }
+
+        return checkLists(node.getStatements(), at.getStatements(), p);
+    }
+
 //    public Boolean visitBreak(BreakTree node, TreePath p) {
 //        throw new UnsupportedOperationException("Not supported yet.");
 //    }
 //        throw new UnsupportedOperationException("Not supported yet.");
 //    }
 
-//    public Boolean visitExpressionStatement(ExpressionStatementTree node, TreePath p) {
-//        throw new UnsupportedOperationException("Not supported yet.");
-//    }
+    public Boolean visitExpressionStatement(ExpressionStatementTree node, TreePath p) {
+        if (p == null) {
+            super.visitExpressionStatement(node, p);
+            return false;
+        }
+
+        ExpressionStatementTree et = (ExpressionStatementTree) p.getLeaf();
+
+        return scan(node.getExpression(), et.getExpression(), p);
+    }
 
 //    public Boolean visitEnhancedForLoop(EnhancedForLoopTree node, TreePath p) {
-//        throw new UnsupportedOperationException("Not supported yet.");
+//        if (p == null) {
+//            super.visitEnhancedForLoop(node, p);
+//            return false;
+//        }
+//
+//        EnhancedForLoopTree ef = (EnhancedForLoopTree) p.getLeaf();
+//
+//        if (!scan(node.getVariable(), ef.getVariable(), p))
+//            return false;
+//
+//        if (!scan(node.getExpression(), ef.getExpression(), p))
+//            return false;
+//
+//        return scan(node.getStatement(), ef.getStatement(), p);
 //    }
 //
 //    public Boolean visitForLoop(ForLoopTree node, TreePath p) {
         
         if (nodeEl == null || pEl == null)
             return false;
+
+        if (nodeEl.getKind() == pEl.getKind() && nodeEl.getKind() == ElementKind.METHOD) {
+            if (info.getElements().overrides((ExecutableElement) nodeEl, (ExecutableElement) pEl, (TypeElement) nodeEl.getEnclosingElement())) {
+                return true;
+            }
+        }
         
         return nodeEl.equals(pEl);
     }
 
-//    public Boolean visitIf(IfTree node, TreePath p) {
-//        throw new UnsupportedOperationException("Not supported yet.");
-//    }
-//
+    public Boolean visitIf(IfTree node, TreePath p) {
+        if (p == null)
+            return super.visitIf(node, p);
+
+        IfTree t = (IfTree) p.getLeaf();
+
+        if (!scan(node.getCondition(), t.getCondition(), p))
+            return false;
+
+        if (!scan(node.getThenStatement(), t.getThenStatement(), p))
+            return false;
+
+        return scan(node.getElseStatement(), t.getElseStatement(), p);
+    }
+
 //    public Boolean visitImport(ImportTree node, TreePath p) {
 //        throw new UnsupportedOperationException("Not supported yet.");
 //    }
         return scan(node.getExpression(), t.getExpression(), p);
     }
 
-//    public Boolean visitReturn(ReturnTree node, TreePath p) {
-//        throw new UnsupportedOperationException("Not supported yet.");
-//    }
+    public Boolean visitReturn(ReturnTree node, TreePath p) {
+        if (p == null) {
+            super.visitReturn(node, p);
+            return false;
+        }
+
+        ReturnTree at = (ReturnTree) p.getLeaf();
+
+        return scan(node.getExpression(), at.getExpression(), p);
+    }
 
     public Boolean visitMemberSelect(MemberSelectTree node, TreePath p) {
         if (p == null)
             return super.visitMemberSelect(node, p);
 
-        Element nodeEl = info.getTrees().getElement(getCurrentPath());
-        Element pEl    = info.getTrees().getElement(p);
+        if (Utilities.isPureMemberSelect(node, true) && Utilities.isPureMemberSelect(p.getLeaf(), true)) {
+            Element nodeEl = info.getTrees().getElement(getCurrentPath());
+            Element pEl    = info.getTrees().getElement(p);
 
-        if (nodeEl == pEl) { //covers null == null
-            if (node.getKind() == p.getLeaf().getKind()) {
-                //to bind any free variables inside:
-                MemberSelectTree t = (MemberSelectTree) p.getLeaf();
+            boolean ret = false;
 
-                scan(node.getExpression(), t.getExpression(), p);
+            if (nodeEl == pEl) { //covers null == null
+                ret = true;
             }
-            return true;
+
+            if (nodeEl != null && pEl != null && nodeEl.getKind() == pEl.getKind() && nodeEl.getKind() == ElementKind.METHOD) {
+                if (info.getElements().overrides((ExecutableElement) nodeEl, (ExecutableElement) pEl, (TypeElement) nodeEl.getEnclosingElement())) {
+                    ret = true;
+                }
+            }
+
+            if (ret) {
+                if (node.getKind() == p.getLeaf().getKind()) {
+                    //to bind any free variables inside:
+                    MemberSelectTree t = (MemberSelectTree) p.getLeaf();
+
+                    scan(node.getExpression(), t.getExpression(), p);
+                }
+                
+                return ret;
+            }
         }
         
         MemberSelectTree t = (MemberSelectTree) p.getLeaf();
 //        throw new UnsupportedOperationException("Not supported yet.");
 //    }
 //
-//    public Boolean visitSynchronized(SynchronizedTree node, TreePath p) {
-//        throw new UnsupportedOperationException("Not supported yet.");
-//    }
+    public Boolean visitSynchronized(SynchronizedTree node, TreePath p) {
+        if (p == null) {
+            super.visitSynchronized(node, p);
+            return false;
+        }
+
+        SynchronizedTree at = (SynchronizedTree) p.getLeaf();
+
+        if (!scan(node.getExpression(), at.getExpression(), p)) {
+            return false;
+        }
+
+        return scan(node.getBlock(), at.getBlock(), p);
+    }
 //
 //    public Boolean visitThrow(ThrowTree node, TreePath p) {
 //        throw new UnsupportedOperationException("Not supported yet.");

hints/test/unit/src/org/netbeans/modules/jackpot30/hints/epi/JavaFixTest.java

+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2008-2009 Sun Microsystems, Inc.
+ */
+
+package org.netbeans.modules.jackpot30.hints.epi;
+
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.ElementFilter;
+import org.netbeans.api.java.source.SourceUtilsTestUtil;
+import org.netbeans.modules.java.source.TreeLoader;
+import org.openide.modules.SpecificationVersion;
+
+/**
+ *
+ * @author Jan Lahoda
+ */
+public class JavaFixTest extends TestBase {
+
+    public JavaFixTest(String name) {
+        super(name);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        SourceUtilsTestUtil.prepareTest(new String[] {"org/netbeans/modules/java/editor/resources/layer.xml"}, new Object[0]);
+        TreeLoader.DISABLE_CONFINEMENT_TEST = true;
+    }
+    
+    public void testSimple() throws Exception {
+        SpecificationVersion v = computeSpecVersion("/**\n" +
+                                                    " * @since 1.5\n" +
+                                                    " */\n");
+
+        assertEquals(0, v.compareTo(new SpecificationVersion("1.5")));
+    }
+    
+    public void testSimpleDate() throws Exception {
+        SpecificationVersion v = computeSpecVersion("/**\n" +
+                                                    " * @since 1.5 (16 May 2005)\n" +
+                                                    " */\n");
+
+        assertEquals(0, v.compareTo(new SpecificationVersion("1.5")));
+    }
+
+    public void testLongText() throws Exception {
+        SpecificationVersion v = computeSpecVersion("/**\n" +
+                                                    " * @since 1.123.2.1 - branch propsheet_issue_29447\n" +
+                                                    " */\n");
+
+        assertEquals(0, v.compareTo(new SpecificationVersion("1.123.2.1")));
+    }
+
+    public void testModuleName() throws Exception {
+        SpecificationVersion v = computeSpecVersion("/**\n" +
+                                                    " * @since org.openide.filesystems 7.15\n" +
+                                                    " */\n");
+
+        assertEquals(0, v.compareTo(new SpecificationVersion("7.15")));
+    }
+
+    public void testModuleNameMajor() throws Exception {
+        SpecificationVersion v = computeSpecVersion("/**\n" +
+                                                    " * @since org.openide/1 4.42\n" +
+                                                    " */\n");
+
+        assertEquals(0, v.compareTo(new SpecificationVersion("4.42")));
+    }
+
+    public void testEnd() throws Exception {
+        SpecificationVersion v = computeSpecVersion("/**\n" +
+                                                    " * @since 1.5 */\n");
+
+        assertEquals(0, v.compareTo(new SpecificationVersion("1.5")));
+    }
+
+    public void testOpenAPI() throws Exception {
+        SpecificationVersion v = computeSpecVersion("/**\n" +
+                                                    " * @since OpenAPI version 2.12" +
+                                                    " */\n");
+
+        assertEquals(0, v.compareTo(new SpecificationVersion("2.12")));
+
+    }
<