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