Skip to content

IdentifierName: accept regex to exempt type name violations #4842

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import com.sun.tools.javac.code.Symbol.VarSymbol;
import com.sun.tools.javac.util.Name;
import java.util.Optional;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import javax.inject.Inject;
Expand Down Expand Up @@ -103,10 +104,14 @@ public final class IdentifierName extends BugChecker

private final boolean allowInitialismsInTypeName;

private final Pattern allowRegexInTypeName;

@Inject
IdentifierName(ErrorProneFlags flags) {
this.allowInitialismsInTypeName =
flags.getBoolean("IdentifierName:AllowInitialismsInTypeName").orElse(false);
this.allowRegexInTypeName =
Pattern.compile(flags.get("IdentifierName:AllowRegexInTypeName").orElse(".+"));
}

@Override
Expand Down Expand Up @@ -294,7 +299,9 @@ private static boolean isConformantLowerCamelName(String name) {
private boolean isConformantTypeName(String name) {
return !name.contains("_")
&& isUpperCase(name.charAt(0))
&& (allowInitialismsInTypeName || !PROBABLE_INITIALISM.matcher(name).find());
&& (allowInitialismsInTypeName
|| allowRegexInTypeName.matcher(name).matches()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

AllowInitialismsInTypeName reads and works approximately like "allow initialisms [when they occur within a] type name". Similarly, AllowRegexInTypeName reads approximately like "allow [this] regex [when it matches within a] type name." However, I've used the anchored matches() instead of the unanchored find() and that makes me think that either

  1. the option name and this placement are incorrect, or
  2. matches() is incorrect.

When I imagine how I would reason about this functionality, I arrive at "a simple-name that satisfies this pattern should be allowed, even when it would have been rejected". That mental model seems to interact with the fewest other rules and therefore be the simplest and easiest to reason about, but it can also be a blanket pass to ignore every other defined rule and that may be too much flexibility. In any case, to accurately implement that mental model

  1. the new regex should be the first thing we matches(), and only on failure should we proceed to the original checks.
  2. the regex's current fallback match-anything pattern would have to change, perhaps just into a presence/absence form.
  3. the name should probably not use the word "in", which can imply find()-semantics, but be something more like AllowTypeNameMatchingRegex.

A completely different approach is to parameterize PROBABLE_INITIALISM with ~its current value as the default. That grants maximal flexibility, but my objective with this proposal is not to bypass or challenge the styleguide's definition of camel case, only to provide what amounts to a high-level suppression mechanic. I think parameterizing PROBABLE_INITIALISM would be a fair bit more difficult to build and to use, and would grant an escape hatch that is too wide.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For demonstration, a version that more faithfully matches my mental model: master...commonquail:error-prone:identifiername-allow-class-regex-harder. If I had to explain to somebody how this worked, that's the version I would rather explain.

|| !PROBABLE_INITIALISM.matcher(name).find());
}

private static boolean isStaticVariable(Symbol symbol) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,21 @@ public void className_underscore() {
.doTest();
}

@Test
public void className_badPattern_allowed() {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

  • Name?
  • Explicit positive case?
  • Interaction with other rules?

helper
.setArgs("-XepOpt:IdentifierName:AllowRegexInTypeName=.+(IT|MX?Bean)")
.addSourceLines(
"SomethingMBean.java", //
"interface SomethingMBean {",
"}")
.addSourceLines(
"SomethingIT.java", //
"class SomethingIT {",
"}")
.doTest();
}

@Test
public void enumName() {
helper
Expand Down