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

Issue #13672: Kill mutation for FileImportControl #13760

Merged
merged 1 commit into from
Oct 5, 2023

Conversation

Kevin222004
Copy link
Contributor

@Kevin222004 Kevin222004 commented Sep 21, 2023

Issue #13672: Kill mutation for FileImportControl

Mutation

<mutation unstable="false">
<sourceFile>FileImportControl.java</sourceFile>
<mutatedClass>com.puppycrawl.tools.checkstyle.checks.imports.FileImportControl</mutatedClass>
<mutatedMethod>&lt;init&gt;</mutatedMethod>
<mutator>org.pitest.mutationtest.engine.gregor.mutators.experimental.ArgumentPropagationMutator</mutator>
<description>replaced call to com/puppycrawl/tools/checkstyle/checks/imports/FileImportControl::encloseInGroup with argument</description>
<lineContent>this.name = encloseInGroup(name);</lineContent>
</mutation>

Explaination

This constructor

/* package */ FileImportControl(PkgImportControl parent, String name, boolean regex) {
super(parent, MismatchStrategy.DELEGATE_TO_PARENT);
this.regex = regex;
if (regex) {
this.name = encloseInGroup(name);

is used called only at line 185
else if (FILE_ELEMENT_NAME.equals(qName)) {
final String name = safeGet(attributes, NAME_ATTRIBUTE_NAME);
final boolean regex = containsRegexAttribute(attributes);
final PkgImportControl parentImportControl = (PkgImportControl) stack.peek();
final AbstractImportControl importControl = new FileImportControl(parentImportControl,
name, regex);

so this elseif statment will execute in case

 <file name="InputImportControl.*" regex="true">
    <disallow class="java.awt.Image"/>
  </file>

where we have file know encloseInGroup is used to non-capture the group I have done some research at
https://stackoverflow.com/questions/3512471/what-is-a-non-capturing-group-in-regular-expressions

@Kevin222004
Copy link
Contributor Author

In explanation, I have only mentioned where it is used. And tried to understand the significance of it but i don't understand why the reason to do this. Please let me know what value this will create

@romani
Copy link
Member

romani commented Sep 24, 2023

hmm, example of "file" tag https://checkstyle.org/checks/imports/importcontrol.html#ImportControl
search <file name=".*(Panel|View|Dialog)" regex="true">

this commit when it was added and example:
e018b2d#diff-b5d1e8bded0094bbf387cf531f3785057bf87530c8f73a637214fecf1a30a50cR170

So pitest does not see coverage for "non-capturing group"

https://stackoverflow.com/a/3513858/1015848

But we put whole regexp in non captured, this strange as it iliminates a purpose of it, as we need sibling group to make meaningful.

@romani
Copy link
Member

romani commented Sep 25, 2023

@rnveach , do you remember why you used non captured group as wrapper?

I don't see that wrapping non-captured whole content make all nested groups as non-captured
https://regex101.com/r/aL1e8T/1 , see details panel.

@romani
Copy link
Member

romani commented Sep 25, 2023

pitest blocks failed due to crash of pitest execution.

imports pitest has:

 <suppressedMutations>
+  <mutation unstable="false">
+    <sourceFile>FileImportControl.java</sourceFile>
+    <mutatedClass>com.puppycrawl.tools.checkstyle.checks.imports.FileImportControl</mutatedClass>
+    <mutatedMethod>&lt;init&gt;</mutatedMethod>
+    <mutator>org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF</mutator>
+    <description>removed conditional - replaced equality check with true</description>
+    <lineContent>if (regex) {</lineContent>
+  </mutation>

we need test where <file name="Dialog.java" regex="false">, this is highly unlikely users will use as hardcoding absolute path is very non-portable solution. if there will be problems to kill mutation by such test, I am ok with pure unit test for this edge case.

@rnveach
Copy link
Member

rnveach commented Sep 26, 2023

@rnveach , do you remember why you used non captured group as wrapper?

What code are you talking about? I am not following.

* @return a grouped pattern.
*/
private static String encloseInGroup(String expression) {
return "(?:" + expression + ")";
Copy link
Member

Choose a reason for hiding this comment

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

@rnveach , This code.

If we don't remember why we did this, we will remove it

Copy link
Member

Choose a reason for hiding this comment

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

The comment above its call says ensure that fullPackage is a self-contained regular expression.

You had to search a bit more in the commit you found.
https://github.com/checkstyle/checkstyle/blob/master/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/PkgImportControl.java#L155-L156 was renamed from ImportControl, and then from PkgControl before that, and that is where the code originally came from. I did not add it.

It appears the code really came from 63e8c1d#diff-f68bc4c425df6a25439881dbcd97576b489f7d71fc7706a450e11a101f0d3e77R148-R149 .
#2999

Some things of interest:
#3438 (comment)
#3438 (comment)
#3438 (comment)

Copy link
Member

Choose a reason for hiding this comment

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

Ok, thanks a lot, after reading all of this, there is no special reason of such code.

Last reason could be performance, as regexp does not need do creation of group. But as we wrap whole regexp it is does not guarantee that all nested groups will be downgraded to non-captured groups.

I am ok to remove this method.

Copy link
Member

Choose a reason for hiding this comment

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

@romani

(?:.*(Panel|View|Dialog))

What happens when the regexp changes to .*(Panel|View|Dialog)? Since this now a capturing group, will it cause any issues?

Copy link
Member

Choose a reason for hiding this comment

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

If no code deals with group, no changes.
We do not use group, we just match, true or false.

Copy link
Member

@rnveach rnveach Sep 26, 2023

Choose a reason for hiding this comment

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

@romani To me the following lines explain why we need encloseInGroup.

* "org.uncommon"}. Without the grouping it would be {@code "com|org.common|uncommon"} which
* would match {@code "com"}, {@code "org.common"}, and {@code "uncommon"}, which clearly is
* undesirable. Adding the group fixes this.

Apparently we concat 2 regexps together and without the enclosing () we would create a very different and wrong regexp than with it. We can't rely on the users adding () themselves and we enclose it in a () in case they don't.

Unless you are saying the javadoc is out of date, and we would need proof of that.

Combination code is at:

final String parentRegex = ensureSelfContainedRegex(parent.fullPackageName,
parent.regex);
final String thisRegex = ensureSelfContainedRegex(subPackageName, regex);
fullPackageName = parentRegex + DOT_REGEX + thisRegex;

Edit: I was concentrating too much on PkgImportControl.

Copy link
Member

Choose a reason for hiding this comment

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

Since this PR is only for FileImportControl, it doesn't do any combination of 2 regexps. The field it assigns is private, so we won't be passing this field to anywhere outside this class.

So yes, it is ok that we remove this.

Copy link
Member

Choose a reason for hiding this comment

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

If no code deals with group, no changes.
We do not use group

Or if we do not combine 2 regexps.

Copy link
Member

Choose a reason for hiding this comment

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

@Kevin222004 , please investigate. Looks like we found a way to make it to work not as expected if we remove such code.

Copy link
Member

Choose a reason for hiding this comment

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

@romani #13760 (comment) . I also approved this PR as I think the code removal is fine.

Copy link
Member

@romani romani left a comment

Choose a reason for hiding this comment

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

Ok to merge

@romani
Copy link
Member

romani commented Sep 26, 2023

@Kevin222004 , please resolve pitest failure:
https://github.com/checkstyle/checkstyle/actions/runs/6266904570/job/17100922604?pr=13760


 <suppressedMutations>
+  <mutation unstable="false">
+    <sourceFile>FileImportControl.java</sourceFile>
+    <mutatedClass>com.puppycrawl.tools.checkstyle.checks.imports.FileImportControl</mutatedClass>
+    <mutatedMethod>&lt;init&gt;</mutatedMethod>
+    <mutator>org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator_EQUAL_IF</mutator>
+    <description>removed conditional - replaced equality check with true</description>
+    <lineContent>if (regex) {</lineContent>
+  </mutation>
+

Please prepare PR for merge.

Copy link
Member

@romani romani left a comment

Choose a reason for hiding this comment

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

See reason above

Copy link
Member

@rnveach rnveach left a comment

Choose a reason for hiding this comment

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

It seems to me we could remove name completely, and transfer everything to patternForExactMatch. We would just have to sanitize name that we put into patternForExactMatch if it is not regexp.

@romani
Copy link
Member

romani commented Oct 1, 2023

@Kevin222004 , please resolve a conflict.

Let us know if you donot know how to resolve this survival, so mentors will look closer.

name is used at:


I do not think we can easily remove it.

to kill mutation on if regex, we need to have:
<allow class="java\..*\.File" regex="true"/>
and
<allow class="java\..*\.File" regex="false"/>

@@ -43,26 +42,8 @@ class FileImportControl extends AbstractImportControl {
*/
/* package */ FileImportControl(PkgImportControl parent, String name, boolean regex) {
super(parent, MismatchStrategy.DELEGATE_TO_PARENT);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the constructor. so after loading all the configuration and setup when visitToken in ImportControl

currentImportControl = root.locateFinest(packageName, fileName);

after executing this statement
public AbstractImportControl locateFinest(String forPkg, String forFileName) {

after this method
protected boolean matchesExactly(String pkg, String fileName) {
final boolean result;
if (fileName == null) {
result = false;
}
else if (regex) {
result = patternForExactMatch.matcher(fileName).matches();
}
else {
result = name.equals(fileName);
}
return result;
}

where we already check that if regex is true or not so that's why replacing this

if (regex) {
this.name = encloseInGroup(name);
patternForExactMatch = createPatternForExactMatch(this.name);
}
else {
this.name = name;
patternForExactMatch = null;
}

if as true will not make any affect.
The only usage of this field is at
else if (regex) {
result = patternForExactMatch.matcher(fileName).matches();
}

so we can remove this field and directly initialize that in method it will not make any issue

Copy link
Member

@romani romani left a comment

Choose a reason for hiding this comment

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

Items

Copy link
Member

@romani romani left a comment

Choose a reason for hiding this comment

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

Ok to merge

@romani romani requested review from Vyom-Yadav and removed request for nrmancuso October 2, 2023 04:32
@romani romani assigned Vyom-Yadav and unassigned romani Oct 2, 2023
@romani romani merged commit a47f896 into checkstyle:master Oct 5, 2023
112 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants