diff --git a/coverage-report/pom.xml b/coverage-report/pom.xml index 54e4a910d..f74f77718 100644 --- a/coverage-report/pom.xml +++ b/coverage-report/pom.xml @@ -4,7 +4,7 @@ eu.rssw.openedge.parsers coverage-report - 2.12.1 + 2.13.0 JaCoCo report Fake module for code coverage report in SonarQube @@ -20,37 +20,37 @@ eu.rssw.openedge.rcode rcode-reader - 2.12.1 + 2.13.0 eu.rssw.sonar.openedge sonar-openedge-plugin - 2.12.1 + 2.13.0 eu.rssw.openedge.parsers proparse - 2.12.1 + 2.13.0 eu.rssw.openedge.parsers profiler-parser - 2.12.1 + 2.13.0 eu.rssw.openedge.parsers database-parser - 2.12.1 + 2.13.0 eu.rssw.openedge.parsers listing-parser - 2.12.1 + 2.13.0 eu.rssw.openedge.checks openedge-checks - 2.12.1 + 2.13.0 diff --git a/database-parser/pom.xml b/database-parser/pom.xml index 1268eb7c4..fbad452cd 100644 --- a/database-parser/pom.xml +++ b/database-parser/pom.xml @@ -4,7 +4,7 @@ eu.rssw.openedge.parsers database-parser - 2.12.1 + 2.13.0 OpenEdge database definition lexer and parser OpenEdge dump files parser @@ -51,12 +51,12 @@ org.antlr antlr4-runtime - 4.9 + 4.9.2 com.google.guava guava - 29.0-jre + 30.1.1-jre org.slf4j @@ -112,7 +112,7 @@ org.antlr antlr4-maven-plugin - 4.9 + 4.9.2 diff --git a/listing-parser/pom.xml b/listing-parser/pom.xml index cc26c32dd..826384f16 100644 --- a/listing-parser/pom.xml +++ b/listing-parser/pom.xml @@ -4,7 +4,7 @@ eu.rssw.openedge.parsers listing-parser - 2.12.1 + 2.13.0 OpenEdge listing so-called parser OpenEdge listing files parser @@ -49,7 +49,7 @@ com.google.guava guava - 29.0-jre + 30.1.1-jre org.slf4j diff --git a/openedge-checks/pom.xml b/openedge-checks/pom.xml index 0f0454260..c79c1c905 100644 --- a/openedge-checks/pom.xml +++ b/openedge-checks/pom.xml @@ -4,7 +4,7 @@ eu.rssw.openedge.checks openedge-checks - 2.12.1 + 2.13.0 OpenEdge checks OpenEdge checks @@ -55,12 +55,12 @@ eu.rssw.openedge.parsers database-parser - 2.12.1 + 2.13.0 eu.rssw.openedge.parsers proparse - 2.12.1 + 2.13.0 org.testng diff --git a/openedge-checks/src/main/java/org/sonar/plugins/openedge/api/LicenseRegistration.java b/openedge-checks/src/main/java/org/sonar/plugins/openedge/api/LicenseRegistration.java index 8cea9db5f..cd9d3c96d 100644 --- a/openedge-checks/src/main/java/org/sonar/plugins/openedge/api/LicenseRegistration.java +++ b/openedge-checks/src/main/java/org/sonar/plugins/openedge/api/LicenseRegistration.java @@ -19,11 +19,15 @@ */ package org.sonar.plugins.openedge.api; +import java.util.Objects; + import org.sonar.api.SonarProduct; import org.sonar.api.scanner.ScannerSide; import org.sonar.api.server.ServerSide; import org.sonarsource.api.sonarlint.SonarLintSide; +import com.google.common.base.Strings; + /** * Implement this interface to register licenses */ @@ -35,19 +39,26 @@ public interface LicenseRegistration { /** * Register set of licenses */ - default void register(Registrar registrar) { } + default void register(Registrar registrar) { + } interface Registrar { /** - * Register customer license for a given permanentID and rules repository + * Register customer license for a given permanentID and rules repository */ @Deprecated - public void registerLicense(String permanentId, String customerName, String salt, String repoName, LicenseType type, - byte[] signature, long expirationDate); + default void registerLicense(String permanentId, String customerName, String salt, String repoName, + LicenseType type, byte[] signature, long expirationDate) { + registerLicense(1, permanentId.replace("sonarlint-", ""), + permanentId.startsWith("sonarlint") ? SonarProduct.SONARLINT : SonarProduct.SONARQUBE, customerName, salt, + repoName, type, signature, expirationDate, 0); + } @Deprecated - public void registerLicense(String permanentId, SonarProduct product, String customerName, String salt, - String repoName, LicenseType type, byte[] signature, long expirationDate); + default void registerLicense(String permanentId, SonarProduct product, String customerName, String salt, + String repoName, LicenseType type, byte[] signature, long expirationDate) { + registerLicense(1, permanentId, product, customerName, salt, repoName, type, signature, expirationDate, 0); + } public void registerLicense(int version, String permanentId, SonarProduct product, String customerName, String salt, String repoName, LicenseType type, byte[] signature, long expirationDate, long lines); @@ -65,18 +76,8 @@ public class License { private String salt; private byte[] signature; - public License(int version, String permanentId, SonarProduct product, String customerName, String salt, String repoName, - LicenseType type, byte[] signature, long expirationDate, long lines) { - this.version = version; - this.permanentId = permanentId; - this.product = product; - this.customerName = customerName; - this.repositoryName = repoName; - this.salt = salt; - this.type = type; - this.signature = signature; - this.expirationDate = expirationDate; - this.lines = lines; + private License() { + // Use Builder pattern } public int getVersion() { @@ -118,9 +119,114 @@ public LicenseType getType() { public long getLines() { return lines; } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + + if (obj == null) + return false; + if (this.getClass() == obj.getClass()) { + License other = (License) obj; + + return customerName.equals(other.customerName) && (product == other.product) + && permanentId.equals(other.permanentId) && repositoryName.equals(other.repositoryName) + && (expirationDate == other.expirationDate) && (salt.equals(other.salt)) && (type == other.type) + && (lines == other.lines); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(customerName, product, permanentId, repositoryName, expirationDate, salt, type, lines); + } + + public static class Builder { + private int version = 1; + private String permanentId = ""; + private String customerName = ""; + private String repositoryName = ""; + private String salt= ""; + private SonarProduct product; + private LicenseType type; + private long expirationDate; + private long lines; + private byte[] signature; + + public Builder setVersion(int version) { + this.version = version; + return this; + } + + public Builder setPermanentId(String permanentId) { + this.permanentId = Strings.nullToEmpty(permanentId); + return this; + } + + public Builder setCustomerName(String customerName) { + this.customerName = Strings.nullToEmpty(customerName); + return this; + } + + public Builder setRepositoryName(String repositoryName) { + this.repositoryName = Strings.nullToEmpty(repositoryName); + return this; + } + + public Builder setSalt(String salt) { + this.salt = Strings.nullToEmpty(salt); + return this; + } + + public Builder setProduct(SonarProduct product) { + this.product = product == null ? SonarProduct.SONARQUBE : product; + return this; + } + + public Builder setType(LicenseType type) { + this.type = type == null ? LicenseType.EVALUATION : type; + return this; + } + + public Builder setExpirationDate(long expirationDate) { + this.expirationDate = expirationDate; + return this; + } + + public Builder setLines(long lines) { + this.lines = lines; + return this; + } + + public Builder setSignature(byte[] signature) { + this.signature = (signature == null) || (signature.length != 256) ? new byte[0] : signature; + return this; + } + + public License build() { + License license = new License(); + license.version = version; + license.permanentId = permanentId; + license.customerName = customerName; + license.repositoryName = repositoryName; + license.salt = salt; + license.product = product; + license.type = type; + license.expirationDate = expirationDate; + license.lines = lines; + license.signature = signature; + + return license; + } + } } public enum LicenseType { - EVALUATION, COMMERCIAL, PARTNER; + EVALUATION, + COMMERCIAL, + PARTNER; } } diff --git a/openedge-plugin/pom.xml b/openedge-plugin/pom.xml index f30ddca8f..6e658e55d 100644 --- a/openedge-plugin/pom.xml +++ b/openedge-plugin/pom.xml @@ -4,7 +4,7 @@ eu.rssw.sonar.openedge sonar-openedge-plugin - 2.12.1 + 2.13.0 sonar-plugin OpenEdge plugin for SonarQube @@ -60,17 +60,17 @@ eu.rssw.openedge.checks openedge-checks - 2.12.1 + 2.13.0 eu.rssw.openedge.parsers listing-parser - 2.12.1 + 2.13.0 eu.rssw.openedge.parsers profiler-parser - 2.12.1 + 2.13.0 commons-io diff --git a/openedge-plugin/src/main/java/org/sonar/plugins/openedge/OpenEdgePlugin.java b/openedge-plugin/src/main/java/org/sonar/plugins/openedge/OpenEdgePlugin.java index 26ba41e60..473c63a37 100644 --- a/openedge-plugin/src/main/java/org/sonar/plugins/openedge/OpenEdgePlugin.java +++ b/openedge-plugin/src/main/java/org/sonar/plugins/openedge/OpenEdgePlugin.java @@ -44,7 +44,6 @@ import org.sonar.plugins.openedge.sensor.OpenEdgeProparseSensor; import org.sonar.plugins.openedge.sensor.OpenEdgeSensor; import org.sonar.plugins.openedge.sensor.OpenEdgeWarningsSensor; -import org.sonar.plugins.openedge.web.OpenEdgeWebService; public class OpenEdgePlugin implements Plugin { private static final String CATEGORY_OPENEDGE = "OpenEdge"; @@ -74,11 +73,6 @@ public void define(Context context) { // Decorators context.addExtensions(CommonMetricsDecorator.class, CommonDBMetricsDecorator.class); - // Web service handler - if (context.getRuntime().getProduct() == SonarProduct.SONARQUBE) { - context.addExtension(OpenEdgeWebService.class); - } - // Properties context.addExtension(PropertyDefinition.builder(Constants.SKIP_RCODE) // .name("Skip rcode parsing") // @@ -90,16 +84,6 @@ public void define(Context context) { .defaultValue(Boolean.FALSE.toString()) // .build()); - context.addExtension(PropertyDefinition.builder(Constants.OE_ANALYTICS) // - .name("Enable analytics") // - .description("Ping remote server for usage analytics") // - .type(PropertyType.BOOLEAN) // - .category(CATEGORY_OPENEDGE) // - .subCategory(SUBCATEGORY_GENERAL) // - .onQualifiers(Qualifiers.PROJECT) // - .defaultValue(Boolean.TRUE.toString()) // - .build()); - context.addExtension(PropertyDefinition.builder(Constants.SKIP_PROPARSE_PROPERTY) // .name("Skip Proparse step") // .description("Don't generate syntax tree and skip lint rules") // diff --git a/openedge-plugin/src/main/java/org/sonar/plugins/openedge/foundation/OpenEdgeComponents.java b/openedge-plugin/src/main/java/org/sonar/plugins/openedge/foundation/OpenEdgeComponents.java index cea95e1e1..441f8a2a0 100644 --- a/openedge-plugin/src/main/java/org/sonar/plugins/openedge/foundation/OpenEdgeComponents.java +++ b/openedge-plugin/src/main/java/org/sonar/plugins/openedge/foundation/OpenEdgeComponents.java @@ -21,9 +21,6 @@ import java.lang.reflect.Field; import java.text.DateFormat; -import java.time.LocalDateTime; -import java.time.ZoneOffset; -import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -31,6 +28,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import org.prorefactor.proparse.antlr4.ProparseListener; import org.sonar.api.SonarProduct; @@ -74,6 +72,7 @@ public class OpenEdgeComponents { private final TreeParserRegistrar parserRegistrar = new TreeParserRegistrar(); private boolean initialized = false; + private String analytics = ""; public OpenEdgeComponents() { this(null, null, null, null); @@ -108,31 +107,19 @@ public OpenEdgeComponents(Server server, CheckRegistration[] checkRegistrars, Li TreeParserRegistration[] tpRegistrars) { this.server = server; if (checkRegistrars != null) { - registerChecks(checkRegistrars); + for (CheckRegistration registration : checkRegistrars) { + registration.register(checkRegistrar); + } } if (licRegistrars != null) { - registerLicences(licRegistrars); + for (LicenseRegistration registration : licRegistrars) { + registration.register(licenseRegistrar); + } } if (tpRegistrars != null) { - registerTreeParser(tpRegistrars); - } - } - - private void registerChecks(CheckRegistration[] registrations) { - for (CheckRegistration registration : registrations) { - registration.register(checkRegistrar); - } - } - - private void registerLicences(LicenseRegistration[] registrations) { - for (LicenseRegistration registration : registrations) { - registration.register(licenseRegistrar); - } - } - - private void registerTreeParser(TreeParserRegistration[] registrations) { - for (TreeParserRegistration registration : registrations) { - registration.register(parserRegistrar); + for (TreeParserRegistration registration : tpRegistrars) { + registration.register(parserRegistrar); + } } } @@ -148,22 +135,14 @@ public License getLicense(SonarProduct product, String permId, String repoName) return licenseRegistrar.getLicense(product, permId, repoName); } - public void initializeLicense(SensorContext context) { - String permId = (context.runtime().getProduct() == SonarProduct.SONARLINT ? "sonarlint-" : "") + getServerId(); - for (License entry : licenseRegistrar.getLicenses()) { - if (permId.equals(entry.getPermanentId())) { - LOG.info("Repository '{}' associated with {} license permanent ID '{}' - Customer '{}' - Expiration date {}", - entry.getRepositoryName(), entry.getType().toString(), entry.getPermanentId(), entry.getCustomerName(), - LocalDateTime.ofEpochSecond(entry.getExpirationDate() / 1000, 0, ZoneOffset.UTC).format( - DateTimeFormatter.ISO_LOCAL_DATE_TIME)); - } - } - } - - public void initializeChecks(SensorContext context) { + public void init(SensorContext context) { if (initialized) return; + initializeChecks(context); + initialized = true; + } + private void initializeChecks(SensorContext context) { String permId = getServerId(); // Proparse and XREF rules @@ -180,8 +159,14 @@ public void initializeChecks(SensorContext context) { dfChecksMap.put(rule, (OpenEdgeDumpFileCheck) lint); } } + } - initialized = true; + public void setAnalytics(String analytics) { + this.analytics = analytics; + } + + public String getAnalytics() { + return analytics; } public Map getProparseRules() { @@ -277,32 +262,12 @@ private static Field getField(Object check, String key) { } public String getServerId() { - if (server == null) - return ""; - - String str = server.getId(); - int dashIndex = str.indexOf('-'); - - return (dashIndex == 8) && (str.length() >= 20) ? str.substring(dashIndex + 1) : str; + return server == null ? "" : server.getId(); } private static class LicenseRegistrar implements LicenseRegistration.Registrar { private final Collection licenses = new ArrayList<>(); - @Override - public void registerLicense(String permanentId, String customerName, String salt, String repoName, - LicenseRegistration.LicenseType type, byte[] signature, long expirationDate) { - registerLicense(1, permanentId.replace("sonarlint-", ""), - permanentId.startsWith("sonarlint") ? SonarProduct.SONARLINT : SonarProduct.SONARQUBE, customerName, salt, - repoName, type, signature, expirationDate, 0); - } - - @Override - public void registerLicense(String permanentId, SonarProduct product, String customerName, String salt, - String repoName, LicenseRegistration.LicenseType type, byte[] signature, long expirationDate) { - registerLicense(1, permanentId, product, customerName, salt, repoName, type, signature, expirationDate, 0); - } - @Override public void registerLicense(int version, String permanentId, SonarProduct product, String customerName, String salt, String repoName, LicenseRegistration.LicenseType type, byte[] signature, long expirationDate, long lines) { @@ -313,8 +278,9 @@ public void registerLicense(int version, String permanentId, SonarProduct produc DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT).format(new Date(expirationDate))); // Only one license per product/ repository / permID License existingLic = hasRegisteredLicense(product, repoName, permanentId); - License newLic = new License(1, permanentId, product, customerName, salt, repoName, type, signature, - expirationDate, lines); + License newLic = new License.Builder().setVersion(version).setPermanentId(permanentId).setProduct( + product).setCustomerName(customerName).setSalt(salt).setRepositoryName(repoName).setType(type).setSignature( + signature).setExpirationDate(expirationDate).setLines(lines).build(); if (existingLic == null) { licenses.add(newLic); } else if (existingLic.getExpirationDate() < newLic.getExpirationDate()) { @@ -342,17 +308,27 @@ private License hasRegisteredLicense(SonarProduct product, String repoName, Stri private License getLicense(SonarProduct product, String permId, String repoName) { if ((permId == null) || (repoName == null)) return null; - for (License lic : licenses) { - if (((lic.getType() == LicenseType.COMMERCIAL) || (lic.getType() == LicenseType.PARTNER)) - && (lic.getProduct() == product) && repoName.equals(lic.getRepositoryName()) - && permId.equals(lic.getPermanentId())) - return lic; - } - for (License lic : licenses) { - if ((lic.getType() == LicenseType.EVALUATION) && (lic.getProduct() == product) - && repoName.equals(lic.getRepositoryName())) - return lic; - } + // TODO Remove this code when old licenses are not used anymore + String miniPermId = (permId.indexOf('-') == 8) && (permId.length() >= 20) + ? permId.substring(permId.indexOf('-') + 1) : permId; + + Optional srch = licenses.stream() // + .filter(lic -> (lic.getType() == LicenseType.COMMERCIAL) || (lic.getType() == LicenseType.PARTNER)) // + .filter(lic -> lic.getProduct() == product) // + .filter(lic -> repoName.equals(lic.getRepositoryName())) // + .filter(lic -> (lic.getVersion() >= 3 && permId.equals(lic.getPermanentId())) + || miniPermId.equals(lic.getPermanentId())).findFirst(); + if (srch.isPresent()) + return srch.get(); + srch = licenses.stream() // + .filter(lic -> lic.getType() == LicenseType.EVALUATION) // + .filter(lic -> lic.getProduct() == product) // + .filter(lic -> repoName.equals(lic.getRepositoryName())) // + .filter(lic -> (lic.getVersion() >= 3 && permId.equals(lic.getPermanentId())) + || miniPermId.equals(lic.getPermanentId())).findFirst(); + if (srch.isPresent()) + return srch.get(); + return null; } } diff --git a/openedge-plugin/src/main/java/org/sonar/plugins/openedge/foundation/OpenEdgeSettings.java b/openedge-plugin/src/main/java/org/sonar/plugins/openedge/foundation/OpenEdgeSettings.java index 04bcfee0a..96112bd47 100644 --- a/openedge-plugin/src/main/java/org/sonar/plugins/openedge/foundation/OpenEdgeSettings.java +++ b/openedge-plugin/src/main/java/org/sonar/plugins/openedge/foundation/OpenEdgeSettings.java @@ -558,15 +558,6 @@ public String getOpenEdgePluginVersion() { return this.oePluginVersion; } - public String getServerId() { - if (server == null) - return ""; - String str = server.getId(); - int dashIndex = str.indexOf('-'); - - return (dashIndex == 8) && (str.length() >= 20) ? str.substring(dashIndex + 1) : str; - } - public String getPropathAsString() { return Joiner.on(',').skipNulls().join(propathFull); } diff --git a/openedge-plugin/src/main/java/org/sonar/plugins/openedge/sensor/OpenEdgeDBRulesSensor.java b/openedge-plugin/src/main/java/org/sonar/plugins/openedge/sensor/OpenEdgeDBRulesSensor.java index a8fe4f85c..104643cb6 100644 --- a/openedge-plugin/src/main/java/org/sonar/plugins/openedge/sensor/OpenEdgeDBRulesSensor.java +++ b/openedge-plugin/src/main/java/org/sonar/plugins/openedge/sensor/OpenEdgeDBRulesSensor.java @@ -59,7 +59,7 @@ public void describe(SensorDescriptor descriptor) { public void execute(SensorContext context) { Map ruleTime = new HashMap<>(); long parseTime = 0L; - components.initializeChecks(context); + components.init(context); for (Map.Entry entry : components.getDumpFileRules().entrySet()) { ruleTime.put(entry.getKey().ruleKey().toString(), 0L); diff --git a/openedge-plugin/src/main/java/org/sonar/plugins/openedge/sensor/OpenEdgeProparseSensor.java b/openedge-plugin/src/main/java/org/sonar/plugins/openedge/sensor/OpenEdgeProparseSensor.java index f076073c1..2c4bd1b31 100644 --- a/openedge-plugin/src/main/java/org/sonar/plugins/openedge/sensor/OpenEdgeProparseSensor.java +++ b/openedge-plugin/src/main/java/org/sonar/plugins/openedge/sensor/OpenEdgeProparseSensor.java @@ -19,7 +19,6 @@ */ package org.sonar.plugins.openedge.sensor; -import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -28,8 +27,6 @@ import java.io.OutputStream; import java.io.PrintWriter; import java.io.UncheckedIOException; -import java.net.HttpURLConnection; -import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -169,8 +166,7 @@ public void execute(SensorContext context) { if (settings.skipProparseSensor()) return; settings.init(); - components.initializeLicense(context); - components.initializeChecks(context); + components.init(context); for (Map.Entry entry : components.getProparseRules().entrySet()) { ruleTime.put(entry.getKey().ruleKey().toString(), 0L); } @@ -203,7 +199,7 @@ public void execute(SensorContext context) { } } - executeAnalytics(context); + computeAnalytics(context); logStatistics(); generateProparseDebugIndex(); } @@ -443,35 +439,12 @@ private void updateParseTime(long elapsedTime) { } } - private void executeAnalytics(SensorContext context) { - if (!settings.useAnalytics()) - return; - - StringBuilder data = new StringBuilder(String.format( // NOSONAR Influx requires LF - "proparse,product=%1$s,sid=%2$s files=%3$d,failures=%4$d,parseTime=%5$d,maxParseTime=%6$d,version=\"%7$s\",ncloc=%8$d,oeversion=\"%9$s\"\n", - context.runtime().getProduct().toString().toLowerCase(), settings.getServerId(), numFiles, numFailures, - parseTime, maxParseTime, context.runtime().getApiVersion().toString(), ncLocs, + private void computeAnalytics(SensorContext context) { + // Store value in OpenEdgeComponents object + components.setAnalytics(String.format( + "files=%1$d,failures=%2$d,parseTime=%3$d,maxParseTime=%4$d,version=\"%5$s\",ncloc=%6$d,oeversion=\"%7$s\"", + numFiles, numFailures, parseTime, maxParseTime, context.runtime().getApiVersion().toString(), ncLocs, settings.getOpenEdgePluginVersion())); - for (Entry entry : ruleTime.entrySet()) { - data.append(String.format("rule,product=%1$s,sid=%2$s,rulename=%3$s ruleTime=%4$d\n", // NOSONAR - context.runtime().getProduct().toString().toLowerCase(), settings.getServerId(), entry.getKey(), - entry.getValue())); - } - - try { - final URL url = new URL("http://sonar-analytics.rssw.eu/write?db=sonar"); - HttpURLConnection connx = (HttpURLConnection) url.openConnection(); - connx.setRequestMethod("POST"); - connx.setConnectTimeout(2000); - connx.setDoOutput(true); - DataOutputStream wr = new DataOutputStream(connx.getOutputStream()); - wr.writeBytes(data.toString()); - wr.flush(); - wr.close(); - connx.getResponseCode(); - } catch (IOException uncaught) { - LOG.debug("Unable to send analytics: {}", uncaught.getMessage()); - } } private void logStatistics() { diff --git a/openedge-plugin/src/main/java/org/sonar/plugins/openedge/web/OpenEdgeWebService.java b/openedge-plugin/src/main/java/org/sonar/plugins/openedge/web/OpenEdgeWebService.java deleted file mode 100644 index f57175fda..000000000 --- a/openedge-plugin/src/main/java/org/sonar/plugins/openedge/web/OpenEdgeWebService.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * OpenEdge plugin for SonarQube - * Copyright (C) 2013-2021 Riverside Software - * contact AT riverside DASH software DOT fr - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.plugins.openedge.web; - -import java.time.LocalDateTime; -import java.time.ZoneOffset; -import java.time.format.DateTimeFormatter; -import java.util.Base64; - -import org.sonar.api.server.ws.Request; -import org.sonar.api.server.ws.RequestHandler; -import org.sonar.api.server.ws.Response; -import org.sonar.api.server.ws.WebService; -import org.sonar.api.utils.text.JsonWriter; -import org.sonar.plugins.openedge.api.LicenseRegistration.License; -import org.sonar.plugins.openedge.foundation.OpenEdgeComponents; - -public class OpenEdgeWebService implements WebService { - private final OpenEdgeComponents components; - - public OpenEdgeWebService(OpenEdgeComponents components) { - this.components = components; - } - - @Override - public void define(Context context) { - NewController controller = context.createController("api/openedge").setDescription("OpenEdge plugin web service"); - controller.createAction("licenses").setDescription("Licenses list").setHandler( - new LicenseRequestHandler()).setSince("2.0.3").setResponseExample( - getClass().getResource("/org/sonar/openedge-licenses-response-example.json")); - controller.done(); - } - - private class LicenseRequestHandler implements RequestHandler { - - @Override - public void handle(Request request, Response response) throws Exception { - try (JsonWriter writer = response.newJsonWriter()) { - writer.beginObject().name("licenses").beginArray(); - for (License lic : components.getLicenses()) { - writer.beginObject() // - .prop("permanentId", lic.getPermanentId()) // - .prop("product", lic.getProduct().toString()) // - .prop("customer", lic.getCustomerName()) // - .prop("repository", lic.getRepositoryName()) // - .prop("type", lic.getType().name()) // - .prop("signature", Base64.getEncoder().encodeToString(lic.getSig())) // - .prop("expiration", LocalDateTime.ofEpochSecond(lic.getExpirationDate() / 1000, 0, ZoneOffset.UTC).format( - DateTimeFormatter.ISO_LOCAL_DATE_TIME)) // - .endObject(); - } - writer.endArray().endObject(); - } - } - } - -} diff --git a/openedge-plugin/src/main/resources/debug-index.html b/openedge-plugin/src/main/resources/debug-index.html index b2aafcf0b..5f12fd3fa 100644 --- a/openedge-plugin/src/main/resources/debug-index.html +++ b/openedge-plugin/src/main/resources/debug-index.html @@ -2,9 +2,9 @@ - - - + + + @@ -12,6 +12,6 @@
- + \ No newline at end of file diff --git a/openedge-plugin/src/main/resources/org/sonar/openedge-licenses-response-example.json b/openedge-plugin/src/main/resources/org/sonar/openedge-licenses-response-example.json deleted file mode 100644 index 627069be7..000000000 --- a/openedge-plugin/src/main/resources/org/sonar/openedge-licenses-response-example.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "licenses": [ - { - "permanentId": "123456789", - "customer": "Riverside Software", - "repository": "rssw-oe-main", - "type": "COMMERCIAL", - "signature": "Base64SignatureHere", - "expiration": "2039-12-31T23:00:00" - }, - { - "permanentId": "sonarlint-123456789", - "customer": "Riverside Software", - "repository": "rssw-oe-main", - "type": "COMMERCIAL", - "signature": "Base64SignatureHere", - "expiration": "2039-12-31T23:00:00" - } - ] -} \ No newline at end of file diff --git a/openedge-plugin/src/test/java/org/sonar/plugins/openedge/OpenEdgePluginTest.java b/openedge-plugin/src/test/java/org/sonar/plugins/openedge/OpenEdgePluginTest.java index 6e8e02cff..49826d097 100644 --- a/openedge-plugin/src/test/java/org/sonar/plugins/openedge/OpenEdgePluginTest.java +++ b/openedge-plugin/src/test/java/org/sonar/plugins/openedge/OpenEdgePluginTest.java @@ -44,14 +44,14 @@ public class OpenEdgePluginTest { public void testExtensionsSonarLint() { Plugin.Context context = new Plugin.Context(SONARLINT_RUNTIME); new OpenEdgePlugin().define(context); - assertEquals(context.getExtensions().size(), 25); + assertEquals(context.getExtensions().size(), 24); } @Test public void testExtensionsSonarQube() { Plugin.Context context = new Plugin.Context(SONARQUBE_RUNTIME); new OpenEdgePlugin().define(context); - assertEquals(context.getExtensions().size(), 30); + assertEquals(context.getExtensions().size(), 28); } } diff --git a/pom.xml b/pom.xml index e675bf34b..985cbb064 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ eu.rssw sonar-openedge pom - 2.12.1 + 2.13.0 OpenEdge plugin for SonarQube http://www.riverside-software.fr/ Open source code analysis for OpenEdge diff --git a/profiler-parser/pom.xml b/profiler-parser/pom.xml index 97a326f8a..ad59f99e0 100644 --- a/profiler-parser/pom.xml +++ b/profiler-parser/pom.xml @@ -4,7 +4,7 @@ eu.rssw.openedge.parsers profiler-parser - 2.12.1 + 2.13.0 OpenEdge profiler output lexer and parser OpenEdge profiler files parser @@ -51,7 +51,7 @@ org.antlr antlr4-runtime - 4.9 + 4.9.2 org.testng @@ -96,7 +96,7 @@ org.antlr antlr4-maven-plugin - 4.9 + 4.9.2 diff --git a/proparse/pom.xml b/proparse/pom.xml index 7360558ea..8db1342a1 100644 --- a/proparse/pom.xml +++ b/proparse/pom.xml @@ -4,7 +4,7 @@ eu.rssw.openedge.parsers proparse - 2.12.1 + 2.13.0 Proparse ABL code parser @@ -55,12 +55,12 @@ eu.rssw.openedge.rcode rcode-reader - 2.12.1 + 2.13.0 org.antlr antlr4-runtime - 4.9 + 4.9.2 org.slf4j @@ -70,7 +70,7 @@ com.google.guava guava - 29.0-jre + 30.1.1-jre com.google.code.gson @@ -91,7 +91,7 @@ javax.xml.bind jaxb-api 2.3.1 - + org.glassfish.jaxb jaxb-runtime @@ -153,7 +153,7 @@ org.antlr antlr4-maven-plugin - 4.9 + 4.9.2 src/main/antlr4/imports diff --git a/proparse/src/main/antlr4/org/prorefactor/proparse/antlr4/Proparse.g4 b/proparse/src/main/antlr4/org/prorefactor/proparse/antlr4/Proparse.g4 index 464407b6b..d3c290fea 100644 --- a/proparse/src/main/antlr4/org/prorefactor/proparse/antlr4/Proparse.g4 +++ b/proparse/src/main/antlr4/org/prorefactor/proparse/antlr4/Proparse.g4 @@ -324,6 +324,7 @@ inclassStatement: | methodStatement | externalProcedureStatement // Only external procedures are accepted | externalFunctionStatement // Only FUNCTION ... IN ... are accepted + | onStatement ; pseudoFunction: @@ -498,6 +499,7 @@ expression: | expression ( EQUAL | EQ | GTORLT | NE | RIGHTANGLE | GTHAN | GTOREQUAL | GE | LEFTANGLE | LTHAN | LTOREQUAL | LE ) expression # expressionComparison | expression ( MATCHES | BEGINS | CONTAINS ) expression # expressionStringComparison | NOT expression # expressionNot + | expression XOR expression # expressionXor | expression AND expression # expressionAnd | expression OR expression # expressionOr | expressionTerm # expressionExprt @@ -987,7 +989,7 @@ classEnd: ; enumStatement: - ENUM typeName2 FLAGS? blockColon + ENUM tn=typeName2 { support.defineEnum($tn.text); } FLAGS? blockColon defEnumStatement+ enumEnd statementEnd @@ -1819,7 +1821,7 @@ varStatementInitialValueArray: ; varStatementInitialValueSub: - TODAY | NOW | TRUE | FALSE | YES | NO | UNKNOWNVALUE | QSTRING | LEXDATE | NUMBER | NULL + TODAY | NOW | TRUE | FALSE | YES | NO | UNKNOWNVALUE | QSTRING | LEXDATE | NUMBER | NULL | expression ; deleteStatement: @@ -2459,7 +2461,7 @@ insertStatement: interfaceStatement: INTERFACE name=typeName2 interfaceInherits? blockColon - { support.defInterface($name.text); } + { support.defineInterface($name.text); } classCodeBlock interfaceEnd statementEnd diff --git a/proparse/src/main/java/org/prorefactor/core/JPNode.java b/proparse/src/main/java/org/prorefactor/core/JPNode.java index 20b6ee49b..27af94346 100644 --- a/proparse/src/main/java/org/prorefactor/core/JPNode.java +++ b/proparse/src/main/java/org/prorefactor/core/JPNode.java @@ -217,7 +217,7 @@ public JPNode firstNaturalChild() { return null; } - /** + /** * @return Last child of the last child of the... */ public JPNode getLastDescendant() { @@ -228,12 +228,21 @@ public JPNode getLastDescendant() { /** * @return First child if there is one, otherwise next sibling + * @deprecated Use JPNode#getNextNode() */ + @Deprecated public JPNode nextNode() { + return getNextNode(); + } + + /** + * @return First child if there is one, otherwise next sibling + */ + public JPNode getNextNode() { return children == null || children.isEmpty() ? getNextSibling() : children.get(0); } - /** + /** * @return Previous sibling if there is one, otherwise parent */ public JPNode getPreviousNode() { diff --git a/proparse/src/main/java/org/prorefactor/core/ProToken.java b/proparse/src/main/java/org/prorefactor/core/ProToken.java index 2080f7a3a..98e1172ef 100644 --- a/proparse/src/main/java/org/prorefactor/core/ProToken.java +++ b/proparse/src/main/java/org/prorefactor/core/ProToken.java @@ -207,19 +207,27 @@ public static boolean isTokenEditableInAB(@Nonnull String str) { if (attrs.isEmpty() || !"_UIB-CODE-BLOCK".equalsIgnoreCase(attrs.get(0))) return false; - if ((attrs.size() >= 3) && "_CUSTOM".equalsIgnoreCase(attrs.get(1)) - && "_DEFINITIONS".equalsIgnoreCase(attrs.get(2))) - return true; - else if ((attrs.size() >= 2) && "_CONTROL".equalsIgnoreCase(attrs.get(1))) - return true; - else if ((attrs.size() == 4) && "_PROCEDURE".equals(attrs.get(1))) - return true; - else if ((attrs.size() == 5) && "_PROCEDURE".equals(attrs.get(1)) && "_FREEFORM".equals(attrs.get(4))) - return true; - else if ((attrs.size() >= 2) && "_FUNCTION".equals(attrs.get(1))) - return true; - - return false; + return (isCustom(attrs) || isEditableControl(attrs) || isEditableFunction(attrs) || isEditableProcedure(attrs)); + } + + private static boolean isEditableProcedure(List attrs) { + if ((attrs.size() < 2) || !"_PROCEDURE".equals(attrs.get(1))) + return false; + return ((attrs.size() == 4) + || ((attrs.size() == 5) && ("_FREEFORM".equals(attrs.get(4)) || "_DB-REQUIRED".equals(attrs.get(4))))); + } + + private static boolean isEditableFunction(List attrs) { + return ((attrs.size() >= 2) && "_FUNCTION".equals(attrs.get(1))); + } + + private static boolean isEditableControl(List attrs) { + return ((attrs.size() >= 2) && "_CONTROL".equals(attrs.get(1))); + } + + private static boolean isCustom(List attrs) { + return ((attrs.size() >= 3) && "_CUSTOM".equalsIgnoreCase(attrs.get(1)) + && ("_DEFINITIONS".equalsIgnoreCase(attrs.get(2)) || "_MAIN-BLOCK".equalsIgnoreCase(attrs.get(2)))); } public ProToken getHiddenBefore() { diff --git a/proparse/src/main/java/org/prorefactor/proparse/InputSource.java b/proparse/src/main/java/org/prorefactor/proparse/InputSource.java index dc250986d..02f6585e8 100644 --- a/proparse/src/main/java/org/prorefactor/proparse/InputSource.java +++ b/proparse/src/main/java/org/prorefactor/proparse/InputSource.java @@ -68,10 +68,6 @@ public InputSource(int sourceNum, String str, int fileIndex, int line, int col) this.nextCol = col; } - public InputSource(int sourceNum, File file, Charset charset, int fileIndex, boolean skipXCode) throws IOException { - this(sourceNum, file, charset, fileIndex, false, skipXCode); - } - public InputSource(int sourceNum, File file, Charset charset, int fileIndex, boolean skipXCode, boolean isPrimary) throws IOException { LOGGER.trace("New InputSource object for file '{}'", file.getName()); this.sourceNum = sourceNum; diff --git a/proparse/src/main/java/org/prorefactor/proparse/JPNodeVisitor.java b/proparse/src/main/java/org/prorefactor/proparse/JPNodeVisitor.java index ba39c6d3f..63a46c4a5 100644 --- a/proparse/src/main/java/org/prorefactor/proparse/JPNodeVisitor.java +++ b/proparse/src/main/java/org/prorefactor/proparse/JPNodeVisitor.java @@ -36,6 +36,7 @@ public class JPNodeVisitor extends ProparseBaseVisitor { private boolean isClass; private boolean isInterface; + private boolean isEnum; private boolean isAbstract; private String className; @@ -52,6 +53,10 @@ public boolean isInterface() { return isInterface; } + public boolean isEnum() { + return isEnum; + } + public boolean isAbstractClass() { return isAbstract; } @@ -292,6 +297,11 @@ public Builder visitExpressionAnd(ExpressionAndContext ctx) { return createTreeFromSecondNode(ctx).setOperator(); } + @Override + public Builder visitExpressionXor(ExpressionXorContext ctx) { + return createTreeFromSecondNode(ctx).setOperator(); + } + @Override public Builder visitExpressionOr(ExpressionOrContext ctx) { return createTreeFromSecondNode(ctx).setOperator(); @@ -741,6 +751,8 @@ public Builder visitChooseOption(ChooseOptionContext ctx) { @Override public Builder visitEnumStatement(EnumStatementContext ctx) { + isEnum = true; + className = ctx.tn.getText(); return createStatementTreeFromFirstNode(ctx); } diff --git a/proparse/src/main/java/org/prorefactor/proparse/Lexer.java b/proparse/src/main/java/org/prorefactor/proparse/Lexer.java index f4e8bfa92..2ac99cff0 100644 --- a/proparse/src/main/java/org/prorefactor/proparse/Lexer.java +++ b/proparse/src/main/java/org/prorefactor/proparse/Lexer.java @@ -87,6 +87,7 @@ public class Lexer implements IPreprocessor { private int currCol; private int currSourceNum; private boolean currMacroExpansion; + private boolean keepProparseDirective = false; private StringBuilder currText = new StringBuilder(); private FilePos prevChar = new FilePos(0, 1, 1, 0); @@ -113,6 +114,7 @@ public class Lexer implements IPreprocessor { // Are we in the middle of a comment? private boolean doingComment; + private boolean doingSingleLineComment; private boolean nestedComment; // Is the current '.' a name dot? (i.e. not followed by whitespace) */ private boolean nameDot; @@ -463,11 +465,8 @@ ProToken whitespace() { ProToken comment() { LOGGER.trace("Entering comment()"); - // Escapes in comments are processed because you can end a comment - // with something dumb like: ~*~/ - // We preserve that text. - // Note that macros are *not* expanded inside comments. - // (See the preprocessor source) + // Escapes in comments are processed because you can end a comment with something dumb like: ~*~/ + // We preserve that text. Note that macros are *not* expanded inside comments. doingComment = true; nestedComment = false; append(); // currChar=='*' @@ -501,10 +500,10 @@ ProToken comment() { ProToken singleLineComment() { LOGGER.trace("Entering singleLineComment()"); - // Single line comments are treated just like regular comments, - // everything till end of line is considered comment - no escape - // character to look after + // Single line comments are treated just like regular comments, everything till end of line is considered comment - + // no escape character to look after doingComment = true; + doingSingleLineComment = true; nestedComment = false; append(); // currChar=='/' @@ -512,6 +511,7 @@ ProToken singleLineComment() { getChar(); if ((currInt == Token.EOF) || (!escapeCurrent && (currChar == '\r' || currChar == '\n'))) { doingComment = false; + doingSingleLineComment = false; return makeToken(ABLNodeType.COMMENT); } else { unEscapedAppend(); @@ -998,14 +998,18 @@ ProToken directive() { String macroType = currText.toString().toLowerCase(); if ("&global-define".startsWith(macroType) && macroType.length() >= 4) { + keepProparseDirective = true; appendToEOL(); + keepProparseDirective = false; // We have to do the define *before* getting next char. macroDefine(Proparse.AMPGLOBALDEFINE); getChar(); return makeToken(ABLNodeType.AMPGLOBALDEFINE); } if ("&scoped-define".startsWith(macroType) && macroType.length() >= 4) { + keepProparseDirective = true; appendToEOL(); + keepProparseDirective = false; // We have to do the define *before* getting next char. macroDefine(Proparse.AMPSCOPEDDEFINE); getChar(); @@ -1246,8 +1250,7 @@ private void laUse() { * We keep a record of discarded escape characters. This is in case the client wants to fetch those and use them. */ private int escape() { - // We may have multiple contiguous discarded characters - // or a new escape sequence. + // We may have multiple contiguous discarded characters or a new escape sequence. if (wasEscape) escapeText += (char) ppCurrChar; else { @@ -1394,12 +1397,16 @@ private int ppGetChar() { ppGetRawChar(); switch (ppCurrChar) { case '\\': - case '~': { - // Escapes are *always* processed, even inside strings and comments. + case '~': + // Backlash is an escape character only on Windows. A switch can turn off this behavior if ((ppCurrChar == '\\') && (prepro.getProparseSettings().getOpSys() == OperatingSystem.WINDOWS) && !prepro.getProparseSettings().useBackslashAsEscape()) { return ppCurrChar; } + // No escape character in single line comments + if (doingSingleLineComment) + return ppCurrChar; + // Escapes are *always* processed, even inside strings and comments. int retChar = escape(); if (retChar == '.') checkForNameDot(); @@ -1407,14 +1414,16 @@ private int ppGetChar() { return retChar; // else do another loop break; - } case '{': // Macros are processed inside strings, but not inside comments. if (doingComment) return ppCurrChar; else { ppMacroReference(); - if ((ppCurrChar == PROPARSE_DIRECTIVE) || (ppCurrChar == INCLUDE_DIRECTIVE)) + // Proparse directives are kept as is within GLOB | SCOP define. In this case, ppCurrChar is still a + // left curly brace, and input source is switched so that the remaining of the directive is returned + // during the next calls to getChar() + if ((ppCurrChar == '{') || (ppCurrChar == PROPARSE_DIRECTIVE) || (ppCurrChar == INCLUDE_DIRECTIVE)) return ppCurrChar; // else do another loop } @@ -1499,15 +1508,23 @@ private void ppMacroReference() { int closingCurly = refTextEnd - 1; if (refText.toLowerCase().startsWith("{&_proparse_") && prepro.getProparseSettings().getProparseDirectives()) { - // Proparse Directive - ppCurrChar = PROPARSE_DIRECTIVE; - // We strip "{&_proparse_", trailing '}', and leading/trailing whitespace - proparseDirectiveText = refText.substring(12, closingCurly).trim(); - // This will be counted as a source whether picked up here or picked - // up as a normal macro ref. - ++sourceCounter; - prepro.getLstListener().macroRef(refPos.line, refPos.col, "_proparse_"); - prepro.getLstListener().macroRefEnd(); + if (keepProparseDirective) { + // We are within a GLOB | SCOP define, so we keep the directive as is + ppCurrChar = '{'; + currentInput = new InputSource(++sourceCounter, refText.substring(1), refPos.file, refPos.line, refPos.col); + currentInclude.addInputSource(currentInput); + prepro.getLstListener().macroRef(refPos.line, refPos.col, "_proparse_"); + } else { + // Proparse Directive + ppCurrChar = PROPARSE_DIRECTIVE; + // We strip "{&_proparse_", trailing '}', and leading/trailing whitespace + proparseDirectiveText = refText.substring(12, closingCurly).trim(); + // This will be counted as a source whether picked up here or picked + // up as a normal macro ref. + ++sourceCounter; + prepro.getLstListener().macroRef(refPos.line, refPos.col, "_proparse_"); + prepro.getLstListener().macroRefEnd(); + } } else if ("{*}".equals(refText)) { // {*} -- all arguments ppNewMacroRef("*", refPos); diff --git a/proparse/src/main/java/org/prorefactor/proparse/support/ParserSupport.java b/proparse/src/main/java/org/prorefactor/proparse/support/ParserSupport.java index f8258a1e6..4cf7dc230 100644 --- a/proparse/src/main/java/org/prorefactor/proparse/support/ParserSupport.java +++ b/proparse/src/main/java/org/prorefactor/proparse/support/ParserSupport.java @@ -54,6 +54,7 @@ public class ParserSupport { private boolean schemaTablePriority = false; private boolean unitIsInterface = false; + private boolean unitIsEnum = false; private boolean allowUnknownMethodCalls = true; private Map funcScopeMap = new HashMap<>(); @@ -167,12 +168,18 @@ public void defineClass(String name) { unitScope.attachTypeInfo(session.getTypeInfo(className)); } - public void defInterface(String name) { + public void defineInterface(String name) { LOG.trace("defineInterface"); unitIsInterface = true; className = ClassFinder.dequote(name); } + public void defineEnum(String name) { + LOG.trace("defineEnum"); + unitIsEnum = true; + className = ClassFinder.dequote(name); + } + public void defTable(String name, SymbolScope.FieldType ttype) { // I think the compiler will only allow table defs at the class/unit scope, // but we don't need to enforce that here. It'll go in the right spot by the @@ -312,6 +319,10 @@ public boolean isInterface() { return unitIsInterface; } + public boolean isEnum() { + return unitIsEnum; + } + public boolean isSchemaTablePriority() { return schemaTablePriority; } diff --git a/proparse/src/main/java/org/prorefactor/treeparser/ParseUnit.java b/proparse/src/main/java/org/prorefactor/treeparser/ParseUnit.java index b0ddb3bd7..fdb3b650d 100644 --- a/proparse/src/main/java/org/prorefactor/treeparser/ParseUnit.java +++ b/proparse/src/main/java/org/prorefactor/treeparser/ParseUnit.java @@ -118,6 +118,7 @@ public class ParseUnit { private boolean isClass; private boolean isInterface; + private boolean isEnum; private boolean isAbstract; private String className; @@ -329,6 +330,7 @@ public void parse() { topNode = (ProgramRootNode) visitor.visit(tree).build(parser.getParserSupport()); isClass = visitor.isClass(); isInterface = visitor.isInterface(); + isEnum = visitor.isEnum(); isAbstract = visitor.isAbstractClass(); className = visitor.getClassName(); @@ -560,6 +562,10 @@ public boolean isInterface() { return isInterface; } + public boolean isEnum() { + return isEnum; + } + public boolean isAbstractClass() { return isAbstract; } diff --git a/proparse/src/main/java/org/prorefactor/treeparser/TreeParserVariableDefinition.java b/proparse/src/main/java/org/prorefactor/treeparser/TreeParserVariableDefinition.java index 0f4e11d4a..2138f7b4b 100644 --- a/proparse/src/main/java/org/prorefactor/treeparser/TreeParserVariableDefinition.java +++ b/proparse/src/main/java/org/prorefactor/treeparser/TreeParserVariableDefinition.java @@ -376,6 +376,11 @@ public void enterExpressionAnd(ExpressionAndContext ctx) { enterExpression(ctx); } + @Override + public void enterExpressionXor(ExpressionXorContext ctx) { + enterExpression(ctx); + } + @Override public void enterExpressionOr(ExpressionOrContext ctx) { enterExpression(ctx); @@ -2042,8 +2047,9 @@ private void defAs(Primative primative, ParserRuleContext ctx) { private void defineInitialValue(Variable var, VarStatementInitialValueContext ctx) { if (ctx.varStatementInitialValueArray() != null) { // Just set initial value to Array, no matter what the values are + var.noteReference(support.getNode(ctx.varStatementInitialValueArray()), ContextQualifier.UPDATING); var.setInitialValue(Variable.CONSTANT_ARRAY); - } else { + } else if (ctx.varStatementInitialValueSub() != null) { VarStatementInitialValueSubContext ctx2 = ctx.varStatementInitialValueSub(); if (ctx2.TODAY() != null) { var.setInitialValue(Variable.CONSTANT_TODAY); @@ -2071,6 +2077,9 @@ private void defineInitialValue(Variable var, VarStatementInitialValueContext ct } } else if (ctx2.LEXDATE() != null) { var.setInitialValue(new Date()); + } else if (ctx2.expression() != null) { + var.setInitialValue(Variable.CONSTANT_EXPRESSION); + var.noteReference(support.getNode(ctx2.expression()), ContextQualifier.UPDATING); } else { var.setInitialValue(Variable.CONSTANT_OTHER); } diff --git a/proparse/src/main/java/org/prorefactor/treeparser/symbols/Variable.java b/proparse/src/main/java/org/prorefactor/treeparser/symbols/Variable.java index cbb2a5e93..4e3022527 100644 --- a/proparse/src/main/java/org/prorefactor/treeparser/symbols/Variable.java +++ b/proparse/src/main/java/org/prorefactor/treeparser/symbols/Variable.java @@ -36,6 +36,7 @@ public class Variable extends Symbol implements Primative { public static final Object CONSTANT_OTHER = new Object(); public static final Object CONSTANT_ARRAY = new Object(); public static final Object CONSTANT_ZERO = new Object(); + public static final Object CONSTANT_EXPRESSION = new Object(); private final Type type; private final List readWriteRefs = new ArrayList<>(); diff --git a/proparse/src/test/java/org/prorefactor/core/BugFixTest.java b/proparse/src/test/java/org/prorefactor/core/BugFixTest.java index 91cae0513..dd9ae28ce 100644 --- a/proparse/src/test/java/org/prorefactor/core/BugFixTest.java +++ b/proparse/src/test/java/org/prorefactor/core/BugFixTest.java @@ -83,8 +83,8 @@ public void setUp() throws IOException, InvalidRCodeException { @AfterTest public void tearDown() throws IOException { PrintWriter writer = new PrintWriter(new File(tempDir, "index.html")); - writer.println(""); - writer.println(""); + writer.println(""); + writer.println(""); writer.println("
"); - writer.println(""); + writer.println(""); writer.close(); } diff --git a/proparse/src/test/java/org/prorefactor/core/JPNodeTest.java b/proparse/src/test/java/org/prorefactor/core/JPNodeTest.java index e7c50e8de..cdd15d173 100644 --- a/proparse/src/test/java/org/prorefactor/core/JPNodeTest.java +++ b/proparse/src/test/java/org/prorefactor/core/JPNodeTest.java @@ -103,8 +103,8 @@ public void setUp() throws IOException, InvalidRCodeException { @AfterTest public void tearDown() throws IOException { PrintWriter writer = new PrintWriter(new File(tempDir, "index.html")); - writer.println(""); - writer.println(""); + writer.println(""); + writer.println(""); writer.println("
"); - writer.println(""); + writer.println(""); writer.close(); } diff --git a/proparse/src/test/java/org/prorefactor/core/ParserTest.java b/proparse/src/test/java/org/prorefactor/core/ParserTest.java index b1c0836a2..1714cbc59 100644 --- a/proparse/src/test/java/org/prorefactor/core/ParserTest.java +++ b/proparse/src/test/java/org/prorefactor/core/ParserTest.java @@ -304,6 +304,15 @@ public void testPackagePrivate() { assertEquals(unit.getTopNode().queryStateHead(ABLNodeType.METHOD).size(), 2); } + @Test + public void testTriggerInClass() { + ParseUnit unit = new ParseUnit(new File(SRC_DIR, "TriggerInClass.cls"), session); + unit.treeParser01(); + assertFalse(unit.hasSyntaxError()); + assertEquals(unit.getTopNode().queryStateHead(ABLNodeType.DEFINE).size(), 1); + assertEquals(unit.getTopNode().queryStateHead(ABLNodeType.METHOD).size(), 1); + } + @Test public void testCreateWidgetPool() { // No widget-pool table, statement is about creating a widget-pool @@ -395,18 +404,21 @@ public void testExpression04() { } @Test - public void testVeryLongMaxK01() { + public void testShortMaxK01() { ParseUnit unit = new ParseUnit(new File(SRC_DIR, "maxk.p"), session); unit.enableProfiler(); unit.parse(); assertFalse(unit.hasSyntaxError()); ParseInfo info = unit.getParseInfo(); - // Not really a unit test, but if max_k is less then 450, then the grammar rules have changed (in a good way) + // Once upon a time, that was a test to see if there were grammar improvements on some specific syntax + // MaxK is the maximum number of lookahead tokens required to decide between two rules. The shortest the number, the + // fastest the parser. An unrelated change on April '21 changed a large maxK to a very small value. Cause is + // unknown and probably related to ANTLR4 internals. Optional decision = Arrays.stream(info.getDecisionInfo()).max( (d1, d2) -> Long.compare(d1.SLL_MaxLook, d2.SLL_MaxLook)); assertTrue(decision.isPresent()); - assertTrue(decision.get().SLL_MaxLook > 90, "MaxK: " + decision.get().SLL_MaxLook + " less than threshold"); + assertTrue(decision.get().SLL_MaxLook < 20, "MaxK: " + decision.get().SLL_MaxLook + " less than threshold"); } @Test @@ -626,6 +638,42 @@ public void testVarStatement12() { assertEquals(unit.getTopNode().queryStateHead().size(), 1); } + @Test + public void testVarStatement13() { + ParseUnit unit = new ParseUnit( + new ByteArrayInputStream("VAR INT a, b, x = a + b, y = a - b, z = x - y.".getBytes()), session); + unit.treeParser01(); + assertFalse(unit.hasSyntaxError()); + assertEquals(unit.getTopNode().queryStateHead().size(), 1); + } + + @Test + public void testVarStatement14() { + ParseUnit unit = new ParseUnit(new ByteArrayInputStream("VAR INT a, b. VAR INT[] x = [ a + b, a - b ].".getBytes()), + session); + unit.treeParser01(); + assertFalse(unit.hasSyntaxError()); + assertEquals(unit.getTopNode().queryStateHead().size(), 2); + } + + @Test + public void testVarStatement15() { + ParseUnit unit = new ParseUnit( + new ByteArrayInputStream("USING Progress.Lang.Object. VAR Object x = NEW Object().".getBytes()), session); + unit.treeParser01(); + assertFalse(unit.hasSyntaxError()); + assertEquals(unit.getTopNode().queryStateHead().size(), 2); + } + + @Test + public void testVarStatement16() { + ParseUnit unit = new ParseUnit(new ByteArrayInputStream("VAR DATETIME dtm = DATETIME(TODAY,MTIME).".getBytes()), + session); + unit.treeParser01(); + assertFalse(unit.hasSyntaxError()); + assertEquals(unit.getTopNode().queryStateHead().size(), 1); + } + @Test public void testDbQualifierSports2000() { // Standard schema, lower-case database name @@ -717,4 +765,15 @@ public void testDbQualifierSP2K() { assertNotNull(rec1.getTableBuffer()); assertEquals(rec1.getTableBuffer().getTargetFullName(), "SP2K.Customer"); } + + @Test + public void testEnum() { + ParseUnit unit = new ParseUnit(new File(SRC_DIR, "enum01.cls"), session); + unit.treeParser01(); + assertFalse(unit.hasSyntaxError()); + assertEquals(unit.getSupport().getClassName(), "rssw.enum01"); + assertTrue(unit.getSupport().isEnum()); + assertEquals(unit.getClassName(), "rssw.enum01"); + assertTrue(unit.isEnum()); + } } diff --git a/proparse/src/test/java/org/prorefactor/core/PreprocessorDirectiveTest.java b/proparse/src/test/java/org/prorefactor/core/PreprocessorDirectiveTest.java index ac6de498a..244e3391c 100644 --- a/proparse/src/test/java/org/prorefactor/core/PreprocessorDirectiveTest.java +++ b/proparse/src/test/java/org/prorefactor/core/PreprocessorDirectiveTest.java @@ -86,9 +86,9 @@ public void test01() { assertFalse(node2.hasProparseDirective("klm")); } - @Test(expectedExceptions = {ParseCancellationException.class}) + @Test public void test02() { - // See issue #341 - Won't fix + // Used to throw an exception, not the case anymore... ParseUnit unit = new ParseUnit(new File(SRC_DIR, "preprocessor07.p"), session); unit.parse(); } diff --git a/proparse/src/test/java/org/prorefactor/core/TreeParser01Test.java b/proparse/src/test/java/org/prorefactor/core/TreeParser01Test.java index 653c61a1c..808c372be 100644 --- a/proparse/src/test/java/org/prorefactor/core/TreeParser01Test.java +++ b/proparse/src/test/java/org/prorefactor/core/TreeParser01Test.java @@ -16,11 +16,13 @@ package org.prorefactor.core; import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; +import java.io.BufferedReader; import java.io.File; +import java.io.FileReader; import java.io.IOException; -import org.apache.commons.io.FileUtils; import org.prorefactor.core.util.AttributedWriter; import org.prorefactor.core.util.UnitTestModule; import org.prorefactor.refactor.RefactorSession; @@ -43,7 +45,15 @@ public void test01() throws IOException { AttributedWriter writer = new AttributedWriter(); writer.write(inName, outFile, session); - assertTrue(FileUtils.contentEquals(new File(expectName), outFile)); + + try (FileReader r1 = new FileReader(expectName); + FileReader r2 = new FileReader(outFile); + BufferedReader br1 = new BufferedReader(r1); + BufferedReader br2 = new BufferedReader(r2)) { + assertTrue(TreeParser02Test.contentEquals(br1, br2)); + } catch (IOException caught) { + fail("Unable to find output file", caught); + } } } diff --git a/proparse/src/test/java/org/prorefactor/core/TreeParser02Test.java b/proparse/src/test/java/org/prorefactor/core/TreeParser02Test.java index 9a2b003ff..863f0e946 100644 --- a/proparse/src/test/java/org/prorefactor/core/TreeParser02Test.java +++ b/proparse/src/test/java/org/prorefactor/core/TreeParser02Test.java @@ -16,11 +16,13 @@ package org.prorefactor.core; import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; +import java.io.BufferedReader; import java.io.File; +import java.io.FileReader; import java.io.IOException; -import org.apache.commons.io.FileUtils; import org.prorefactor.core.util.AttributedWriter; import org.prorefactor.core.util.UnitTestModule; import org.prorefactor.refactor.RefactorSession; @@ -304,7 +306,26 @@ public void test51() throws IOException { private void genericTest(String name) throws IOException { AttributedWriter writer = new AttributedWriter(); writer.write(SOURCEDIR + name, new File(TARGETDIR + name), session); - assertTrue(FileUtils.contentEquals(new File(EXPECTDIR + name), new File(TARGETDIR + name))); + try (FileReader r1 = new FileReader(EXPECTDIR + name); + FileReader r2 = new FileReader(TARGETDIR + name); + BufferedReader br1 = new BufferedReader(r1); + BufferedReader br2 = new BufferedReader(r2)) { + assertTrue(contentEquals(br1, br2)); + } catch (IOException caught) { + fail("Unable to find output file", caught); + } + } + + protected static boolean contentEquals(BufferedReader r1, BufferedReader r2) throws IOException { + String s1 = r1.readLine(); + String s2 = r2.readLine(); + while (s1 != null) { + if (!s1.equals(s2)) + return false; + s1 = r1.readLine(); + s2 = r2.readLine(); + } + + return true; } - } diff --git a/proparse/src/test/java/org/prorefactor/core/TreeParser03Test.java b/proparse/src/test/java/org/prorefactor/core/TreeParser03Test.java index c7f512566..9ea1c96d2 100644 --- a/proparse/src/test/java/org/prorefactor/core/TreeParser03Test.java +++ b/proparse/src/test/java/org/prorefactor/core/TreeParser03Test.java @@ -835,6 +835,156 @@ public void testVarStatement12() { assertEquals(v1.getExtent(), -1); } + @Test + public void testVarStatement13() { + ParseUnit unit = new ParseUnit( + new ByteArrayInputStream("VAR INT a, b, x = a + b, y = a - b, z = x - y.".getBytes()), session); + unit.treeParser01(); + assertFalse(unit.hasSyntaxError()); + assertEquals(unit.getTopNode().queryStateHead().size(), 1); + + assertEquals(unit.getRootScope().getVariables().size(), 5); + Variable varA = null; + Variable varB = null; + Variable varX = null; + Variable varY = null; + Variable varZ = null; + for (Variable var : unit.getRootScope().getVariables()) { + if ("a".equals(var.getName())) + varA = var; + else if ("b".equals(var.getName())) + varB = var; + else if ("x".equals(var.getName())) + varX = var; + else if ("y".equals(var.getName())) + varY = var; + else if ("z".equals(var.getName())) + varZ = var; + } + assertNotNull(varA); + assertEquals(varA.getDataType(), DataType.INTEGER); + assertEquals(varA.getExtent(), -1); + assertEquals(varA.getInitialValue(), null); + assertEquals(varA.getNumReads(), 2); + assertEquals(varA.getNumWrites(), 0); + + assertNotNull(varB); + assertEquals(varB.getDataType(), DataType.INTEGER); + assertEquals(varB.getExtent(), -1); + assertEquals(varB.getInitialValue(), null); + assertEquals(varB.getNumReads(), 2); + assertEquals(varB.getNumWrites(), 0); + + assertNotNull(varX); + assertEquals(varX.getDataType(), DataType.INTEGER); + assertEquals(varX.getExtent(), -1); + assertEquals(varX.getInitialValue(), Variable.CONSTANT_EXPRESSION); + assertEquals(varX.getNumReads(), 1); + assertEquals(varX.getNumWrites(), 1); + + assertNotNull(varY); + assertEquals(varY.getDataType(), DataType.INTEGER); + assertEquals(varY.getExtent(), -1); + assertEquals(varY.getInitialValue(), Variable.CONSTANT_EXPRESSION); + assertEquals(varY.getNumReads(), 1); + assertEquals(varY.getNumWrites(), 1); + + assertNotNull(varZ); + assertEquals(varZ.getDataType(), DataType.INTEGER); + assertEquals(varZ.getExtent(), -1); + assertEquals(varZ.getInitialValue(), Variable.CONSTANT_EXPRESSION); + assertEquals(varZ.getNumWrites(), 1); + } + + @Test + public void testVarStatement14() { + ParseUnit unit = new ParseUnit(new ByteArrayInputStream("VAR INT a, b. VAR INT[] x = [ a + b, a - b ].".getBytes()), + session); + unit.treeParser01(); + assertFalse(unit.hasSyntaxError()); + assertEquals(unit.getTopNode().queryStateHead().size(), 2); + + assertEquals(unit.getRootScope().getVariables().size(), 3); + Variable varA = null; + Variable varB = null; + Variable varX = null; + for (Variable var : unit.getRootScope().getVariables()) { + if ("a".equals(var.getName())) + varA = var; + else if ("b".equals(var.getName())) + varB = var; + else if ("x".equals(var.getName())) + varX = var; + } + assertNotNull(varA); + assertEquals(varA.getDataType(), DataType.INTEGER); + assertEquals(varA.getExtent(), -1); + assertEquals(varA.getInitialValue(), null); + assertEquals(varA.getNumReads(), 2); + assertEquals(varA.getNumWrites(), 0); + + assertNotNull(varB); + assertEquals(varB.getDataType(), DataType.INTEGER); + assertEquals(varB.getExtent(), -1); + assertEquals(varB.getInitialValue(), null); + assertEquals(varB.getNumReads(), 2); + assertEquals(varB.getNumWrites(), 0); + + assertNotNull(varX); + assertEquals(varX.getDataType(), DataType.INTEGER); + assertEquals(varX.getExtent(), 0); + assertEquals(varX.getInitialValue(), Variable.CONSTANT_ARRAY); + assertEquals(varX.getNumReads(), 0); + assertEquals(varX.getNumWrites(), 1); + } + + @Test + public void testVarStatement15() { + ParseUnit unit = new ParseUnit( + new ByteArrayInputStream("USING Progress.Lang.Object. VAR Object x = NEW Object().".getBytes()), session); + unit.treeParser01(); + assertFalse(unit.hasSyntaxError()); + assertEquals(unit.getTopNode().queryStateHead().size(), 2); + + assertEquals(unit.getRootScope().getVariables().size(), 1); + Variable varX = null; + for (Variable var : unit.getRootScope().getVariables()) { + if ("x".equals(var.getName())) + varX = var; + + assertNotNull(varX); + assertEquals(varX.getDataType(), DataType.CLASS); + assertEquals(varX.getClassName(), "Progress.Lang.Object"); + assertEquals(varX.getExtent(), -1); + assertEquals(varX.getInitialValue(), Variable.CONSTANT_EXPRESSION); + assertEquals(varX.getNumReads(), 0); + assertEquals(varX.getNumWrites(), 1); + } + } + + @Test + public void testVarStatement16() { + ParseUnit unit = new ParseUnit(new ByteArrayInputStream("VAR DATETIME dtm = DATETIME(TODAY,MTIME).".getBytes()), + session); + unit.treeParser01(); + assertFalse(unit.hasSyntaxError()); + assertEquals(unit.getTopNode().queryStateHead().size(), 1); + + assertEquals(unit.getRootScope().getVariables().size(), 1); + Variable varX = null; + for (Variable var : unit.getRootScope().getVariables()) { + if ("dtm".equals(var.getName())) + varX = var; + + assertNotNull(varX); + assertEquals(varX.getDataType(), DataType.DATETIME); + assertEquals(varX.getExtent(), -1); + assertEquals(varX.getInitialValue(), Variable.CONSTANT_EXPRESSION); + assertEquals(varX.getNumReads(), 0); + assertEquals(varX.getNumWrites(), 1); + } + } + @Test public void testShorthandOperator01() { ParseUnit unit = new ParseUnit(new ByteArrayInputStream("VAR INT i1. ASSIGN i1 += 1.".getBytes()), session); diff --git a/proparse/src/test/java/org/prorefactor/proparse/ABLLexerTest.java b/proparse/src/test/java/org/prorefactor/proparse/ABLLexerTest.java index 82f4c61c3..d511fd733 100644 --- a/proparse/src/test/java/org/prorefactor/proparse/ABLLexerTest.java +++ b/proparse/src/test/java/org/prorefactor/proparse/ABLLexerTest.java @@ -142,12 +142,13 @@ public void testAnalyzeSuspend() { nextMessageToken(lexer, true, false); nextMessageToken(lexer, true, true); nextMessageToken(lexer, true, false); - nextMessageToken(lexer, true, false); + nextMessageToken(lexer, true, true); nextMessageToken(lexer, true, true); nextMessageToken(lexer, true, false); nextMessageToken(lexer, true, true); nextMessageToken(lexer, true, true); nextMessageToken(lexer, true, true); + nextMessageToken(lexer, true, true); } catch (IOException uncaught) { fail("Unable to open file", uncaught); } @@ -411,10 +412,33 @@ public void testNestedComments() { assertTrue(tok.hasNestedComments()); } + @Test + public void testTilde() { + ABLLexer lexer = new ABLLexer(session, ByteSource.wrap("IF TRUE // W1\\rW2 ~\n THEN MESSAGE \"XXX\".\n ELSE MESSAGE \"YYY\".".getBytes()), "file.txt"); + ProToken tok = firstToken(lexer, ABLNodeType.COMMENT); + assertNotNull(tok); + // Backslash and tildes are not escaped + assertEquals(tok.getText(), "// W1\\rW2 ~"); + tok = (ProToken) lexer.nextToken(); + assertNotNull(tok); + assertEquals(tok.getNodeType(), ABLNodeType.WS); + tok = (ProToken) lexer.nextToken(); + assertNotNull(tok); + assertEquals(tok.getNodeType(), ABLNodeType.THEN); + } + // ********* // Utilities // ********* + private ProToken firstToken(TokenSource lexer, ABLNodeType type) { + ProToken tok = (ProToken) lexer.nextToken(); + while ((tok != null) && (tok.getNodeType() != type)) { + tok = (ProToken) lexer.nextToken(); + } + return tok; + } + private void nextMessageToken(TokenSource lexer, boolean suspend, boolean editable) { ProToken tok = (ProToken) lexer.nextToken(); while (tok.getNodeType() != ABLNodeType.MESSAGE) { diff --git a/proparse/src/test/java/org/prorefactor/proparse/NameDotTokenFilterTest.java b/proparse/src/test/java/org/prorefactor/proparse/NameDotTokenFilterTest.java index 813ac39c4..de6966d8d 100644 --- a/proparse/src/test/java/org/prorefactor/proparse/NameDotTokenFilterTest.java +++ b/proparse/src/test/java/org/prorefactor/proparse/NameDotTokenFilterTest.java @@ -79,7 +79,7 @@ public void testNameDot00() { assertNotNull(tok); assertEquals(tok.getNodeType(), ABLNodeType.PERIOD); } - + @Test public void testNameDot01() { ABLLexer lexer = new ABLLexer(session, ByteSource.wrap("using Riverside.Lang.Object.".getBytes()), "file.txt"); @@ -173,6 +173,25 @@ public void testNameDot04() { assertEquals(tok.getNodeType(), ABLNodeType.EOF_ANTLR4); } + @Test + public void testNameDot05() { + // Still a NAMEDOT if there's a tilde before the dot... + ABLLexer lexer = new ABLLexer(session, ByteSource.wrap("~.Lang.Object.".getBytes()), "file.txt"); + TokenSource filter = new NameDotTokenFilter(lexer.getTokenSource()); + + ProToken tok = (ProToken) filter.nextToken(); + assertNotNull(tok); + assertEquals(tok.getNodeType(), ABLNodeType.NAMEDOT); + assertEquals(tok.getText(), "."); + tok = (ProToken) filter.nextToken(); + assertNotNull(tok); + assertEquals(tok.getNodeType(), ABLNodeType.ID); + assertEquals(tok.getText(), "Lang.Object"); + tok = (ProToken) filter.nextToken(); + assertNotNull(tok); + assertEquals(tok.getNodeType(), ABLNodeType.PERIOD); + } + @Test public void testAnnotation01() { ABLLexer lexer = new ABLLexer(session, ByteSource.wrap("@Riverside.Lang.Object. MESSAGE 'foo'.".getBytes()), "file.txt"); diff --git a/proparse/src/test/java/org/prorefactor/proparse/PostLexerTest.java b/proparse/src/test/java/org/prorefactor/proparse/PostLexerTest.java index f3fded8c0..e053f8d07 100644 --- a/proparse/src/test/java/org/prorefactor/proparse/PostLexerTest.java +++ b/proparse/src/test/java/org/prorefactor/proparse/PostLexerTest.java @@ -646,6 +646,44 @@ public void testEndOfIncInIncludeParameter() { assertEquals(tok.getNodeType(), ABLNodeType.PERIOD); } + @Test + public void test22() { + Injector injector = Guice.createInjector(new UnitTestWindowsModule()); + RefactorSession session = injector.getInstance(RefactorSession.class); + ParseUnit unit = new ParseUnit(new File(SRC_DIR, "lexer22.p"), session); + TokenSource src = unit.preprocess(); + ProToken tok = (ProToken) nextVisibleToken(src); + assertEquals(tok.getNodeType(), ABLNodeType.IF); + tok = (ProToken) nextVisibleToken(src); + assertEquals(tok.getNodeType(), ABLNodeType.TRUE); + tok = (ProToken) nextVisibleToken(src); + assertEquals(tok.getNodeType(), ABLNodeType.THEN); + tok = (ProToken) src.nextToken(); + assertEquals(tok.getNodeType(), ABLNodeType.WS); + tok = (ProToken) src.nextToken(); + assertEquals(tok.getNodeType(), ABLNodeType.PROPARSEDIRECTIVE); + assertEquals(tok.getText(), "prolint-nowarn(use-index)"); + } + + @Test + public void test23() { + Injector injector = Guice.createInjector(new UnitTestWindowsModule()); + RefactorSession session = injector.getInstance(RefactorSession.class); + ParseUnit unit = new ParseUnit(new File(SRC_DIR, "lexer23.p"), session); + TokenSource src = unit.preprocess(); + ProToken tok = (ProToken) nextVisibleToken(src); + assertEquals(tok.getNodeType(), ABLNodeType.IF); + tok = (ProToken) nextVisibleToken(src); + assertEquals(tok.getNodeType(), ABLNodeType.TRUE); + tok = (ProToken) nextVisibleToken(src); + assertEquals(tok.getNodeType(), ABLNodeType.THEN); + tok = (ProToken) src.nextToken(); + assertEquals(tok.getNodeType(), ABLNodeType.WS); + tok = (ProToken) src.nextToken(); + assertEquals(tok.getNodeType(), ABLNodeType.PROPARSEDIRECTIVE); + assertEquals(tok.getText(), "prolint-nowarn(use-index)"); + } + /** * Utility method for tests, returns next node of given type */ diff --git a/proparse/src/test/resources/data/bugsfixed/xor.p b/proparse/src/test/resources/data/bugsfixed/xor.p index 7fd769cb5..116b660de 100644 --- a/proparse/src/test/resources/data/bugsfixed/xor.p +++ b/proparse/src/test/resources/data/bugsfixed/xor.p @@ -1,3 +1,7 @@ DEFINE VARIABLE xx AS OpenEdge.Core.System.ErrorSeverityEnum. +DEFINE VARIABLE zz AS OpenEdge.Core.System.ErrorSeverityEnum. + xx = OpenEdge.Core.System.ErrorSeverityEnum:Critical. MESSAGE xx XOR OpenEdge.Core.System.ErrorSeverityEnum:Critical XOR OpenEdge.Core.System.ErrorSeverityEnum:MESSAGE. +zz = xx XOR OpenEdge.Core.System.ErrorSeverityEnum:Critical XOR OpenEdge.Core.System.ErrorSeverityEnum:MESSAGE. +ASSIGN zz = xx XOR OpenEdge.Core.System.ErrorSeverityEnum:Critical XOR OpenEdge.Core.System.ErrorSeverityEnum:MESSAGE. diff --git a/proparse/src/test/resources/data/lexer/lexer05.p b/proparse/src/test/resources/data/lexer/lexer05.p index e3dc18b4b..54876562e 100644 --- a/proparse/src/test/resources/data/lexer/lexer05.p +++ b/proparse/src/test/resources/data/lexer/lexer05.p @@ -47,3 +47,8 @@ MESSAGE "". // Editable MESSAGE "". &ANALYZE-RESUME + +&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE zzz DataLogicProcedure _DB-REQUIRED +// Editable +MESSAGE "". +&ANALYZE-RESUME diff --git a/proparse/src/test/resources/data/lexer/lexer22.p b/proparse/src/test/resources/data/lexer/lexer22.p new file mode 100644 index 000000000..0715ef47e --- /dev/null +++ b/proparse/src/test/resources/data/lexer/lexer22.p @@ -0,0 +1,2 @@ +&GLOBAL-DEFINE DEF1 IF TRUE THEN {&_proparse_ prolint-nowarn(use-index)} RUN Foo{1}Bar. +{&DEF1} diff --git a/proparse/src/test/resources/data/lexer/lexer23.i b/proparse/src/test/resources/data/lexer/lexer23.i new file mode 100644 index 000000000..f42d4321e --- /dev/null +++ b/proparse/src/test/resources/data/lexer/lexer23.i @@ -0,0 +1 @@ +&GLOBAL-DEFINE DEF2 {&_proparse_ prolint-nowarn(use-index)} RUN Foo{1}Bar. diff --git a/proparse/src/test/resources/data/lexer/lexer23.p b/proparse/src/test/resources/data/lexer/lexer23.p new file mode 100644 index 000000000..22b0af714 --- /dev/null +++ b/proparse/src/test/resources/data/lexer/lexer23.p @@ -0,0 +1,3 @@ +{ lexer/lexer23.i } +&GLOBAL-DEFINE DEF1 IF TRUE THEN {&DEF2}. +{&DEF1} diff --git a/proparse/src/test/resources/data/parser/TriggerInClass.cls b/proparse/src/test/resources/data/parser/TriggerInClass.cls new file mode 100644 index 000000000..d00b86b54 --- /dev/null +++ b/proparse/src/test/resources/data/parser/TriggerInClass.cls @@ -0,0 +1,13 @@ +class package.foobar: + + define private static property prop1 as int64 no-undo get. + + on 'entry':u anywhere do: + // Yes, we can add triggers... + end. + + method private static int64 xxx(zz as int64): + // + end method. + +end class. diff --git a/proparse/src/test/resources/data/parser/enum01.cls b/proparse/src/test/resources/data/parser/enum01.cls new file mode 100644 index 000000000..89b6943f9 --- /dev/null +++ b/proparse/src/test/resources/data/parser/enum01.cls @@ -0,0 +1,4 @@ +enum rssw.enum01: + define enum val1 = 1. + define enum val2 = 2. +end enum. diff --git a/rcode-reader/pom.xml b/rcode-reader/pom.xml index 15550f137..bcf40f556 100644 --- a/rcode-reader/pom.xml +++ b/rcode-reader/pom.xml @@ -4,7 +4,7 @@ eu.rssw.openedge.rcode rcode-reader - 2.12.1 + 2.13.0 rcode-reader rcode reader @@ -49,7 +49,7 @@ com.google.guava guava - 29.0-jre + 30.1.1-jre org.testng