when parsing signatures, create GenericBoundUsage only for classes mentioned in signature bounds;

mark dependencies caused by GenericBoundUsage only in chunk being compiled and all chunks that depend on it recursively
This commit is contained in:
Eugene Zhuravlev
2015-08-10 11:54:35 +02:00
parent d759f0fd1e
commit 2e2d02473d
6 changed files with 158 additions and 54 deletions

View File

@@ -1,8 +1,10 @@
Cleaning output files:
out/production/ChangeExtends/Super.class
out/production/ChangeExtends/Super2.class
End of files
Compiling files:
src/Super.java
src/Super2.java
End of files
Cleaning output files:
out/production/ChangeExtends/Client.class
@@ -13,4 +15,4 @@ Compiling files:
src/Client.java
src/Client2.java
src/Client3.java
End of files
End of files

View File

@@ -0,0 +1,3 @@
class Super2 {
char s = 's';
}

View File

@@ -0,0 +1,2 @@
class Client4 extends Hyper<Client4>{
}

View File

@@ -0,0 +1,3 @@
class Super2 extends Hyper<Integer> {
char s = 's';
}

View File

@@ -217,61 +217,21 @@ class ClassfileAnalyzer {
}
}
private final SignatureVisitor mySignatureCrawler = new SignatureVisitor(Opcodes.ASM5) {
public void visitFormalTypeParameter(String name) {
}
private final SignatureVisitor mySignatureCrawler = new BaseSignatureVisitor() {
public SignatureVisitor visitClassBound() {
return this;
return mySignatureWithGenericBoundUsageCrawler;
}
public SignatureVisitor visitInterfaceBound() {
return this;
}
public SignatureVisitor visitSuperclass() {
return this;
}
public SignatureVisitor visitInterface() {
return this;
}
public SignatureVisitor visitParameterType() {
return this;
}
public SignatureVisitor visitReturnType() {
return this;
}
public SignatureVisitor visitExceptionType() {
return this;
}
public void visitBaseType(char descriptor) {
}
public void visitTypeVariable(String name) {
}
public SignatureVisitor visitArrayType() {
return this;
}
public void visitInnerClassType(String name) {
}
public void visitTypeArgument() {
return mySignatureWithGenericBoundUsageCrawler;
}
public SignatureVisitor visitTypeArgument(char wildcard) {
return this;
}
public void visitEnd() {
return mySignatureWithGenericBoundUsageCrawler;
}
};
private final SignatureVisitor mySignatureWithGenericBoundUsageCrawler = new BaseSignatureVisitor() {
public void visitClassType(String name) {
final int className = myContext.get(name);
myUsages.add(UsageRepr.createClassUsage(myContext, className));
@@ -653,6 +613,72 @@ class ClassfileAnalyzer {
myLocalClassFlag.set(true);
}
}
private class BaseSignatureVisitor extends SignatureVisitor {
public BaseSignatureVisitor() {
super(Opcodes.ASM5);
}
public void visitFormalTypeParameter(String name) {
}
public SignatureVisitor visitClassBound() {
return this;
}
public SignatureVisitor visitInterfaceBound() {
return this;
}
public SignatureVisitor visitSuperclass() {
return this;
}
public SignatureVisitor visitInterface() {
return this;
}
public SignatureVisitor visitParameterType() {
return this;
}
public SignatureVisitor visitReturnType() {
return this;
}
public SignatureVisitor visitExceptionType() {
return this;
}
public void visitBaseType(char descriptor) {
}
public void visitTypeVariable(String name) {
}
public SignatureVisitor visitArrayType() {
return this;
}
public void visitInnerClassType(String name) {
}
public void visitTypeArgument() {
}
public SignatureVisitor visitTypeArgument(char wildcard) {
return this;
}
public void visitEnd() {
}
public void visitClassType(String name) {
final int className = myContext.get(name);
myUsages.add(UsageRepr.createClassUsage(myContext, className));
}
}
}
public Pair<ClassRepr, Set<UsageRepr.Usage>> analyze(final int fileName, final ClassReader cr) {

View File

@@ -716,6 +716,28 @@ public class Mappings {
public abstract boolean checkResidence(final int residence);
}
public class FileFilterConstraint extends UsageConstraint {
@NotNull
private final DependentFilesFilter myFilter;
public FileFilterConstraint(@NotNull DependentFilesFilter filter) {
myFilter = filter;
}
public boolean checkResidence(int residence) {
final Collection<File> fNames = myClassToSourceFile.get(residence);
if (fNames == null || fNames.isEmpty()) {
return true;
}
for (File fName : fNames) {
if (myFilter.accept(fName)) {
return true;
}
}
return false;
}
}
public class PackageConstraint extends UsageConstraint {
public final String packageName;
@@ -1132,6 +1154,11 @@ public class Mappings {
debug("Class is annotation, skipping method analysis");
return;
}
assert myFuture != null;
assert myPresent != null;
assert myAffectedFiles != null;
Ref<ClassRepr> oldItRef = null;
for (final MethodRepr m : added) {
debug("Method: ", m.name);
@@ -1256,6 +1283,10 @@ public class Mappings {
if (removed.isEmpty()) {
return;
}
assert myFuture != null;
assert myAffectedFiles != null;
assert myCompiledFiles != null;
debug("Processing removed methods:");
for (final MethodRepr m : removed) {
debug("Method ", m.name);
@@ -1362,6 +1393,10 @@ public class Mappings {
return;
}
debug("Processing changed methods:");
assert myFuture != null;
assert myAffectedFiles != null;
for (final Pair<MethodRepr, Difference> mr : changed) {
final MethodRepr m = mr.first;
final MethodRepr.Diff d = (MethodRepr.Diff)mr.second;
@@ -1473,6 +1508,11 @@ public class Mappings {
}
debug("Processing added fields");
assert myFuture != null;
assert myPresent != null;
assert myCompiledFiles != null;
assert myAffectedFiles != null;
for (final FieldRepr f : added) {
debug("Field: ", f.name);
@@ -1535,23 +1575,23 @@ public class Mappings {
// nothing
}
else {
Util.UsageConstraint constaint;
Util.UsageConstraint constraint;
if ((ff.isProtected() && f.isPublic()) || (f.isProtected() && ff.isPublic()) || (ff.isPackageLocal() && f.isProtected())) {
constaint = myFuture.new NegationConstraint(myFuture.new InheritanceConstraint(cc.name));
constraint = myFuture.new NegationConstraint(myFuture.new InheritanceConstraint(cc.name));
}
else if (ff.isPublic() && ff.isPackageLocal()) {
constaint = myFuture.new NegationConstraint(myFuture.new PackageConstraint(cc.getPackageName()));
constraint = myFuture.new NegationConstraint(myFuture.new PackageConstraint(cc.getPackageName()));
}
else {
constaint =
constraint =
myFuture.new IntersectionConstraint(myFuture.new NegationConstraint(myFuture.new InheritanceConstraint(cc.name)),
myFuture.new NegationConstraint(
myFuture.new PackageConstraint(cc.getPackageName())));
}
for (final UsageRepr.Usage usage : localUsages) {
state.myUsageConstraints.put(usage, constaint);
state.myUsageConstraints.put(usage, constraint);
}
}
@@ -1569,6 +1609,8 @@ public class Mappings {
if (removed.isEmpty()) {
return true;
}
assert myFuture != null;
debug("Processing removed fields:");
for (final FieldRepr f : removed) {
@@ -1577,6 +1619,7 @@ public class Mappings {
if (!f.isPrivate() && (f.access & DESPERATE_MASK) == DESPERATE_MASK && f.hasValue()) {
debug("Field had value and was (non-private) final static => a switch to non-incremental mode requested");
if (myConstantSearch != null) {
assert myDelayedWorks != null;
myDelayedWorks.addConstantWork(it.name, f, true, false);
}
else {
@@ -1601,6 +1644,7 @@ public class Mappings {
return true;
}
debug("Processing changed fields:");
assert myFuture != null;
for (final Pair<FieldRepr, Difference> f : changed) {
final Difference d = f.second;
@@ -1619,6 +1663,7 @@ public class Mappings {
if (harmful || valueChanged || becameLessAccessible) {
debug("Inline field changed it's access or value => a switch to non-incremental mode requested");
if (myConstantSearch != null) {
assert myDelayedWorks != null;
myDelayedWorks.addConstantWork(it.name, field, false, accessChanged);
}
else {
@@ -1687,6 +1732,10 @@ public class Mappings {
final Collection<Pair<ClassRepr, Difference>> changedClasses = state.myClassDiff.changed();
if (!changedClasses.isEmpty()) {
debug("Processing changed classes:");
assert myFuture != null;
assert myPresent != null;
final Util.FileFilterConstraint fileFilterConstraint = myFilter != null? myPresent.new FileFilterConstraint(myFilter) : null;
for (final Pair<ClassRepr, Difference> changed : changedClasses) {
final ClassRepr changedClass = changed.first;
@@ -1753,7 +1802,11 @@ public class Mappings {
@Override
public boolean execute(int className) {
debug("Affecting usages in generic type parameter bounds of class: ", className);
state.myAffectedUsages.add(UsageRepr.createClassAsGenericBoundUsage(myContext, className));
final UsageRepr.Usage usage = UsageRepr.createClassAsGenericBoundUsage(myContext, className);
state.myAffectedUsages.add(usage);
if (fileFilterConstraint != null) {
state.myUsageConstraints.put(usage, fileFilterConstraint);
}
final TIntHashSet depClasses = myClassToClassDependency.get(className);
if (depClasses != null) {
@@ -1869,6 +1922,9 @@ public class Mappings {
if (removed.isEmpty()) {
return;
}
assert myPresent != null;
assert myDelta.myChangedFiles != null;
myDelta.myChangedFiles.add(fileName);
debug("Processing removed classes:");
@@ -1896,6 +1952,9 @@ public class Mappings {
if (!myEasyMode && myFilter != null) {
// checking if this newly added class duplicates already existing one
assert myCompiledFiles != null;
assert myAffectedFiles != null;
for (ClassRepr c : addedClasses) {
if (!c.isLocal() && !c.isAnonymous() && isEmpty(c.getOuterClassName())) {
final Set<File> candidates = new THashSet<File>(FileUtil.FILE_HASHING_STRATEGY);
@@ -1976,6 +2035,8 @@ public class Mappings {
}
private void affectCorrespondingSourceFiles(TIntHashSet toAffect) {
assert myAffectedFiles != null;
toAffect.forEach(new TIntProcedure() {
@Override
public boolean execute(int depClass) {
@@ -1995,6 +2056,8 @@ public class Mappings {
private void calculateAffectedFiles(final DiffState state) {
debug("Checking dependent classes:");
assert myAffectedFiles != null;
assert myCompiledFiles != null;
state.myDependants.forEach(new TIntProcedure() {
@Override
@@ -2106,6 +2169,8 @@ public class Mappings {
if (myEasyMode) {
return false;
}
assert myAffectedFiles != null;
assert myDelayedWorks != null;
final Collection<String> removed = myDelta.myRemovedFiles;
if (removed != null) {
@@ -2117,6 +2182,7 @@ public class Mappings {
}
finally {
if (myFilesToCompile != null) {
assert myDelta.myChangedFiles != null;
// if some class is associated with several sources,
// some of them may not have been compiled in this round, so such files should be considered unchanged
myDelta.myChangedFiles.retainAll(myFilesToCompile);
@@ -2463,7 +2529,9 @@ public class Mappings {
}
for (final String s : staticImports) {
int i = s.length() - 1;
for (; s.charAt(i) != '.'; i--) ;
while (s.charAt(i) != '.') {
i--;
}
final String anImport = s.substring(0, i);
if (!anImport.endsWith("*")) {
allImports.add(anImport); // filter out wildcard imports