Skip to content

Commit

Permalink
Release 3.6.0, HAPI 6.10.2, fixes for build warnings (#1318)
Browse files Browse the repository at this point in the history
* Prep for release 3.6.0, fix some build warnings

* Fixup formatting

* Fixes for identifier hiding

* Fixes for Android not having all the 11 APIs
  • Loading branch information
JPercival authored Jan 19, 2024
1 parent a6875a0 commit c1da431
Show file tree
Hide file tree
Showing 17 changed files with 1,693 additions and 317 deletions.
5 changes: 5 additions & 0 deletions Src/java/.vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,23 @@
"bools",
"Bryn",
"checkstyle",
"Codeable",
"Codesystem",
"cqframework",
"datumedge",
"fhir",
"fhirpath",
"hamcrest",
"Inferencing",
"Instancio",
"JAXB",
"modelinfo",
"Objenesis",
"opdef",
"opencds",
"qicore",
"Randomizer",
"redeclaration",
"testng",
"tngtech",
"trackback",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ tasks.withType(JavaCompile).configureEach {

tasks {
compileTestJava {
// TODO: Talk to the team about warnings in tests
options.errorprone.disableAllWarnings = true
options.errorprone.disableWarningsInGeneratedCode = true
}
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
/**
* Simple POJO using for identifier hider that maintains the identifier and Trackable type of the construct being evaluated.
*/
public class HidingIdentifierContext {
public class IdentifierContext {
private final String identifier;
private final Class<? extends Trackable> elementSubclass;

public HidingIdentifierContext(String identifier, Class<? extends Trackable> elementSubclass) {
public IdentifierContext(String identifier, Class<? extends Trackable> elementSubclass) {
this.identifier = identifier;
this.elementSubclass = elementSubclass;
}
Expand All @@ -32,7 +32,7 @@ public boolean equals(Object other) {
if (other == null || getClass() != other.getClass()) {
return false;
}
HidingIdentifierContext that = (HidingIdentifierContext) other;
IdentifierContext that = (IdentifierContext) other;
return Objects.equals(identifier, that.identifier) && Objects.equals(elementSubclass, that.elementSubclass);
}

Expand All @@ -43,7 +43,7 @@ public int hashCode() {

@Override
public String toString() {
return new StringJoiner(", ", HidingIdentifierContext.class.getSimpleName() + "[", "]")
return new StringJoiner(", ", IdentifierContext.class.getSimpleName() + "[", "]")
.add("identifier='" + identifier + "'")
.add("elementSubclass=" + elementSubclass)
.toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
* Created by Bryn on 12/29/2016.
*/
public class LibraryBuilder {
public static enum SignatureLevel {
public enum SignatureLevel {
/*
Indicates signatures will never be included in operator invocations
*/
Expand Down Expand Up @@ -116,7 +116,8 @@ public LibraryManager getLibraryManager() {
private final Stack<String> expressionContext = new Stack<>();
private final ExpressionDefinitionContextStack expressionDefinitions = new ExpressionDefinitionContextStack();
private final Stack<FunctionDef> functionDefs = new Stack<>();
private final Deque<HidingIdentifierContext> hidingIdentifiersContexts = new ArrayDeque<>();
private final Deque<IdentifierContext> globalIdentifiers = new ArrayDeque<>();
private final Stack<Deque<IdentifierContext>> localIdentifierStack = new Stack<>();
private int literalContext = 0;
private int typeSpecifierContext = 0;
private final NamespaceInfo namespaceInfo;
Expand Down Expand Up @@ -3127,6 +3128,11 @@ private DataType getExpressionDefResultType(ExpressionDef expressionDef) {
currentExpressionContext(), expressionDef.getContext()));
}

public enum IdentifierScope {
GLOBAL,
LOCAL
}

/**
* Add an identifier to the deque to indicate that we are considering it for consideration for identifier hiding and
* adding a compiler warning if this is the case.
Expand All @@ -3140,46 +3146,93 @@ private DataType getExpressionDefResultType(ExpressionDef expressionDef) {
* <p/>
* Also, special case function overloads so that only a single overloaded function name is taken into account.
*
* Default scope is {@link IdentifierScope#LOCAL}
*
* @param identifier The identifier belonging to the parameter, expression, function, alias, etc, to be evaluated.
* @param trackable The construct trackable, for example {@link ExpressionRef}.
*/
void pushIdentifierForHiding(String identifier, Trackable trackable) {
final boolean hasRelevantMatch = hidingIdentifiersContexts.stream()
.filter(innerContext -> innerContext.getIdentifier().equals(identifier))
.peek(matchedContext -> {
// If we are passing an overloaded function definition, do not issue a warning
if (trackable instanceof FunctionDef
&& FunctionDef.class == matchedContext.getTrackableSubclass()) {
return;
}
void pushIdentifier(String identifier, Trackable trackable) {
pushIdentifier(identifier, trackable, IdentifierScope.LOCAL);
}

reportWarning(
resolveWarningMessage(matchedContext.getIdentifier(), identifier, trackable), trackable);
})
.findAny()
.isPresent();
/**
* Add an identifier to the deque to indicate that we are considering it for consideration for identifier hiding and
* adding a compiler warning if this is the case.
* <p/>
* For example, if an alias within an expression body has the same name as a parameter, execution would have
* added the parameter identifier and the next execution would consider an alias with the same name, thus resulting
* in a warning.
* <p/>
* Exact case matching as well as case-insensitive matching are considered. If known, the type of the structure
* in question will be considered in crafting the warning message, as per the {@link Element} parameter.
* <p/>
* Also, special case function overloads so that only a single overloaded function name is taken into account.
*
* @param identifier The identifier belonging to the parameter, expression, function, alias, etc, to be evaluated.
* @param trackable The construct trackable, for example {@link ExpressionRef}.
* @param scope the scope of the current identifier
*/
void pushIdentifier(String identifier, Trackable trackable, IdentifierScope scope) {
var localMatch = !localIdentifierStack.isEmpty()
? findMatchingIdentifierContext(localIdentifierStack.peek(), identifier)
: Optional.<IdentifierContext>empty();
var globalMatch = findMatchingIdentifierContext(globalIdentifiers, identifier);

if (globalMatch.isPresent() || localMatch.isPresent()) {
var matchedContext = globalMatch.isPresent() ? globalMatch.get() : localMatch.get();

boolean matchedOnFunctionOverloads =
matchedContext.getTrackableSubclass().equals(FunctionDef.class) && trackable instanceof FunctionDef;

if (!matchedOnFunctionOverloads) {
reportWarning(resolveWarningMessage(matchedContext.getIdentifier(), identifier, trackable), trackable);
}
}

// We will only add function definitions once
if (!(trackable instanceof FunctionDef) || !hasRelevantMatch) {
if (shouldPushHidingContext(trackable)) {
final Class<? extends Trackable> trackableOrNull = trackable != null ? trackable.getClass() : null;
// Sometimes the underlying Trackable doesn't resolve in the calling code
hidingIdentifiersContexts.push(
new HidingIdentifierContext(identifier, trackable != null ? trackable.getClass() : null));
if (shouldAddIdentifierContext(trackable)) {
final Class<? extends Trackable> trackableOrNull = trackable != null ? trackable.getClass() : null;
// Sometimes the underlying Trackable doesn't resolve in the calling code
if (scope == IdentifierScope.GLOBAL) {
globalIdentifiers.push(new IdentifierContext(identifier, trackableOrNull));
} else {
localIdentifierStack.peek().push(new IdentifierContext(identifier, trackableOrNull));
}
}
}

private Optional<IdentifierContext> findMatchingIdentifierContext(
Collection<IdentifierContext> identifierContext, String identifier) {
return identifierContext.stream()
.filter(innerContext -> innerContext.getIdentifier().equals(identifier))
.findFirst();
}

/**
* Pop the last resolved identifier off the deque. This is needed in case of a context in which an identifier
* falls out of scope, for an example, an alias within an expression or function body
* falls out of scope, for an example, an alias within an expression or function body.
*/
void popIdentifierForHiding() {
hidingIdentifiersContexts.pop();
void popIdentifier() {
popIdentifier(IdentifierScope.LOCAL);
}

void popIdentifier(IdentifierScope scope) {
if (scope == IdentifierScope.GLOBAL) {
globalIdentifiers.pop();
} else {
localIdentifierStack.peek().pop();
}
}

void pushIdentifierScope() {
localIdentifierStack.push(new ArrayDeque<>());
}

void popIdentifierScope() {
localIdentifierStack.pop();
}

// TODO: consider other structures that should only trigger a readonly check of identifier hiding
private boolean shouldPushHidingContext(Trackable trackable) {
private boolean shouldAddIdentifierContext(Trackable trackable) {
return !(trackable instanceof Literal);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
import static org.cqframework.cql.cql2elm.matchers.QuickDataType.quickDataType;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertEquals;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.cqframework.cql.cql2elm.CqlCompilerOptions;
import org.cqframework.cql.cql2elm.CqlTranslator;
import org.cqframework.cql.cql2elm.LibraryBuilder.SignatureLevel;
import org.cqframework.cql.cql2elm.TestUtils;
import org.cqframework.cql.cql2elm.model.CompiledLibrary;
import org.hl7.elm.r1.*;
Expand Down Expand Up @@ -323,4 +325,11 @@ public void testRetrieveWithConcept() throws IOException {
ToList toList = (ToList) retrieve.getCodes();
assertThat(toList.getOperand(), instanceOf(CodeRef.class));
}

@Test
public void testExm108IdentifierHiding() throws IOException {
var translator = TestUtils.runSemanticTest("fhir/r4/exm108/EXM108.cql", 0, SignatureLevel.All);
// Should only be one identifier being hid after fixes, "Warafin"
assertEquals(1, translator.getExceptions().size());
}
}
Loading

0 comments on commit c1da431

Please sign in to comment.