IDEA-158203 Allow JPS plugins to be notified when annotations on method return type or parameter types are changed

This commit is contained in:
Eugene Zhuravlev
2016-07-25 15:12:00 +02:00
parent 3b5e89b16e
commit b8f5bde005
8 changed files with 188 additions and 62 deletions
@@ -88,13 +88,13 @@ public class ClassRepr extends Proto {
}
public abstract static class Diff extends Difference {
public abstract Specifier<TypeRepr.AbstractType> interfaces();
public abstract Specifier<TypeRepr.AbstractType, Difference> interfaces();
public abstract Specifier<FieldRepr> fields();
public abstract Specifier<FieldRepr, FieldRepr.Diff> fields();
public abstract Specifier<MethodRepr> methods();
public abstract Specifier<MethodRepr, MethodRepr.Diff> methods();
public abstract Specifier<ElemType> targets();
public abstract Specifier<ElemType, Difference> targets();
public abstract boolean retentionChanged();
@@ -150,22 +150,22 @@ public class ClassRepr extends Proto {
}
@Override
public Difference.Specifier<TypeRepr.AbstractType> interfaces() {
public Difference.Specifier<TypeRepr.AbstractType, Difference> interfaces() {
return Difference.make(pastClass.myInterfaces, myInterfaces);
}
@Override
public Difference.Specifier<FieldRepr> fields() {
public Difference.Specifier<FieldRepr, FieldRepr.Diff> fields() {
return Difference.make(pastClass.myFields, myFields);
}
@Override
public Difference.Specifier<MethodRepr> methods() {
public Difference.Specifier<MethodRepr, MethodRepr.Diff> methods() {
return Difference.make(pastClass.myMethods, myMethods);
}
@Override
public Specifier<ElemType> targets() {
public Specifier<ElemType, Difference> targets() {
return Difference.make(pastClass.myAnnotationTargets, myAnnotationTargets);
}
@@ -29,7 +29,10 @@ import org.jetbrains.org.objectweb.asm.signature.SignatureVisitor;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Array;
import java.util.*;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author: db
@@ -385,7 +388,7 @@ class ClassfileAnalyzer {
processSignature(signature);
return new FieldVisitor(ASM_API_VERSION) {
final List<TypeRepr.ClassType> annotations = new SmartList<TypeRepr.ClassType>();
final Set<TypeRepr.ClassType> annotations = new THashSet<TypeRepr.ClassType>();
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
@@ -413,8 +416,8 @@ class ClassfileAnalyzer {
@Override
public MethodVisitor visitMethod(final int access, final String n, final String desc, final String signature, final String[] exceptions) {
final Ref<Object> defaultValue = Ref.create();
final Collection<TypeRepr.ClassType> annotations = new SmartList<TypeRepr.ClassType>();
final Collection<ParamAnnotation> paramAnnotations = new SmartList<ParamAnnotation>();
final Set<TypeRepr.ClassType> annotations = new THashSet<TypeRepr.ClassType>();
final Set<ParamAnnotation> paramAnnotations = new THashSet<ParamAnnotation>();
processSignature(signature);
return new MethodVisitor(ASM_API_VERSION) {
@@ -43,21 +43,22 @@ abstract class Difference {
public static final int SIGNATURE = 8;
public static final int SUPERCLASS = 16;
public static final int USAGES = 32;
public static final int ANNOTATIONS = 64;
public interface Specifier<T> {
public interface Specifier<T, D extends Difference> {
Collection<T> added();
Collection<T> removed();
Collection<Pair<T, Difference>> changed();
Collection<Pair<T, D>> changed();
boolean unchanged();
}
public static <T> Specifier<T> make(final Set<T> past, final Set<T> now) {
public static <T, D extends Difference> Specifier<T, D> make(final Set<T> past, final Set<T> now) {
if (past == null) {
final Collection<T> _now = Collections.unmodifiableCollection(now);
return new Specifier<T>() {
return new Specifier<T, D>() {
public Collection<T> added() {
return _now;
}
@@ -66,7 +67,7 @@ abstract class Difference {
return Collections.emptyList();
}
public Collection<Pair<T, Difference>> changed() {
public Collection<Pair<T, D>> changed() {
return Collections.emptyList();
}
@@ -84,9 +85,9 @@ abstract class Difference {
removed.removeAll(now);
final Set<Pair<T, Difference>> changed;
final Set<Pair<T, D>> changed;
if (canContainChangedElements(past, now)) {
changed = new HashSet<Pair<T, Difference>>();
changed = new HashSet<Pair<T, D>>();
final Set<T> intersect = new HashSet<T>(past);
final Map<T, T> nowMap = new HashMap<T, T>();
@@ -101,7 +102,8 @@ abstract class Difference {
for (T x : intersect) {
final Proto px = (Proto)x;
final Proto py = (Proto)nowMap.get(x);
final Difference diff = py.difference(px);
//noinspection unchecked
final D diff = (D)py.difference(px);
if (!diff.no()) {
changed.add(Pair.create(x, diff));
@@ -112,7 +114,7 @@ abstract class Difference {
changed = Collections.emptySet();
}
return new Specifier<T>() {
return new Specifier<T, D>() {
public Collection<T> added() {
return added;
}
@@ -121,7 +123,7 @@ abstract class Difference {
return removed;
}
public Collection<Pair<T, Difference>> changed() {
public Collection<Pair<T, D>> changed() {
return changed;
}
@@ -21,7 +21,6 @@ import org.jetbrains.annotations.NotNull;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.List;
import java.util.Set;
/**
@@ -39,7 +38,7 @@ class FieldRepr extends ProtoMember {
final int descriptor,
final int signature,
@NotNull
final List<TypeRepr.ClassType> annotations, final Object value) {
final Set<TypeRepr.ClassType> annotations, final Object value) {
super(access, signature, name, TypeRepr.getType(context, descriptor), annotations, value);
}
@@ -25,6 +25,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.builders.storage.BuildDataCorruptedException;
import org.jetbrains.jps.incremental.storage.FileKeyDescriptor;
import org.jetbrains.jps.service.JpsServiceManager;
import org.jetbrains.org.objectweb.asm.ClassReader;
import org.jetbrains.org.objectweb.asm.Opcodes;
@@ -954,6 +955,9 @@ public class Mappings {
final boolean myEasyMode; // true means: no need to search for affected files, only preprocess data for integrate
private final Iterable<MemberAnnotationsChangeTracker> myAnnotationChangeTracker =
JpsServiceManager.getInstance().getExtensions(MemberAnnotationsChangeTracker.class);
private class DelayedWorks {
class Triple {
final int owner;
@@ -1055,9 +1059,9 @@ public class Mappings {
final public Set<UsageRepr.AnnotationUsage> myAnnotationQuery = new HashSet<UsageRepr.AnnotationUsage>();
final public Map<UsageRepr.Usage, Util.UsageConstraint> myUsageConstraints = new HashMap<UsageRepr.Usage, Util.UsageConstraint>();
final Difference.Specifier<ClassRepr> myClassDiff;
final Difference.Specifier<ClassRepr, ClassRepr.Diff> myClassDiff;
private DiffState(Difference.Specifier<ClassRepr> classDiff) {
private DiffState(Difference.Specifier<ClassRepr, ClassRepr.Diff> classDiff) {
this.myClassDiff = classDiff;
}
}
@@ -1395,7 +1399,7 @@ public class Mappings {
}
private void processChangedMethods(final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) {
final Collection<Pair<MethodRepr, Difference>> changed = diff.methods().changed();
final Collection<Pair<MethodRepr, MethodRepr.Diff>> changed = diff.methods().changed();
if (changed.isEmpty()) {
return;
}
@@ -1404,9 +1408,9 @@ public class Mappings {
assert myFuture != null;
assert myAffectedFiles != null;
for (final Pair<MethodRepr, Difference> mr : changed) {
for (final Pair<MethodRepr, MethodRepr.Diff> mr : changed) {
final MethodRepr m = mr.first;
final MethodRepr.Diff d = (MethodRepr.Diff)mr.second;
final MethodRepr.Diff d = mr.second;
final boolean throwsChanged = !d.exceptions().unchanged();
debug("Method: ", m.name);
@@ -1427,7 +1431,7 @@ public class Mappings {
boolean affected = false;
boolean constrained = false;
final Set<UsageRepr.Usage> usages = new HashSet<UsageRepr.Usage>();
final Set<UsageRepr.Usage> usages = new THashSet<UsageRepr.Usage>();
if (d.packageLocalOn()) {
debug("Method became package-private, affecting method usages outside the package");
@@ -1463,6 +1467,7 @@ public class Mappings {
}
state.myAffectedUsages.addAll(usages);
affected = true;
}
}
else if ((d.base() & Difference.ACCESS) > 0) {
@@ -1473,6 +1478,7 @@ public class Mappings {
debug("Added static or private specifier or removed static specifier --- affecting method usages");
myFuture.affectMethodUsages(m, propagated, m.createUsage(myContext, it.name), usages, state.myDependants);
state.myAffectedUsages.addAll(usages);
affected = true;
}
if ((d.addedModifiers() & Opcodes.ACC_STATIC) > 0) {
@@ -1494,15 +1500,38 @@ public class Mappings {
if (!affected) {
myFuture.affectMethodUsages(m, propagated, m.createUsage(myContext, it.name), usages, state.myDependants);
state.myAffectedUsages.addAll(usages);
affected = true;
}
for (final UsageRepr.Usage usage : usages) {
state.myUsageConstraints.put(usage, myFuture.new InheritanceConstraint(it.name));
}
constrained = true;
}
}
}
}
if ((!affected || constrained) && (d.base() & Difference.ANNOTATIONS) > 0) {
final Difference.Specifier<TypeRepr.ClassType, Difference> annotationsDiff = d.annotations();
final Difference.Specifier<ParamAnnotation, Difference> paramAnnotationsDiff = d.parameterAnnotations();
for (MemberAnnotationsChangeTracker extension : myAnnotationChangeTracker) {
final MemberAnnotationsChangeTracker.Action action = extension.methodAnnotationsChanged(m, annotationsDiff, paramAnnotationsDiff);
if (action == MemberAnnotationsChangeTracker.Action.RECOMPILE_USAGES) {
debug("Extension "+extension.getClass().getName()+" requested recompilation because of changes in annotations list --- affecting method usages");
myFuture.affectMethodUsages(m, propagated, m.createUsage(myContext, it.name), usages, state.myDependants);
state.myAffectedUsages.addAll(usages);
if (constrained) {
// remove any constraints so that all usages of this method are recompiled
for (UsageRepr.Usage usage : usages) {
state.myUsageConstraints.remove(usage);
}
}
affected = true;
break;
}
}
}
}
}
debug("End of changed methods processing");
@@ -1646,15 +1675,15 @@ public class Mappings {
}
private boolean processChangedFields(final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) {
final Collection<Pair<FieldRepr, Difference>> changed = diff.fields().changed();
final Collection<Pair<FieldRepr, FieldRepr.Diff>> changed = diff.fields().changed();
if (changed.isEmpty()) {
return true;
}
debug("Processing changed fields:");
assert myFuture != null;
for (final Pair<FieldRepr, Difference> f : changed) {
final Difference d = f.second;
for (final Pair<FieldRepr, FieldRepr.Diff> f : changed) {
final FieldRepr.Diff d = f.second;
final FieldRepr field = f.first;
debug("Field: ", field.name);
@@ -1684,11 +1713,13 @@ public class Mappings {
if (d.base() != Difference.NONE) {
final TIntHashSet propagated = myFuture.propagateFieldAccess(field.name, it.name);
boolean affected = false;
if ((d.base() & Difference.TYPE) > 0 || (d.base() & Difference.SIGNATURE) > 0) {
debug("Type or signature changed --- affecting field usages");
myFuture
.affectFieldUsages(field, propagated, field.createUsage(myContext, it.name), state.myAffectedUsages, state.myDependants);
affected = true;
}
else if ((d.base() & Difference.ACCESS) > 0) {
if ((d.addedModifiers() & Opcodes.ACC_STATIC) > 0 ||
@@ -1698,10 +1729,10 @@ public class Mappings {
debug("Added/removed static modifier or added private/volatile modifier --- affecting field usages");
myFuture
.affectFieldUsages(field, propagated, field.createUsage(myContext, it.name), state.myAffectedUsages, state.myDependants);
affected = true;
}
else {
boolean affected = false;
final Set<UsageRepr.Usage> usages = new HashSet<UsageRepr.Usage>();
final Set<UsageRepr.Usage> usages = new THashSet<UsageRepr.Usage>();
if ((d.addedModifiers() & Opcodes.ACC_FINAL) > 0) {
debug("Added final modifier --- affecting field assign usages");
@@ -1715,6 +1746,7 @@ public class Mappings {
if (!affected) {
myFuture.affectFieldUsages(field, propagated, field.createUsage(myContext, it.name), usages, state.myDependants);
state.myAffectedUsages.addAll(usages);
affected = true;
}
for (final UsageRepr.Usage usage : usages) {
@@ -1728,6 +1760,26 @@ public class Mappings {
}
}
}
if (!affected && (d.base() & Difference.ANNOTATIONS) > 0) {
final Difference.Specifier<TypeRepr.ClassType, Difference> annotationsDiff = d.annotations();
for (MemberAnnotationsChangeTracker extension : myAnnotationChangeTracker) {
final MemberAnnotationsChangeTracker.Action action = extension.fieldAnnotationsChanged(field, annotationsDiff);
if (action == MemberAnnotationsChangeTracker.Action.RECOMPILE_USAGES) {
debug("Extension "+extension.getClass().getName()+" requested recompilation because of changes in annotations list --- affecting field usages");
final Set<UsageRepr.Usage> usages = new THashSet<UsageRepr.Usage>();
myFuture.affectFieldUsages(field, propagated, field.createUsage(myContext, it.name), usages, state.myDependants);
state.myAffectedUsages.addAll(usages);
// remove any constraints to ensure all field usages are recompiled
for (UsageRepr.Usage usage : usages) {
state.myUsageConstraints.remove(usage);
}
affected = true;
break;
}
}
}
}
}
debug("End of changed fields processing");
@@ -1736,7 +1788,7 @@ public class Mappings {
}
private boolean processChangedClasses(final DiffState state) {
final Collection<Pair<ClassRepr, Difference>> changedClasses = state.myClassDiff.changed();
final Collection<Pair<ClassRepr, ClassRepr.Diff>> changedClasses = state.myClassDiff.changed();
if (!changedClasses.isEmpty()) {
debug("Processing changed classes:");
assert myFuture != null;
@@ -1744,9 +1796,9 @@ public class Mappings {
final Util.FileFilterConstraint fileFilterConstraint = myFilter != null? myPresent.new FileFilterConstraint(myFilter) : null;
for (final Pair<ClassRepr, Difference> changed : changedClasses) {
for (final Pair<ClassRepr, ClassRepr.Diff> changed : changedClasses) {
final ClassRepr changedClass = changed.first;
final ClassRepr.Diff diff = (ClassRepr.Diff)changed.second;
final ClassRepr.Diff diff = changed.second;
myDelta.addChangedClass(changedClass.name);
@@ -2154,7 +2206,7 @@ public class Mappings {
final File fileName = compiledFile.myFileName;
final Set<ClassRepr> classes = compiledFile.myFileClasses;
final Set<ClassRepr> pastClasses = (Set<ClassRepr>)mySourceFileToClasses.get(fileName);
final DiffState state = new DiffState(Difference.make(pastClasses, classes));
final DiffState state = new DiffState(Difference.<ClassRepr, ClassRepr.Diff>make(pastClasses, classes));
if (!processChangedClasses(state)) {
if (!myEasyMode) {
@@ -0,0 +1,36 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jps.builders.java.dependencyView;
/**
* @author Eugene Zhuravlev
* Date: 25-Jul-16
*/
public abstract class MemberAnnotationsChangeTracker {
public enum Action {
NO_ACTION, RECOMPILE_USAGES;
}
public abstract Action methodAnnotationsChanged(
MethodRepr method,
Difference.Specifier<TypeRepr.ClassType, Difference> annotationsDiff,
Difference.Specifier<ParamAnnotation, Difference> paramAnnotationsDiff
);
public abstract Action fieldAnnotationsChanged(FieldRepr field, Difference.Specifier<TypeRepr.ClassType, Difference> annotationsDiff);
}
@@ -15,7 +15,6 @@
*/
package org.jetbrains.jps.builders.java.dependencyView;
import com.intellij.util.SmartList;
import com.intellij.util.io.DataExternalizer;
import com.intellij.util.io.DataInputOutputUtil;
import gnu.trove.THashSet;
@@ -27,7 +26,10 @@ import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.PrintStream;
import java.util.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Set;
/**
* @author: db
@@ -39,12 +41,15 @@ class MethodRepr extends ProtoMember {
boolean satisfy(MethodRepr m);
}
public final Collection<ParamAnnotation> myParameterAnnotations;
public final Set<ParamAnnotation> myParameterAnnotations;
public final TypeRepr.AbstractType[] myArgumentTypes;
public final Set<TypeRepr.AbstractType> myExceptions;
public abstract class Diff extends Difference {
public abstract Specifier<TypeRepr.AbstractType> exceptions();
public static abstract class Diff extends ProtoMember.Diff {
public abstract Specifier<ParamAnnotation, Difference> parameterAnnotations();
public abstract Specifier<TypeRepr.AbstractType, Difference> exceptions();
public abstract boolean defaultAdded();
@@ -52,11 +57,24 @@ class MethodRepr extends ProtoMember {
}
@Override
public Difference difference(final Proto past) {
public Diff difference(final Proto past) {
final MethodRepr m = (MethodRepr)past;
final Difference diff = super.difference(past);
final Difference.Specifier<TypeRepr.AbstractType> excs = Difference.make(((MethodRepr)past).myExceptions, myExceptions);
final Difference.Specifier<TypeRepr.AbstractType, Difference> excs = Difference.make(m.myExceptions, myExceptions);
final Difference.Specifier<TypeRepr.ClassType, Difference> annotations = Difference.make(m.myAnnotations, myAnnotations);
final Difference.Specifier<ParamAnnotation, Difference> paramAnnotations = Difference.make(m.myParameterAnnotations, myParameterAnnotations);
return new Diff() {
@Override
public Specifier<TypeRepr.ClassType, Difference> annotations() {
return annotations;
}
@Override
public Specifier<ParamAnnotation, Difference> parameterAnnotations() {
return paramAnnotations;
}
@Override
public int addedModifiers() {
return diff.addedModifiers();
@@ -69,27 +87,28 @@ class MethodRepr extends ProtoMember {
@Override
public boolean no() {
return base() == NONE && !defaultAdded() && !defaultRemoved() && excs.unchanged();
return base() == NONE && !defaultAdded() && !defaultRemoved() && excs.unchanged() && paramAnnotations.unchanged();
}
@Override
public boolean defaultAdded() {
return hasValue() && !((MethodRepr)past).hasValue();
return hasValue() && !m.hasValue();
}
@Override
public boolean defaultRemoved() {
return !hasValue() && ((MethodRepr)past).hasValue();
return !hasValue() && m.hasValue();
}
@Override
public Specifier<TypeRepr.AbstractType> exceptions() {
public Specifier<TypeRepr.AbstractType, Difference> exceptions() {
return excs;
}
@Override
public int base() {
return diff.base();
final int base = diff.base();
return paramAnnotations.unchanged()? base : base | Difference.ANNOTATIONS;
}
@Override
@@ -99,7 +118,7 @@ class MethodRepr extends ProtoMember {
@Override
public boolean hadValue() {
return ((MethodRepr)past).hasValue();
return m.hasValue();
}
@Override
@@ -128,7 +147,7 @@ class MethodRepr extends ProtoMember {
final int name,
final int signature,
final String descriptor,
final Collection<TypeRepr.ClassType> annotations, Collection<ParamAnnotation> parameterAnnotations, final String[] exceptions,
final Set<TypeRepr.ClassType> annotations, Set<ParamAnnotation> parameterAnnotations, final String[] exceptions,
final Object defaultValue) {
super(accessFlags, signature, name, TypeRepr.getType(context, Type.getReturnType(descriptor)), annotations, defaultValue);
myParameterAnnotations = parameterAnnotations;
@@ -149,7 +168,7 @@ class MethodRepr extends ProtoMember {
myExceptions = (Set<TypeRepr.AbstractType>)RW.read(externalizer, new THashSet<TypeRepr.AbstractType>(0), in);
final DataExternalizer<TypeRepr.ClassType> clsTypeExternalizer = TypeRepr.classTypeExternalizer(context);
myParameterAnnotations = RW.read(new DataExternalizer<ParamAnnotation>() {
myParameterAnnotations = (Set<ParamAnnotation>)RW.read(new DataExternalizer<ParamAnnotation>() {
@Override
public void save(@NotNull DataOutput out, ParamAnnotation value) throws IOException {
value.save(out);
@@ -158,7 +177,7 @@ class MethodRepr extends ProtoMember {
public ParamAnnotation read(@NotNull DataInput in) throws IOException {
return new ParamAnnotation(clsTypeExternalizer, in);
}
}, new SmartList<ParamAnnotation>(), in);
}, new THashSet<ParamAnnotation>(), in);
}
catch (IOException e) {
throw new BuildDataCorruptedException(e);
@@ -15,8 +15,8 @@
*/
package org.jetbrains.jps.builders.java.dependencyView;
import com.intellij.util.SmartList;
import com.intellij.util.io.DataInputOutputUtil;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.builders.storage.BuildDataCorruptedException;
@@ -27,7 +27,7 @@ import java.io.DataOutput;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Set;
/**
* @author: db
@@ -38,7 +38,7 @@ abstract class ProtoMember extends Proto {
@NotNull
public final TypeRepr.AbstractType myType;
@NotNull
public final Collection<TypeRepr.ClassType> myAnnotations;
public final Set<TypeRepr.ClassType> myAnnotations;
public final Object myValue;
private static abstract class DataDescriptor<T> {
@@ -201,7 +201,7 @@ abstract class ProtoMember extends Proto {
@NotNull
final TypeRepr.AbstractType t,
@NotNull
Collection<TypeRepr.ClassType> annotations,
Set<TypeRepr.ClassType> annotations,
final Object value) {
super(access, signature, name);
myType = t;
@@ -214,7 +214,7 @@ abstract class ProtoMember extends Proto {
try {
myType = TypeRepr.externalizer(context).read(in);
myValue = loadTyped(in);
myAnnotations = RW.read(TypeRepr.classTypeExternalizer(context), new SmartList<TypeRepr.ClassType>(), in);
myAnnotations = (Set<TypeRepr.ClassType>)RW.read(TypeRepr.classTypeExternalizer(context), new THashSet<TypeRepr.ClassType>(), in);
}
catch (IOException e) {
throw new BuildDataCorruptedException(e);
@@ -278,7 +278,11 @@ abstract class ProtoMember extends Proto {
RW.save(myAnnotations, out);
}
public Difference difference(final Proto past) {
public abstract static class Diff extends Difference {
public abstract Specifier<TypeRepr.ClassType, Difference> annotations();
}
public Diff difference(final Proto past) {
final ProtoMember m = (ProtoMember)past;
final Difference diff = super.difference(past);
int base = diff.base();
@@ -287,6 +291,12 @@ abstract class ProtoMember extends Proto {
base |= Difference.TYPE;
}
final Difference.Specifier<TypeRepr.ClassType, Difference> annotations = Difference.make(m.myAnnotations, myAnnotations);
if (!annotations.unchanged()) {
base |= Difference.ANNOTATIONS;
}
switch ((myValue == null ? 0 : 1) + (m.myValue == null ? 0 : 2)) {
case 3:
if (!myValue.equals(m.myValue)) {
@@ -308,7 +318,12 @@ abstract class ProtoMember extends Proto {
final int newBase = base;
return new Difference() {
return new Diff() {
@Override
public Specifier<TypeRepr.ClassType, Difference> annotations() {
return annotations;
}
@Override
public int base() {
return newBase;