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

Add validation for Ordering.explicit() to contain all enum values #14

Merged
merged 2 commits into from
Mar 30, 2021

Conversation

ivan-fedorov
Copy link
Member

According to the Ordering.explicit() documentation it can throw ClassCastException when it receives an input parameter that isn't among the provided values.

So in case when we had such method in a codebase with enum values and after time someone adds new values to that enum we need to make sure that the logic where Ordering.explicit() is used works as expected and include a new value there aswell.

@Stephan202 Stephan202 force-pushed the ivan-fedorov/ordering-explicit-for-enums branch from 668b0b5 to b2a75cc Compare March 28, 2021 16:15
Copy link
Member

@Stephan202 Stephan202 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice. Rebased and added a commit. Suggested commit message:

Flag `Ordering#explicit` invocations listing a subset of an enum's values (#14)

Will merge if you're okay with my changes :)

.map(Name::toString)
.collect(toImmutableSet());

LinkedHashSet<String> enumValues =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
LinkedHashSet<String> enumValues =
Set<String> enumValues =

Comment on lines 45 to 46
if (not(staticMethod().onClass(Ordering.class.getName()).named("explicit"))
.matches(tree, state)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (not(staticMethod().onClass(Ordering.class.getName()).named("explicit"))
.matches(tree, state)) {
if (!staticMethod().onClass(Ordering.class.getName()).named("explicit")
.matches(tree, state)) {

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also: we should move the matcher construction to a static field, so that this isn't repeated for every method invocation.

}

private static boolean isNotEnumType(List<? extends ExpressionTree> arguments) {
return arguments.stream().anyMatch(Predicate.not(arg -> ASTHelpers.getSymbol(arg).isEnum()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return arguments.stream().anyMatch(Predicate.not(arg -> ASTHelpers.getSymbol(arg).isEnum()));
return arguments.stream().anyMatch(arg -> !ASTHelpers.getSymbol(arg).isEnum());

.build();
}

private static boolean isNotEnumType(List<? extends ExpressionTree> arguments) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private static boolean isNotEnumType(List<? extends ExpressionTree> arguments) {
private static boolean containsNonEnumValue(List<? extends ExpressionTree> arguments) {

.collect(toImmutableSet());

LinkedHashSet<String> enumValues =
getTypeSymbolStream(arguments).map(ASTHelpers::enumValues).findFirst().orElseThrow();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making clearer that only one map will be performed:

Suggested change
getTypeSymbolStream(arguments).map(ASTHelpers::enumValues).findFirst().orElseThrow();
getTypeSymbolStream(arguments).findFirst().map(ASTHelpers::enumValues).orElseThrow();

Though then we can just do:

Suggested change
getTypeSymbolStream(arguments).map(ASTHelpers::enumValues).findFirst().orElseThrow();
ASTHelpers.enumValues(getTypeSymbolStream(arguments).findFirst().orElseThrow());

"import java.util.Comparator;",
"",
"enum A {",
" ONE, TWO, THREE",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're using non-AOSP style here, so two space indent :)

"",
"class B {",
" // BUG: Diagnostic contains: Method should include all values from A enum",
" Comparator<A> explicit = Ordering.explicit(A.TWO, A.ONE);",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's also test with statically imported enum values.

Comment on lines 36 to 38
linkType = BugPattern.LinkType.NONE,
severity = BugPattern.SeverityLevel.WARNING,
tags = BugPattern.StandardTags.FRAGILE_CODE)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like in the other classes:

Suggested change
linkType = BugPattern.LinkType.NONE,
severity = BugPattern.SeverityLevel.WARNING,
tags = BugPattern.StandardTags.FRAGILE_CODE)
linkType = LinkType.NONE,
severity = SeverityLevel.WARNING,
tags = StandardTags.FRAGILE_CODE)

Comment on lines 27 to 30
/**
* A {@link BugChecker} which flags that {@link com.google.common.collect.Ordering#explicit(Object,
* Object[])}} for enums does not contain all it's values.
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/**
* A {@link BugChecker} which flags that {@link com.google.common.collect.Ordering#explicit(Object,
* Object[])}} for enums does not contain all it's values.
*/
/**
* A {@link BugChecker} which flags {@link Ordering#explicit(Object, Object[])}} invocations listing
* a subset of an enum type's values.
*/

*/
@AutoService(BugChecker.class)
@BugPattern(
name = "OrderingExplicitMethod",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about:

Suggested change
name = "OrderingExplicitMethod",
name = "ExplicitEnumOrdering",

@Stephan202
Copy link
Member

Build failure is unrelated to this PR; will fix master before merging.

@Stephan202 Stephan202 force-pushed the ivan-fedorov/ordering-explicit-for-enums branch from b2a75cc to 0543be9 Compare March 30, 2021 06:04
@Stephan202 Stephan202 merged commit acfe87f into master Mar 30, 2021
@Stephan202 Stephan202 deleted the ivan-fedorov/ordering-explicit-for-enums branch March 30, 2021 06:19
@Stephan202 Stephan202 added this to the 0.1.0 milestone Apr 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants