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
muzzle field and method matching #422
muzzle field and method matching #422
Conversation
51cfe37
to
c1ec598
Compare
17f343f
to
4087187
Compare
53be9dc
to
0cbef2d
Compare
log.debug( | ||
"Instrumentation muzzled: {} -- {} on {}", | ||
instrumentationPrimaryName, | ||
this.getClass().getName(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this this
es would get wiped out by our current IDEA config - but I guess not by gradle formatter
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removing for consistency.
} finally { | ||
findLoadedClassMethod.setAccessible(false); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wasn 't the plan to remove these methods to avoid Java10 problems?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, I brought that back when I resolved a merge conflict. I forgot that we intentionally removed it.
3441638
to
50ed54c
Compare
import java.util.HashSet; | ||
import java.util.List; | ||
import java.util.Set; | ||
import net.bytebuddy.jar.asm.Opcodes; | ||
import net.bytebuddy.jar.asm.Type; | ||
|
||
/** An immutable reference to a jvm class. */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This didn't change in this PR, but this is not really 'immutable' because as far as I can see it uses mutable collections.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reference's immutability is more of a convention than a strict enforcement. I'd like to address this in another "cleanup" PR for easier reviewing.
@@ -79,7 +80,7 @@ public Reference merge(Reference anotherReference) { | |||
|
|||
return new Reference( | |||
merge(sources, anotherReference.sources), | |||
merge(flags, anotherReference.flags), | |||
mergeFlags(flags, anotherReference.flags), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method has TODO in it, was that TODO meant to be addressed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
merge(fields, anotherReference.fields),
merge(methods, anotherReference.methods)
these two lines below simply merge sets. Code in withField
and withMethod
does 'deep merging'. Is this expected? If so - could you please consider adding comment explaining why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Merging should be a deep merge. Fixing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The TODO in flag merging is an optimization. No need to check for PRIVATE_OR_HIGHER
if PUBLIC
is already being checked.
@@ -195,111 +175,361 @@ String getMismatchDetails() { | |||
return "Missing class " + className; | |||
} | |||
} | |||
|
|||
public static class MissingFlag extends Mismatch { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would have been very useful if classes had javadoc describing their meaning.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@@ -195,111 +175,361 @@ String getMismatchDetails() { | |||
return "Missing class " + className; | |||
} | |||
} | |||
|
|||
public static class MissingFlag extends Mismatch { | |||
final Flag expectedFlag; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like majority (all?) fields on Mismatches can be made final.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
public ReferenceCheckError( | ||
Exception e, Reference referenceBeingChecked, ClassLoader classLoaderBeingChecked) { | ||
super(new Source[0]); | ||
this.referenceCheckExcetpion = e; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: Exception
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this looks very good. I've left a few comments, but some of them are just typos and others are just suggestions to improve design a little bit.
|
||
@Override | ||
public boolean matches(int asmFlags) { | ||
return (Opcodes.ACC_PUBLIC & asmFlags) != 0 || (Opcodes.ACC_PROTECTED & asmFlags) != 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of repeating (Opcodes.ACC_PUBLIC & asmFlags) != 0
you could consider using PUBLIC.matches
NON_STATIC, | ||
INTERFACE, | ||
NON_INTERFACE | ||
public enum Flag { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think overall this whole file is quite large now and covers multiple concerns which makes it harder to read. You may want consider splitting 'helper' classes like this one into a separate package.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea. I'll save that for a cleanup PR.
Source[] sources, Flag[] flags, String name, Type returnType, Type[] parameterTypes) { | ||
this( | ||
new HashSet<>(Arrays.asList(sources)), | ||
new HashSet<>(Arrays.asList(flags)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This implementation makes instances mutable. Is there any reason not to:
- Use Guava immutable containers
- Use actual container types (lists) as inputs, not arrays:
ImmutableList.of(value1, value1)
is quite convenient.
@Override | ||
public String toString() { | ||
// <init>()V | ||
// toString()Ljava/lang/String; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this comment meant to be here? If so, I'm not sure I can follow the meaning of it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That should have been removed.
} | ||
} | ||
return true; | ||
return toString().equals(o.toString()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please add a comment outlining why this is a valid way of comparing these objects?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactored the code to make it cleaner.
.withFlag(computeMinimumClassAccess(refSourceType, paramType)) | ||
.build()); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like some copy-paste is going on here and there might be an opportunity for some helper methods - see comments above.
@@ -56,7 +63,7 @@ public boolean matches(final ClassLoader loader) { | |||
// Don't reference-check helper classes. | |||
// They will be injected by the instrumentation's HelperInjector. | |||
if (!helperClassNames.contains(reference.getClassName())) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is slightly unclear: wouldn't this prevent references of helper classes from being checked as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, just the helper class itself won't be checked. Any reference created by the helper will be checked.
} | ||
} | ||
if (typeOnClasspath.getSuperClass() != null) { | ||
FieldDescription.InDefinedShape fieldOnSupertype = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't this see private fields on super type as local private fields which is probably wrong?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but then an access mismatch will be raised. I think a mismatched access error is clearer than a missing field error. I'll add a comment explaining that.
return methodOnSupertype; | ||
} | ||
} | ||
return null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be to large extent the same logic as findField
- which goes back to my previous comment this there might be an opportunity to refactor things so field
and method
are joined into one 'member' type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That might be best long-term, but for now I don't see much benefit of joining the two types.
} | ||
} | ||
return null | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are these helpers needed? From the looks of it in current implementation Set's .get
should do exactly the same
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO It makes the test code easier to read.
Plus misc cleanup.
Thanks for the review! Cleanup feedback backlogged and other feedback addressed.
merged.set(i, merged.get(i).merge(field)); | ||
} | ||
} | ||
return new HashSet<>(merged); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an odd way of merging sets, that also may be slow. Would you consider using something like new HashSet<>(Sets.union(fields2, fields1))
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I see now why this has been done this way, please ignore that comment
Merging to integration branch.
Add new muzzle checks:
With these changes muzzle can now check everything
classLoaderHasClasses
can check. There's still work to be done to hook up the version scan plugin, update the version ranges, and remove classLoaderHas* checks. That work will go into a later PR against the same integration branch.