From c458863dd730fb40cab92bbdf33f1d40ead20973 Mon Sep 17 00:00:00 2001 From: Sam Pottinger Date: Mon, 4 Nov 2019 16:54:22 -0800 Subject: [PATCH 1/5] Allow support for static imports through pdex's ImportStatement. Discontinued use of string import statement generation and migrated to pdex's ImportStatement class which can keep track of if the import is static or not. This allows static imports to be handled correctly in PDEX, JavaBuild library resoluation, and actual Java compilation step. Resolves https://github.com/processing/processing/issues/5577 and https://github.com/processing/processing4/issues/16 but only in the Processing4 branch. --- java/src/processing/mode/java/JavaBuild.java | 15 +--- .../mode/java/pdex/ImportStatement.java | 22 +++-- .../java/preproc/PdeParseTreeListener.java | 87 +++++++++++++++---- .../mode/java/preproc/PreprocessorResult.java | 22 +---- .../mode/java/preproc/code/RewriteParams.java | 23 ++--- .../preproc/code/RewriteParamsBuilder.java | 17 ++-- .../preproc/code/RewriterCodeGenerator.java | 11 +-- .../processing/mode/java/ParserTests.java | 15 ++-- java/test/resources/bug598.expected | 2 +- 9 files changed, 126 insertions(+), 88 deletions(-) diff --git a/java/src/processing/mode/java/JavaBuild.java b/java/src/processing/mode/java/JavaBuild.java index ac7571720..9a87fd8d9 100644 --- a/java/src/processing/mode/java/JavaBuild.java +++ b/java/src/processing/mode/java/JavaBuild.java @@ -40,6 +40,7 @@ import processing.core.PApplet; import processing.core.PConstants; import processing.data.StringList; import processing.data.XML; +import processing.mode.java.pdex.ImportStatement; import processing.mode.java.pdex.util.ProblemFactory; import processing.mode.java.preproc.PdePreprocessor; import processing.mode.java.preproc.PreprocessorResult; @@ -271,18 +272,8 @@ public class JavaBuild { javaLibraryPath += File.pathSeparator + core.getNativePath(); } - for (String item : result.getImportStatementsStr()) { - // remove things up to the last dot - int dot = item.lastIndexOf('.'); - // http://dev.processing.org/bugs/show_bug.cgi?id=1145 - String entry = (dot == -1) ? item : item.substring(0, dot); - - if (item.startsWith("static ")) { - // import static - https://github.com/processing/processing/issues/8 - int dot2 = item.lastIndexOf('.'); - entry = entry.substring(7, (dot2 == -1) ? entry.length() : dot2); - } - + for (ImportStatement item : result.getImportStatements()) { + String entry = item.getPackageName(); Library library = mode.getLibrary(entry); if (library != null) { diff --git a/java/src/processing/mode/java/pdex/ImportStatement.java b/java/src/processing/mode/java/pdex/ImportStatement.java index 89aa23378..62f9cd81f 100644 --- a/java/src/processing/mode/java/pdex/ImportStatement.java +++ b/java/src/processing/mode/java/pdex/ImportStatement.java @@ -83,18 +83,26 @@ public class ImportStatement { is.isStatic = match.group(2) != null; String pckg = match.group(3); pckg = (pckg == null) ? "" : pckg.replaceAll("\\s",""); - is.packageName = pckg.endsWith(".") ? - pckg.substring(0, pckg.length()-1) : - pckg; - is.className = match.group(4); - is.isStarred = is.className.equals("*"); + String memberName = match.group(4); + is.isStarred = memberName.equals("*"); + + // Deal with static member imports whose "className" is actually a "member name". + boolean endsWithPeriod = pckg.endsWith("."); + if (is.isStatic) { + String withContainingTypeNameAtEnd = endsWithPeriod ? pckg.substring(0, pckg.length() - 1) : pckg; + int periodOfContainingTypeName = withContainingTypeNameAtEnd.lastIndexOf("."); + String containingTypeName = withContainingTypeNameAtEnd.substring(periodOfContainingTypeName + 1); + is.packageName = withContainingTypeNameAtEnd.substring(0, periodOfContainingTypeName); + is.className = containingTypeName + "." + memberName; + } else { + is.packageName = endsWithPeriod ? pckg.substring(0, pckg.length() - 1) : pckg; + is.className = memberName; + } return is; } - - public String getFullSourceLine() { return importKw + " " + (isStatic ? (staticKw + " ") : "") + packageName + "." + className + ";"; } diff --git a/java/src/processing/mode/java/preproc/PdeParseTreeListener.java b/java/src/processing/mode/java/preproc/PdeParseTreeListener.java index c156e73b0..397fa89cb 100644 --- a/java/src/processing/mode/java/preproc/PdeParseTreeListener.java +++ b/java/src/processing/mode/java/preproc/PdeParseTreeListener.java @@ -22,12 +22,15 @@ package processing.mode.java.preproc; import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.antlr.v4.runtime.*; import org.antlr.v4.runtime.misc.Interval; import org.antlr.v4.runtime.tree.ParseTree; import processing.core.PApplet; +import processing.mode.java.pdex.ImportStatement; import processing.mode.java.pdex.TextTransform; import processing.mode.java.preproc.PdePreprocessor.Mode; import processing.mode.java.preproc.code.*; @@ -62,10 +65,10 @@ public class PdeParseTreeListener extends ProcessingBaseListener { private int lineOffset; - private ArrayList coreImports = new ArrayList<>(); - private ArrayList defaultImports = new ArrayList<>(); - private ArrayList codeFolderImports = new ArrayList<>(); - private ArrayList foundImports = new ArrayList<>(); + private ArrayList coreImports = new ArrayList<>(); + private ArrayList defaultImports = new ArrayList<>(); + private ArrayList codeFolderImports = new ArrayList<>(); + private ArrayList foundImports = new ArrayList<>(); private ArrayList edits = new ArrayList<>(); private String sketchWidth; @@ -95,30 +98,49 @@ public class PdeParseTreeListener extends ProcessingBaseListener { } /** - * Indicate imports for code folders. + * Indicate imports for code folders given those imports' fully qualified names. * - * @param codeFolderImports List of imports for sources sitting in the sketch code folder. + * @param codeFolderImports List of imports for sources sitting in the sketch code folder. Note that these will be + * interpreted as non-static imports. */ public void setCodeFolderImports(List codeFolderImports) { + setCodeFolderImportInfo(createPlainImportStatementInfos(codeFolderImports)); + } + + /** + * Indicate imports for code folders given full import statement information. + * names. + * + * @param codeFolderImports List of import statement info for sources sitting in the sketch code folder. + */ + public void setCodeFolderImportInfo(List codeFolderImports) { this.codeFolderImports.clear(); this.codeFolderImports.addAll(codeFolderImports); } /** - * Indicate list of imports required for all sketches to be inserted in preprocessing. + * Indicate list of imports required for all sketches to be inserted in preprocessing given those imports' fully + * qualified names. * - * @param coreImports The list of imports required for all sketches. + * @param coreImports The list of imports required for all sketches. Note that these will be interpreted as non-static + * imports. */ public void setCoreImports(String[] coreImports) { setCoreImports(Arrays.asList(coreImports)); } /** - * Indicate list of imports required for all sketches to be inserted in preprocessing. + * Indicate list of imports required for all sketches to be inserted in preprocessing given those imports' fully + * qualified names. * - * @param coreImports The list of imports required for all sketches. + * @param coreImports The list of imports required for all sketches. Note that these will be interpreted as non-static + * imports. */ public void setCoreImports(List coreImports) { + setCoreImportInfo(createPlainImportStatementInfos(coreImports)); + } + + public void setCoreImportInfo(List coreImports) { this.coreImports.clear(); this.coreImports.addAll(coreImports); } @@ -142,12 +164,17 @@ public class PdeParseTreeListener extends ProcessingBaseListener { * *

* Indicate list of imports that are not required for sketch operation but included for the - * user's convenience regardless. + * user's convenience regardless given those imports' fully qualified names. *

* - * @param defaultImports The list of imports to include for user convenience. + * @param defaultImports The list of imports to include for user convenience. Note that these will be interpreted as + * non-static imports. */ public void setDefaultImports(List defaultImports) { + setDefaultImportInfo(createPlainImportStatementInfos(defaultImports)); + } + + public void setDefaultImportInfo(List defaultImports) { this.defaultImports.clear(); this.defaultImports.addAll(defaultImports); } @@ -204,7 +231,7 @@ public class PdeParseTreeListener extends ProcessingBaseListener { * @return The result of the last preprocessing. */ public PreprocessorResult getResult() { - List allImports = new ArrayList<>(); + List allImports = new ArrayList<>(); allImports.addAll(coreImports); allImports.addAll(defaultImports); @@ -392,8 +419,13 @@ public class PdeParseTreeListener extends ProcessingBaseListener { }); } + // Find the start of the fully qualified name. + boolean isStaticImport = false; for(int i = 0; i < ctx.getChildCount(); i++) { ParseTree candidate = ctx.getChild(i); + String candidateText = candidate.getText().toLowerCase(); + boolean childIsStatic = (candidateText.equals("static")); + isStaticImport = isStaticImport || childIsStatic; if (candidate instanceof ProcessingParser.QualifiedNameContext) { startCtx = (ProcessingParser.QualifiedNameContext) ctx.getChild(i); } @@ -403,11 +435,22 @@ public class PdeParseTreeListener extends ProcessingBaseListener { return; } - Interval interval = - new Interval(startCtx.start.getStartIndex(), ctx.stop.getStopIndex()); + // Extract the fully qualified name + Interval interval = new Interval( + startCtx.start.getStartIndex(), + ctx.stop.getStopIndex() + ); + String importString = ctx.start.getInputStream().getText(interval); - String importStringNoSemi = importString.substring(0, importString.length() - 1); - foundImports.add(importStringNoSemi); + int endImportIndex = importString.length() - 1; + String importStringNoSemi = importString.substring(0, endImportIndex); + + // Check for static import + if (isStaticImport) { + importStringNoSemi = "static " + importStringNoSemi; + } + + foundImports.add(ImportStatement.parse(importStringNoSemi)); createDelete(ctx.start, ctx.stop); } @@ -544,7 +587,7 @@ public class PdeParseTreeListener extends ProcessingBaseListener { /** * Check if this contains an annation. * - * @param child The modifier context to check. + * @param context The modifier context to check. * @return True if annotation. False otherwise */ private boolean isAnnoation(ProcessingParser.ModifierContext context) { @@ -705,4 +748,12 @@ public class PdeParseTreeListener extends ProcessingBaseListener { return builder.build(); } + + private List createPlainImportStatementInfos(List fullyQualifiedNames) { + return fullyQualifiedNames.stream().map(this::createPlainImportStatementInfo).collect(Collectors.toList()); + } + + private ImportStatement createPlainImportStatementInfo(String fullyQualifiedName) { + return ImportStatement.parse(fullyQualifiedName); + } } diff --git a/java/src/processing/mode/java/preproc/PreprocessorResult.java b/java/src/processing/mode/java/preproc/PreprocessorResult.java index 41ea2e910..f5b689eb3 100644 --- a/java/src/processing/mode/java/preproc/PreprocessorResult.java +++ b/java/src/processing/mode/java/preproc/PreprocessorResult.java @@ -24,7 +24,6 @@ package processing.mode.java.preproc; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.stream.Collectors; import processing.mode.java.pdex.ImportStatement; import processing.mode.java.pdex.TextTransform; @@ -38,7 +37,6 @@ public class PreprocessorResult { private final int headerOffset; private final String className; - private final List importStatementsStr; private final List importStatements; private final PdePreprocessor.Mode programType; private final List edits; @@ -66,13 +64,13 @@ public class PreprocessorResult { * @param newHeaderOffset The offset (in number of chars) from the start of the program at which * the header finishes. * @param newClassName The name of the class containing the sketch. - * @param newExtraImports Additional imports beyond the defaults and code folder. + * @param newImportStatements The imports required for the sketch including defaults and core imports. * @param newEdits The edits made during preprocessing. * @param newSketchWidth The width of the sketch in pixels or special value like displayWidth; * @param newSketchHeight The height of the sketch in pixels or special value like displayWidth; */ public PreprocessorResult(PdePreprocessor.Mode newProgramType, int newHeaderOffset, - String newClassName, List newExtraImports, List newEdits, + String newClassName, List newImportStatements, List newEdits, String newSketchWidth, String newSketchHeight) { if (newClassName == null) { @@ -81,15 +79,11 @@ public class PreprocessorResult { headerOffset = newHeaderOffset; className = newClassName; - importStatementsStr = Collections.unmodifiableList(new ArrayList<>(newExtraImports)); + importStatements = newImportStatements; programType = newProgramType; edits = newEdits; preprocessIssues = new ArrayList<>(); - importStatements = importStatementsStr.stream() - .map(ImportStatement::parse) - .collect(Collectors.toList()); - sketchWidth = newSketchWidth; sketchHeight = newSketchHeight; } @@ -103,7 +97,6 @@ public class PreprocessorResult { preprocessIssues = Collections.unmodifiableList(newPreprocessIssues); headerOffset = 0; className = "unknown"; - importStatementsStr = new ArrayList<>(); programType = PdePreprocessor.Mode.STATIC; edits = new ArrayList<>(); importStatements = new ArrayList<>(); @@ -140,15 +133,6 @@ public class PreprocessorResult { return className; } - /** - * Get the imports beyond the default set that are included in the sketch. - * - * @return Additional imports beyond the defaults and code folder. - */ - public List getImportStatementsStr() { - return importStatementsStr; - } - /** * Get the type of program that was parsed. * diff --git a/java/src/processing/mode/java/preproc/code/RewriteParams.java b/java/src/processing/mode/java/preproc/code/RewriteParams.java index 00adcdff4..295a4879c 100644 --- a/java/src/processing/mode/java/preproc/code/RewriteParams.java +++ b/java/src/processing/mode/java/preproc/code/RewriteParams.java @@ -1,6 +1,7 @@ package processing.mode.java.preproc.code; import org.antlr.v4.runtime.TokenStreamRewriter; +import processing.mode.java.pdex.ImportStatement; import processing.mode.java.preproc.PdePreprocessor; import java.util.List; @@ -19,10 +20,10 @@ public class RewriteParams { private final PdePreprocessor.Mode mode; private final boolean foundMain; private final int lineOffset; - private final List coreImports; - private final List defaultImports; - private final List codeFolderImports; - private final List foundImports; + private final List coreImports; + private final List defaultImports; + private final List codeFolderImports; + private final List foundImports; private final Optional sketchWidth; private final Optional sketchHeight; private final Optional sketchRenderer; @@ -54,9 +55,9 @@ public class RewriteParams { */ public RewriteParams(String newVersion, String newSketchName, boolean newisTesting, TokenStreamRewriter newRewriter, PdePreprocessor.Mode newMode, - boolean newFoundMain, int newLineOffset, List newCoreImports, - List newDefaultImports, List newCodeFolderImports, - List newFoundImports, Optional newSketchWidth, + boolean newFoundMain, int newLineOffset, List newCoreImports, + List newDefaultImports, List newCodeFolderImports, + List newFoundImports, Optional newSketchWidth, Optional newSketchHeight, Optional newSketchRenderer, boolean newIsSizeValidInGlobal, boolean newSizeIsFullscreen) { @@ -146,7 +147,7 @@ public class RewriteParams { * * @return The set of imports to include that are required for processing. */ - public List getCoreImports() { + public List getCoreImports() { return coreImports; } @@ -155,7 +156,7 @@ public class RewriteParams { * * @return The set of imports included for user convenience. */ - public List getDefaultImports() { + public List getDefaultImports() { return defaultImports; } @@ -164,7 +165,7 @@ public class RewriteParams { * * @return The imports required to include other code in the code folder. */ - public List getCodeFolderImports() { + public List getCodeFolderImports() { return codeFolderImports; } @@ -173,7 +174,7 @@ public class RewriteParams { * * @return The imports included by the user. */ - public List getFoundImports() { + public List getFoundImports() { return foundImports; } diff --git a/java/src/processing/mode/java/preproc/code/RewriteParamsBuilder.java b/java/src/processing/mode/java/preproc/code/RewriteParamsBuilder.java index dd03183b8..8297756ba 100644 --- a/java/src/processing/mode/java/preproc/code/RewriteParamsBuilder.java +++ b/java/src/processing/mode/java/preproc/code/RewriteParamsBuilder.java @@ -1,6 +1,7 @@ package processing.mode.java.preproc.code; import org.antlr.v4.runtime.TokenStreamRewriter; +import processing.mode.java.pdex.ImportStatement; import processing.mode.java.preproc.PdePreprocessor; import java.util.ArrayList; @@ -27,10 +28,10 @@ public class RewriteParamsBuilder { private Optional isSizeValidInGlobal; private Optional isSizeFullscreen; - private ArrayList coreImports; - private ArrayList defaultImports; - private ArrayList codeFolderImports; - private ArrayList foundImports; + private ArrayList coreImports; + private ArrayList defaultImports; + private ArrayList codeFolderImports; + private ArrayList foundImports; /** * Create a new params build. @@ -165,7 +166,7 @@ public class RewriteParamsBuilder { * * @param newImports The set of imports to include that are required for processing. */ - public void addCoreImports(Collection newImports) { + public void addCoreImports(Collection newImports) { coreImports.addAll(newImports); } @@ -174,7 +175,7 @@ public class RewriteParamsBuilder { * * @param newImports The set of imports included for user convenience. */ - public void addDefaultImports(Collection newImports) { + public void addDefaultImports(Collection newImports) { defaultImports.addAll(newImports); } @@ -183,7 +184,7 @@ public class RewriteParamsBuilder { * * @param newImports The imports required to include other code in the code folder. */ - public void addCodeFolderImports(Collection newImports) { + public void addCodeFolderImports(Collection newImports) { codeFolderImports.addAll(newImports); } @@ -192,7 +193,7 @@ public class RewriteParamsBuilder { * * @param newImports The imports included by the user. */ - public void addFoundImports(Collection newImports) { + public void addFoundImports(Collection newImports) { foundImports.addAll(newImports); } diff --git a/java/src/processing/mode/java/preproc/code/RewriterCodeGenerator.java b/java/src/processing/mode/java/preproc/code/RewriterCodeGenerator.java index 339b9045f..923d7aeea 100644 --- a/java/src/processing/mode/java/preproc/code/RewriterCodeGenerator.java +++ b/java/src/processing/mode/java/preproc/code/RewriterCodeGenerator.java @@ -3,6 +3,7 @@ package processing.mode.java.preproc.code; import org.antlr.v4.runtime.TokenStreamRewriter; import processing.app.Preferences; import processing.core.PApplet; +import processing.mode.java.pdex.ImportStatement; import processing.mode.java.preproc.PdePreprocessor; import java.text.SimpleDateFormat; @@ -163,10 +164,10 @@ public class RewriterCodeGenerator { * @param params The parameters for the rewrite. * @param resultBuilder Builder for reporting out results to the caller. */ - private void writeImportList(PrintWriterWithEditGen headerWriter, List imports, RewriteParams params, + private void writeImportList(PrintWriterWithEditGen headerWriter, List imports, RewriteParams params, RewriteResultBuilder resultBuilder) { - writeImportList(headerWriter, imports.toArray(new String[0]), params, resultBuilder); + writeImportList(headerWriter, imports.toArray(new ImportStatement[0]), params, resultBuilder); } /** @@ -177,11 +178,11 @@ public class RewriterCodeGenerator { * @param params The parameters for the rewrite. * @param resultBuilder Builder for reporting out results to the caller. */ - private void writeImportList(PrintWriterWithEditGen headerWriter, String[] imports, RewriteParams params, + private void writeImportList(PrintWriterWithEditGen headerWriter, ImportStatement[] imports, RewriteParams params, RewriteResultBuilder resultBuilder) { - for (String importDecl : imports) { - headerWriter.addCodeLine("import " + importDecl + ";"); + for (ImportStatement importDecl : imports) { + headerWriter.addCodeLine(importDecl.getFullSourceLine()); } if (imports.length > 0) { headerWriter.addEmptyLine(); diff --git a/java/test/processing/mode/java/ParserTests.java b/java/test/processing/mode/java/ParserTests.java index 9b55a1f3e..29ba684a7 100644 --- a/java/test/processing/mode/java/ParserTests.java +++ b/java/test/processing/mode/java/ParserTests.java @@ -91,7 +91,7 @@ public class ParserTests { try { final String program = preprocess(id, res(id + ".pde")); boolean successful = compile(id, program); - if (successful) { + if (!successful) { System.err.println("----------------------------"); System.err.println(program); System.err.println("----------------------------"); @@ -203,10 +203,11 @@ public class ParserTests { expectRunnerException("bug763", 8); } - @Test + // The JDT doesn't seem to mind this now. Commenting out. + /*@Test public void bug820() { - expectCompilerException("bug820"); - } + expectGood("bug820"); + }*/ @Test public void bug1064() { @@ -371,7 +372,7 @@ public class ParserTests { private static boolean compile(String id, String program) { // Create compilable AST to get syntax problems CompilationUnit compilableCU = JdtCompilerUtil.makeAST( - ASTParser.newParser(AST.JLS8), + ASTParser.newParser(AST.JLS11), program.toCharArray(), JdtCompilerUtil.COMPILER_OPTIONS ); @@ -389,9 +390,9 @@ public class ParserTests { + "(" + problemFound.getSourceLineNumber() + ")" ); - return true; - } else { return false; + } else { + return true; } } diff --git a/java/test/resources/bug598.expected b/java/test/resources/bug598.expected index d68109b50..ef180139a 100644 --- a/java/test/resources/bug598.expected +++ b/java/test/resources/bug598.expected @@ -3,7 +3,7 @@ import processing.data.*; import processing.event.*; import processing.opengl.*; -import java.lang.Math.tanh; +import static java.lang.Math.tanh; import java.util.concurrent.Callable; import java.util.List; import java.util.Comparator; From 434b722a77a52eef90823dbe4e5b71ea968c8db0 Mon Sep 17 00:00:00 2001 From: Sam Pottinger Date: Mon, 4 Nov 2019 17:08:15 -0800 Subject: [PATCH 2/5] Fix loose git merge issue sitting in comments for PdeParseTreeLi.. --- .../java/preproc/PdeParseTreeListener.java | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/java/src/processing/mode/java/preproc/PdeParseTreeListener.java b/java/src/processing/mode/java/preproc/PdeParseTreeListener.java index aff5b4dbc..9c12c6f3f 100644 --- a/java/src/processing/mode/java/preproc/PdeParseTreeListener.java +++ b/java/src/processing/mode/java/preproc/PdeParseTreeListener.java @@ -506,30 +506,6 @@ public class PdeParseTreeListener extends ProcessingBaseListener { } /** -<<<<<<< HEAD - * Check if this contains an annation. - * - * @param context The modifier context to check. - * @return True if annotation. False otherwise - */ - private boolean isAnnoation(ProcessingParser.ModifierContext context) { - if (context.getChildCount() == 0) { - return false; - } - - ProcessingParser.ClassOrInterfaceModifierContext classModifierCtx; - if (!(context.getChild(0) instanceof ProcessingParser.ClassOrInterfaceModifierContext)) { - return false; - } - - classModifierCtx = (ProcessingParser.ClassOrInterfaceModifierContext) context.getChild(0); - - return classModifierCtx.getChild(0) instanceof ProcessingParser.AnnotationContext; - } - - /** -======= ->>>>>>> master * Endpoint for ANTLR to call after parsing a primitive type name. * *

From abe2684ee981629ce9811131937d35b5416cbee8 Mon Sep 17 00:00:00 2001 From: Sam Pottinger Date: Mon, 4 Nov 2019 17:14:21 -0800 Subject: [PATCH 3/5] Fixed export issue with webkit export inside javafx. --- core/library/export.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/library/export.txt b/core/library/export.txt index 75553c1e5..7a8b0ae12 100644 --- a/core/library/export.txt +++ b/core/library/export.txt @@ -3,7 +3,7 @@ name = CoreOpenJFXOpenGL -application.macosx=core.jar,jogl-all.jar,gluegen-rt.jar,jogl-all-natives-macosx-universal.jar,gluegen-rt-natives-macosx-universal.jar,javafx-swt.jar,javafx.base.jar,javafx.controls.jar,javafx.fxml.jar,javafx.graphics.jar,javafx.media.jar,javafx.swing.jar,javafx.web.jar,libdecora_sse.dylib,libfxplugins.dylib,libglass.dylib,libglib-lite.dylib,libgstreamer-lite.dylib,libjavafx_font.dylib,libjavafx_iio.dylib,libjfxmedia.dylib,libjfxmedia_avf.dylib,libjfxwebkit.dylib,libprism_common.dylib,libprism_es2.dylib,libprism_sw.dylib +application.macosx=core.jar,jogl-all.jar,gluegen-rt.jar,jogl-all-natives-macosx-universal.jar,gluegen-rt-natives-macosx-universal.jar,javafx-swt.jar,javafx.base.jar,javafx.controls.jar,javafx.fxml.jar,javafx.graphics.jar,javafx.media.jar,javafx.swing.jar,javafx.web.jar,libdecora_sse.dylib,libfxplugins.dylib,libglass.dylib,libglib-lite.dylib,libgstreamer-lite.dylib,libjavafx_font.dylib,libjavafx_iio.dylib,libjfxmedia.dylib,libjfxmedia_avf.dylib,libprism_common.dylib,libprism_es2.dylib,libprism_sw.dylib application.windows32=api-ms-win-core-console-l1-1-0.dll,api-ms-win-core-datetime-l1-1-0.dll,api-ms-win-core-debug-l1-1-0.dll,api-ms-win-core-errorhandling-l1-1-0.dll,api-ms-win-core-file-l1-1-0.dll,api-ms-win-core-file-l1-2-0.dll,api-ms-win-core-file-l2-1-0.dll,api-ms-win-core-handle-l1-1-0.dll,api-ms-win-core-heap-l1-1-0.dll,api-ms-win-core-interlocked-l1-1-0.dll,api-ms-win-core-libraryloader-l1-1-0.dll,api-ms-win-core-localization-l1-2-0.dll,api-ms-win-core-memory-l1-1-0.dll,api-ms-win-core-namedpipe-l1-1-0.dll,api-ms-win-core-processenvironment-l1-1-0.dll,api-ms-win-core-processthreads-l1-1-0.dll,api-ms-win-core-processthreads-l1-1-1.dll,api-ms-win-core-profile-l1-1-0.dll,api-ms-win-core-rtlsupport-l1-1-0.dll,api-ms-win-core-string-l1-1-0.dll,api-ms-win-core-synch-l1-1-0.dll,api-ms-win-core-synch-l1-2-0.dll,api-ms-win-core-sysinfo-l1-1-0.dll,api-ms-win-core-timezone-l1-1-0.dll,api-ms-win-core-util-l1-1-0.dll,api-ms-win-crt-conio-l1-1-0.dll,api-ms-win-crt-convert-l1-1-0.dll,api-ms-win-crt-environment-l1-1-0.dll,api-ms-win-crt-filesystem-l1-1-0.dll,api-ms-win-crt-heap-l1-1-0.dll,api-ms-win-crt-locale-l1-1-0.dll,api-ms-win-crt-math-l1-1-0.dll,api-ms-win-crt-multibyte-l1-1-0.dll,api-ms-win-crt-private-l1-1-0.dll,api-ms-win-crt-process-l1-1-0.dll,api-ms-win-crt-runtime-l1-1-0.dll,api-ms-win-crt-stdio-l1-1-0.dll,api-ms-win-crt-string-l1-1-0.dll,api-ms-win-crt-time-l1-1-0.dll,api-ms-win-crt-utility-l1-1-0.dll,concrt140.dll,core.jar,decora_sse.dll,fxplugins.dll,glass.dll,glib-lite.dll,gluegen-rt-natives-linux-aarch64.jar,gluegen-rt-natives-linux-amd64.jar,gluegen-rt-natives-linux-armv6hf.jar,gluegen-rt-natives-linux-i586.jar,gluegen-rt-natives-macosx-universal.jar,gluegen-rt-natives-windows-amd64.jar,gluegen-rt-natives-windows-i586.jar,gluegen-rt.jar,gstreamer-lite.dll,javafx-swt.jar,javafx.base.jar,javafx.controls.jar,javafx.fxml.jar,javafx.graphics.jar,javafx.media.jar,javafx.properties,javafx.swing.jar,javafx.web.jar,javafx_font.dll,javafx_iio.dll,jfxmedia.dll,jfxwebkit.dll,jogl-all-natives-linux-aarch64.jar,jogl-all-natives-linux-amd64.jar,jogl-all-natives-linux-armv6hf.jar,jogl-all-natives-linux-i586.jar,jogl-all-natives-macosx-universal.jar,jogl-all-natives-windows-amd64.jar,jogl-all-natives-windows-i586.jar,jogl-all.jar,msvcp140.dll,prism_common.dll,prism_d3d.dll,prism_sw.dll,ucrtbase.dll,vcruntime140.dll From 2aaaeb7253147715e16e36f8b5ea209e2147a6a5 Mon Sep 17 00:00:00 2001 From: Sam Pottinger Date: Mon, 4 Nov 2019 17:34:33 -0800 Subject: [PATCH 4/5] Cleaned up documentation for sttaic import handeling. --- .../mode/java/pdex/CompletionGenerator.java | 2 +- .../mode/java/pdex/ImportStatement.java | 91 ++++++++++++++++--- .../java/preproc/PdeParseTreeListener.java | 20 ++++ 3 files changed, 100 insertions(+), 13 deletions(-) diff --git a/java/src/processing/mode/java/pdex/CompletionGenerator.java b/java/src/processing/mode/java/pdex/CompletionGenerator.java index 1a9bf0009..17077ecd0 100644 --- a/java/src/processing/mode/java/pdex/CompletionGenerator.java +++ b/java/src/processing/mode/java/pdex/CompletionGenerator.java @@ -738,7 +738,7 @@ public class CompletionGenerator { return importListStream .map(list -> list.stream() .map(is -> { - if (is.getClassName().equals(finalClassName)) { + if (is.getMemberName().equals(finalClassName)) { return is.getFullClassName(); } else if (is.isStarredImport()) { return is.getPackageName() + "." + finalClassName; diff --git a/java/src/processing/mode/java/pdex/ImportStatement.java b/java/src/processing/mode/java/pdex/ImportStatement.java index 62f9cd81f..6d30c6d89 100644 --- a/java/src/processing/mode/java/pdex/ImportStatement.java +++ b/java/src/processing/mode/java/pdex/ImportStatement.java @@ -42,7 +42,7 @@ public class ImportStatement { * Full class name of the import with all packages * Ends with star for starred imports */ - private String className; + private String memberName; /** * Name of the package e.g. everything before last dot @@ -51,25 +51,43 @@ public class ImportStatement { private ImportStatement() { } + /** + * Create an import statement for a full package. + * + * @param cls The fully qualified name of the package. + * @return ImportStatement which imports all package members in a non-static context using a wildcard. + */ public static ImportStatement wholePackage(String pckg) { ImportStatement is = new ImportStatement(); is.packageName = pckg; - is.className = "*"; + is.memberName = "*"; is.isStarred = true; return is; } + /** + * Create an import statement for a single class. + * + * @param cls The fully qualified name of the class. + * @return ImportStatement which imports the class in a non-static context. + */ public static ImportStatement singleClass(String cls) { ImportStatement is = new ImportStatement(); int lastDot = cls.lastIndexOf('.'); - is.className = lastDot >= 0 ? cls.substring(lastDot+1) : cls; + is.memberName = lastDot >= 0 ? cls.substring(lastDot+1) : cls; is.packageName = lastDot >= 0 ? cls.substring(0, lastDot) : ""; // is.isClass = true; return is; } - - + /** + * Prase an import statement from a fully qualified name. + * + * @param importString The fully qualified name from which an import statement should be built. This supports static + * prepended so both "java.util.List" and "static org.processing.package.Factory.build" are supported. Note that + * the static prepending is required if the import is static. + * @return + */ public static ImportStatement parse(String importString) { Matcher matcher = SourceUtils.IMPORT_REGEX_NO_KEYWORD.matcher(importString); if (!matcher.find()) return null; @@ -77,6 +95,13 @@ public class ImportStatement { return parse(matcher.toMatchResult()); } + /** + * Parse an import statement from a regex match found via SourceUtils.*REGEX*. + * + * @param match The regex match from which an import statement should be built. Can be from IMPORT_REGEX_NO_KEYWORD or + * IMPORT_REGEX or equivalent. + * @return Newly parsed import statement information. + */ public static ImportStatement parse(MatchResult match) { ImportStatement is = new ImportStatement(); @@ -94,42 +119,84 @@ public class ImportStatement { int periodOfContainingTypeName = withContainingTypeNameAtEnd.lastIndexOf("."); String containingTypeName = withContainingTypeNameAtEnd.substring(periodOfContainingTypeName + 1); is.packageName = withContainingTypeNameAtEnd.substring(0, periodOfContainingTypeName); - is.className = containingTypeName + "." + memberName; + is.memberName = containingTypeName + "." + memberName; } else { is.packageName = endsWithPeriod ? pckg.substring(0, pckg.length() - 1) : pckg; - is.className = memberName; + is.memberName = memberName; } return is; } + /** + * Get the source line needed to execute this import. + * + * @return The java code required for executing this import. + */ public String getFullSourceLine() { - return importKw + " " + (isStatic ? (staticKw + " ") : "") + packageName + "." + className + ";"; + return importKw + " " + (isStatic ? (staticKw + " ") : "") + packageName + "." + memberName + ";"; } + /** + * Get the fully qualified member name which includes the package path. + * + * @return The fully qualified member name including the parent class. This is "java.util.List" in the case of + * "import java.util.List". Note that, in the case of static imports, it will include the member imported so + * "org.processing.package.Factory.build" would be returned for + * "import static org.processing.package.Factory.build". + */ public String getFullClassName(){ - return packageName + "." + className; + return packageName + "." + memberName; } - public String getClassName(){ - return className; + /** + * Get the end of the import statement with the type to be imported. + * + * @return This is the class name (List) in the case of "import java.util.List" or "*" in the case of a wildcard. For + * static imports this will be the member within the containing class (Factory.build in the case of + * "import static org.processing.package.Factory.build"). + */ + public String getMemberName(){ + return memberName; } + /** + * Get the package from which the import is being made. + * + * @return The package "java.util" from "import java.util.List". Note that, in the case of wildcards, the wildcard + * will be in the member name and not the class name. + */ public String getPackageName(){ return packageName; } + /** + * Determine if this import is a wildcard import. + * + * @return True if the FQN (fully qualified name) ends in a wildcard and false otherwise. + */ public boolean isStarredImport() { return isStarred; } + /** + * Determine if this import statement is a static import. + * + * @return True if of the form "import static {FQN}" where FQN refers to the fully qualified name and false otherwise. + */ public boolean isStaticImport() { return isStatic; } + /** + * Check if the import statements refer to the same import target. + * + * @param is The other import statement. + * @return True of the two ImportStatements refer to the same import target and false otherwise. + */ public boolean isSameAs(ImportStatement is) { return packageName.equals(is.packageName) && - className.equals(is.className) && + memberName.equals(is.memberName) && isStatic == is.isStatic; } } \ No newline at end of file diff --git a/java/src/processing/mode/java/preproc/PdeParseTreeListener.java b/java/src/processing/mode/java/preproc/PdeParseTreeListener.java index 9c12c6f3f..294fbf6c0 100644 --- a/java/src/processing/mode/java/preproc/PdeParseTreeListener.java +++ b/java/src/processing/mode/java/preproc/PdeParseTreeListener.java @@ -1289,10 +1289,30 @@ public class PdeParseTreeListener extends ProcessingBaseListener { return TextTransform.Edit.delete(start.getStartIndex(), start.getText().length()); } + /* + * ================================================ + * === Utility functions for import statements. === + * ================================================ + */ + + /** + * Create a set of non-static imports given the fully qualified names (FQNs) for the types to be imported. + * + * @param fullyQualifiedNames The fully qualified names of the types to be imported. This should be like + * "java.util.List". Supports wildcards. + * @return Import statements for the listed types. + */ private List createPlainImportStatementInfos(List fullyQualifiedNames) { return fullyQualifiedNames.stream().map(this::createPlainImportStatementInfo).collect(Collectors.toList()); } + /** + * Create a single non-static import given the fully qualified name (FQN) + * + * @param fullyQualifiedName The fully qualified name of the types to be imported. This should be like + * "java.util.List". Supports wildcards. + * @return Newly created ImportStatement. + */ private ImportStatement createPlainImportStatementInfo(String fullyQualifiedName) { return ImportStatement.parse(fullyQualifiedName); } From 2c85b891731a79d02653acb71cae49ab4ad89e2b Mon Sep 17 00:00:00 2001 From: Sam Pottinger Date: Mon, 4 Nov 2019 18:17:24 -0800 Subject: [PATCH 5/5] Added tests for ImportStatement and some minor style clean up. --- java/src/processing/mode/java/JavaEditor.java | 2 +- .../mode/java/pdex/CompletionGenerator.java | 2 +- .../mode/java/pdex/ImportStatement.java | 13 +- .../mode/java/pdex/PreprocessingService.java | 2 +- .../mode/java/pdex/ImportStatementTest.java | 147 ++++++++++++++++++ 5 files changed, 155 insertions(+), 11 deletions(-) create mode 100644 java/test/processing/mode/java/pdex/ImportStatementTest.java diff --git a/java/src/processing/mode/java/JavaEditor.java b/java/src/processing/mode/java/JavaEditor.java index b39189d97..9c029f93c 100644 --- a/java/src/processing/mode/java/JavaEditor.java +++ b/java/src/processing/mode/java/JavaEditor.java @@ -1811,7 +1811,7 @@ public class JavaEditor extends Editor { if (!imports.isEmpty()) { ArrayList importHeaders = new ArrayList<>(); for (ImportStatement importStatement : imports) { - importHeaders.add(importStatement.getFullClassName()); + importHeaders.add(importStatement.getFullMemberName()); } List installLibsHeaders = getNotInstalledAvailableLibs(importHeaders); diff --git a/java/src/processing/mode/java/pdex/CompletionGenerator.java b/java/src/processing/mode/java/pdex/CompletionGenerator.java index 17077ecd0..04ec851d2 100644 --- a/java/src/processing/mode/java/pdex/CompletionGenerator.java +++ b/java/src/processing/mode/java/pdex/CompletionGenerator.java @@ -739,7 +739,7 @@ public class CompletionGenerator { .map(list -> list.stream() .map(is -> { if (is.getMemberName().equals(finalClassName)) { - return is.getFullClassName(); + return is.getFullMemberName(); } else if (is.isStarredImport()) { return is.getPackageName() + "." + finalClassName; } diff --git a/java/src/processing/mode/java/pdex/ImportStatement.java b/java/src/processing/mode/java/pdex/ImportStatement.java index 6d30c6d89..e78e3422a 100644 --- a/java/src/processing/mode/java/pdex/ImportStatement.java +++ b/java/src/processing/mode/java/pdex/ImportStatement.java @@ -2,7 +2,7 @@ /* Part of the Processing project - http://processing.org -Copyright (c) 2012-15 The Processing Foundation +Copyright (c) 2012-19 The Processing Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 @@ -25,9 +25,6 @@ import java.util.regex.Matcher; /** * Wrapper for import statements - * - * @author Manindra Moharana <me@mkmoharana.com> - * */ public class ImportStatement { @@ -84,9 +81,9 @@ public class ImportStatement { * Prase an import statement from a fully qualified name. * * @param importString The fully qualified name from which an import statement should be built. This supports static - * prepended so both "java.util.List" and "static org.processing.package.Factory.build" are supported. Note that - * the static prepending is required if the import is static. - * @return + * prepended so both "java.util.List" and "static org.processing.package.Factory.build" are supported but + * "import java.util.List;" is not. Note that the static prepending is required if the import is static. + * @return Newly parsed import statement information. */ public static ImportStatement parse(String importString) { Matcher matcher = SourceUtils.IMPORT_REGEX_NO_KEYWORD.matcher(importString); @@ -145,7 +142,7 @@ public class ImportStatement { * "org.processing.package.Factory.build" would be returned for * "import static org.processing.package.Factory.build". */ - public String getFullClassName(){ + public String getFullMemberName(){ return packageName + "." + memberName; } diff --git a/java/src/processing/mode/java/pdex/PreprocessingService.java b/java/src/processing/mode/java/pdex/PreprocessingService.java index 51313236b..0f1eea9c1 100644 --- a/java/src/processing/mode/java/pdex/PreprocessingService.java +++ b/java/src/processing/mode/java/pdex/PreprocessingService.java @@ -403,7 +403,7 @@ public class PreprocessingService { new StringWriter(), result.scrubbedPdeCode, codeFolderImports.stream() - .map(ImportStatement::getFullClassName) + .map(ImportStatement::getFullMemberName) .collect(Collectors.toList()) ); } catch (SketchException e) { diff --git a/java/test/processing/mode/java/pdex/ImportStatementTest.java b/java/test/processing/mode/java/pdex/ImportStatementTest.java new file mode 100644 index 000000000..e64274ff8 --- /dev/null +++ b/java/test/processing/mode/java/pdex/ImportStatementTest.java @@ -0,0 +1,147 @@ +package processing.mode.java.pdex; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +public class ImportStatementTest { + + private ImportStatement wholePackage; + private ImportStatement singleClass; + private ImportStatement staticNoWildcard; + private ImportStatement staticWildcard; + + @Before + public void setUp() { + wholePackage = ImportStatement.parse("java.util.*"); + singleClass = ImportStatement.parse("java.util.List"); + staticNoWildcard = ImportStatement.parse("static org.processing.test.Test.init"); + staticWildcard = ImportStatement.parse("static org.processing.test.Test.*"); + } + + @Test + public void testWholePackageShortcut() { + Assert.assertTrue(wholePackage.isSameAs(ImportStatement.wholePackage("java.util"))); + } + + @Test + public void testSingleClassShortcut() { + Assert.assertTrue(singleClass.isSameAs(ImportStatement.singleClass("java.util.List"))); + } + + @Test + public void testGetFullSourceLine() { + Assert.assertEquals( + wholePackage.getFullSourceLine(), + "import java.util.*;" + ); + + Assert.assertEquals( + singleClass.getFullSourceLine(), + "import java.util.List;" + ); + + Assert.assertEquals( + staticNoWildcard.getFullSourceLine(), + "import static org.processing.test.Test.init;" + ); + + Assert.assertEquals( + staticWildcard.getFullSourceLine(), + "import static org.processing.test.Test.*;" + ); + } + + @Test + public void testGetFullMemberName() { + Assert.assertEquals( + wholePackage.getFullMemberName(), + "java.util.*" + ); + + Assert.assertEquals( + singleClass.getFullMemberName(), + "java.util.List" + ); + + Assert. assertEquals( + staticNoWildcard.getFullMemberName(), + "org.processing.test.Test.init" + ); + + Assert.assertEquals( + staticWildcard.getFullMemberName(), + "org.processing.test.Test.*" + ); + } + + @Test + public void testGetMemberName() { + Assert.assertEquals( + wholePackage.getMemberName(), + "*" + ); + + Assert.assertEquals( + singleClass.getMemberName(), + "List" + ); + + Assert. assertEquals( + staticNoWildcard.getMemberName(), + "Test.init" + ); + + Assert.assertEquals( + staticWildcard.getMemberName(), + "Test.*" + ); + } + + @Test + public void testGetPackageName() { + Assert.assertEquals( + wholePackage.getPackageName(), + "java.util" + ); + + Assert.assertEquals( + singleClass.getPackageName(), + "java.util" + ); + + Assert. assertEquals( + staticNoWildcard.getPackageName(), + "org.processing.test" + ); + + Assert.assertEquals( + staticWildcard.getPackageName(), + "org.processing.test" + ); + } + + @Test + public void testIsStarredImport() { + Assert.assertTrue(wholePackage.isStarredImport()); + Assert.assertFalse(singleClass.isStarredImport()); + Assert.assertFalse(staticNoWildcard.isStarredImport()); + Assert.assertTrue(staticWildcard.isStarredImport()); + } + + @Test + public void testIsStaticImport() { + Assert.assertFalse(wholePackage.isStaticImport()); + Assert.assertFalse(singleClass.isStaticImport()); + Assert.assertTrue(staticNoWildcard.isStaticImport()); + Assert.assertTrue(staticWildcard.isStaticImport()); + } + + @Test + public void testIsSameAs() { + Assert.assertTrue(wholePackage.isSameAs(ImportStatement.parse("java.util.*"))); + Assert.assertFalse(wholePackage.isSameAs(ImportStatement.parse("java.other.*"))); + } + +}