IDEA-176693 incremental modules compilation

This commit is contained in:
Eugene Zhuravlev
2017-10-13 14:34:54 +02:00
parent 1a93adc7ae
commit 3233c3606c
114 changed files with 1921 additions and 345 deletions
@@ -0,0 +1,6 @@
Cleaning output files:
out/production/A/module-info.class
End of files
Compiling files:
moduleA/src/module-info.java
End of files
@@ -0,0 +1,7 @@
package ppp;
public class Util {
public static void perform() {
System.out.println("Util.perform");
}
}
@@ -0,0 +1,7 @@
package qqq;
public class Client {
public void perform() {
ppp.Util.perform();
}
}
@@ -0,0 +1,9 @@
package qqq2;
import ppp.Util;
public class ClientC {
public void perform() {
Util.perform();
}
}
@@ -0,0 +1,14 @@
Cleaning output files:
out/production/A/module-info.class
End of files
Compiling files:
moduleA/src/module-info.java
End of files
Cleaning output files:
out/production/B/module-info.class
out/production/B/qqq/Client.class
End of files
Compiling files:
moduleB/src/module-info.java
moduleB/src/qqq/Client.java
End of files
@@ -0,0 +1,7 @@
package ppp;
public class Util {
public static void perform() {
System.out.println("Util.perform");
}
}
@@ -0,0 +1,7 @@
package qqq;
public class Client {
public void perform() {
// do perform
}
}
@@ -0,0 +1,9 @@
package qqq2;
import ppp.Util;
public class ClientC {
public void perform() {
Util.perform();
}
}
@@ -0,0 +1,14 @@
Cleaning output files:
out/production/A/module-info.class
End of files
Compiling files:
moduleA/src/module-info.java
End of files
Cleaning output files:
out/production/C/module-info.class
out/production/C/qqq2/ClientC.class
End of files
Compiling files:
moduleC/src/module-info.java
moduleC/src/qqq2/ClientC.java
End of files
@@ -0,0 +1,7 @@
package ppp;
public class Util {
public static void perform() {
System.out.println("Util.perform");
}
}
@@ -0,0 +1,7 @@
package qqq;
public class Client {
public void perform() {
ppp.Util.perform();
}
}
@@ -0,0 +1,9 @@
package qqq2;
import ppp.Util;
public class ClientC {
public void perform() {
Util.perform();
}
}
@@ -0,0 +1,14 @@
Cleaning output files:
out/production/B/module-info.class
End of files
Compiling files:
moduleB/src/module-info.java
End of files
Cleaning output files:
out/production/C/module-info.class
out/production/C/qqq2/ClientC.class
End of files
Compiling files:
moduleC/src/module-info.java
moduleC/src/qqq2/ClientC.java
End of files
@@ -0,0 +1,7 @@
package ppp;
public class Util {
public static void perform() {
System.out.println("Util.perform");
}
}
@@ -0,0 +1,7 @@
package qqq;
public class Client {
public void perform() {
System.out.println("ClientB.perform");
}
}
@@ -0,0 +1,7 @@
package qqq2;
public class ClientC {
public void perform() {
// do perform
}
}
@@ -0,0 +1,14 @@
Cleaning output files:
out/production/B/module-info.class
End of files
Compiling files:
moduleB/src/module-info.java
End of files
Cleaning output files:
out/production/C/module-info.class
out/production/C/qqq2/ClientC.class
End of files
Compiling files:
moduleC/src/module-info.java
moduleC/src/qqq2/ClientC.java
End of files
@@ -0,0 +1,7 @@
package ppp;
public class Util {
public static void perform() {
System.out.println("Util.perform");
}
}
@@ -0,0 +1,7 @@
package qqq;
public class Client {
public void perform() {
System.out.println("ClientB.perform");
}
}
@@ -0,0 +1,9 @@
package qqq2;
import ppp.Util;
public class ClientC {
public void perform() {
Util.perform();
}
}
@@ -0,0 +1,14 @@
Cleaning output files:
out/production/A/module-info.class
End of files
Compiling files:
moduleA/src/module-info.java
End of files
Cleaning output files:
out/production/B/module-info.class
out/production/B/qqq/Client.class
End of files
Compiling files:
moduleB/src/module-info.java
moduleB/src/qqq/Client.java
End of files
@@ -0,0 +1,7 @@
package ppp;
public class Util {
public static void perform() {
System.out.println("Util.perform");
}
}
@@ -0,0 +1,7 @@
package qqq;
public class Client {
public void perform() {
// do perform
}
}
@@ -0,0 +1,8 @@
package qqq2;
public class ClientC {
public void perform() {
// do perform
}
}
@@ -0,0 +1,14 @@
Cleaning output files:
out/production/B/module-info.class
End of files
Compiling files:
moduleB/src/module-info.java
End of files
Cleaning output files:
out/production/B/module-info.class
out/production/B/qqq/Client.class
End of files
Compiling files:
moduleB/src/module-info.java
moduleB/src/qqq/Client.java
End of files
@@ -0,0 +1,7 @@
package ppp;
public class Util {
public static void perform() {
System.out.println("Util.perform");
}
}
@@ -0,0 +1,8 @@
package qqq;
import ppp.Util;
public class Client {
public void perform() {
Util.perform();
}
}
@@ -0,0 +1,9 @@
package qqq2;
import qqq.Client;
public class Client {
public void perform() {
new Client().perform();
}
}
@@ -0,0 +1,6 @@
Cleaning output files:
out/production/A/module-info.class
End of files
Compiling files:
moduleA/src/module-info.java
End of files
@@ -0,0 +1,7 @@
package ppp;
public class Util {
public static void perform() {
System.out.println("Util.perform");
}
}
@@ -0,0 +1,7 @@
package qqq;
public class Client {
public void perform() {
// do perform
}
}
@@ -0,0 +1,8 @@
package qqq2;
public class ClientC {
public void perform() {
// do perform
}
}
@@ -0,0 +1,14 @@
Cleaning output files:
out/production/A/module-info.class
End of files
Compiling files:
moduleA/src/module-info.java
End of files
Cleaning output files:
out/production/C/module-info.class
out/production/C/qqq2/ClientC.class
End of files
Compiling files:
moduleC/src/module-info.java
moduleC/src/qqq2/ClientC.java
End of files
@@ -0,0 +1,7 @@
package ppp;
public class Util {
public static void perform() {
System.out.println("Util.perform");
}
}
@@ -0,0 +1,7 @@
package qqq;
public class Client {
public void perform() {
// do perform
}
}
@@ -0,0 +1,9 @@
package qqq2;
import ppp.Util;
public class ClientC {
public void perform() {
Util.perform();
}
}
@@ -0,0 +1,22 @@
Cleaning output files:
out/production/A/module-info.class
End of files
Compiling files:
moduleA/src/module-info.java
End of files
Cleaning output files:
out/production/B/module-info.class
out/production/B/qqq/Client.class
End of files
Compiling files:
moduleB/src/module-info.java
moduleB/src/qqq/Client.java
End of files
Cleaning output files:
out/production/C/module-info.class
out/production/C/qqq2/ClientC.class
End of files
Compiling files:
moduleC/src/module-info.java
moduleC/src/qqq2/ClientC.java
End of files
@@ -0,0 +1,7 @@
package ppp;
public class Util {
public static void perform() {
System.out.println("Util.perform");
}
}
@@ -0,0 +1,7 @@
package qqq;
public class Client {
public void perform() {
System.out.println("ClientB.perform");
}
}
@@ -0,0 +1,9 @@
package qqq2;
import ppp.Util;
public class ClientC {
public void perform() {
Util.perform();
}
}
@@ -0,0 +1,22 @@
Cleaning output files:
out/production/B/module-info.class
End of files
Compiling files:
moduleB/src/module-info.java
End of files
Cleaning output files:
out/production/B/module-info.class
out/production/B/qqq/Client.class
End of files
Compiling files:
moduleB/src/module-info.java
moduleB/src/qqq/Client.java
End of files
Cleaning output files:
out/production/C/module-info.class
out/production/C/qqq2/ClientC.class
End of files
Compiling files:
moduleC/src/module-info.java
moduleC/src/qqq2/ClientC.java
End of files
@@ -0,0 +1,7 @@
package ppp;
public class Util {
public static void perform() {
System.out.println("Util.perform");
}
}
@@ -0,0 +1,7 @@
package qqq;
public class Client {
public void perform() {
System.out.println("ClientB.perform");
}
}
@@ -0,0 +1,9 @@
package qqq2;
import ppp.Util;
public class ClientC {
public void perform() {
Util.perform();
}
}
@@ -37,6 +37,9 @@ import org.jetbrains.jps.incremental.messages.BuildMessage;
import org.jetbrains.jps.incremental.messages.CompilerMessage;
import org.jetbrains.jps.incremental.messages.ProgressMessage;
import org.jetbrains.jps.model.JpsDummyElement;
import org.jetbrains.jps.model.JpsProject;
import org.jetbrains.jps.model.java.JavaModuleIndex;
import org.jetbrains.jps.model.java.JpsJavaExtensionService;
import org.jetbrains.jps.model.java.JpsJavaSdkType;
import org.jetbrains.jps.model.library.JpsTypedLibrary;
import org.jetbrains.jps.model.library.sdk.JpsSdk;
@@ -63,6 +66,7 @@ public class JavaBuilderUtil {
private static final Key<Set<File>> SUCCESSFULLY_COMPILED_FILES_KEY = Key.create("_successfully_compiled_files_");
private static final Key<List<FileFilter>> SKIP_MARKING_DIRTY_FILTERS_KEY = Key.create("_skip_marking_dirty_filters_");
private static final Key<Pair<Mappings, Callbacks.Backend>> MAPPINGS_DELTA_KEY = Key.create("_mappings_delta_");
private static final String MODULE_INFO_FILE = "module-info.java";
public static void registerFileToCompile(CompileContext context, File file) {
registerFilesToCompile(context, Collections.singleton(file));
@@ -214,6 +218,7 @@ public class JavaBuilderUtil {
LOG.debug("End Of Differentiate Results.");
}
final boolean compilingIncrementally = isCompileJavaIncrementally(context);
if (incremental) {
final Set<File> newlyAffectedFiles = new HashSet<>(allAffectedFiles);
newlyAffectedFiles.removeAll(affectedBeforeDif);
@@ -241,10 +246,47 @@ public class JavaBuilderUtil {
}
}
Set<ModuleBuildTarget> targetsToMark = null;
final JavaModuleIndex moduleIndex = getJavaModuleIndex(context);
for (File file : newlyAffectedFiles) {
FSOperations.markDirtyIfNotDeleted(context, markDirtyRound, file);
if (MODULE_INFO_FILE.equals(file.getName())) {
final JavaSourceRootDescriptor rootDescr = context.getProjectDescriptor().getBuildRootIndex().findJavaRootDescriptor(context, file);
if (rootDescr != null) {
final ModuleBuildTarget target = rootDescr.getTarget();
final File targetModuleInfo = moduleIndex.getModuleInfoFile(target.getModule(), target.isTests());
if (FileUtil.filesEqual(targetModuleInfo, file)) {
if (targetsToMark == null) {
targetsToMark = new THashSet<>(); // lazy init
}
targetsToMark.add(target);
}
}
}
else {
FSOperations.markDirtyIfNotDeleted(context, markDirtyRound, file);
}
}
additionalPassRequired = isCompileJavaIncrementally(context) && chunkContainsAffectedFiles(context, chunk, newlyAffectedFiles);
if (targetsToMark != null) {
boolean currentChunkAfected = false;
for (ModuleBuildTarget target : targetsToMark) {
if (chunk.getTargets().contains(target)) {
currentChunkAfected = true;
}
else {
FSOperations.markDirty(context, markDirtyRound, target, null);
}
}
if (currentChunkAfected) {
if (compilingIncrementally) {
// turn on non-incremental mode for targets from the current chunk, if at least one of them was affected.
for (ModuleBuildTarget target : chunk.getTargets()) {
context.markNonIncremental(target);
}
}
FSOperations.markDirty(context, markDirtyRound, chunk, null);
}
}
additionalPassRequired = compilingIncrementally && chunkContainsAffectedFiles(context, chunk, newlyAffectedFiles);
}
}
else {
@@ -254,7 +296,7 @@ public class JavaBuilderUtil {
context.processMessage(new ProgressMessage(messageText));
final boolean alreadyMarkedDirty = FSOperations.isMarkedDirty(context, chunk);
additionalPassRequired = isCompileJavaIncrementally(context) && !alreadyMarkedDirty;
additionalPassRequired = compilingIncrementally && !alreadyMarkedDirty;
if (alreadyMarkedDirty) {
// need this to make sure changes data stored in Delta is complete
@@ -303,6 +345,17 @@ public class JavaBuilderUtil {
}
}
@Nullable
public static File findModuleInfoFile(CompileContext context, ModuleBuildTarget target) {
return getJavaModuleIndex(context).getModuleInfoFile(target.getModule(), target.isTests());
}
private static JavaModuleIndex getJavaModuleIndex(CompileContext context) {
JpsProject project = context.getProjectDescriptor().getProject();
File storageRoot = context.getProjectDescriptor().dataManager.getDataPaths().getDataStorageRoot();
return JpsJavaExtensionService.getInstance().getJavaModuleIndex(project, storageRoot);
}
private static FileFilter createOrFilter(final List<FileFilter> filters) {
if (filters == null || filters.isEmpty()) return null;
return pathname -> {
@@ -0,0 +1,97 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.jps.builders.java.dependencyView;
import com.intellij.util.io.DataInputOutputUtil;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.builders.storage.BuildDataCorruptedException;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Set;
/**
* @author Eugene Zhuravlev
* Date: 30-Sep-17
*/
public abstract class ClassFileRepr extends Proto {
protected final DependencyContext myContext;
private final int myFileName;
private final Set<UsageRepr.Usage> myUsages;
public ClassFileRepr(
int access,
int signature,
int name,
@NotNull Set<TypeRepr.ClassType> annotations,
final int fileName, final DependencyContext context, final Set<UsageRepr.Usage> usages) {
super(access, signature, name, annotations);
myFileName = fileName;
this.myContext = context;
this.myUsages = usages;
}
public ClassFileRepr(DependencyContext context, DataInput in) {
super(context, in);
myContext = context;
try {
myFileName = DataInputOutputUtil.readINT(in);
myUsages = RW.read(UsageRepr.externalizer(context), new THashSet<>(), in);
}
catch (IOException e) {
throw new BuildDataCorruptedException(e);
}
}
public int getFileName() {
return myFileName;
}
public Set<UsageRepr.Usage> getUsages() {
return myUsages;
}
public boolean addUsage(final UsageRepr.Usage usage) {
return myUsages.add(usage);
}
protected abstract void updateClassUsages(DependencyContext context, Set<UsageRepr.Usage> s);
public void toStream(DependencyContext context, PrintStream stream) {
super.toStream(context, stream);
stream.print(" Filename : ");
stream.println(context.getValue(myFileName));
}
@Override
public void save(final DataOutput out) {
try {
super.save(out);
DataInputOutputUtil.writeINT(out, myFileName);
RW.save(myUsages, UsageRepr.externalizer(myContext), out);
}
catch (IOException e) {
throw new BuildDataCorruptedException(e);
}
}
@Override
public int hashCode() {
return 31 * myFileName + name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ClassFileRepr classRepr = (ClassFileRepr)o;
if (myFileName != classRepr.myFileName) return false;
if (name != classRepr.name) return false;
return true;
}
}
@@ -0,0 +1,41 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.jps.builders.java.dependencyView;
import com.intellij.util.io.DataExternalizer;
import org.jetbrains.annotations.NotNull;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* @author Eugene Zhuravlev
* Date: 04-Oct-17
*/
class ClassFileReprExternalizer implements DataExternalizer<ClassFileRepr> {
private static final byte CLASS = 0x1;
private static final byte MODULE = 0x2;
private final DataExternalizer<ClassRepr> myClassReprExternalizer;
private final DataExternalizer<ModuleRepr> myModuleReprExternalizer;
public ClassFileReprExternalizer(DependencyContext context) {
myClassReprExternalizer = ClassRepr.externalizer(context);
myModuleReprExternalizer = ModuleRepr.externalizer(context);
}
public void save(@NotNull DataOutput out, ClassFileRepr value) throws IOException {
if (value instanceof ClassRepr) {
out.writeByte(CLASS);
myClassReprExternalizer.save(out, (ClassRepr)value);
}
else {
out.writeByte(MODULE);
myModuleReprExternalizer.save(out, (ModuleRepr)value);
}
}
public ClassFileRepr read(@NotNull DataInput in) throws IOException {
return in.readByte() == CLASS ? myClassReprExternalizer.read(in) : myModuleReprExternalizer.read(in);
}
}
@@ -31,9 +31,7 @@ import java.util.*;
* @author: db
* Date: 01.02.11
*/
public class ClassRepr extends Proto {
private final DependencyContext myContext;
private final int myFileName;
public class ClassRepr extends ClassFileRepr {
private final TypeRepr.ClassType mySuperClass;
private final Set<TypeRepr.AbstractType> myInterfaces;
private final Set<ElemType> myAnnotationTargets;
@@ -41,7 +39,6 @@ public class ClassRepr extends Proto {
private final Set<FieldRepr> myFields;
private final Set<MethodRepr> myMethods;
private final Set<UsageRepr.Usage> myUsages;
private final int myOuterClassName;
private final boolean myIsLocal;
@@ -75,19 +72,16 @@ public class ClassRepr extends Proto {
return myRetentionPolicy;
}
public Set<UsageRepr.Usage> getUsages() {
return myUsages;
}
public boolean addUsage(final UsageRepr.Usage usage) {
return myUsages.add(usage);
}
public boolean isInterface() {
return (access & Opcodes.ACC_INTERFACE) != 0;
}
public abstract static class Diff extends Difference {
public abstract static class Diff extends DifferenceImpl {
Diff(@NotNull Difference delegate) {
super(delegate);
}
public abstract Specifier<TypeRepr.AbstractType, Difference> interfaces();
public abstract Specifier<FieldRepr, Difference> fields();
@@ -119,12 +113,12 @@ public class ClassRepr extends Proto {
base |= Difference.SUPERCLASS;
}
if (!myUsages.equals(pastClass.myUsages)) {
if (!getUsages().equals(pastClass.getUsages())) {
base |= Difference.USAGES;
}
final int d = base;
return new Diff() {
return new Diff(diff) {
@Override
public boolean extendsAdded() {
if ((d & Difference.SUPERCLASS) <= 0) {
@@ -134,21 +128,6 @@ public class ClassRepr extends Proto {
return "java/lang/Object".equals(pastSuperName);
}
@Override
public boolean packageLocalOn() {
return diff.packageLocalOn();
}
@Override
public int addedModifiers() {
return diff.addedModifiers();
}
@Override
public int removedModifiers() {
return diff.removedModifiers();
}
@Override
public Difference.Specifier<TypeRepr.AbstractType, Difference> interfaces() {
return Difference.make(pastClass.myInterfaces, myInterfaces);
@@ -169,10 +148,6 @@ public class ClassRepr extends Proto {
return Difference.make(pastClass.myAnnotationTargets, myAnnotationTargets);
}
public Specifier<TypeRepr.ClassType, Difference> annotations() {
return diff.annotations();
}
@Override
public boolean retentionChanged() {
return !((myRetentionPolicy == null && pastClass.myRetentionPolicy == RetentionPolicy.CLASS) ||
@@ -189,11 +164,6 @@ public class ClassRepr extends Proto {
public boolean hadValue() {
return false;
}
@Override
public boolean weakedAccess() {
return diff.weakedAccess();
}
};
}
@@ -211,7 +181,7 @@ public class ClassRepr extends Proto {
return result;
}
public void updateClassUsages(final DependencyContext context, final Set<UsageRepr.Usage> s) {
protected void updateClassUsages(final DependencyContext context, final Set<UsageRepr.Usage> s) {
mySuperClass.updateClassUsages(context, name, s);
for (TypeRepr.AbstractType t : myInterfaces) {
@@ -239,9 +209,7 @@ public class ClassRepr extends Proto {
final boolean localClassFlag,
final boolean anonymousClassFlag,
final Set<UsageRepr.Usage> usages) {
super(access, sig, name, annotations);
this.myContext = context;
myFileName = fileName;
super(access, sig, name, annotations, fileName, context, usages);
mySuperClass = TypeRepr.createClassType(context, superClass);
myInterfaces = (Set<TypeRepr.AbstractType>)TypeRepr.createClassType(context, interfaces, new THashSet<>(1));
myFields = fields;
@@ -251,19 +219,17 @@ public class ClassRepr extends Proto {
this.myOuterClassName = outerClassName;
this.myIsLocal = localClassFlag;
this.myIsAnonymous = anonymousClassFlag;
this.myUsages = usages;
updateClassUsages(context, usages);
}
public ClassRepr(final DependencyContext context, final DataInput in) {
super(context, in);
try {
this.myContext = context;
myFileName = DataInputOutputUtil.readINT(in);
mySuperClass = (TypeRepr.ClassType)TypeRepr.externalizer(context).read(in);
myInterfaces = (Set<TypeRepr.AbstractType>)RW.read(TypeRepr.externalizer(context), new THashSet<>(1), in);
myFields = (Set<FieldRepr>)RW.read(FieldRepr.externalizer(context), new THashSet<>(), in);
myMethods = (Set<MethodRepr>)RW.read(MethodRepr.externalizer(context), new THashSet<>(), in);
myAnnotationTargets = (Set<ElemType>)RW.read(UsageRepr.AnnotationUsage.elementTypeExternalizer, EnumSet.noneOf(ElemType.class), in);
myInterfaces = RW.read(TypeRepr.externalizer(context), new THashSet<>(1), in);
myFields = RW.read(FieldRepr.externalizer(context), new THashSet<>(), in);
myMethods = RW.read(MethodRepr.externalizer(context), new THashSet<>(), in);
myAnnotationTargets = RW.read(UsageRepr.AnnotationUsage.elementTypeExternalizer, EnumSet.noneOf(ElemType.class), in);
final String s = RW.readUTF(in);
@@ -273,7 +239,6 @@ public class ClassRepr extends Proto {
int flags = DataInputOutputUtil.readINT(in);
myIsLocal = (flags & LOCAL_MASK) != 0;
myIsAnonymous = (flags & ANONYMOUS_MASK) != 0;
myUsages =(Set<UsageRepr.Usage>)RW.read(UsageRepr.externalizer(context), new THashSet<>(), in);
}
catch (IOException e) {
throw new BuildDataCorruptedException(e);
@@ -287,7 +252,6 @@ public class ClassRepr extends Proto {
public void save(final DataOutput out) {
try {
super.save(out);
DataInputOutputUtil.writeINT(out, myFileName);
mySuperClass.save(out);
RW.save(myInterfaces, out);
RW.save(myFields, out);
@@ -296,32 +260,12 @@ public class ClassRepr extends Proto {
RW.writeUTF(out, myRetentionPolicy == null ? "" : myRetentionPolicy.toString());
DataInputOutputUtil.writeINT(out, myOuterClassName);
DataInputOutputUtil.writeINT(out, (myIsLocal ? LOCAL_MASK:0) | (myIsAnonymous ? ANONYMOUS_MASK : 0));
RW.save(myUsages, UsageRepr.externalizer(myContext), out);
}
catch (IOException e) {
throw new BuildDataCorruptedException(e);
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ClassRepr classRepr = (ClassRepr)o;
if (myFileName != classRepr.myFileName) return false;
if (name != classRepr.name) return false;
return true;
}
@Override
public int hashCode() {
return 31 * myFileName + name;
}
public UsageRepr.Usage createUsage() {
return UsageRepr.createClassUsage(myContext, name);
}
@@ -400,9 +344,6 @@ public class ClassRepr extends Proto {
public void toStream(final DependencyContext context, final PrintStream stream) {
super.toStream(context, stream);
stream.print(" Filename : ");
stream.println(context.getValue(myFileName));
stream.print(" Superclass : ");
stream.println(mySuperClass == null ? "<null>" : mySuperClass.getDescr(context));
@@ -494,7 +435,7 @@ public class ClassRepr extends Proto {
final List<String> usages = new LinkedList<>();
for (final UsageRepr.Usage u : myUsages) {
for (final UsageRepr.Usage u : getUsages()) {
final ByteArrayOutputStream bas = new ByteArrayOutputStream();
u.toStream(myContext, new PrintStream(bas));
@@ -16,7 +16,6 @@
package org.jetbrains.jps.builders.java.dependencyView;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.util.SmartList;
import gnu.trove.THashMap;
@@ -29,10 +28,7 @@ import org.jetbrains.org.objectweb.asm.signature.SignatureVisitor;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Array;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
/**
* @author: db
@@ -242,6 +238,51 @@ class ClassfileAnalyzer {
}
}
private class ModuleCrawler extends ModuleVisitor {
public ModuleCrawler() {
super(ASM_API_VERSION);
}
@Override
public void visitMainClass(String mainClass) {
myUsages.add(UsageRepr.createClassUsage(myContext, myContext.get(mainClass)));
}
@Override
public void visitRequire(String module, int access, String version) {
if (isExplicit(access)) {
// collect non-synthetic dependencies only
myModuleRequires.add(new ModuleRequiresRepr(myContext, access, myContext.get(module), version));
}
}
@Override
public void visitExport(String packaze, int access, String... modules) {
if (isExplicit(access)) {
// collect non-synthetic dependencies only
myModuleExports.add(new ModulePackageRepr(myContext, myContext.get(packaze), modules != null? Arrays.asList(modules) : Collections.emptyList()));
}
}
public void visitUse(String service) {
myUsages.add(UsageRepr.createClassUsage(myContext, myContext.get(service)));
}
@Override
public void visitProvide(String service, String... providers) {
myUsages.add(UsageRepr.createClassUsage(myContext, myContext.get(service)));
if (providers != null) {
for (String provider : providers) {
myUsages.add(UsageRepr.createClassUsage(myContext, myContext.get(provider)));
}
}
}
private boolean isExplicit(int access) {
return (access & (Opcodes.ACC_SYNTHETIC | Opcodes.ACC_MANDATED)) == 0;
}
}
private void processSignature(final String sig) {
if (sig != null) {
try {
@@ -278,11 +319,12 @@ class ClassfileAnalyzer {
}
};
private Boolean myTakeIntoAccount = false;
private boolean myTakeIntoAccount = false;
private boolean myIsModule = false;
private final int myFileName;
private int myAccess;
private int myName;
private int myVersion; // for class contains a class bytecode version, for module contains a module version
private String mySuperClass;
private String[] myInterfaces;
private String mySignature;
@@ -302,6 +344,9 @@ class ClassfileAnalyzer {
private final Map<TypeRepr.ClassType, Set<ElemType>> myAnnotationTargets = new THashMap<>();
private final Set<TypeRepr.ClassType> myAnnotations = new THashSet<>();
private final Set<ModuleRequiresRepr> myModuleRequires = new THashSet<>();
private final Set<ModulePackageRepr> myModuleExports = new THashSet<>();
public ClassCrawler(final int fn) {
super(ASM_API_VERSION);
myFileName = fn;
@@ -311,17 +356,18 @@ class ClassfileAnalyzer {
return (access & Opcodes.ACC_PRIVATE) == 0;
}
public Pair<ClassRepr, Set<UsageRepr.Usage>> getResult() {
ClassRepr repr = myTakeIntoAccount ? new ClassRepr(
public ClassFileRepr getResult() {
if (!myTakeIntoAccount) {
return null;
}
if (myIsModule) {
return new ModuleRepr(myContext, myAccess, myVersion, myFileName, myName, myModuleRequires, myModuleExports, myUsages);
}
return new ClassRepr(
myContext, myAccess, myFileName, myName, myContext.get(mySignature), myContext.get(mySuperClass), myInterfaces,
myFields, myMethods, myAnnotations, myTargets, myRetentionPolicy, myContext.get(myOuterClassName.get()), myLocalClassFlag.get(),
myAnonymousClassFlag.get(), myUsages) : null;
if (repr != null) {
repr.updateClassUsages(myContext, myUsages);
}
return Pair.create(repr, myUsages);
myAnonymousClassFlag.get(), myUsages
);
}
@Override
@@ -330,6 +376,7 @@ class ClassfileAnalyzer {
myAccess = access;
myName = myContext.get(name);
myVersion = version;
mySignature = sig;
mySuperClass = superName;
myInterfaces = interfaces;
@@ -364,6 +411,15 @@ class ClassfileAnalyzer {
}
}
@Override
public ModuleVisitor visitModule(String name, int access, String version) {
myIsModule = true;
myAccess = access;
myName = myContext.get(name);
myVersion = myContext.get(version);
return new ModuleCrawler();
}
@Override
public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
if (desc.equals("Ljava/lang/annotation/Target;")) {
@@ -779,7 +835,7 @@ class ClassfileAnalyzer {
}
}
public Pair<ClassRepr, Set<UsageRepr.Usage>> analyze(int fileName, ClassReader cr) {
public ClassFileRepr analyze(int fileName, ClassReader cr) {
ClassCrawler visitor = new ClassCrawler(fileName);
try {
@@ -56,6 +56,26 @@ public abstract class Difference {
}
public static <T, D extends Difference> Specifier<T, D> make(final Set<T> past, final Set<T> now) {
if ((past == null || past.isEmpty()) && (now == null || now.isEmpty())) {
return new Specifier<T, D>() {
public Collection<T> added() {
return Collections.emptySet();
}
public Collection<T> removed() {
return Collections.emptySet();
}
public Collection<Pair<T, D>> changed() {
return Collections.emptySet();
}
public boolean unchanged() {
return true;
}
};
}
if (past == null) {
final Collection<T> _now = Collections.unmodifiableCollection(now);
return new Specifier<T, D>() {
@@ -78,11 +98,9 @@ public abstract class Difference {
}
final Set<T> added = new HashSet<>(now);
added.removeAll(past);
final Set<T> removed = new HashSet<>(past);
removed.removeAll(now);
final Set<Pair<T, D>> changed;
@@ -133,7 +151,7 @@ public abstract class Difference {
};
}
private static <T> boolean canContainChangedElements(final Set<T> past, final Set<T> now) {
private static <T> boolean canContainChangedElements(final Collection<T> past, final Collection<T> now) {
if (past != null && now != null && !past.isEmpty() && !now.isEmpty()) {
return past.iterator().next() instanceof Proto;
}
@@ -0,0 +1,49 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.jps.builders.java.dependencyView;
import org.jetbrains.annotations.NotNull;
/**
* @author Eugene Zhuravlev
* Date: 02-Oct-17
*/
class DifferenceImpl extends Difference{
private final Difference myDelegate;
public DifferenceImpl(@NotNull Difference delegate) {
myDelegate = delegate;
}
public int base() {
return myDelegate.base();
}
public boolean no() {
return myDelegate.no();
}
public boolean weakedAccess() {
return myDelegate.weakedAccess();
}
public int addedModifiers() {
return myDelegate.addedModifiers();
}
public int removedModifiers() {
return myDelegate.removedModifiers();
}
public boolean packageLocalOn() {
return myDelegate.packageLocalOn();
}
public boolean hadValue() {
return myDelegate.hadValue();
}
public Specifier<TypeRepr.ClassType, Difference> annotations() {
return myDelegate.annotations();
}
}
@@ -53,12 +53,6 @@ public class Mappings {
private static final IntInlineKeyDescriptor INT_KEY_DESCRIPTOR = new IntInlineKeyDescriptor();
private static final int DEFAULT_SET_CAPACITY = 32;
private static final float DEFAULT_SET_LOAD_FACTOR = 0.98f;
private static final CollectionFactory<ClassRepr> ourClassSetConstructor = new CollectionFactory<ClassRepr>() {
public Set<ClassRepr> create() {
// for IDEA codebase on average there is no more than 2.5 classes out of one source file, so we use smaller estimate
return new THashSet<>(5, DEFAULT_SET_LOAD_FACTOR);
}
};
private final boolean myIsDelta;
private final boolean myDeltaIsTransient;
@@ -67,7 +61,7 @@ public class Mappings {
private final TIntHashSet myChangedClasses;
private final THashSet<File> myChangedFiles;
private final Set<Pair<ClassRepr, File>> myDeletedClasses;
private final Set<Pair<ClassFileRepr, File>> myDeletedClasses;
private final Set<ClassRepr> myAddedClasses;
private final Object myLock;
private final File myRootDir;
@@ -85,7 +79,7 @@ public class Mappings {
values: class names that use the class registered as the key
*/
private IntIntMultiMaplet myClassToClassDependency;
private ObjectObjectMultiMaplet<File, ClassRepr> mySourceFileToClasses;
private ObjectObjectMultiMaplet<File, ClassFileRepr> mySourceFileToClasses;
private IntObjectMultiMaplet<File> myClassToSourceFile;
/**
* [short className] -> list of FQ names
@@ -148,7 +142,7 @@ public class Mappings {
myClassToSubclasses = new IntIntTransientMultiMaplet();
myClassToClassDependency = new IntIntTransientMultiMaplet();
myShortClassNameIndex = null;
mySourceFileToClasses = new ObjectObjectTransientMultiMaplet<>(FileUtil.FILE_HASHING_STRATEGY, ourClassSetConstructor);
mySourceFileToClasses = new ObjectObjectTransientMultiMaplet<>(FileUtil.FILE_HASHING_STRATEGY, () -> new THashSet<>(5, DEFAULT_SET_LOAD_FACTOR));
myClassToSourceFile = new IntObjectTransientMultiMaplet<>(fileCollectionFactory);
}
else {
@@ -159,12 +153,12 @@ public class Mappings {
myClassToClassDependency = new IntIntPersistentMultiMaplet(DependencyContext.getTableFile(myRootDir, CLASS_TO_CLASS), INT_KEY_DESCRIPTOR);
myShortClassNameIndex = myIsDelta? null : new IntIntPersistentMultiMaplet(DependencyContext.getTableFile(myRootDir, SHORT_NAMES), INT_KEY_DESCRIPTOR);
mySourceFileToClasses = new ObjectObjectPersistentMultiMaplet<>(
DependencyContext.getTableFile(myRootDir, SOURCE_TO_CLASS), new FileKeyDescriptor(), ClassRepr.externalizer(myContext),
ourClassSetConstructor
DependencyContext.getTableFile(myRootDir, SOURCE_TO_CLASS), new FileKeyDescriptor(), new ClassFileReprExternalizer(myContext),
() -> new THashSet<>(5, DEFAULT_SET_LOAD_FACTOR)
);
myClassToSourceFile = new IntObjectPersistentMultiMaplet<>(
DependencyContext.getTableFile(myRootDir, CLASS_TO_SOURCE), INT_KEY_DESCRIPTOR, new FileKeyDescriptor(), fileCollectionFactory
);
myClassToSourceFile =
new IntObjectPersistentMultiMaplet<>(DependencyContext.getTableFile(myRootDir, CLASS_TO_SOURCE), INT_KEY_DESCRIPTOR,
new FileKeyDescriptor(), fileCollectionFactory);
}
}
@@ -196,14 +190,19 @@ public class Mappings {
}
@Nullable
private ClassRepr getReprByName(final @Nullable File source, final int qName) {
private ClassRepr getClassReprByName(final @Nullable File source, final int qName) {
final ClassFileRepr reprByName = getReprByName(source, qName);
return reprByName instanceof ClassRepr? (ClassRepr)reprByName : null;
}
@Nullable
private ClassFileRepr getReprByName(@Nullable File source, int qName) {
final Collection<File> sources = source != null? Collections.singleton(source) : myClassToSourceFile.get(qName);
if (sources != null) {
for (File src : sources) {
final Collection<ClassRepr> reprs = mySourceFileToClasses.get(src);
final Collection<ClassFileRepr> reprs = mySourceFileToClasses.get(src);
if (reprs != null) {
for (ClassRepr repr : reprs) {
for (ClassFileRepr repr : reprs) {
if (repr.name == qName) {
return repr;
}
@@ -236,9 +235,9 @@ public class Mappings {
private final LinkedBlockingQueue<Runnable> myPostPasses = new LinkedBlockingQueue<>();
private void runPostPasses() {
final Set<Pair<ClassRepr, File>> deleted = myDeletedClasses;
final Set<Pair<ClassFileRepr, File>> deleted = myDeletedClasses;
if (deleted != null) {
for (Pair<ClassRepr, File> pair : deleted) {
for (Pair<ClassFileRepr, File> pair : deleted) {
final int deletedClassName = pair.first.name;
final Collection<File> sources = myClassToSourceFile.get(deletedClassName);
if (sources == null || sources.isEmpty()) { // if really deleted and not e.g. moved
@@ -270,7 +269,7 @@ public class Mappings {
myMappings = mappings;
}
void appendDependents(final ClassRepr c, final TIntHashSet result) {
void appendDependents(final ClassFileRepr c, final TIntHashSet result) {
final TIntHashSet depClasses = myClassToClassDependency.get(c.name);
if (depClasses != null) {
@@ -279,7 +278,7 @@ public class Mappings {
}
void propagateMemberAccessRec(final TIntHashSet acc, final boolean isField, final boolean root, final MemberComparator comparator, final int reflcass) {
final ClassRepr repr = reprByName(reflcass);
final ClassRepr repr = classReprByName(reflcass);
if (repr != null) {
if (!root) {
final Set<? extends ProtoMember> members = isField ? repr.getFields() : repr.getMethods();
@@ -370,7 +369,7 @@ public class Mappings {
}
final TIntHashSet _visitedClasses = visitedClasses;
subClasses.forEach(subClassName -> {
final ClassRepr r = reprByName(subClassName);
final ClassRepr r = classReprByName(subClassName);
if (r != null) {
boolean cont = true;
@@ -415,7 +414,7 @@ public class Mappings {
if (!visitedClasses.add(superName) || superName == myObjectClassName) {
continue;
}
final ClassRepr superClass = reprByName(superName);
final ClassRepr superClass = classReprByName(superName);
if (superClass != null) {
for (MethodRepr mm : superClass.findMethods(predicate)) {
if (isVisibleIn(superClass, mm, fromClass)) {
@@ -439,7 +438,7 @@ public class Mappings {
if (!visitedClasses.add(superName) || superName == myObjectClassName) {
continue;
}
final ClassRepr superClass = reprByName(superName);
final ClassRepr superClass = classReprByName(superName);
if (superClass == null || extendsLibraryClass(superClass, visitedClasses)) {
return true;
}
@@ -456,7 +455,7 @@ public class Mappings {
if (!visitedClasses.add(superName)) {
continue; // prevent SOE
}
final ClassRepr superClass = reprByName(superName);
final ClassRepr superClass = classReprByName(superName);
if (superClass != null) {
boolean cont = true;
final Collection<MethodRepr> methods = superClass.findMethods(predicate);
@@ -485,7 +484,7 @@ public class Mappings {
if (!visitedClasses.add(supername) || supername == myObjectClassName) {
continue;
}
final ClassRepr superClass = reprByName(supername);
final ClassRepr superClass = classReprByName(supername);
if (superClass != null) {
final FieldRepr ff = superClass.findField(f.name);
if (ff != null && isVisibleIn(superClass, ff, fromClass)) {
@@ -507,7 +506,7 @@ public class Mappings {
if (!visitedClasses.add(supername) || supername == myObjectClassName) {
continue;
}
final ClassRepr superClass = reprByName(supername);
final ClassRepr superClass = classReprByName(supername);
if (superClass != null) {
final FieldRepr ff = superClass.findField(f.name);
if (ff != null && isVisibleIn(superClass, ff, fromClass)) {
@@ -523,9 +522,21 @@ public class Mappings {
}
@Nullable
ClassRepr reprByName(final int name) {
ClassRepr classReprByName(final int name) {
final ClassFileRepr r = reprByName(name);
return r instanceof ClassRepr? (ClassRepr)r : null;
}
@Nullable
ModuleRepr moduleReprByName(final int name) {
final ClassFileRepr r = reprByName(name);
return r instanceof ModuleRepr? (ModuleRepr)r : null;
}
@Nullable
ClassFileRepr reprByName(final int name) {
if (myMappings != null) {
final ClassRepr r = myMappings.getReprByName(null, name);
final ClassFileRepr r = myMappings.getReprByName(null, name);
if (r != null) {
return r;
@@ -541,7 +552,7 @@ public class Mappings {
return Boolean.TRUE;
}
final ClassRepr repr = reprByName(who);
final ClassRepr repr = classReprByName(who);
if (repr != null) {
if (visitedClasses == null) {
@@ -598,7 +609,7 @@ public class Mappings {
}
boolean isFieldVisible(final int className, final FieldRepr field) {
final ClassRepr r = reprByName(className);
final ClassRepr r = classReprByName(className);
if (r == null || r.getFields().contains(field)) {
return true;
}
@@ -606,7 +617,7 @@ public class Mappings {
}
void collectSupersRecursively(final int className, @NotNull final TIntHashSet container) {
final ClassRepr classRepr = reprByName(className);
final ClassRepr classRepr = classReprByName(className);
if (classRepr != null) {
final int[] supers = classRepr.getSupers();
if (container.addAll(supers)) {
@@ -637,7 +648,7 @@ public class Mappings {
if (usages) {
debug("Class usages affection requested");
final ClassRepr classRepr = reprByName(className);
final ClassRepr classRepr = classReprByName(className);
if (classRepr != null) {
debug("Added class usage for ", classRepr.name);
affectedUsages.add(classRepr.createUsage());
@@ -698,11 +709,50 @@ public class Mappings {
}
}
public abstract class UsageConstraint {
public abstract boolean checkResidence(final int residence);
void affectModule(ModuleRepr m, final Collection<File> affectedFiles) {
final Collection<File> depFiles = myClassToSourceFile.get(m.name);
if (depFiles != null) {
debug("Affecting module ", m.name);
affectedFiles.addAll(depFiles);
}
}
public class FileFilterConstraint extends UsageConstraint {
void affectDependentModules(Differential.DiffState state, final int moduleName, @Nullable UsageConstraint constraint, boolean checkTransitive) {
new Object() {
final TIntHashSet visited = new TIntHashSet();
void perform(final int modName) {
final TIntHashSet depNames = myClassToClassDependency.get(modName);
if (depNames != null && !depNames.isEmpty()) {
final TIntHashSet next = new TIntHashSet();
final UsageRepr.Usage moduleUsage = UsageRepr.createModuleUsage(myContext, modName);
state.myAffectedUsages.add(moduleUsage);
final UsageConstraint prevConstraint = state.myUsageConstraints.put(moduleUsage, constraint == null? UsageConstraint.ANY : constraint);
if (prevConstraint != null) {
state.myUsageConstraints.put(moduleUsage, prevConstraint.or(constraint));
}
depNames.forEach(depName -> {
if (visited.add(depName)) {
final ClassFileRepr depRepr = reprByName(depName);
if (depRepr instanceof ModuleRepr) {
state.myDependants.add(depName);
if (checkTransitive && ((ModuleRepr)depRepr).requiresTransitevely(modName)) {
next.add(depName);
}
}
}
return true;
});
next.forEach(m -> {
perform(m);
return true;
});
}
}
}.perform(moduleName);
}
public class FileFilterConstraint implements UsageConstraint {
@NotNull
private final DependentFilesFilter myFilter;
@@ -724,7 +774,7 @@ public class Mappings {
}
}
public class PackageConstraint extends UsageConstraint {
public class PackageConstraint implements UsageConstraint {
public final String packageName;
public PackageConstraint(final String packageName) {
@@ -751,34 +801,6 @@ public class Mappings {
return inheritorOf == null || !inheritorOf || super.checkResidence(residence);
}
}
public class NegationConstraint extends UsageConstraint {
final UsageConstraint x;
public NegationConstraint(UsageConstraint x) {
this.x = x;
}
@Override
public boolean checkResidence(final int residence) {
return !x.checkResidence(residence);
}
}
public class IntersectionConstraint extends UsageConstraint {
final UsageConstraint x;
final UsageConstraint y;
public IntersectionConstraint(final UsageConstraint x, final UsageConstraint y) {
this.x = x;
this.y = y;
}
@Override
public boolean checkResidence(final int residence) {
return x.checkResidence(residence) && y.checkResidence(residence);
}
}
}
void affectAll(final int className, @NotNull final File sourceFile, final Collection<File> affectedFiles, final Collection<File> alreadyCompiledFiles, @Nullable final DependentFilesFilter filter) {
@@ -1022,11 +1044,19 @@ public class Mappings {
private class FileClasses {
final File myFileName;
final Set<ClassRepr> myFileClasses;
final Set<ClassRepr> myFileClasses = new THashSet<>();
final Set<ModuleRepr> myFileModules = new THashSet<>();
FileClasses(File fileName, Collection<ClassRepr> fileClasses) {
this.myFileName = fileName;
this.myFileClasses = new HashSet<>(fileClasses);
FileClasses(File fileName, Collection<ClassFileRepr> fileContent) {
myFileName = fileName;
for (ClassFileRepr repr : fileContent) {
if (repr instanceof ClassRepr) {
myFileClasses.add((ClassRepr)repr);
}
else {
myFileModules.add((ModuleRepr)repr);
}
}
}
}
@@ -1035,12 +1065,14 @@ public class Mappings {
final public Set<UsageRepr.Usage> myAffectedUsages = new HashSet<>();
final public Set<UsageRepr.AnnotationUsage> myAnnotationQuery = new HashSet<>();
final public Map<UsageRepr.Usage, Util.UsageConstraint> myUsageConstraints = new HashMap<>();
final public Map<UsageRepr.Usage, UsageConstraint> myUsageConstraints = new HashMap<>();
final Difference.Specifier<ClassRepr, ClassRepr.Diff> myClassDiff;
final Difference.Specifier<ModuleRepr, ModuleRepr.Diff> myModulesDiff;
private DiffState(Difference.Specifier<ClassRepr, ClassRepr.Diff> classDiff) {
this.myClassDiff = classDiff;
DiffState(Difference.Specifier<ClassRepr, ClassRepr.Diff> classDiff, Difference.Specifier<ModuleRepr, ModuleRepr.Diff> modulesDiff) {
myClassDiff = classDiff;
myModulesDiff = modulesDiff;
}
}
@@ -1120,10 +1152,10 @@ public class Mappings {
if (removed != null) {
for (final String file : removed) {
final File sourceFile = new File(file);
final Collection<ClassRepr> classes = mySourceFileToClasses.get(sourceFile);
final Collection<ClassFileRepr> classes = mySourceFileToClasses.get(sourceFile);
if (classes != null) {
for (ClassRepr c : classes) {
for (ClassFileRepr c : classes) {
debug("Affecting usages of removed class ", c.name);
affectAll(c.name, sourceFile, myAffectedFiles, myCompiledFiles, myFilter);
}
@@ -1160,7 +1192,7 @@ public class Mappings {
if (!m.isPrivate() && m.name != myInitName) {
if (oldItRef == null) {
oldItRef = new Ref<>(getReprByName(null, it.name)); // lazy init
oldItRef = new Ref<>(getClassReprByName(null, it.name)); // lazy init
}
final ClassRepr oldIt = oldItRef.get();
@@ -1240,7 +1272,7 @@ public class Mappings {
final TIntHashSet subClasses = getAllSubclasses(it.name);
subClasses.forEach(subClass -> {
final ClassRepr r = myFuture.reprByName(subClass);
final ClassRepr r = myFuture.classReprByName(subClass);
if (r == null) {
return true;
}
@@ -1248,7 +1280,7 @@ public class Mappings {
if (sourceFileNames != null && !myCompiledFiles.containsAll(sourceFileNames)) {
final int outerClass = r.getOuterClassName();
if (!isEmpty(outerClass)) {
final ClassRepr outerClassRepr = myFuture.reprByName(outerClass);
final ClassRepr outerClassRepr = myFuture.classReprByName(outerClass);
if (outerClassRepr != null && (myFuture.isMethodVisible(outerClassRepr, m) || myFuture.extendsLibraryClass(outerClassRepr, null))) {
myAffectedFiles.addAll(sourceFileNames);
for (File sourceFileName : sourceFileNames) {
@@ -1320,7 +1352,7 @@ public class Mappings {
if (!m.isAbstract()) {
propagated.forEach(p -> {
if (p != it.name) {
final ClassRepr s = myFuture.reprByName(p);
final ClassRepr s = myFuture.classReprByName(p);
if (s != null) {
final Collection<Pair<MethodRepr, ClassRepr>> overridenInS = myFuture.findOverriddenMethods(m, s);
@@ -1538,7 +1570,7 @@ public class Mappings {
if (!f.isPrivate()) {
final TIntHashSet subClasses = getAllSubclasses(classRepr.name);
subClasses.forEach(subClass -> {
final ClassRepr r = myFuture.reprByName(subClass);
final ClassRepr r = myFuture.classReprByName(subClass);
if (r != null) {
final Collection<File> sourceFileNames = myClassToSourceFile.get(subClass);
if (sourceFileNames != null && !myCompiledFiles.containsAll(sourceFileNames)) {
@@ -1591,19 +1623,18 @@ public class Mappings {
// nothing
}
else {
Util.UsageConstraint constraint;
UsageConstraint constraint;
if ((ff.isProtected() && f.isPublic()) || (f.isProtected() && ff.isPublic()) || (ff.isPackageLocal() && f.isProtected())) {
constraint = myFuture.new NegationConstraint(myFuture.new InheritanceConstraint(cc.name));
constraint = myFuture.new InheritanceConstraint(cc.name).negate();
}
else if (ff.isPublic() && ff.isPackageLocal()) {
constraint = myFuture.new NegationConstraint(myFuture.new PackageConstraint(cc.getPackageName()));
constraint = myFuture.new PackageConstraint(cc.getPackageName()).negate();
}
else {
constraint =
myFuture.new IntersectionConstraint(myFuture.new NegationConstraint(myFuture.new InheritanceConstraint(cc.name)),
myFuture.new NegationConstraint(
myFuture.new PackageConstraint(cc.getPackageName())));
final Util.InheritanceConstraint inherit = myFuture.new InheritanceConstraint(cc.name);
final Util.PackageConstraint matchPackage = myFuture.new PackageConstraint(cc.getPackageName());
constraint = inherit.negate().and(matchPackage.negate());
}
for (final UsageRepr.Usage usage : localUsages) {
@@ -1803,7 +1834,7 @@ public class Mappings {
if (superClassChanged) {
myDelta.registerRemovedSuperClass(changedClass.name, changedClass.getSuperClass().className);
final ClassRepr newClass = myDelta.getReprByName(null, changedClass.name);
final ClassRepr newClass = myDelta.getClassReprByName(null, changedClass.name);
assert (newClass != null);
@@ -2143,12 +2174,12 @@ public class Mappings {
debug("Dependent class: ", depClass);
final ClassRepr classRepr = getReprByName(depFile, depClass);
if (classRepr == null) {
final ClassFileRepr repr = getReprByName(depFile, depClass);
if (repr == null) {
return;
}
final Set<UsageRepr.Usage> depUsages = classRepr.getUsages();
final Set<UsageRepr.Usage> depUsages = repr.getUsages();
if (depUsages == null || depUsages.isEmpty()) {
return;
}
@@ -2164,7 +2195,7 @@ public class Mappings {
}
}
else if (state.myAffectedUsages.contains(usage)) {
final Util.UsageConstraint constraint = state.myUsageConstraints.get(usage);
final UsageConstraint constraint = state.myUsageConstraints.get(usage);
if (constraint == null) {
debug("Added file with no constraints");
myAffectedFiles.add(depFile);
@@ -2196,13 +2227,13 @@ public class Mappings {
processDisappearedClasses();
final List<FileClasses> newClasses = new ArrayList<>();
myDelta.mySourceFileToClasses.forEachEntry(new TObjectObjectProcedure<File, Collection<ClassRepr>>() {
myDelta.mySourceFileToClasses.forEachEntry(new TObjectObjectProcedure<File, Collection<ClassFileRepr>>() {
@Override
public boolean execute(File fileName, Collection<ClassRepr> classes) {
public boolean execute(File fileName, Collection<ClassFileRepr> content) {
if (myFilesToCompile == null || myFilesToCompile.contains(fileName)) {
// Consider only files actually compiled in this round.
// For other sources the list of classes taken from this map will be possibly incomplete.
newClasses.add(new FileClasses(fileName, classes));
newClasses.add(new FileClasses(fileName, content));
}
return true;
}
@@ -2210,10 +2241,28 @@ public class Mappings {
for (final FileClasses compiledFile : newClasses) {
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 Set<ClassRepr> pastClasses = new THashSet<>();
final Set<ModuleRepr> pastModules = new THashSet<>();
final Collection<ClassFileRepr> past = mySourceFileToClasses.get(fileName);
if (past != null) {
for (ClassFileRepr repr : past) {
if (repr instanceof ClassRepr) {
pastClasses.add((ClassRepr)repr);
}
else {
pastModules.add((ModuleRepr)repr);
}
}
}
final DiffState state = new DiffState(
Difference.make(pastClasses, compiledFile.myFileClasses),
Difference.make(pastModules, compiledFile.myFileModules)
);
if (!myEasyMode) {
processModules(state, fileName);
}
if (!processChangedClasses(state)) {
if (!myEasyMode) {
// turning non-incremental
@@ -2280,6 +2329,112 @@ public class Mappings {
}
}
}
private void processModules(final DiffState state, File fileName) {
final Difference.Specifier<ModuleRepr, ModuleRepr.Diff> modulesDiff = state.myModulesDiff;
if (modulesDiff.unchanged()) {
return;
}
for (ModuleRepr removedModule : modulesDiff.removed()) {
myDelta.addDeletedClass(removedModule, fileName);
myPresent.affectDependentModules(state, removedModule.name, null, true);
}
for (Pair<ModuleRepr, ModuleRepr.Diff> pair : modulesDiff.changed()) {
final ModuleRepr moduleRepr = pair.first;
final ModuleRepr.Diff d = pair.second;
boolean affectSelf = false;
boolean affectDeps = false;
UsageConstraint constraint = null;
myDelta.addChangedClass(moduleRepr.name);
if (d.versionChanged()) {
final int version = moduleRepr.getVersion();
myPresent.affectDependentModules(state, moduleRepr.name, new UsageConstraint() {
public boolean checkResidence(int dep) {
final ModuleRepr depModule = myPresent.moduleReprByName(dep);
if (depModule != null) {
for (ModuleRequiresRepr requires : depModule.getRequires()) {
if (requires.name == moduleRepr.name && requires.getVersion() == version) {
return true;
}
}
}
return false;
}
}, false);
}
final Difference.Specifier<ModuleRequiresRepr, ModuleRequiresRepr.Diff> requiresDiff = d.requires();
for (ModuleRequiresRepr removed : requiresDiff.removed()) {
affectSelf = true;
if (removed.isTransitive()) {
affectDeps = true;
constraint = UsageConstraint.ANY;
break;
}
}
for (Pair<ModuleRequiresRepr, ModuleRequiresRepr.Diff> changed : requiresDiff.changed()) {
affectSelf |= changed.second.versionChanged();
if (changed.second.becameNonTransitive()) {
affectDeps = true;
// we could have created more precise constraint here: analyze if required module (recursively)
// has only qualified exports that include given module's name. But this seems to be excessive since
// in most cases module's exports are unqualified, so that any other module can access the exported API.
constraint = UsageConstraint.ANY;
}
}
final Difference.Specifier<ModulePackageRepr, ModulePackageRepr.Diff> exportsDiff = d.exports();
if (!affectDeps) {
for (ModulePackageRepr removedPackage : exportsDiff.removed()) {
affectDeps = true;
if (!removedPackage.isQualified()) {
constraint = UsageConstraint.ANY;
break;
}
for (Integer name : removedPackage.getModuleNames()) {
final UsageConstraint matchName = UsageConstraint.exactMatch(name);
if (constraint == null) {
constraint = matchName;
}
else {
constraint = constraint.or(matchName);
}
}
}
}
if (!affectDeps || constraint != UsageConstraint.ANY) {
for (Pair<ModulePackageRepr, ModulePackageRepr.Diff> p : exportsDiff.changed()) {
final Collection<Integer> removedModuleNames = p.second.targetModules().removed();
affectDeps |= !removedModuleNames.isEmpty();
if (!removedModuleNames.isEmpty()) {
affectDeps = true;
for (Integer name : removedModuleNames) {
final UsageConstraint matchName = UsageConstraint.exactMatch(name);
if (constraint == null) {
constraint = matchName;
}
else {
constraint = constraint.or(matchName);
}
}
}
}
}
if (affectSelf) {
myPresent.affectModule(moduleRepr, myAffectedFiles);
}
if (affectDeps) {
myPresent.affectDependentModules(state, moduleRepr.name, constraint, true);
}
}
}
}
public void differentiateOnRebuild(final Mappings delta) {
@@ -2304,11 +2459,9 @@ public class Mappings {
return new Differential(delta, removed, filesToCompile, compiledWithErrors, compiledFiles, affectedFiles, filter, constantSearch).differentiate();
}
private void cleanupBackDependency(final int className,
@Nullable Set<UsageRepr.Usage> usages,
final IntIntMultiMaplet buffer) {
private void cleanupBackDependency(final int className, @Nullable Set<UsageRepr.Usage> usages, final IntIntMultiMaplet buffer) {
if (usages == null) {
final ClassRepr repr = getReprByName(null, className);
final ClassFileRepr repr = getReprByName(null, className);
if (repr != null) {
usages = repr.getUsages();
@@ -2322,7 +2475,7 @@ public class Mappings {
}
}
private void cleanupRemovedClass(final Mappings delta, @NotNull final ClassRepr cr, File sourceFile, final Set<UsageRepr.Usage> usages, final IntIntMultiMaplet dependenciesTrashBin) {
private void cleanupRemovedClass(final Mappings delta, @NotNull final ClassFileRepr cr, File sourceFile, final Set<UsageRepr.Usage> usages, final IntIntMultiMaplet dependenciesTrashBin) {
final int className = cr.name;
// it is safe to cleanup class information if it is mapped to non-existing files only
@@ -2346,8 +2499,10 @@ public class Mappings {
}
}
for (final int superSomething : cr.getSupers()) {
delta.registerRemovedSuperClass(className, superSomething);
if (cr instanceof ClassRepr) {
for (final int superSomething : ((ClassRepr)cr).getSupers()) {
delta.registerRemovedSuperClass(className, superSomething);
}
}
cleanupBackDependency(className, usages, dependenciesTrashBin);
@@ -2355,8 +2510,11 @@ public class Mappings {
myClassToClassDependency.remove(className);
myClassToSubclasses.remove(className);
myClassToSourceFile.remove(className);
if (!cr.isLocal() && !cr.isAnonymous()) {
myShortClassNameIndex.removeFrom(myContext.get(cr.getShortName()), className);
if (cr instanceof ClassRepr) {
final ClassRepr _cr = (ClassRepr)cr;
if (!_cr.isLocal() && !_cr.isAnonymous()) {
myShortClassNameIndex.removeFrom(myContext.get(_cr.getShortName()), className);
}
}
}
@@ -2374,10 +2532,10 @@ public class Mappings {
if (removed != null) {
for (final String file : removed) {
final File deletedFile = new File(file);
final Set<ClassRepr> fileClasses = (Set<ClassRepr>)mySourceFileToClasses.get(deletedFile);
final Set<ClassFileRepr> fileClasses = (Set<ClassFileRepr>)mySourceFileToClasses.get(deletedFile);
if (fileClasses != null) {
for (final ClassRepr aClass : fileClasses) {
for (final ClassFileRepr aClass : fileClasses) {
cleanupRemovedClass(delta, aClass, deletedFile, aClass.getUsages(), dependenciesTrashBin);
}
mySourceFileToClasses.remove(deletedFile);
@@ -2386,8 +2544,8 @@ public class Mappings {
}
if (!delta.isRebuild()) {
for (final Pair<ClassRepr, File> pair : delta.getDeletedClasses()) {
final ClassRepr deletedClass = pair.first;
for (final Pair<ClassFileRepr, File> pair : delta.getDeletedClasses()) {
final ClassFileRepr deletedClass = pair.first;
cleanupRemovedClass(delta, deletedClass, pair.second, deletedClass.getUsages(), dependenciesTrashBin);
}
for (ClassRepr repr : delta.getAddedClasses()) {
@@ -2450,7 +2608,7 @@ public class Mappings {
});
delta.getChangedFiles().forEach(fileName -> {
final Collection<ClassRepr> classes = delta.mySourceFileToClasses.get(fileName);
final Collection<ClassFileRepr> classes = delta.mySourceFileToClasses.get(fileName);
mySourceFileToClasses.replace(fileName, classes);
return true;
});
@@ -2459,9 +2617,9 @@ public class Mappings {
// In case some of these sources was not compiled, but the class was changed, we need to update
// sourceToClasses mapping for such sources to include the updated ClassRepr version of the changed class
final THashSet<File> unchangedSources = new THashSet<>(FileUtil.FILE_HASHING_STRATEGY);
delta.mySourceFileToClasses.forEachEntry(new TObjectObjectProcedure<File, Collection<ClassRepr>>() {
delta.mySourceFileToClasses.forEachEntry(new TObjectObjectProcedure<File, Collection<ClassFileRepr>>() {
@Override
public boolean execute(File source, Collection<ClassRepr> b) {
public boolean execute(File source, Collection<ClassFileRepr> b) {
unchangedSources.add(source);
return true;
}
@@ -2469,11 +2627,11 @@ public class Mappings {
unchangedSources.removeAll(delta.getChangedFiles());
if (!unchangedSources.isEmpty()) {
unchangedSources.forEach(unchangedSource -> {
final Collection<ClassRepr> updatedClasses = delta.mySourceFileToClasses.get(unchangedSource);
final Collection<ClassFileRepr> updatedClasses = delta.mySourceFileToClasses.get(unchangedSource);
if (updatedClasses != null && !updatedClasses.isEmpty()) {
final List<ClassRepr> classesToPut = new ArrayList<>();
final List<ClassFileRepr> classesToPut = new ArrayList<>();
final TIntHashSet updatedClassNames = new TIntHashSet();
for (ClassRepr aClass : updatedClasses) {
for (ClassFileRepr aClass : updatedClasses) {
// from all generated classes on this round consider only 'differentiated' ones, for
// which we can reliably say that the class has changed. Keep classes, for which no such checks were made,
// to make it possible to create a diff and compare changes on next compilation rounds.
@@ -2482,9 +2640,9 @@ public class Mappings {
updatedClassNames.add(aClass.name);
}
}
Collection<ClassRepr> currentClasses = mySourceFileToClasses.get(unchangedSource);
final Collection<ClassFileRepr> currentClasses = mySourceFileToClasses.get(unchangedSource);
if (currentClasses != null) {
for (ClassRepr aClass : currentClasses) {
for (ClassFileRepr aClass : currentClasses) {
if (!updatedClassNames.contains(aClass.name)) {
classesToPut.add(aClass);
}
@@ -2500,11 +2658,14 @@ public class Mappings {
myClassToSubclasses.putAll(delta.myClassToSubclasses);
myClassToSourceFile.replaceAll(delta.myClassToSourceFile);
mySourceFileToClasses.replaceAll(delta.mySourceFileToClasses);
delta.mySourceFileToClasses.forEachEntry(new TObjectObjectProcedure<File, Collection<ClassRepr>>() {
public boolean execute(File src, Collection<ClassRepr> classes) {
for (ClassRepr repr : classes) {
if (!repr.isAnonymous() && !repr.isLocal()) {
myShortClassNameIndex.put(myContext.get(repr.getShortName()), repr.name);
delta.mySourceFileToClasses.forEachEntry(new TObjectObjectProcedure<File, Collection<ClassFileRepr>>() {
public boolean execute(File src, Collection<ClassFileRepr> classes) {
for (ClassFileRepr repr : classes) {
if (repr instanceof ClassRepr) {
final ClassRepr clsRepr = (ClassRepr)repr;
if (!clsRepr.isAnonymous() && !clsRepr.isLocal()) {
myShortClassNameIndex.put(myContext.get(clsRepr.getShortName()), repr.name);
}
}
}
return true;
@@ -2564,25 +2725,25 @@ public class Mappings {
public void associate(String classFileName, Collection<String> sources, ClassReader cr) {
synchronized (myLock) {
final int classFileNameS = myContext.get(classFileName);
final Pair<ClassRepr, Set<UsageRepr.Usage>> result = new ClassfileAnalyzer(myContext).analyze(classFileNameS, cr);
final ClassRepr repr = result.first;
if (repr != null) {
final Set<UsageRepr.Usage> localUsages = result.second;
final int className = repr.name;
final ClassFileRepr result = new ClassfileAnalyzer(myContext).analyze(classFileNameS, cr);
if (result != null) {
// since java9 'repr' can represent either a class or a compiled module-info.java
final int className = result.name;
for (String sourceFileName : sources) {
final File sourceFile = new File(sourceFileName);
myClassToSourceFile.put(className, sourceFile);
mySourceFileToClasses.put(sourceFile, repr);
mySourceFileToClasses.put(sourceFile, result);
}
for (final int s : repr.getSupers()) {
myClassToSubclasses.put(s, className);
if (result instanceof ClassRepr) {
for (final int s : ((ClassRepr)result).getSupers()) {
myClassToSubclasses.put(s, className);
}
}
for (final UsageRepr.Usage u : localUsages) {
for (final UsageRepr.Usage u : result.getUsages()) {
final int owner = u.getOwner();
if (owner != className) {
myClassToClassDependency.put(owner, className);
}
@@ -2618,7 +2779,7 @@ public class Mappings {
myPostPasses.offer(() -> {
final int rootClassName = myContext.get(className.replace(".", "/"));
final Collection<File> fileNames = myClassToSourceFile.get(rootClassName);
final ClassRepr repr = fileNames != null && !fileNames.isEmpty()? getReprByName(fileNames.iterator().next(), rootClassName) : null;
final ClassRepr repr = fileNames != null && !fileNames.isEmpty()? getClassReprByName(fileNames.iterator().next(), rootClassName) : null;
for (final String i : allImports) {
final int iname = myContext.get(i.replace('.', '/'));
@@ -2637,8 +2798,19 @@ public class Mappings {
@Nullable
public Set<ClassRepr> getClasses(final String sourceFileName) {
final File f = new File(sourceFileName);
synchronized (myLock) {
return (Set<ClassRepr>)mySourceFileToClasses.get(new File(sourceFileName));
final Collection<ClassFileRepr> reprs = mySourceFileToClasses.get(f);
if (reprs == null || reprs.isEmpty()) {
return null;
}
final Set<ClassRepr> result = new THashSet<>();
for (ClassFileRepr repr : reprs) {
if (repr instanceof ClassRepr) {
result.add((ClassRepr)repr);
}
}
return result;
}
}
@@ -2736,7 +2908,7 @@ public class Mappings {
return myIsRebuild;
}
private void addDeletedClass(final ClassRepr cr, File fileName) {
private void addDeletedClass(final ClassFileRepr cr, File fileName) {
assert (myDeletedClasses != null);
myDeletedClasses.add(Pair.create(cr, fileName));
@@ -2764,7 +2936,7 @@ public class Mappings {
}
@NotNull
private Set<Pair<ClassRepr, File>> getDeletedClasses() {
private Set<Pair<ClassFileRepr, File>> getDeletedClasses() {
return myDeletedClasses == null ? Collections.emptySet() : Collections.unmodifiableSet(myDeletedClasses);
}
@@ -45,7 +45,11 @@ class MethodRepr extends ProtoMember {
public final TypeRepr.AbstractType[] myArgumentTypes;
public final Set<TypeRepr.AbstractType> myExceptions;
public static abstract class Diff extends Difference {
public static abstract class Diff extends DifferenceImpl {
Diff(@NotNull Difference delegate) {
super(delegate);
}
public abstract Specifier<ParamAnnotation, Difference> parameterAnnotations();
@@ -62,28 +66,14 @@ class MethodRepr extends ProtoMember {
final Difference diff = super.difference(past);
final Difference.Specifier<TypeRepr.AbstractType, Difference> excs = Difference.make(m.myExceptions, myExceptions);
final Difference.Specifier<ParamAnnotation, Difference> paramAnnotations = Difference.make(m.myParameterAnnotations, myParameterAnnotations);
final int base = paramAnnotations.unchanged()? diff.base() : diff.base() | Difference.ANNOTATIONS;
return new Diff() {
@Override
public Specifier<TypeRepr.ClassType, Difference> annotations() {
return diff.annotations();
}
return new Diff(diff) {
@Override
public Specifier<ParamAnnotation, Difference> parameterAnnotations() {
return paramAnnotations;
}
@Override
public int addedModifiers() {
return diff.addedModifiers();
}
@Override
public int removedModifiers() {
return diff.removedModifiers();
}
@Override
public boolean no() {
return base() == NONE && !defaultAdded() && !defaultRemoved() && excs.unchanged() && paramAnnotations.unchanged();
@@ -106,24 +96,13 @@ class MethodRepr extends ProtoMember {
@Override
public int base() {
final int base = diff.base();
return paramAnnotations.unchanged()? base : base | Difference.ANNOTATIONS;
}
@Override
public boolean packageLocalOn() {
return diff.packageLocalOn();
return base;
}
@Override
public boolean hadValue() {
return m.hasValue();
}
@Override
public boolean weakedAccess() {
return diff.weakedAccess();
}
};
}
@@ -164,10 +143,10 @@ class MethodRepr extends ProtoMember {
final int size = DataInputOutputUtil.readINT(in);
myArgumentTypes = RW.read(externalizer, in, new TypeRepr.AbstractType[size]);
myExceptions = (Set<TypeRepr.AbstractType>)RW.read(externalizer, new THashSet<>(0), in);
myExceptions = RW.read(externalizer, new THashSet<>(0), in);
final DataExternalizer<TypeRepr.ClassType> clsTypeExternalizer = TypeRepr.classTypeExternalizer(context);
myParameterAnnotations = (Set<ParamAnnotation>)RW.read(new DataExternalizer<ParamAnnotation>() {
myParameterAnnotations = RW.read(new DataExternalizer<ParamAnnotation>() {
@Override
public void save(@NotNull DataOutput out, ParamAnnotation value) throws IOException {
value.save(out);
@@ -0,0 +1,121 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.jps.builders.java.dependencyView;
import com.intellij.util.io.DataExternalizer;
import com.intellij.util.io.DataInputOutputUtil;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.PrintStream;
import java.util.*;
/**
* @author Eugene Zhuravlev
* Date: 02-Oct-17
*/
public class ModulePackageRepr extends Proto {
private static final DataExternalizer<Integer> INT_EXTERNALIZER = new DataExternalizer<Integer>() {
public void save(@NotNull DataOutput out, Integer value) throws IOException {
DataInputOutputUtil.writeINT(out, value);
}
public Integer read(@NotNull DataInput in) throws IOException {
return DataInputOutputUtil.readINT(in);
}
};
private final Set<Integer> myModuleNames = new THashSet<>();
protected ModulePackageRepr(DependencyContext context, int name, Collection<String> modules) {
super(0, context.get(null), name, Collections.emptySet());
for (String module : modules) {
myModuleNames.add(context.get(module));
}
}
protected ModulePackageRepr(DependencyContext context, DataInput in) {
super(context, in);
RW.read(INT_EXTERNALIZER, myModuleNames, in);
}
public Set<Integer> getModuleNames() {
return Collections.unmodifiableSet(myModuleNames);
}
public boolean isQualified() {
return !myModuleNames.isEmpty();
}
public void save(DataOutput out) {
super.save(out);
RW.save(myModuleNames, INT_EXTERNALIZER, out);
}
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
return name == ((ModulePackageRepr)o).name;
}
public int hashCode() {
return 31 * name;
}
public abstract static class Diff extends DifferenceImpl {
public abstract Specifier<Integer, Difference> targetModules();
Diff(@NotNull Difference delegate) {
super(delegate);
}
}
public Diff difference(Proto past) {
final Difference.Specifier<Integer, Difference> targetModulesDiff = Difference.make(((ModulePackageRepr)past).myModuleNames, myModuleNames);
return new Diff(super.difference(past)) {
public Specifier<Integer, Difference> targetModules() {
return targetModulesDiff;
}
public boolean no() {
return super.no() && targetModules().unchanged();
}
};
}
public void toStream(DependencyContext context, PrintStream stream) {
final StringBuilder sb = new StringBuilder();
sb.append("Module package: ").append(context.getValue(name));
final Set<Integer> moduleNames = myModuleNames;
if (moduleNames != null && !moduleNames.isEmpty()) {
final List<String> names = new ArrayList<>();
for (Integer moduleName : moduleNames) {
names.add(context.getValue(moduleName));
}
Collections.sort(names, String::compareToIgnoreCase);
sb.append(" to");
for (String s : names) {
sb.append(" ").append(s);
}
}
stream.println(sb.toString());
}
public static DataExternalizer<ModulePackageRepr> externalizer(final DependencyContext context) {
return new DataExternalizer<ModulePackageRepr>() {
public void save(@NotNull DataOutput out, ModulePackageRepr value) {
value.save(out);
}
public ModulePackageRepr read(@NotNull DataInput in) {
return new ModulePackageRepr(context, in);
}
};
}
}
@@ -0,0 +1,160 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.jps.builders.java.dependencyView;
import com.intellij.util.io.DataExternalizer;
import com.intellij.util.io.DataInputOutputUtil;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.builders.storage.BuildDataCorruptedException;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.PrintStream;
import java.util.*;
/**
* @author Eugene Zhuravlev
* Date: 30-Sep-17
*/
public class ModuleRepr extends ClassFileRepr{
private final int myVersion;
private final Set<ModuleRequiresRepr> myRequires; // module names
private final Set<ModulePackageRepr> myExports; // package names
public ModuleRepr(DependencyContext context, int access, int version, int fileName, int name, Set<ModuleRequiresRepr> requires, Set<ModulePackageRepr> exports, Set<UsageRepr.Usage> usages) {
super(access, context.get(null), name, Collections.emptySet(), fileName, context, usages);
myVersion = version;
myRequires = requires;
myExports = exports;
updateClassUsages(context, usages);
}
public ModuleRepr(DependencyContext context, DataInput in) {
super(context, in);
try {
myVersion = DataInputOutputUtil.readINT(in);
myRequires = RW.read(ModuleRequiresRepr.externalizer(context), new THashSet<>(), in);
myExports = RW.read(ModulePackageRepr.externalizer(context), new THashSet<>(), in);
}
catch (IOException e) {
throw new BuildDataCorruptedException(e);
}
}
public int getVersion() {
return myVersion;
}
public Set<ModuleRequiresRepr> getRequires() {
return myRequires;
}
public Set<ModulePackageRepr> getExports() {
return myExports;
}
public void save(DataOutput out) {
super.save(out);
try {
DataInputOutputUtil.writeINT(out, myVersion);
RW.save(myRequires, out);
RW.save(myExports, out);
}
catch (IOException e) {
throw new BuildDataCorruptedException(e);
}
}
protected void updateClassUsages(DependencyContext context, Set<UsageRepr.Usage> s) {
for (ModuleRequiresRepr require : myRequires) {
if (require.name != name) {
s.add(UsageRepr.createModuleUsage(context, require.name));
}
}
}
public void toStream(DependencyContext context, PrintStream stream) {
super.toStream(context, stream);
stream.println(" Requires:");
streamProtoCollection(context, stream, myRequires);
stream.println(" End Of Requires");
stream.println(" Exports:");
streamProtoCollection(context, stream, myExports);
stream.println(" End Of Exports");
}
private static <T extends Proto> void streamProtoCollection(DependencyContext context, PrintStream stream, final Collection<T> collection) {
final List<T> list = new ArrayList<>(collection);
list.sort(Comparator.comparingInt(o -> o.name));
for (T reqRepr : list) {
reqRepr.toStream(context, stream);
}
}
public boolean requiresTransitevely(int requirementName) {
for (ModuleRequiresRepr require : myRequires) {
if (require.name == requirementName) {
return require.isTransitive();
}
}
return false;
}
public abstract static class Diff extends DifferenceImpl {
Diff(@NotNull Difference delegate) {
super(delegate);
}
public abstract Specifier<ModuleRequiresRepr, ModuleRequiresRepr.Diff> requires();
public abstract Specifier<ModulePackageRepr, ModulePackageRepr.Diff> exports();
public abstract boolean versionChanged();
public boolean no() {
return base() == NONE && requires().unchanged() && exports().unchanged() && !versionChanged();
}
}
public Diff difference(Proto past) {
final Difference delegate = super.difference(past);
final ModuleRepr pastModule = (ModuleRepr)past;
final int base = !getUsages().equals(pastModule.getUsages())? delegate.base() | Difference.USAGES : delegate.base();
return new Diff(delegate) {
public Specifier<ModuleRequiresRepr, ModuleRequiresRepr.Diff> requires() {
return Difference.make(pastModule.myRequires, myRequires);
}
public Specifier<ModulePackageRepr, ModulePackageRepr.Diff> exports() {
return Difference.make(pastModule.myExports, myExports);
}
public boolean versionChanged() {
return pastModule.getVersion() != myVersion;
}
public int base() {
return base;
}
};
}
public static DataExternalizer<ModuleRepr> externalizer(final DependencyContext context) {
return new DataExternalizer<ModuleRepr>() {
@Override
public void save(@NotNull final DataOutput out, final ModuleRepr value) throws IOException {
value.save(out);
}
@Override
public ModuleRepr read(@NotNull final DataInput in) throws IOException {
return new ModuleRepr(context, in);
}
};
}
}
@@ -0,0 +1,116 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.jps.builders.java.dependencyView;
import com.intellij.util.io.DataExternalizer;
import com.intellij.util.io.DataInputOutputUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.builders.storage.BuildDataCorruptedException;
import org.jetbrains.org.objectweb.asm.Opcodes;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Collections;
/**
* @author Eugene Zhuravlev
* Date: 02-Oct-17
*/
public class ModuleRequiresRepr extends Proto {
private final int myVersion;
public ModuleRequiresRepr(DependencyContext context, int access, int name, String version) {
super(access, context.get(null), name, Collections.emptySet());
myVersion = context.get(version);
}
public ModuleRequiresRepr(DependencyContext context, DataInput in) {
super(context, in);
try {
myVersion = DataInputOutputUtil.readINT(in);
}
catch (IOException e) {
throw new BuildDataCorruptedException(e);
}
}
public boolean isTransitive() {
return (access & Opcodes.ACC_TRANSITIVE) != 0;
}
public int getVersion() {
return myVersion;
}
@Override
public void save(final DataOutput out) {
try {
super.save(out);
DataInputOutputUtil.writeINT(out, myVersion);
}
catch (IOException e) {
throw new BuildDataCorruptedException(e);
}
}
public static DataExternalizer<ModuleRequiresRepr> externalizer(DependencyContext context) {
return new DataExternalizer<ModuleRequiresRepr>() {
public void save(@NotNull DataOutput out, ModuleRequiresRepr value) throws IOException {
value.save(out);
}
public ModuleRequiresRepr read(@NotNull DataInput in) throws IOException {
return new ModuleRequiresRepr(context, in);
}
};
}
public abstract static class Diff extends DifferenceImpl {
Diff(@NotNull Difference delegate) {
super(delegate);
}
public abstract boolean versionChanged();
public abstract boolean becameNonTransitive();
}
public Diff difference(Proto past) {
final ModuleRequiresRepr pastRequirement = (ModuleRequiresRepr)past;
return new Diff(super.difference(past)) {
public boolean versionChanged() {
return pastRequirement.myVersion != myVersion;
}
public boolean no() {
return super.no() && !versionChanged();
}
public boolean becameNonTransitive() {
return pastRequirement.isTransitive() && !ModuleRequiresRepr.this.isTransitive();
}
};
}
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
return name == ((ModuleRequiresRepr)o).name;
}
public int hashCode() {
return 31 * name;
}
@Override
public void toStream(final DependencyContext context, final PrintStream stream) {
stream.println("Requires module: " + context.getValue(name) + ":" + access + ":" + myVersion);
}
}

Some files were not shown because too many files have changed in this diff Show More