Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

minor: do not check details if checker suppression is unstable #12211

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion .ci/StarterRuleSet-AllRulesByCategory.groovy.txt
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ ruleset {
ImplementationAsType
Instanceof
LocaleSetDefault
NestedForLoop
// Sometimes we need more complex logic, such as fuzzy stirng matching
//NestedForLoop
PrivateFieldCouldBeFinal
PublicInstanceField
ReturnsNullInsteadOfEmptyArray
Expand Down
98 changes: 96 additions & 2 deletions .ci/checker-framework.groovy
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import groovy.transform.EqualsAndHashCode
import groovy.transform.Field
import groovy.transform.Immutable
import groovy.util.slurpersupport.GPathResult
Expand Down Expand Up @@ -382,7 +381,6 @@ private static Set<CheckerFrameworkError> setDifference(final Set<CheckerFramewo
/**
* A class to represent the XML {@code checkerFrameworkError} node.
*/
@EqualsAndHashCode(excludes = ["lineNumber", "unstable"])
@Immutable
class CheckerFrameworkError implements Comparable<CheckerFrameworkError> {

Expand Down Expand Up @@ -473,4 +471,100 @@ class CheckerFrameworkError implements Comparable<CheckerFrameworkError> {
return toXmlString
}

@Override
boolean equals(other) {
if (this.is(other)) {
return true
}

if (getClass() != other.class) {
return false
}

CheckerFrameworkError that = (CheckerFrameworkError) other

boolean isEqualExceptDetails = fileName == that.fileName &&
lineContent == that.lineContent &&
specifier == that.specifier

if (that.isUnstable()) {
// do not compare details for unstable suppression
return isEqualExceptDetails &&
isFuzzyMatch(message, that.message)
romani marked this conversation as resolved.
Show resolved Hide resolved

}

return isEqualExceptDetails &&
message == that.message &&
details == that.details
}

/**
* Compares given strings and returns true if they are similar.
*
* @param stringOne string to compare
* @param stringTwo string to compare
* @return true if two strings are similar by our definition
*/
static boolean isFuzzyMatch(String stringOne, String stringTwo) {
int averageLength = (int) ((stringOne.length() + stringTwo.length()) / 2)
return getFuzzyScore(stringOne, stringTwo) > averageLength / 2
}

/**
* Get "fuzzy score" of two strings.
* Stolen from https://github.com/apache/commons-text.
*
* @param stringOne string to compare
* @param stringTwo string to compare
* @return matching score
*/
static int getFuzzyScore(final CharSequence stringOne, final CharSequence stringTwo) {
if (stringOne == null || stringTwo == null) {
throw new IllegalArgumentException("CharSequences must not be null")
}

// fuzzy logic is case insensitive. We normalize the Strings to lower
// case right from the start.
final String termLowerCase = stringOne.toString().toLowerCase()
final String queryLowerCase = stringTwo.toString().toLowerCase()

// the resulting score
int score = 0

// the position in the stringOne which will be scanned next for potential
// stringTwo character matches
int termIndex = 0

// index of the previously matched character in the stringOne
int previousMatchingCharacterIndex = Integer.MIN_VALUE

for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) {
final char queryChar = queryLowerCase.charAt(queryIndex)

boolean termCharacterMatchFound = false
for (; termIndex < termLowerCase.length()
&& !termCharacterMatchFound; termIndex++) {
final char termChar = termLowerCase.charAt(termIndex)

if (queryChar == termChar) {
// simple character matches result in one point
score++

// subsequent character matches further improve
// the score.
if (previousMatchingCharacterIndex + 1 == termIndex) {
score += 2
}

previousMatchingCharacterIndex = termIndex

// we can leave the nested loop. Every character in the
// stringTwo can match at most one character in the stringOne.
termCharacterMatchFound = true
}
}
}
return score
}
}