From 1dab577fa8b893e7b47d49bfe549bdea567865f5 Mon Sep 17 00:00:00 2001 From: Jakub Valtar Date: Tue, 29 Mar 2016 13:35:04 +0200 Subject: [PATCH] ECS: move import suggestion code to ECS --- .../mode/java/pdex/ASTGenerator.java | 87 -------- .../mode/java/pdex/ErrorCheckerService.java | 195 +++++++++++------- 2 files changed, 120 insertions(+), 162 deletions(-) diff --git a/java/src/processing/mode/java/pdex/ASTGenerator.java b/java/src/processing/mode/java/pdex/ASTGenerator.java index bb40e5651..e222ff984 100644 --- a/java/src/processing/mode/java/pdex/ASTGenerator.java +++ b/java/src/processing/mode/java/pdex/ASTGenerator.java @@ -92,7 +92,6 @@ import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.select.Elements; -import processing.app.Library; import processing.app.Messages; import processing.app.SketchCode; import processing.app.Util; @@ -100,11 +99,9 @@ import processing.app.syntax.JEditTextArea; import processing.app.ui.EditorStatus; import processing.app.ui.Toolkit; import processing.mode.java.JavaEditor; -import processing.mode.java.JavaMode; import processing.mode.java.preproc.PdePreprocessor; import com.google.classpath.ClassPath; -import com.google.classpath.ClassPathFactory; import com.google.classpath.RegExpResourceFilter; @SuppressWarnings({ "unchecked" }) @@ -129,9 +126,6 @@ public class ASTGenerator { //loadJavaDoc(); } - - protected final ClassPathFactory factory = new ClassPathFactory(); - /** * Used for searching for package declaration of a class */ @@ -2479,87 +2473,6 @@ public class ASTGenerator { return null; } - public String[] getSuggestImports(final String className) { - Messages.log("* getSuggestImports"); - if (classPath == null) { - return null; - } - - // TODO: make sure search class path is complete, - // prepare it beforehand and reuse it - // - // this in not the same as sketch class path! - // should include: - // - all contributed libraries - // - core libraries - // - code folder - // - mode search path - // - Java classpath - - log("Looking for class " + className); - RegExpResourceFilter regf = - new RegExpResourceFilter(Pattern.compile(".*"), - Pattern.compile("(.*\\$)?" + className + "\\.class", - Pattern.CASE_INSENSITIVE)); - // TODO once saw NPE here...possible for classPath to be null? [fry 150808] - List candidates = new ArrayList<>(); - - - { // Mode search path - String searchPath = ((JavaMode) editor.getMode()).getSearchPath(); - - // Make sure class path does not contain empty string (home dir) - String[] paths = searchPath.split(File.pathSeparator); - - List entries = new ArrayList<>(); - - for (int i = 0; i < paths.length; i++) { - String path = paths[i]; - if (path != null && !path.trim().isEmpty()) { - entries.add(path); - } - } - - String[] pathArray = entries.toArray(new String[entries.size()]); - classPath = factory.createFromPaths(pathArray); - - String[] resources = classPath.findResources("", regf); - for (String res : resources) { - candidates.add(res); - log("Res: " + res); - } - } - - for (Library lib : editor.getMode().contribLibraries) { - ClassPath cp = factory.createFromPath(lib.getClassPath()); - String[] resources = cp.findResources("", regf); - for (String res : resources) { - candidates.add(res); - log("Res: " + res); - } - } - - if (editor.getSketch().hasCodeFolder()) { - File codeFolder = editor.getSketch().getCodeFolder(); - // get a list of .jar files in the "code" folder - // (class files in subfolders should also be picked up) - ClassPath cp = factory.createFromPath(Util.contentsToClassPath(codeFolder)); - String[] resources = cp.findResources("", regf); - for (String res : resources) { - candidates.add(res); - log("Res: " + res); - } - } - - String[] resources = new String[candidates.size()]; - for (int i = 0; i < resources.length; i++) { - resources[i] = candidates.get(i).replace('/', '.').replace('$', '.') - .substring(0, candidates.get(i).length() - 6); - } - - return resources; - } - public static boolean isAddableASTNode(ASTNode node) { switch (node.getNodeType()) { diff --git a/java/src/processing/mode/java/pdex/ErrorCheckerService.java b/java/src/processing/mode/java/pdex/ErrorCheckerService.java index 60403c681..2fa7adf63 100644 --- a/java/src/processing/mode/java/pdex/ErrorCheckerService.java +++ b/java/src/processing/mode/java/pdex/ErrorCheckerService.java @@ -22,6 +22,7 @@ package processing.mode.java.pdex; import com.google.classpath.ClassPath; import com.google.classpath.ClassPathFactory; +import com.google.classpath.RegExpResourceFilter; import java.awt.EventQueue; import java.io.ByteArrayOutputStream; @@ -45,16 +46,14 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.text.BadLocationException; import javax.swing.text.Document; -import javax.swing.text.Element; -import javax.swing.text.PlainDocument; import javax.swing.tree.DefaultMutableTreeNode; -import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.core.compiler.IProblem; @@ -92,8 +91,6 @@ import processing.mode.java.JavaEditor; import processing.mode.java.preproc.PdePreprocessor; import processing.mode.java.preproc.PdePreprocessor.Mode; -import static processing.app.Util.countLines; - /** * The main error checking service @@ -204,8 +201,6 @@ public class ErrorCheckerService { final DefaultMutableTreeNode tree = ASTGenerator.buildTree(latestResult.compilationUnit); - checkForMissingImports(latestResult); - if (JavaMode.errorCheckEnabled) { if (scheduledUiUpdate != null) { scheduledUiUpdate.cancel(true); @@ -292,22 +287,6 @@ public class ErrorCheckerService { } - protected void checkForMissingImports(PreprocessedSketch result) { - if (Preferences.getBoolean(JavaMode.SUGGEST_IMPORTS_PREF)) { - for (Problem p : result.problems) { - if (p.getIProblem().getID() == IProblem.UndefinedType) { - String args[] = p.getIProblem().getArguments(); - if (args.length > 0) { - String missingClass = args[0]; - Messages.log("Will suggest for type:" + missingClass); - //astGenerator.suggestImports(missingClass); - } - } - } - } - } - - public ASTGenerator getASTGenerator() { return astGenerator; } @@ -365,7 +344,7 @@ public class ErrorCheckerService { protected PreprocessedSketch checkCode() { PreprocessedSketch result = new PreprocessedSketch(); - PreprocessedSketch prevResult = null; // TODO: get previous result + PreprocessedSketch prevResult = latestResult; List coreAndDefaultImports = result.coreAndDefaultImports; List codeFolderImports = result.codeFolderImports; @@ -426,9 +405,6 @@ public class ErrorCheckerService { // TODO: do we need to do this? why? //SourceUtils.substituteUnicode(rawCode); - List syntaxProblems = Collections.emptyList(); - List compilationProblems = Collections.emptyList(); - CompilationUnit syntaxCU; {{ // SYNTAX CHECK @@ -460,7 +436,7 @@ public class ErrorCheckerService { syntaxCU = makeAST(parser, syntaxStage.toCharArray(), COMPILER_OPTIONS); // Get syntax problems - syntaxProblems = Arrays.asList(syntaxCU.getProblems()); + List syntaxProblems = Arrays.asList(syntaxCU.getProblems()); // Update result result.mode = mode; @@ -468,11 +444,12 @@ public class ErrorCheckerService { result.compilationUnit = syntaxCU; result.preprocessedCode = syntaxStage; for (IProblem problem : syntaxProblems) { - if (problem.isError()) { - result.hasSyntaxErrors = true; - } + result.hasSyntaxErrors |= problem.isError(); } - + List mappedSyntaxProblems = + mapProblems(syntaxProblems, result.tabStarts, result.pdeCode, + result.syntaxMapping); + result.problems.addAll(mappedSyntaxProblems); }} if (!result.hasSyntaxErrors) { @@ -526,15 +503,10 @@ public class ErrorCheckerService { } // Compile it - try { - compilationProblems = - compileAndReturnProblems(className, javaStageChars, - COMPILER_OPTIONS, classLoader, - classPath); - } catch (NoClassDefFoundError e) { - // TODO: can this happen? - e.printStackTrace(); - } + List compilationProblems = + compileAndReturnProblems(className, javaStageChars, + COMPILER_OPTIONS, classLoader, + classPath); // Update result result.compilationMapping = compilationMapping; @@ -542,29 +514,118 @@ public class ErrorCheckerService { result.classLoader = classLoader; result.preprocessedCode = javaStage; result.compilationUnit = compilationCU; - for (IProblem problem : compilationProblems) { - if (problem.isError()) { - result.hasCompilationErrors = true; + + Map importSuggestions = new HashMap<>(); + if (Preferences.getBoolean(JavaMode.SUGGEST_IMPORTS_PREF)) { + for (IProblem problem : compilationProblems) { + if (problem.getID() == IProblem.UndefinedType) { + String missingClass = problem.getArguments()[0]; + if (!importSuggestions.containsKey(missingClass)) { + importSuggestions.put(missingClass, getSuggestImports(missingClass)); + } + } } } + + boolean hasCompilationErrors = false; + + List mappedCompilationProblems = + mapProblems(compilationProblems, result.tabStarts, result.pdeCode, + result.compilationMapping, result.syntaxMapping); + + for (Problem p : mappedCompilationProblems) { + hasCompilationErrors |= p.isError(); + IProblem ip = p.getIProblem(); + if (ip.getID() == IProblem.UndefinedType) { + p.setImportSuggestions(importSuggestions.get(ip.getArguments()[0])); + } + } + + result.problems.addAll(mappedCompilationProblems); + result.hasCompilationErrors = hasCompilationErrors; + }} } - List mappedSyntaxProblems = - mapProblems(syntaxProblems, result.tabStarts, result.pdeCode, - result.syntaxMapping); - - List mappedCompilationProblems = - mapProblems(compilationProblems, result.tabStarts, result.pdeCode, - result.compilationMapping, result.syntaxMapping); - - result.problems.addAll(mappedSyntaxProblems); - result.problems.addAll(mappedCompilationProblems); - return result; } + public String[] getSuggestImports(final String className) { + Messages.log("* getSuggestImports"); + + // TODO: make sure search class path is complete, + // prepare it beforehand and reuse it + // + // this in not the same as sketch class path! + // should include: + // - all contributed libraries + // - core libraries + // - code folder + // - mode search path + // - Java classpath + + RegExpResourceFilter regf = + new RegExpResourceFilter(Pattern.compile(".*"), + Pattern.compile("(.*\\$)?" + className + "\\.class", + Pattern.CASE_INSENSITIVE)); + // TODO once saw NPE here...possible for classPath to be null? [fry 150808] + List candidates = new ArrayList<>(); + + + { // Mode search path + String searchPath = ((JavaMode) editor.getMode()).getSearchPath(); + + // Make sure class path does not contain empty string (home dir) + String[] paths = searchPath.split(File.pathSeparator); + + List entries = new ArrayList<>(); + + for (int i = 0; i < paths.length; i++) { + String path = paths[i]; + if (path != null && !path.trim().isEmpty()) { + entries.add(path); + } + } + + String[] pathArray = entries.toArray(new String[entries.size()]); + ClassPath classPath = classPathFactory.createFromPaths(pathArray); + + String[] resources = classPath.findResources("", regf); + for (String res : resources) { + candidates.add(res); + } + } + + for (Library lib : editor.getMode().contribLibraries) { + ClassPath cp = classPathFactory.createFromPath(lib.getClassPath()); + String[] resources = cp.findResources("", regf); + for (String res : resources) { + candidates.add(res); + } + } + + if (editor.getSketch().hasCodeFolder()) { + File codeFolder = editor.getSketch().getCodeFolder(); + // get a list of .jar files in the "code" folder + // (class files in subfolders should also be picked up) + ClassPath cp = classPathFactory.createFromPath(Util.contentsToClassPath(codeFolder)); + String[] resources = cp.findResources("", regf); + for (String res : resources) { + candidates.add(res); + } + } + + String[] resources = new String[candidates.size()]; + for (int i = 0; i < resources.length; i++) { + resources[i] = candidates.get(i).replace('/', '.').replace('$', '.') + .substring(0, candidates.get(i).length() - 6); + } + + return resources; + } + + protected static List mapProblems(List problems, int[] tabStarts, String pdeCode, SourceMapping... mappings) { @@ -860,29 +921,13 @@ public class ErrorCheckerService { ErrorTable table = editor.getErrorTable(); table.clearRows(); - Map suggestions = new HashMap<>(); - Sketch sketch = editor.getSketch(); for (Problem p : problems) { String message = p.getMessage(); - if (Preferences.getBoolean(JavaMode.SUGGEST_IMPORTS_PREF)) { - if (p.getIProblem().getID() == IProblem.UndefinedType) { - String[] args = p.getIProblem().getArguments(); - if (args.length > 0) { - String missingClass = args[0]; - String[] si = suggestions.get(missingClass); - if (si == null) { - synchronized (astGenerator) { - si = astGenerator.getSuggestImports(missingClass); - } - suggestions.put(missingClass, si); - } - if (si != null && si.length > 0) { - p.setImportSuggestions(si); - message += " (double-click for suggestions)"; - } - } - } + if (Preferences.getBoolean(JavaMode.SUGGEST_IMPORTS_PREF) && + p.getImportSuggestions() != null && + p.getImportSuggestions().length > 0) { + message += " (double-click for suggestions)"; } table.addRow(p, message,