diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 032b86267..7af634096 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -51,6 +51,9 @@ jobs: run: | python3 -m pip install --upgrade pip if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + - name: Spotless Check + if: matrix.jdk == 11 || matrix.jdk == 17 + run: ./gradlew spotlessCheck - name: Build run: | export JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF8 diff --git a/build.gradle b/build.gradle index 47c39b36a..bbe606cb0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,14 @@ +buildscript { + dependencies { + if (JavaVersion.current() >= JavaVersion.VERSION_11) { + // Code formatting; defines targets "spotlessApply" and "spotlessCheck". + // https://github.com/diffplug/spotless/tags ; see tags starting "gradle/" + // Only works on JDK 11+. + classpath 'com.diffplug.spotless:spotless-plugin-gradle:6.22.0' + } + } +} + plugins { id 'com.github.johnrengelman.shadow' version '7.1.2' } @@ -19,22 +30,54 @@ ext { // On a Java 8 JVM, use error-prone javac and source/target 8. // On a Java 9+ JVM, use the host javac, default source/target, and required module flags. isJava8 = JavaVersion.current() == JavaVersion.VERSION_1_8 - + isJava11plus = JavaVersion.current() >= JavaVersion.VERSION_11 errorproneJavacVersion = '9+181-r4173-1' // Keep in sync with checker-framework/build.gradle. // TODO: find a way to directly use that variable. compilerArgsForRunningCF = [ - "--add-exports", "jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", - "--add-exports", "jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED", - "--add-exports", "jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", - "--add-exports", "jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", - "--add-exports", "jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED", - "--add-exports", "jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED", - "--add-exports", "jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", - "--add-exports", "jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", - "--add-opens", "jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED", + "--add-exports", + "jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", + "--add-exports", + "jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED", + "--add-exports", + "jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", + "--add-exports", + "jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", + "--add-exports", + "jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED", + "--add-exports", + "jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED", + "--add-exports", + "jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", + "--add-exports", + "jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", + "--add-opens", + "jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED", ] + if (isJava11plus) { + apply plugin: 'com.diffplug.spotless' + spotless { + format 'misc', { + target '*.md', '*.tex', '.gitignore', 'Makefile' + indentWithSpaces(2) + trimTrailingWhitespace() + } + + java { + googleJavaFormat().aosp() + importOrder('com', 'jdk', 'lib', 'lombok', 'org', 'java', 'javax') + formatAnnotations().addTypeAnnotation("PolyInitialized") + } + + groovyGradle { + target '**/*.gradle' + greclipse() // which formatter Spotless should use to format .gradle files. + indentWithSpaces(4) + trimTrailingWhitespace() + } + } + } } println '====================================' @@ -127,7 +170,7 @@ test { dependsOn('dist') systemProperties 'path.afu.scripts': "${afu}/scripts", - 'use.hacks': true + 'use.hacks': true systemProperties += [JDK_JAR: "${checkerFrameworkPath}/checker/dist/jdk8.jar"] @@ -136,7 +179,9 @@ test { } if (isJava8) { - jvmArgs += ["-Xbootclasspath/p:${configurations.javacJar.asPath}"] + jvmArgs += [ + "-Xbootclasspath/p:${configurations.javacJar.asPath}" + ] } else { // Without this, the test throw "java.lang.OutOfMemoryError: Java heap space" // Corresponding pull request: https://github.com/opprop/checker-framework-inference/pull/263 @@ -166,7 +211,6 @@ test { "Skipped: ${result.skippedTestCount}, " + "Time elapsed: ${seconds} sec\n" } - } } @@ -174,13 +218,14 @@ compileJava { dependsOn(buildLingeling) dependsOn(buildDLJC) options.compilerArgs = [ - '-implicit:class', - '-Awarns', - '-Xmaxwarns', '10000', - // Can't use this because JSON library contains raw types: - // '-Xlint:unchecked', - '-Xlint:deprecation', - '-Werror', + '-implicit:class', + '-Awarns', + '-Xmaxwarns', + '10000', + // Can't use this because JSON library contains raw types: + // '-Xlint:unchecked', + '-Xlint:deprecation', + '-Werror', ] } @@ -214,7 +259,7 @@ task dist(dependsOn: shadowJar, type: Copy) { "${checkerFrameworkPath}/checker/dist/checker-qual.jar", "${checkerFrameworkPath}/checker/dist/checker-util.jar", "${checkerFrameworkPath}/checker/dist/javac.jar", - ) + ) into file('dist') } @@ -270,20 +315,30 @@ task cloneAndBuildDependencies(type: Exec) { task testCheckerInferenceScript(type: Exec, dependsOn: dist) { description 'Basic sanity check of scripts/inference' executable './scripts/inference' - args = ['--mode', 'TYPECHECK', - '--checker', 'ostrusted.OsTrustedChecker', - '--solver', 'checkers.inference.solver.PropagationSolver', - 'testdata/ostrusted/Test.java'] + args = [ + '--mode', + 'TYPECHECK', + '--checker', + 'ostrusted.OsTrustedChecker', + '--solver', + 'checkers.inference.solver.PropagationSolver', + 'testdata/ostrusted/Test.java' + ] } task testCheckerInferenceDevScript(type: Exec, dependsOn: [dist, dependenciesJar]) { description 'Basic sanity check of scripts/inference-dev' executable './scripts/inference-dev' - args = ['--mode', 'INFER', - '--checker', 'interning.InterningChecker', - '--solver', 'checkers.inference.solver.MaxSat2TypeSolver', - '--hacks=true', - 'testdata/interning/MapAssignment.java'] + args = [ + '--mode', + 'INFER', + '--checker', + 'interning.InterningChecker', + '--solver', + 'checkers.inference.solver.MaxSat2TypeSolver', + '--hacks=true', + 'testdata/interning/MapAssignment.java' + ] } task testDataflowExternalSolvers(type: Exec, dependsOn: [dist, dependenciesJar]) { @@ -294,10 +349,10 @@ task testDataflowExternalSolvers(type: Exec, dependsOn: [dist, dependenciesJar]) afterEvaluate { // Create a task for each test class whose name is the same as the class name. sourceSets.test.java.filter { - it.path.contains('tests/checkers') && - it.path.endsWith('Test.java') && - !it.path.contains('CFInferenceTest') - }.forEach { file -> + it.path.contains('tests/checkers') && + it.path.endsWith('Test.java') && + !it.path.contains('CFInferenceTest') + }.forEach { file -> String junitClassName = file.name.replaceAll(".java", "") tasks.create(name: "${junitClassName}", type: Test, group: 'Verification') { description "Run ${junitClassName} tests." @@ -310,16 +365,18 @@ afterEvaluate { dependsOn(shadowJar) systemProperties 'path.afu.scripts': "${afu}/scripts", - 'path.inference.script': "${projectDir}/scripts/inference", - 'use.hacks': true, - JDK_JAR: "${checkerFrameworkPath}/checker/dist/jdk8.jar" + 'path.inference.script': "${projectDir}/scripts/inference", + 'use.hacks': true, + JDK_JAR: "${checkerFrameworkPath}/checker/dist/jdk8.jar" if (project.hasProperty('emit.test.debug')) { systemProperties += ["emit.test.debug": 'true'] } if (isJava8) { - jvmArgs += ["-Xbootclasspath/p:${configurations.javacJar.asPath}"] + jvmArgs += [ + "-Xbootclasspath/p:${configurations.javacJar.asPath}" + ] } testLogging { diff --git a/src/checkers/inference/BaseInferrableChecker.java b/src/checkers/inference/BaseInferrableChecker.java index 96e0c078f..57fef3348 100644 --- a/src/checkers/inference/BaseInferrableChecker.java +++ b/src/checkers/inference/BaseInferrableChecker.java @@ -1,11 +1,15 @@ package checkers.inference; +import com.sun.source.tree.Tree; +import com.sun.source.util.Trees; + import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; import org.checkerframework.framework.flow.CFAnalysis; import org.checkerframework.framework.flow.CFStore; import org.checkerframework.framework.flow.CFTransfer; import org.checkerframework.framework.flow.CFValue; import org.checkerframework.framework.type.GenericAnnotatedTypeFactory; + import java.lang.annotation.Annotation; import java.util.Collections; import java.util.Set; @@ -14,13 +18,7 @@ import checkers.inference.dataflow.InferenceTransfer; import checkers.inference.model.ConstraintManager; -import com.sun.source.tree.Tree; -import com.sun.source.util.Trees; - -/** - * Default implementation of InferrableChecker. - * - */ +/** Default implementation of InferrableChecker. */ public abstract class BaseInferrableChecker extends InferenceChecker implements InferrableChecker { @Override @@ -29,7 +27,7 @@ public void initChecker() { // except for the last line assigning the visitor { Trees trees = Trees.instance(processingEnv); - assert( trees != null ); /*nninvariant*/ + assert (trees != null); /*nninvariant*/ this.trees = trees; this.messager = processingEnv.getMessager(); @@ -40,7 +38,8 @@ public void initChecker() { } @Override - public InferenceVisitor createVisitor(InferenceChecker ichecker, BaseAnnotatedTypeFactory factory, boolean infer) { + public InferenceVisitor createVisitor( + InferenceChecker ichecker, BaseAnnotatedTypeFactory factory, boolean infer) { return new InferenceVisitor<>(this, ichecker, factory, infer); } @@ -51,11 +50,11 @@ public BaseInferenceRealTypeFactory createRealTypeFactory(boolean infer) { @Override public CFAnalysis createInferenceAnalysis( - InferenceChecker checker, - GenericAnnotatedTypeFactory factory, - SlotManager slotManager, - ConstraintManager constraintManager, - InferrableChecker realChecker) { + InferenceChecker checker, + GenericAnnotatedTypeFactory factory, + SlotManager slotManager, + ConstraintManager constraintManager, + InferrableChecker realChecker) { return new InferenceAnalysis(checker, factory, slotManager, constraintManager, realChecker); } @@ -81,12 +80,20 @@ public boolean shouldStoreConstantSlots() { } @Override - public InferenceAnnotatedTypeFactory createInferenceATF(InferenceChecker inferenceChecker, - InferrableChecker realChecker, BaseAnnotatedTypeFactory realTypeFactory, - SlotManager slotManager, ConstraintManager constraintManager) { - InferenceAnnotatedTypeFactory InferenceAFT = new InferenceAnnotatedTypeFactory( - inferenceChecker, realChecker.withCombineConstraints(), realTypeFactory, realChecker, - slotManager, constraintManager); + public InferenceAnnotatedTypeFactory createInferenceATF( + InferenceChecker inferenceChecker, + InferrableChecker realChecker, + BaseAnnotatedTypeFactory realTypeFactory, + SlotManager slotManager, + ConstraintManager constraintManager) { + InferenceAnnotatedTypeFactory InferenceAFT = + new InferenceAnnotatedTypeFactory( + inferenceChecker, + realChecker.withCombineConstraints(), + realTypeFactory, + realChecker, + slotManager, + constraintManager); return InferenceAFT; } diff --git a/src/checkers/inference/BytecodeTypeAnnotator.java b/src/checkers/inference/BytecodeTypeAnnotator.java index b8d69fcb2..ba4ecacf9 100644 --- a/src/checkers/inference/BytecodeTypeAnnotator.java +++ b/src/checkers/inference/BytecodeTypeAnnotator.java @@ -7,34 +7,33 @@ import checkers.inference.util.CopyUtil; - /** - * Adds annotations to types that have come from bytecode. Note, these types will - * receive concrete "real" annotations from the real type factory AND a VarAnnot. + * Adds annotations to types that have come from bytecode. Note, these types will receive concrete + * "real" annotations from the real type factory AND a VarAnnot. * - * The VarAnnot is so that we have an annotation in both hierarchies and so that - * for cases like Verigames the shape of a gameboard won't differ depending on - * whether a library was in bytecode or source code. Note: I believe this is - * much less of an issue these days since the game is more akin to - * human aided automatic solving. + *

The VarAnnot is so that we have an annotation in both hierarchies and so that for cases like + * Verigames the shape of a gameboard won't differ depending on whether a library was in bytecode or + * source code. Note: I believe this is much less of an issue these days since the game is more akin + * to human aided automatic solving. */ public class BytecodeTypeAnnotator { private final AnnotatedTypeFactory realTypeFactory; private final InferenceAnnotatedTypeFactory inferenceTypeFactory; - - public BytecodeTypeAnnotator(InferenceAnnotatedTypeFactory inferenceTypeFactory, - AnnotatedTypeFactory realTypeFactory) { + public BytecodeTypeAnnotator( + InferenceAnnotatedTypeFactory inferenceTypeFactory, + AnnotatedTypeFactory realTypeFactory) { this.realTypeFactory = realTypeFactory; this.inferenceTypeFactory = inferenceTypeFactory; } /** - * Get the type of element from the realTypeFactory. Copy it's annotations to inferenceType. - * Add a @VarAnnot to all definite type use locations (locations that can be defaulted) in inferenceType and - * add an equality constraint between it and the "real" annotations + * Get the type of element from the realTypeFactory. Copy it's annotations to inferenceType. Add + * a @VarAnnot to all definite type use locations (locations that can be defaulted) in + * inferenceType and add an equality constraint between it and the "real" annotations + * * @param element The bytecode declaration from which inferenceType was created - * @param inferenceType The type of element. inferenceType will be annotated by this method + * @param inferenceType The type of element. inferenceType will be annotated by this method */ public void annotate(final Element element, final AnnotatedTypeMirror inferenceType) { final AnnotatedTypeMirror realType = realTypeFactory.getAnnotatedType(element); diff --git a/src/checkers/inference/CheckerFrameworkUtil.java b/src/checkers/inference/CheckerFrameworkUtil.java index 410239e89..f0182ee5d 100644 --- a/src/checkers/inference/CheckerFrameworkUtil.java +++ b/src/checkers/inference/CheckerFrameworkUtil.java @@ -1,22 +1,23 @@ package checkers.inference; -import java.io.PrintWriter; -import java.nio.charset.Charset; - -import javax.tools.JavaFileManager; - import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.main.Main; import com.sun.tools.javac.main.Main.Result; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.Context.Factory; +import java.io.PrintWriter; +import java.nio.charset.Charset; + +import javax.tools.JavaFileManager; + public class CheckerFrameworkUtil { public static boolean invokeCheckerFramework(String[] args, PrintWriter outputCapture) { Main compiler = new Main("javac", outputCapture); - // see https://github.com/google/error-prone-javac/blob/a53d069bbdb2c60232ed3811c19b65e41c3e60e0/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Main.java#L159 + // see + // https://github.com/google/error-prone-javac/blob/a53d069bbdb2c60232ed3811c19b65e41c3e60e0/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Main.java#L159 Context context = new Context(); DummyJavacFileManager.preRegister(context); Result compilerResult = compiler.compile(args, context); @@ -25,10 +26,9 @@ public static boolean invokeCheckerFramework(String[] args, PrintWriter outputCa } /** - * This class prevents InferenceMain from being loaded by the bootstrap class - * loader, resulting in two instances of the class of InferenceMain in both - * AppClassLoader and bootstrap class loader. See - * https://github.com/eisop/checker-framework-inference/pull/7 and + * This class prevents InferenceMain from being loaded by the bootstrap class loader, resulting + * in two instances of the class of InferenceMain in both AppClassLoader and bootstrap class + * loader. See https://github.com/eisop/checker-framework-inference/pull/7 and * https://github.com/eisop/checker-framework-inference/pull/9 */ private static class DummyJavacFileManager extends JavacFileManager { @@ -37,8 +37,9 @@ public DummyJavacFileManager(Context context, boolean register, Charset charset) } public static void preRegister(Context context) { - context.put(JavaFileManager.class, - (Factory)c -> new DummyJavacFileManager(c, true, null)); + context.put( + JavaFileManager.class, + (Factory) c -> new DummyJavacFileManager(c, true, null)); } } } diff --git a/src/checkers/inference/ConstraintNormalizer.java b/src/checkers/inference/ConstraintNormalizer.java index e9261a858..84ed62c8b 100644 --- a/src/checkers/inference/ConstraintNormalizer.java +++ b/src/checkers/inference/ConstraintNormalizer.java @@ -1,6 +1,5 @@ package checkers.inference; -import checkers.inference.model.VariableSlot; import org.checkerframework.javacutil.BugInCF; import java.util.ArrayList; @@ -19,11 +18,12 @@ import checkers.inference.model.Constraint; import checkers.inference.model.ExistentialVariableSlot; import checkers.inference.model.Slot; +import checkers.inference.model.VariableSlot; /** - * This class currently just removes ExistentialVariables from the set of constraints - * and replaces them with ExistentialConstraints. In the future, we may want to make - * this an interface or make it customizable + * This class currently just removes ExistentialVariables from the set of constraints and replaces + * them with ExistentialConstraints. In the future, we may want to make this an interface or make it + * customizable */ public class ConstraintNormalizer { @@ -33,9 +33,7 @@ protected interface Normalizer { boolean accept(Constraint constraint); } - public ConstraintNormalizer() { - - } + public ConstraintNormalizer() {} public Set normalize(Set constraints) { Set filteredConstraints = new LinkedHashSet<>(constraints); @@ -69,8 +67,9 @@ public Set getConstraints() { } /** - * Returns true if this constraint contains an ExistentialVariable and - * this constraint will be replaced by this normalizer + * Returns true if this constraint contains an ExistentialVariable and this constraint will + * be replaced by this normalizer + * * @param constraint * @return */ @@ -99,7 +98,8 @@ protected void collectConstraints(final BinaryConstraint constraint) { addToTree(leftSlot, rightSlot, constraint); } - // TODO: DOCUMENT THAT WE BASICALLY (FOR BINARY CONSTRAINTS) BUILD UP ALL POSSIBLE EXISTS/DOESN'T EXISTS + // TODO: DOCUMENT THAT WE BASICALLY (FOR BINARY CONSTRAINTS) BUILD UP ALL POSSIBLE + // EXISTS/DOESN'T EXISTS // TODO: FOR EITHER SIDE OF THE CONSTRAINT THEN TAKE THE CARTESIAN PRODUCT protected List slotsToConditionals(final Slot existentialVariableSlot) { @@ -125,21 +125,23 @@ protected List slotsToConditionals(final Slot existentialVariableSlot) { // !1 2 !5 1 => [ filtered out as it unsatisfiable // !1 2 !5 !1 6 => 2 [ 6 // ... - protected void addToTree(final List leftSlots, - final List rightSlots, - final BinaryConstraint constraint) { + protected void addToTree( + final List leftSlots, + final List rightSlots, + final BinaryConstraint constraint) { - final int initialSize = (int) Math.floor((Math.pow(leftSlots.size() * leftSlots.size(), 2) * 3/4)); + final int initialSize = + (int) Math.floor((Math.pow(leftSlots.size() * leftSlots.size(), 2) * 3 / 4)); // a list of values from leftSlots, where exist == false // we have already added their positive cases to implications final HashSet previouslyEncountered = new HashSet<>(initialSize); - final int lastLeftIndex = leftSlots.size() - 1; + final int lastLeftIndex = leftSlots.size() - 1; final int lastRightIndex = rightSlots.size() - 1; for (int leftIndex = 0; leftIndex < leftSlots.size(); leftIndex++) { - final Slot left = leftSlots.get(leftIndex); + final Slot left = leftSlots.get(leftIndex); final boolean lastLeft = leftIndex == lastLeftIndex; final TreeSet encountered = new TreeSet<>(previouslyEncountered); @@ -165,8 +167,6 @@ protected void addToTree(final List leftSlots, } } } - - } private static class ExistentialTree { @@ -192,7 +192,8 @@ public void addConstraints(final TreeSet path, final Constraint constrain current.constraints.add(constraint); } - private static ExistentialNode getOrCreateNode(final TreeMap nodes, Value value) { + private static ExistentialNode getOrCreateNode( + final TreeMap nodes, Value value) { ExistentialNode node; if (!nodes.containsKey(value.slot)) { node = new ExistentialNode(value); @@ -212,10 +213,8 @@ public Set toConstraints() { } return constraints; } - } - private static class ExistentialNode { private final Slot slot; private final TreeMap ifExists; @@ -250,11 +249,11 @@ public Set toConstraints() { } final LinkedHashSet ret = new LinkedHashSet<>(); - ret.add(InferenceMain - .getInstance() - .getConstraintManager() - .createExistentialConstraint(slot, ifExistsConstraints, - ifNotExistsConstraints)); + ret.add( + InferenceMain.getInstance() + .getConstraintManager() + .createExistentialConstraint( + slot, ifExistsConstraints, ifNotExistsConstraints)); return ret; } } @@ -296,8 +295,9 @@ public String toString() { if (alwaysExists) { sb.append("["); sb.append( - slot instanceof VariableSlot ? slot.getId() - : ((ConstantSlot) slot).getValue()); + slot instanceof VariableSlot + ? slot.getId() + : ((ConstantSlot) slot).getValue()); sb.append("]"); } else { if (!exists) { @@ -310,6 +310,7 @@ public String toString() { } private static SlotComparator SLOT_COMPARATOR = new SlotComparator(); + private static class SlotComparator implements Comparator { @Override @@ -319,9 +320,10 @@ public int compare(Slot o1, Slot o2) { } if (o1 instanceof ConstantSlot) { if (o2 instanceof ConstantSlot) { - return ((ConstantSlot) o1).getValue().toString().compareTo( - ((ConstantSlot) o2).getValue().toString() - ); + return ((ConstantSlot) o1) + .getValue() + .toString() + .compareTo(((ConstantSlot) o2).getValue().toString()); } else { return 1; } @@ -342,8 +344,11 @@ public boolean accept(Constraint constraint) { for (Slot slot : constraint.getSlots()) { if (slot == null) { if (!InferenceMain.isHackMode()) { - throw new BugInCF("Null slot in constraint " + constraint.getClass().getName() + "\n" - + constraint); + throw new BugInCF( + "Null slot in constraint " + + constraint.getClass().getName() + + "\n" + + constraint); } return true; } diff --git a/src/checkers/inference/DefaultInferenceResult.java b/src/checkers/inference/DefaultInferenceResult.java index 6c13037da..8b443f633 100644 --- a/src/checkers/inference/DefaultInferenceResult.java +++ b/src/checkers/inference/DefaultInferenceResult.java @@ -1,31 +1,32 @@ package checkers.inference; -import checkers.inference.model.Constraint; - -import javax.lang.model.element.AnnotationMirror; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; +import javax.lang.model.element.AnnotationMirror; + +import checkers.inference.model.Constraint; + /** * Default implementation of {@link InferenceResult}. * - * This class'es implementation follows this pattern: - * No solution == {@link #varIdToAnnotation} is null - * Has solution == empty {@link #varIdToAnnotation solution} or non-empty {@link #varIdToAnnotation solution} + *

This class'es implementation follows this pattern: No solution == {@link #varIdToAnnotation} + * is null Has solution == empty {@link #varIdToAnnotation solution} or non-empty {@link + * #varIdToAnnotation solution} * * @see {@link #hasSolution()} */ public class DefaultInferenceResult implements InferenceResult { /** - * A map from variable Id of {@link checkers.inference.model.Slot Slot} - * to {@link AnnotationMirror}. + * A map from variable Id of {@link checkers.inference.model.Slot Slot} to {@link + * AnnotationMirror}. * - * No solution should set this field to null. Otherwise, if the map is empty, it means - * empty solution(solution with no variable IDs). This happens for trivial testcase that - * doesn't need to insert annotations to source code. + *

No solution should set this field to null. Otherwise, if the map is empty, it means empty + * solution(solution with no variable IDs). This happens for trivial testcase that doesn't need + * to insert annotations to source code. * * @see #hasSolution() */ @@ -34,26 +35,25 @@ public class DefaultInferenceResult implements InferenceResult { /** * Set of {@link Constraint}s that caused solver not being able to give solutions. * - * If {@link #varIdToAnnotation} is null, there is no solution. This field then needs to + *

If {@link #varIdToAnnotation} is null, there is no solution. This field then needs to * passed in a non-null non-empty set as explanation. But if a solver backend doesn't support - * explanation feature, an empty set is allowed to be passed in, so that caller knows the backend - * can not explain unsolvable reason. - * If {@link #varIdToAnnotation} is non-null, solution exists. In this case, this field - * is not accessed(otherwise, throw {@code UnsupportedOperationException}), so it does't really - * matter what to be passed in here. But conservatively, an empty set is preferred. There is a - * dedicated constructor {@link DefaultInferenceResult(Map)} for this - * situation. For the best pratice, client should always call this constructor for cases with solutions. + * explanation feature, an empty set is allowed to be passed in, so that caller knows the + * backend can not explain unsolvable reason. If {@link #varIdToAnnotation} is non-null, + * solution exists. In this case, this field is not accessed(otherwise, throw {@code + * UnsupportedOperationException}), so it does't really matter what to be passed in here. But + * conservatively, an empty set is preferred. There is a dedicated constructor {@link + * DefaultInferenceResult(Map)} for this situation. For the best + * pratice, client should always call this constructor for cases with solutions. */ protected final Collection unsatisfiableConstraints; /** * No-arg constructor. * - * Should be called in situations: - * 1) Try to create empty solution - * 2) Subclass calls this super constructor to begin with an empty map. Then subclass - * has its logic to adding solutions to the mapping {@link #varIdToAnnotation}. The existing two - * subclasses are: {@link dataflow.solvers.classic.DataflowResult} and {@link sparta.checkers.sat.IFlowResult}. + *

Should be called in situations: 1) Try to create empty solution 2) Subclass calls this + * super constructor to begin with an empty map. Then subclass has its logic to adding solutions + * to the mapping {@link #varIdToAnnotation}. The existing two subclasses are: {@link + * dataflow.solvers.classic.DataflowResult} and {@link sparta.checkers.sat.IFlowResult}. */ public DefaultInferenceResult() { this(new HashMap<>()); @@ -62,10 +62,11 @@ public DefaultInferenceResult() { /** * One-arg constructor that accepts {@code varIdToAnnotation}. * - * Should be called when inference has solutions(either empty or non-empty, but never - * null). This case should be the most frequent. + *

Should be called when inference has solutions(either empty or non-empty, but never null). + * This case should be the most frequent. * - * @param varIdToAnnotation mapping from variable ID to inferred solution {@code AnnotationMirror} + * @param varIdToAnnotation mapping from variable ID to inferred solution {@code + * AnnotationMirror} */ public DefaultInferenceResult(Map varIdToAnnotation) { this(varIdToAnnotation, new HashSet<>()); @@ -74,17 +75,18 @@ public DefaultInferenceResult(Map varIdToAnnotation) /** * One-arg constructor that accepts {@code unsatisfiableConstraints}. * - * Should be called when inference failed to give solutions. + *

Should be called when inference failed to give solutions. * - * @param unsatisfiableConstraints non-null set of unsolable constraints. If a solver backend doesn't - * support explaining, empty set should be passed. + * @param unsatisfiableConstraints non-null set of unsolable constraints. If a solver backend + * doesn't support explaining, empty set should be passed. */ public DefaultInferenceResult(Collection unsatisfiableConstraints) { this(null, unsatisfiableConstraints); } - private DefaultInferenceResult(Map varIdToAnnotation, - Collection unsatisfiableConstraints) { + private DefaultInferenceResult( + Map varIdToAnnotation, + Collection unsatisfiableConstraints) { if (unsatisfiableConstraints == null) { throw new IllegalArgumentException("unsatisfiableConstraints should never be null!"); } diff --git a/src/checkers/inference/DefaultSlotManager.java b/src/checkers/inference/DefaultSlotManager.java index 964bd28d0..808bf450e 100644 --- a/src/checkers/inference/DefaultSlotManager.java +++ b/src/checkers/inference/DefaultSlotManager.java @@ -1,18 +1,18 @@ package checkers.inference; -import checkers.inference.util.SlotDefaultTypeResolver; import com.sun.source.tree.ClassTree; import com.sun.source.tree.CompilationUnitTree; import com.sun.source.tree.Tree; -import com.sun.source.util.TreePath; import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.util.Pair; + +import org.checkerframework.afu.scenelib.io.ASTIndex; +import org.checkerframework.afu.scenelib.io.ASTRecord; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; -import org.checkerframework.framework.type.AnnotatedTypeFactory; import org.checkerframework.framework.type.AnnotatedTypeMirror; import org.checkerframework.javacutil.AnnotationBuilder; import org.checkerframework.javacutil.AnnotationMirrorMap; -import org.checkerframework.javacutil.AnnotationUtils; import org.checkerframework.javacutil.BugInCF; import org.checkerframework.javacutil.TreeUtils; import org.checkerframework.javacutil.TypeKindUtils; @@ -21,7 +21,6 @@ import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.Comparator; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -37,26 +36,23 @@ import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; -import checkers.inference.model.LubVariableSlot; - -import com.sun.tools.javac.util.Pair; - import checkers.inference.model.AnnotationLocation; import checkers.inference.model.ArithmeticVariableSlot; import checkers.inference.model.CombVariableSlot; import checkers.inference.model.ComparisonVariableSlot; import checkers.inference.model.ConstantSlot; import checkers.inference.model.ExistentialVariableSlot; +import checkers.inference.model.LubVariableSlot; import checkers.inference.model.RefinementVariableSlot; import checkers.inference.model.Slot; import checkers.inference.model.SourceVariableSlot; import checkers.inference.model.VariableSlot; import checkers.inference.qual.VarAnnot; -import org.checkerframework.afu.scenelib.io.ASTIndex; -import org.checkerframework.afu.scenelib.io.ASTRecord; +import checkers.inference.util.SlotDefaultTypeResolver; /** * The default implementation of SlotManager. + * * @see checkers.inference.SlotManager */ public class DefaultSlotManager implements SlotManager { @@ -64,8 +60,8 @@ public class DefaultSlotManager implements SlotManager { private final AnnotationMirror varAnnot; /** - * The top annotation in the real qualifier hierarchy. - * Currently, we assume there's only one top. + * The top annotation in the real qualifier hierarchy. Currently, we assume there's only one + * top. */ private final AnnotationMirror realTop; @@ -76,84 +72,82 @@ public class DefaultSlotManager implements SlotManager { private int nextId = 1; /** - * A map for storing all the slots encountered by this slot manager. Key is - * an {@link Integer}, representing a slot id. Value is a - * {@link Slot} that corresponds to this slot id. Note that - * ConstantSlots are also stored in this map, since ConstantSlot is subclass - * of Slot. + * A map for storing all the slots encountered by this slot manager. Key is an {@link Integer}, + * representing a slot id. Value is a {@link Slot} that corresponds to this slot id. Note that + * ConstantSlots are also stored in this map, since ConstantSlot is subclass of Slot. */ private final Map slots; /** - * A map of {@link AnnotationMirror} to {@link Integer} for caching - * ConstantSlot. Each {@link AnnotationMirror} uniquely identify a - * ConstantSlot. {@link Integer} is the id of the corresponding ConstantSlot + * A map of {@link AnnotationMirror} to {@link Integer} for caching ConstantSlot. Each {@link + * AnnotationMirror} uniquely identify a ConstantSlot. {@link Integer} is the id of the + * corresponding ConstantSlot */ private final Map constantCache; /** - * A map of {@link AnnotationLocation} to {@link Integer} for caching - * VariableSlot and RefinementVariableSlot. Those two kinds of slots can be - * uniquely identified by their {@link AnnotationLocation}(Except MissingLocation). - * {@link Integer} is the id of the corresponding VariableSlot or RefinementVariableSlot + * A map of {@link AnnotationLocation} to {@link Integer} for caching VariableSlot and + * RefinementVariableSlot. Those two kinds of slots can be uniquely identified by their {@link + * AnnotationLocation}(Except MissingLocation). {@link Integer} is the id of the corresponding + * VariableSlot or RefinementVariableSlot */ private final Map locationCache; /** - * A map of {@link Pair} of {@link Slot} to {@link Integer} for - * caching ExistentialVariableSlot. Each ExistentialVariableSlot can be - * uniquely identified by its potential and alternative VariablesSlots. - * {@link Integer} is the id of the corresponding ExistentialVariableSlot + * A map of {@link Pair} of {@link Slot} to {@link Integer} for caching ExistentialVariableSlot. + * Each ExistentialVariableSlot can be uniquely identified by its potential and alternative + * VariablesSlots. {@link Integer} is the id of the corresponding ExistentialVariableSlot */ private final Map, Integer> existentialSlotPairCache; /** - * A map of {@link Pair} of {@link Slot} to {@link Integer} for caching - * CombVariableSlot. Each combination of receiver slot and declared slot - * uniquely identifies a CombVariableSlot. {@link Integer} is the id of the - * corresponding CombVariableSlott + * A map of {@link Pair} of {@link Slot} to {@link Integer} for caching CombVariableSlot. Each + * combination of receiver slot and declared slot uniquely identifies a CombVariableSlot. {@link + * Integer} is the id of the corresponding CombVariableSlott */ private final Map, Integer> combSlotPairCache; + private final Map, Integer> lubSlotPairCache; private final Map, Integer> glbSlotPairCache; /** - * A map of tree to {@link AnnotationMirror} for caching - * a set of pre-computed default types for the current compilation unit. + * A map of tree to {@link AnnotationMirror} for caching a set of pre-computed default types for + * the current compilation unit. */ private final Map defaultAnnotationsCache; /** - * A map of {@link AnnotationLocation} to {@link Integer} for caching - * {@link ArithmeticVariableSlot}s. The annotation location uniquely identifies an - * {@link ArithmeticVariableSlot}. The {@link Integer} is the Id of the corresponding - * {@link ArithmeticVariableSlot}. + * A map of {@link AnnotationLocation} to {@link Integer} for caching {@link + * ArithmeticVariableSlot}s. The annotation location uniquely identifies an {@link + * ArithmeticVariableSlot}. The {@link Integer} is the Id of the corresponding {@link + * ArithmeticVariableSlot}. */ private final Map arithmeticSlotCache; /** - * A map of {@link AnnotationLocation} to {@link Integer} for caching - * {@link ComparisonVariableSlot}s. The annotation location uniquely identifies an - * {@link ComparisonVariableSlot}. The {@link Integer} is the Id of the corresponding - * {@link ComparisonVariableSlot}. + * A map of {@link AnnotationLocation} to {@link Integer} for caching {@link + * ComparisonVariableSlot}s. The annotation location uniquely identifies an {@link + * ComparisonVariableSlot}. The {@link Integer} is the Id of the corresponding {@link + * ComparisonVariableSlot}. */ private final Map comparisonThenSlotCache; /** - * A map of {@link AnnotationLocation} to {@link Integer} for caching - * {@link ComparisonVariableSlot}s. The annotation location uniquely identifies an - * {@link ComparisonVariableSlot}. The {@link Integer} is the Id of the corresponding - * {@link ComparisonVariableSlot}. + * A map of {@link AnnotationLocation} to {@link Integer} for caching {@link + * ComparisonVariableSlot}s. The annotation location uniquely identifies an {@link + * ComparisonVariableSlot}. The {@link Integer} is the Id of the corresponding {@link + * ComparisonVariableSlot}. */ private final Map comparisonElseSlotCache; private final Set> realQualifiers; private final ProcessingEnvironment processingEnvironment; - public DefaultSlotManager( final ProcessingEnvironment processingEnvironment, - final AnnotationMirror realTop, - final Set> realQualifiers, - boolean storeConstants) { + public DefaultSlotManager( + final ProcessingEnvironment processingEnvironment, + final AnnotationMirror realTop, + final Set> realQualifiers, + boolean storeConstants) { this.processingEnvironment = processingEnvironment; this.realTop = realTop; // sort the qualifiers so that they are always assigned the same varId @@ -161,7 +155,7 @@ public DefaultSlotManager( final ProcessingEnvironment processingEnvironment, slots = new LinkedHashMap<>(); AnnotationBuilder builder = new AnnotationBuilder(processingEnvironment, VarAnnot.class); - builder.setValue("value", -1 ); + builder.setValue("value", -1); this.varAnnot = builder.build(); // Construct empty caches @@ -178,30 +172,37 @@ public DefaultSlotManager( final ProcessingEnvironment processingEnvironment, if (storeConstants) { for (Class annoClass : this.realQualifiers) { - AnnotationMirror am = new AnnotationBuilder(processingEnvironment, annoClass).build(); + AnnotationMirror am = + new AnnotationBuilder(processingEnvironment, annoClass).build(); ConstantSlot constantSlot = new ConstantSlot(nextId(), am); addToSlots(constantSlot); constantCache.put(am, constantSlot.getId()); } } } - private Set> sortAnnotationClasses(Set> annotations) { - TreeSet> set = new TreeSet<>(new Comparator>() { - @Override - public int compare(Class o1, Class o2) { - if (o1 == o2) { - return 0; - } - if (o1 == null) { - return -1; - } - if (o2 == null) { - return 1; - } - return o1.getCanonicalName().compareTo(o2.getCanonicalName()); - } - }); + private Set> sortAnnotationClasses( + Set> annotations) { + + TreeSet> set = + new TreeSet<>( + new Comparator>() { + @Override + public int compare( + Class o1, + Class o2) { + if (o1 == o2) { + return 0; + } + if (o1 == null) { + return -1; + } + if (o2 == null) { + return 1; + } + return o1.getCanonicalName().compareTo(o2.getCanonicalName()); + } + }); set.addAll(annotations); return set; } @@ -211,22 +212,20 @@ public void setTopLevelClass(ClassTree classTree) { // If the top level has changed, we refresh our cache with the new scope. defaultAnnotationsCache.clear(); - Map defaultTypes = SlotDefaultTypeResolver.resolve( - classTree, - InferenceMain.getInstance().getRealTypeFactory() - ); + Map defaultTypes = + SlotDefaultTypeResolver.resolve( + classTree, InferenceMain.getInstance().getRealTypeFactory()); // find default types in the current hierarchy and save them to the cache for (Map.Entry entry : defaultTypes.entrySet()) { defaultAnnotationsCache.put( - entry.getKey(), - entry.getValue().getAnnotationInHierarchy(this.realTop) - ); + entry.getKey(), entry.getValue().getAnnotationInHierarchy(this.realTop)); } } /** - * Returns the next unique variable id. These id's are monotonically increasing. + * Returns the next unique variable id. These id's are monotonically increasing. + * * @return the next variable id to be used in VariableCreation */ private int nextId() { @@ -241,7 +240,7 @@ private void addToSlots(final Slot slot) { * @inheritDoc */ @Override - public Slot getSlot( int id ) { + public Slot getSlot(int id) { return slots.get(id); } @@ -252,20 +251,21 @@ public Slot getSlot( int id ) { public AnnotationMirror getAnnotation(final Slot slot) { // We need to build the AnnotationBuilder each time because AnnotationBuilders are only // allowed to build their annotations once - return convertVariable(slot, - new AnnotationBuilder(processingEnvironment, VarAnnot.class)); + return convertVariable(slot, new AnnotationBuilder(processingEnvironment, VarAnnot.class)); } /** * Converts the given VariableSlot into an annotation using the given AnnotationBuiklder + * * @param variable VariableSlot to convert - * @param annotationBuilder appropriate annotation for the actual class of the VariableSlot which could be subtype - * of VariableSlot. Eg. CombVariableSlots use combVarBuilder which is parameterized to - * build @CombVarAnnots + * @param annotationBuilder appropriate annotation for the actual class of the VariableSlot + * which could be subtype of VariableSlot. Eg. CombVariableSlots use combVarBuilder which is + * parameterized to build @CombVarAnnots * @return An annotation representing variable */ - private AnnotationMirror convertVariable( final Slot variable, final AnnotationBuilder annotationBuilder) { - annotationBuilder.setValue("value", variable.getId() ); + private AnnotationMirror convertVariable( + final Slot variable, final AnnotationBuilder annotationBuilder) { + annotationBuilder.setValue("value", variable.getId()); return annotationBuilder.build(); } @@ -274,7 +274,7 @@ private AnnotationMirror convertVariable( final Slot variable, final AnnotationB * @inheritDoc */ @Override - public Slot getSlot( final AnnotatedTypeMirror atm ) { + public Slot getSlot(final AnnotatedTypeMirror atm) { AnnotationMirror annot = atm.getAnnotationInHierarchy(this.varAnnot); if (annot == null) { @@ -292,29 +292,32 @@ public Slot getSlot( final AnnotatedTypeMirror atm ) { * @inheritDoc */ @Override - public Slot getSlot( final AnnotationMirror annotationMirror ) { + public Slot getSlot(final AnnotationMirror annotationMirror) { final int id; if (InferenceQualifierHierarchy.isVarAnnot(annotationMirror)) { if (annotationMirror.getElementValues().isEmpty()) { return null; // TODO: should we instead throw an exception? } else { - final AnnotationValue annoValue = annotationMirror.getElementValues().values().iterator().next(); - id = Integer.valueOf( annoValue.toString() ); + final AnnotationValue annoValue = + annotationMirror.getElementValues().values().iterator().next(); + id = Integer.valueOf(annoValue.toString()); } - return getSlot( id ); + return getSlot(id); } else { if (constantCache.containsKey(annotationMirror)) { - ConstantSlot constantSlot = (ConstantSlot) getSlot( - constantCache.get(annotationMirror)); + ConstantSlot constantSlot = + (ConstantSlot) getSlot(constantCache.get(annotationMirror)); return constantSlot; } else { for (Class realAnno : realQualifiers) { - if (InferenceMain.getInstance().getRealTypeFactory().areSameByClass(annotationMirror, realAnno)) { + if (InferenceMain.getInstance() + .getRealTypeFactory() + .areSameByClass(annotationMirror, realAnno)) { return createConstantSlot(annotationMirror); } } @@ -322,10 +325,17 @@ public Slot getSlot( final AnnotationMirror annotationMirror ) { } if (InferenceMain.isHackMode()) { - return createConstantSlot(InferenceMain.getInstance().getRealTypeFactory(). - getQualifierHierarchy().getTopAnnotations().iterator().next()); + return createConstantSlot( + InferenceMain.getInstance() + .getRealTypeFactory() + .getQualifierHierarchy() + .getTopAnnotations() + .iterator() + .next()); } - throw new BugInCF( annotationMirror + " is a type of AnnotationMirror not handled by getVariableSlot." ); + throw new BugInCF( + annotationMirror + + " is a type of AnnotationMirror not handled by getVariableSlot."); } /** @@ -371,10 +381,7 @@ public int getNumberOfSlots() { } private SourceVariableSlot createSourceVariableSlot( - AnnotationLocation location, - TypeMirror type, - boolean insertable - ) { + AnnotationLocation location, TypeMirror type, boolean insertable) { AnnotationMirror defaultAnnotation = null; if (!InferenceOptions.makeDefaultsExplicit) { // retrieve the default annotation when needed @@ -384,8 +391,10 @@ private SourceVariableSlot createSourceVariableSlot( SourceVariableSlot sourceVarSlot; if (location.getKind() == AnnotationLocation.Kind.MISSING) { if (InferenceMain.isHackMode()) { - //Don't cache slot for MISSING LOCATION. Just create a new one and return. - sourceVarSlot = new SourceVariableSlot(nextId(), location, type, defaultAnnotation, insertable); + // Don't cache slot for MISSING LOCATION. Just create a new one and return. + sourceVarSlot = + new SourceVariableSlot( + nextId(), location, type, defaultAnnotation, insertable); addToSlots(sourceVarSlot); } else { throw new BugInCF("Creating SourceVariableSlot on MISSING_LOCATION!"); @@ -395,7 +404,8 @@ private SourceVariableSlot createSourceVariableSlot( int id = locationCache.get(location); sourceVarSlot = (SourceVariableSlot) getSlot(id); } else { - sourceVarSlot = new SourceVariableSlot(nextId(), location, type, defaultAnnotation, insertable); + sourceVarSlot = + new SourceVariableSlot(nextId(), location, type, defaultAnnotation, insertable); addToSlots(sourceVarSlot); locationCache.put(location, sourceVarSlot.getId()); } @@ -403,12 +413,14 @@ private SourceVariableSlot createSourceVariableSlot( } @Override - public SourceVariableSlot createSourceVariableSlot(AnnotationLocation location, TypeMirror type) { + public SourceVariableSlot createSourceVariableSlot( + AnnotationLocation location, TypeMirror type) { return createSourceVariableSlot(location, type, true); } @Override - public VariableSlot createPolymorphicInstanceSlot(AnnotationLocation location, TypeMirror type) { + public VariableSlot createPolymorphicInstanceSlot( + AnnotationLocation location, TypeMirror type) { // TODO: For now, a polymorphic instance slot is just equivalent to a non-insertable // source variable slot. We may consider changing this implementation later. return createSourceVariableSlot(location, type, false); @@ -416,10 +428,12 @@ public VariableSlot createPolymorphicInstanceSlot(AnnotationLocation location, T /** * Find the default annotation for this location by checking the real type factory. + * * @param location location to create a new {@link SourceVariableSlot} * @return the default annotation for the given location */ - private @Nullable AnnotationMirror getDefaultAnnotationForLocation(AnnotationLocation location, TypeMirror type) { + private @Nullable AnnotationMirror getDefaultAnnotationForLocation( + AnnotationLocation location, TypeMirror type) { if (location == AnnotationLocation.MISSING_LOCATION) { if (InferenceMain.isHackMode()) { return null; @@ -434,11 +448,9 @@ public VariableSlot createPolymorphicInstanceSlot(AnnotationLocation location, T if (location instanceof AnnotationLocation.AstPathLocation) { tree = getTreeForLocation((AnnotationLocation.AstPathLocation) location); } else if (location instanceof AnnotationLocation.ClassDeclLocation) { - tree = getTreeForLocation( - (AnnotationLocation.ClassDeclLocation) location, - type, - realTypeFactory - ); + tree = + getTreeForLocation( + (AnnotationLocation.ClassDeclLocation) location, type, realTypeFactory); } else { throw new BugInCF("Unable to find default annotation for location " + location); } @@ -452,11 +464,15 @@ public VariableSlot createPolymorphicInstanceSlot(AnnotationLocation location, T // to lack of information. We may want to investigate if // this issue ever happens. if (TreeUtils.isTypeTree(tree)) { - realAnnotation = realTypeFactory.getAnnotatedTypeFromTypeTree(tree) - .getAnnotationInHierarchy(this.realTop); + realAnnotation = + realTypeFactory + .getAnnotatedTypeFromTypeTree(tree) + .getAnnotationInHierarchy(this.realTop); } else { - realAnnotation = realTypeFactory.getAnnotatedType(tree) - .getAnnotationInHierarchy(this.realTop); + realAnnotation = + realTypeFactory + .getAnnotatedType(tree) + .getAnnotationInHierarchy(this.realTop); } } return realAnnotation; @@ -464,9 +480,10 @@ public VariableSlot createPolymorphicInstanceSlot(AnnotationLocation location, T /** * Find the tree associated with the given {@link AnnotationLocation.AstPathLocation}. + * * @param location location to find the tree - * @return the tree associated with the given location, which can be null if the location - * is not under the current compilation unit + * @return the tree associated with the given location, which can be null if the location is not + * under the current compilation unit */ private @Nullable Tree getTreeForLocation(AnnotationLocation.AstPathLocation location) { ASTRecord astRecord = location.getAstRecord(); @@ -476,6 +493,7 @@ public VariableSlot createPolymorphicInstanceSlot(AnnotationLocation location, T /** * Find the class tree associated with the given {@link AnnotationLocation.ClassDeclLocation}. + * * @param realTypeFactory the current real {@link BaseAnnotatedTypeFactory} * @param location location to find the tree * @param type type of the associated class @@ -484,16 +502,16 @@ public VariableSlot createPolymorphicInstanceSlot(AnnotationLocation location, T private Tree getTreeForLocation( AnnotationLocation.ClassDeclLocation location, TypeMirror type, - BaseAnnotatedTypeFactory realTypeFactory - ) { + BaseAnnotatedTypeFactory realTypeFactory) { Element element = processingEnvironment.getTypeUtils().asElement(type); if (!(element instanceof TypeElement)) { throw new BugInCF( - "Expected to get a TypeElement for %s at %s, but received %s.", type, location, element); + "Expected to get a TypeElement for %s at %s, but received %s.", + type, location, element); } TypeElement typeElement = (TypeElement) element; - Name fullyQualifiedName = ((Symbol.ClassSymbol)typeElement).flatName(); + Name fullyQualifiedName = ((Symbol.ClassSymbol) typeElement).flatName(); if (!fullyQualifiedName.contentEquals(location.getFullyQualifiedClassName())) { throw new BugInCF( "TypeElement for %s has qualified name %s, and it doesn't match with the location %s", @@ -504,7 +522,8 @@ private Tree getTreeForLocation( } @Override - public RefinementVariableSlot createRefinementVariableSlot(AnnotationLocation location, Slot declarationSlot, Slot valueSlot) { + public RefinementVariableSlot createRefinementVariableSlot( + AnnotationLocation location, Slot declarationSlot, Slot valueSlot) { // If the location is already cached, return the corresponding refinement slot in the cache if (locationCache.containsKey(location)) { int id = locationCache.get(location); @@ -517,7 +536,9 @@ public RefinementVariableSlot createRefinementVariableSlot(AnnotationLocation lo addToSlots(refinementVariableSlot); if (valueSlot != null) { // If the rhs value slot passed in is non-null, create the equality constraint on it - InferenceMain.getInstance().getConstraintManager().addEqualityConstraint(refinementVariableSlot, valueSlot); + InferenceMain.getInstance() + .getConstraintManager() + .addEqualityConstraint(refinementVariableSlot, valueSlot); } // Only cache slot for non-MISSING LOCATION @@ -587,14 +608,16 @@ private LubVariableSlot createMergeVariableSlot(Slot left, Slot right, boolean i } @Override - public ExistentialVariableSlot createExistentialVariableSlot(Slot potentialSlot, Slot alternativeSlot) { + public ExistentialVariableSlot createExistentialVariableSlot( + Slot potentialSlot, Slot alternativeSlot) { ExistentialVariableSlot existentialVariableSlot; Pair pair = new Pair<>(potentialSlot, alternativeSlot); if (existentialSlotPairCache.containsKey(pair)) { int id = existentialSlotPairCache.get(pair); existentialVariableSlot = (ExistentialVariableSlot) getSlot(id); } else { - existentialVariableSlot = new ExistentialVariableSlot(nextId(), potentialSlot, alternativeSlot); + existentialVariableSlot = + new ExistentialVariableSlot(nextId(), potentialSlot, alternativeSlot); addToSlots(existentialVariableSlot); existentialSlotPairCache.put(pair, existentialVariableSlot.getId()); } @@ -602,12 +625,15 @@ public ExistentialVariableSlot createExistentialVariableSlot(Slot potentialSlot, } /** - * Determine the type kind of an arithmetic operation, based on Binary Numeric Promotion in JLS 5.6.2. + * Determine the type kind of an arithmetic operation, based on Binary Numeric Promotion in JLS + * 5.6.2. + * * @param lhsAtm atm of left operand * @param rhsAtm atm of right operand * @return type kind of the arithmetic operation */ - private TypeKind getArithmeticResultKind(AnnotatedTypeMirror lhsAtm, AnnotatedTypeMirror rhsAtm) { + private TypeKind getArithmeticResultKind( + AnnotatedTypeMirror lhsAtm, AnnotatedTypeMirror rhsAtm) { TypeMirror lhsType = lhsAtm.getUnderlyingType(); TypeMirror rhsType = rhsAtm.getUnderlyingType(); @@ -646,7 +672,8 @@ public ArithmeticVariableSlot createArithmeticVariableSlot( } @Override - public ComparisonVariableSlot createComparisonVariableSlot(AnnotationLocation location, Slot refined, boolean thenBranch) { + public ComparisonVariableSlot createComparisonVariableSlot( + AnnotationLocation location, Slot refined, boolean thenBranch) { if (location == null || location.getKind() == AnnotationLocation.Kind.MISSING) { throw new BugInCF( "Cannot create an ComparisonVariableSlot with a missing annotation location."); diff --git a/src/checkers/inference/ImpliedTypeAnnotator.java b/src/checkers/inference/ImpliedTypeAnnotator.java index 5090f1267..e2f4539a0 100644 --- a/src/checkers/inference/ImpliedTypeAnnotator.java +++ b/src/checkers/inference/ImpliedTypeAnnotator.java @@ -1,10 +1,6 @@ package checkers.inference; import org.checkerframework.afu.scenelib.io.ASTRecord; -import checkers.inference.model.AnnotationLocation; -import checkers.inference.model.AnnotationLocation.AstPathLocation; -import checkers.inference.model.SourceVariableSlot; -import checkers.inference.util.ASTPathUtil; import org.checkerframework.framework.type.AnnotatedTypeMirror; import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType; import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable; @@ -13,11 +9,16 @@ import java.util.HashMap; import java.util.Map; +import checkers.inference.model.AnnotationLocation; +import checkers.inference.model.AnnotationLocation.AstPathLocation; +import checkers.inference.model.SourceVariableSlot; +import checkers.inference.util.ASTPathUtil; + /** - * The ImpliedTypeAnnotator will create variables and add VarAnnots to all definite type use locations - * on an input type. If a parent ASTRecord is passed to the ImpliedTypeAnnotator it will also create - * new ASTPathLocations representing the location of these annotations for each variable created. - * + * The ImpliedTypeAnnotator will create variables and add VarAnnots to all definite type use + * locations on an input type. If a parent ASTRecord is passed to the ImpliedTypeAnnotator it will + * also create new ASTPathLocations representing the location of these annotations for each variable + * created. */ public class ImpliedTypeAnnotator { @@ -25,8 +26,10 @@ public class ImpliedTypeAnnotator { private final ExistentialVariableInserter existentialVariableInserter; private final InferenceAnnotatedTypeFactory typeFactory; - public ImpliedTypeAnnotator(InferenceAnnotatedTypeFactory typeFactory, SlotManager slotManager, - ExistentialVariableInserter existentialVariableInserter) { + public ImpliedTypeAnnotator( + InferenceAnnotatedTypeFactory typeFactory, + SlotManager slotManager, + ExistentialVariableInserter existentialVariableInserter) { this.slotManager = slotManager; this.existentialVariableInserter = existentialVariableInserter; this.typeFactory = typeFactory; @@ -34,17 +37,21 @@ public ImpliedTypeAnnotator(InferenceAnnotatedTypeFactory typeFactory, SlotManag /** * Applies annotations to all definite type use locations on impliedType. + * * @param impliedType The type to annotate * @param isUse Whether or not this type should be treated as a use * @param parent The AST Path to the parent tree on which type would be added */ public void annotate(AnnotatedTypeMirror impliedType, boolean isUse, final ASTRecord parent) { Map typeToRecord = - (parent == null) ? new HashMap() : ASTPathUtil.getImpliedRecordForUse(parent, impliedType); + (parent == null) + ? new HashMap() + : ASTPathUtil.getImpliedRecordForUse(parent, impliedType); new Visitor(isUse).scan(impliedType, typeToRecord); } - protected class Visitor extends AnnotatedTypeScanner> { + protected class Visitor + extends AnnotatedTypeScanner> { // When a type variable is passed to annotate the caller may or may not want to // treat it as a type use, for type parameters should not be treated as uses @@ -55,7 +62,8 @@ public Visitor(boolean isUse) { } @Override - public Void visitExecutable(AnnotatedExecutableType type, Map astRecords) { + public Void visitExecutable( + AnnotatedExecutableType type, Map astRecords) { scan(type.getReturnType(), null); if (type.getReceiverType() != null) { scanAndReduce(type.getReceiverType(), null, null); @@ -66,24 +74,35 @@ public Void visitExecutable(AnnotatedExecutableType type, Map astRecords) { + protected void insertExistentialVariable( + AnnotatedTypeVariable typeVariableUse, + Map astRecords) { if (typeVariableUse.isDeclaration()) { throw new RuntimeException( "ExistentialVariables should only be placed on type variable uses, not their declarations!\n" - + "typeVariableUse=" + typeVariableUse + "\n" - + "record=" + astRecords + "\n"); + + "typeVariableUse=" + + typeVariableUse + + "\n" + + "record=" + + astRecords + + "\n"); } - AnnotatedTypeVariable declaration = (AnnotatedTypeVariable) - typeFactory.getAnnotatedType(typeVariableUse.getUnderlyingType().asElement()); + AnnotatedTypeVariable declaration = + (AnnotatedTypeVariable) + typeFactory.getAnnotatedType( + typeVariableUse.getUnderlyingType().asElement()); AnnotationLocation location = getLocation(typeVariableUse, astRecords); - SourceVariableSlot potentialVar = slotManager.createSourceVariableSlot(location, typeVariableUse.getUnderlyingType()); + SourceVariableSlot potentialVar = + slotManager.createSourceVariableSlot( + location, typeVariableUse.getUnderlyingType()); existentialVariableInserter.insert(potentialVar, typeVariableUse, declaration); } @Override - protected Void scan(AnnotatedTypeMirror type, Map astRecords) { + protected Void scan( + AnnotatedTypeMirror type, Map astRecords) { switch (type.getKind()) { case TYPEVAR: @@ -91,7 +110,8 @@ protected Void scan(AnnotatedTypeMirror type, Map astRecords) { + protected void addVariablePrimaryAnnotation( + final AnnotatedTypeMirror type, Map astRecords) { AnnotationLocation location = getLocation(type, astRecords); - SourceVariableSlot slot = slotManager.createSourceVariableSlot(location, type.getUnderlyingType()); + SourceVariableSlot slot = + slotManager.createSourceVariableSlot(location, type.getUnderlyingType()); type.addAnnotation(slotManager.getAnnotation(slot)); } /** - * searches for an ASTRecord for type in AstRecords. If none is found, AnnotationLocation.MISSING_LOCATION - * is returned, otherwise an AstPathLocation is returned. + * searches for an ASTRecord for type in AstRecords. If none is found, + * AnnotationLocation.MISSING_LOCATION is returned, otherwise an AstPathLocation is + * returned. */ - protected AnnotationLocation getLocation(AnnotatedTypeMirror type, Map astRecords) { + protected AnnotationLocation getLocation( + AnnotatedTypeMirror type, Map astRecords) { ASTRecord record = astRecords.get(type); - return record == null ? AnnotationLocation.MISSING_LOCATION : new AstPathLocation(record); + return record == null + ? AnnotationLocation.MISSING_LOCATION + : new AstPathLocation(record); } } } diff --git a/src/checkers/inference/InferenceAnnotatedTypeFactory.java b/src/checkers/inference/InferenceAnnotatedTypeFactory.java index a949467b2..d2e7a9752 100644 --- a/src/checkers/inference/InferenceAnnotatedTypeFactory.java +++ b/src/checkers/inference/InferenceAnnotatedTypeFactory.java @@ -1,6 +1,13 @@ package checkers.inference; -import checkers.inference.model.Slot; +import com.sun.source.tree.ClassTree; +import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.tree.ExpressionTree; +import com.sun.source.tree.MemberSelectTree; +import com.sun.source.tree.MethodInvocationTree; +import com.sun.source.tree.NewClassTree; +import com.sun.source.tree.Tree; + import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; import org.checkerframework.framework.flow.CFAbstractAnalysis; import org.checkerframework.framework.flow.CFAnalysis; @@ -49,49 +56,45 @@ import checkers.inference.dataflow.InferenceAnalysis; import checkers.inference.model.ConstraintManager; +import checkers.inference.model.Slot; import checkers.inference.qual.VarAnnot; import checkers.inference.util.ConstantToVariableAnnotator; import checkers.inference.util.InferenceUtil; import checkers.inference.util.InferenceViewpointAdapter; import checkers.inference.util.defaults.InferenceQualifierDefaults; -import com.sun.source.tree.ClassTree; -import com.sun.source.tree.CompilationUnitTree; -import com.sun.source.tree.ExpressionTree; -import com.sun.source.tree.MemberSelectTree; -import com.sun.source.tree.MethodInvocationTree; -import com.sun.source.tree.NewClassTree; -import com.sun.source.tree.Tree; - /** - * InferenceAnnotatedTypeFactory is responsible for creating AnnotatedTypeMirrors that are annotated with - * "variable" or "real" annotations. Variable annotations, represented by checkers.inference.@VarAnnot, indicate - * an annotation with a value to be inferred. Real annotations, those found in the hierarchy of the type system - * for which we are inferring values, indicate that the given type has a constant value in the "real" type system. - * - * Adding annotations is accomplished through three means: - * 1. If we have the source code for a particular type, the InferenceTreeAnnotator and the VariableAnnotator - * will add the relevant annotation (either VarAnnot or constant real annotation) based on the type's corresponding - * tree and the rules of the InferrableChecker. If the InferrableChecker determines that a value is constant - * then the realAnnotatedTypeFactory is consulted to get this value. - * @see checkers.inference.InferenceAnnotatedTypeFactory#annotateImplicit(com.sun.source.tree.Tree, checkers.types.AnnotatedTypeMirror) + * InferenceAnnotatedTypeFactory is responsible for creating AnnotatedTypeMirrors that are annotated + * with "variable" or "real" annotations. Variable annotations, represented by + * checkers.inference.@VarAnnot, indicate an annotation with a value to be inferred. Real + * annotations, those found in the hierarchy of the type system for which we are inferring values, + * indicate that the given type has a constant value in the "real" type system. * - * 2. If we do NOT have the source code then the realAnnotatedTypeFactory is used to determine a constant value - * to place on the given "library", i.e. from bytecode, type. - * @see checkers.inference.InferenceAnnotatedTypeFactory#annotateImplicit(javax.lang.model.element.Element, checkers.types.AnnotatedTypeMirror) + *

Adding annotations is accomplished through three means: 1. If we have the source code for a + * particular type, the InferenceTreeAnnotator and the VariableAnnotator will add the relevant + * annotation (either VarAnnot or constant real annotation) based on the type's corresponding tree + * and the rules of the InferrableChecker. If the InferrableChecker determines that a value is + * constant then the realAnnotatedTypeFactory is consulted to get this value. * - * 3. Types representing declarations generated using methods 1 and 2 are stored via - * VariableAnnotator#storeElementType. If these elements are encountered again, the annotations from the stored - * type are copied to the annotations of the type being annotated. - * @see checkers.inference.InferenceAnnotatedTypeFactory#annotateImplicit(javax.lang.model.element.Element, checkers.types.AnnotatedTypeMirror) - * - * Note: a number of constraints are created by members of this class + * @see checkers.inference.InferenceAnnotatedTypeFactory#annotateImplicit(com.sun.source.tree.Tree, + * checkers.types.AnnotatedTypeMirror) + *

2. If we do NOT have the source code then the realAnnotatedTypeFactory is used to + * determine a constant value to place on the given "library", i.e. from bytecode, type. + * @see + * checkers.inference.InferenceAnnotatedTypeFactory#annotateImplicit(javax.lang.model.element.Element, + * checkers.types.AnnotatedTypeMirror) + *

3. Types representing declarations generated using methods 1 and 2 are stored via + * VariableAnnotator#storeElementType. If these elements are encountered again, the annotations + * from the stored type are copied to the annotations of the type being annotated. + * @see + * checkers.inference.InferenceAnnotatedTypeFactory#annotateImplicit(javax.lang.model.element.Element, + * checkers.types.AnnotatedTypeMirror) + *

Note: a number of constraints are created by members of this class * @see checkers.inference.InferenceQualifierHierarchy * @see checkers.inference.InferenceTypeHierarchy - * - * Finally, Variables are created while flow is being performed (every time getAnnotatedType is called on a - * class tree that hasn't yet been annotated). Constraints are created after flow has been for a given class when - * the visitor requests types. + *

Finally, Variables are created while flow is being performed (every time getAnnotatedType + * is called on a class tree that hasn't yet been annotated). Constraints are created after flow + * has been for a given class when the visitor requests types. */ public class InferenceAnnotatedTypeFactory extends BaseAnnotatedTypeFactory { @@ -110,9 +113,11 @@ public class InferenceAnnotatedTypeFactory extends BaseAnnotatedTypeFactory { private final InferenceQualifierPolymorphism inferencePoly; private final ConstantToVariableAnnotator constantToVariableAnnotator; - public static final Logger logger = Logger.getLogger(InferenceAnnotatedTypeFactory.class.getSimpleName()); + public static final Logger logger = + Logger.getLogger(InferenceAnnotatedTypeFactory.class.getSimpleName()); - // Used to indicate progress in the output log. Before calling inference, if you count the number of + // Used to indicate progress in the output log. Before calling inference, if you count the + // number of // Java files you are compiling, you can use this number to gauge progress of inference. // See setRoot below public int compilationUnitsHandled = 0; @@ -139,15 +144,13 @@ public InferenceAnnotatedTypeFactory( varAnnot = new AnnotationBuilder(processingEnv, VarAnnot.class).build(); realTop = realTypeFactory.getQualifierHierarchy().getTopAnnotations().iterator().next(); - existentialInserter = new ExistentialVariableInserter(slotManager, constraintManager, - realTop, varAnnot, variableAnnotator); + existentialInserter = + new ExistentialVariableInserter( + slotManager, constraintManager, realTop, varAnnot, variableAnnotator); - inferencePoly = new InferenceQualifierPolymorphism( - slotManager, - variableAnnotator, - this, - realTypeFactory, - varAnnot); + inferencePoly = + new InferenceQualifierPolymorphism( + slotManager, variableAnnotator, this, realTypeFactory, varAnnot); constantToVariableAnnotator = new ConstantToVariableAnnotator(realTop, varAnnot); // Every subclass must call postInit! @@ -158,6 +161,7 @@ public InferenceAnnotatedTypeFactory( /** * Get the real qualifier hierarchy from {@link #realTypeFactory}. + * * @return the real qualifier hierarchy. */ public QualifierHierarchy getRealQualifierHierarchy() { @@ -166,11 +170,13 @@ public QualifierHierarchy getRealQualifierHierarchy() { @Override protected CFAnalysis createFlowAnalysis() { - return realChecker.createInferenceAnalysis(inferenceChecker, this, slotManager, constraintManager, realChecker); + return realChecker.createInferenceAnalysis( + inferenceChecker, this, slotManager, constraintManager, realChecker); } @Override - public CFTransfer createFlowTransferFunction(CFAbstractAnalysis analysis) { + public CFTransfer createFlowTransferFunction( + CFAbstractAnalysis analysis) { return realChecker.createInferenceTransferFunction((InferenceAnalysis) analysis); } @@ -193,8 +199,10 @@ protected TypeAnnotator createTypeAnnotator() { @Override public TreeAnnotator createTreeAnnotator() { - return new ListTreeAnnotator(new LiteralTreeAnnotator(this), new InferenceTreeAnnotator(this, - realChecker, realTypeFactory, variableAnnotator, slotManager)); + return new ListTreeAnnotator( + new LiteralTreeAnnotator(this), + new InferenceTreeAnnotator( + this, realChecker, realTypeFactory, variableAnnotator, slotManager)); } @Override @@ -220,7 +228,8 @@ protected TypeHierarchy createTypeHierarchy() { @Override protected QualifierHierarchy createQualifierHierarchy() { - return new InferenceQualifierHierarchy(getSupportedTypeQualifiers(), elements, realTypeFactory); + return new InferenceQualifierHierarchy( + getSupportedTypeQualifiers(), elements, realTypeFactory); } @Override @@ -239,12 +248,12 @@ protected void checkForDefaultQualifierInHierarchy(QualifierDefaults defs) { // since in inference we don't need a default. } - -// @Override -// protected TypeArgumentInference createTypeArgumentInference() { -// return new InferenceTypeArgumentInference(slotManager, constraintManager, variableAnnotator, -// this, realTypeFactory, varAnnot); -// } + // @Override + // protected TypeArgumentInference createTypeArgumentInference() { + // return new InferenceTypeArgumentInference(slotManager, constraintManager, + // variableAnnotator, + // this, realTypeFactory, varAnnot); + // } @Override protected TypeVariableSubstitutor createTypeVariableSubstitutor() { @@ -252,22 +261,23 @@ protected TypeVariableSubstitutor createTypeVariableSubstitutor() { } /** - * Copies the primary annotations on the use type "type" onto each "supertype". - * E.g. for a call: - * postDirectSuperTypes( @9 ArrayList< @7 String>, List( @4 List<@7 String>, @0 Object ) ) - * we would like supertypes to become: - * List( @9 List<@7 String>, @9 Object ) + * Copies the primary annotations on the use type "type" onto each "supertype". E.g. for a call: + * postDirectSuperTypes( @9 ArrayList< @7 String>, List( @4 List<@7 String>, @0 Object ) ) we + * would like supertypes to become: List( @9 List<@7 String>, @9 Object ) * - * This does NOTHING to the type parameters of a declared type. The superTypeFinder should appropriately - * fix these up. + *

This does NOTHING to the type parameters of a declared type. The superTypeFinder should + * appropriately fix these up. */ @Override - protected void postDirectSuperTypes(AnnotatedTypeMirror type, List supertypes) { + protected void postDirectSuperTypes( + AnnotatedTypeMirror type, List supertypes) { - // TODO: Move postdirectSupertypes to a "copyTypeToSuperType method" that can just be called by this method? + // TODO: Move postdirectSupertypes to a "copyTypeToSuperType method" that can just be called + // by this method? // At the time of writing this is the same as AnnotatedTypeFactory.postDirectSuperTypes // we cannot call super.postDirectSuperTypes because GenericAnnotatedTypeFactory will cause - // annotateImplicit(element,type) to be called on the supertype which will overwrite the annotations from type + // annotateImplicit(element,type) to be called on the supertype which will overwrite the + // annotations from type // with those for the declaration of the super type Set annotations = type.getEffectiveAnnotations(); for (AnnotatedTypeMirror supertype : supertypes) { @@ -282,13 +292,13 @@ protected void postDirectSuperTypes(AnnotatedTypeMirror type, List parameters = - AnnotatedTypes.adaptParameters(this, method, methodInvocationTree.getArguments(), null); + AnnotatedTypes.adaptParameters( + this, method, methodInvocationTree.getArguments(), null); method.setParameterTypes(parameters); inferencePoly.replacePolys(methodInvocationTree, method); - if (methodInvocationTree.getKind() == Tree.Kind.METHOD_INVOCATION && - TreeUtils.isMethodInvocation(methodInvocationTree, objectGetClass, processingEnv)) { + if (methodInvocationTree.getKind() == Tree.Kind.METHOD_INVOCATION + && TreeUtils.isMethodInvocation( + methodInvocationTree, objectGetClass, processingEnv)) { adaptGetClassReturnTypeToReceiver(method, receiverType, methodInvocationTree); } return mType; } - private final AnnotatedTypeScanner fullyQualifiedVisitor = new AnnotatedTypeScanner() { - @Override - public Boolean visitDeclared(AnnotatedDeclaredType type, Void p) { - if (type.getAnnotations().size() != qualHierarchy.getWidth()) { - return false; - } - return super.visitDeclared(type, p); - } - }; + private final AnnotatedTypeScanner fullyQualifiedVisitor = + new AnnotatedTypeScanner() { + @Override + public Boolean visitDeclared(AnnotatedDeclaredType type, Void p) { + if (type.getAnnotations().size() != qualHierarchy.getWidth()) { + return false; + } + return super.visitDeclared(type, p); + } + }; /** - * This method is similar to the one in its superclass AnnotatedTypeFactory, but it has additional logic to handle - * constraints in the context of type inference. - * @see org.checkerframework.checker.type.AnnotatedTypeFactory#constructorFromUse(com.sun.source.tree.NewClassTree) + * This method is similar to the one in its superclass AnnotatedTypeFactory, but it has + * additional logic to handle constraints in the context of type inference. * + * @see + * org.checkerframework.checker.type.AnnotatedTypeFactory#constructorFromUse(com.sun.source.tree.NewClassTree) * @param newClassTree * @return a ParameterizedExecutableType */ - @Override public ParameterizedExecutableType constructorFromUse(final NewClassTree newClassTree) { - assert newClassTree != null : "NewClassTree was null when attempting to get constructorFromUse. " + - "Current path:\n" + getVisitorTreePath(); + assert newClassTree != null + : "NewClassTree was null when attempting to get constructorFromUse. " + + "Current path:\n" + + getVisitorTreePath(); final ExecutableElement constructorElem = TreeUtils.elementFromUse(newClassTree); // TODO Super seems calling the same thing. Add a note for future clear up. @@ -388,41 +415,50 @@ public ParameterizedExecutableType constructorFromUse(final NewClassTree newClas addComputedTypeAnnotations(newClassTree, constructorReturnType); ParameterizedExecutableType result = super.constructorFromUse(newClassTree); - ParameterizedExecutableType substitutedPair = substituteTypeArgs(newClassTree, constructorElem, result.executableType); + ParameterizedExecutableType substitutedPair = + substituteTypeArgs(newClassTree, constructorElem, result.executableType); inferencePoly.replacePolys(newClassTree, substitutedPair.executableType); return substitutedPair; } /** - * Get a map of the type arguments for any type variables in tree. Create a list of type arguments by - * replacing each type parameter of exeEle by it's corresponding argument in the map. Substitute the - * type parameters in exeType with those in the type arg map. + * Get a map of the type arguments for any type variables in tree. Create a list of type + * arguments by replacing each type parameter of exeEle by it's corresponding argument in the + * map. Substitute the type parameters in exeType with those in the type arg map. * * @param expressionTree Tree representing the method or constructor we are analyzing * @param methodElement The element corresponding with tree * @param methodType The type as determined by this class of exeEle - * @return A list of the actual type arguments for the type parameters of exeEle and exeType with it's type - * parameters replaced by the actual type arguments + * @return A list of the actual type arguments for the type parameters of exeEle and exeType + * with it's type parameters replaced by the actual type arguments */ private ParameterizedExecutableType substituteTypeArgs( - EXP_TREE expressionTree, final ExecutableElement methodElement, final AnnotatedExecutableType methodType) { + EXP_TREE expressionTree, + final ExecutableElement methodElement, + final AnnotatedExecutableType methodType) { // determine substitution for method type variables final Map typeVarMapping = - AnnotatedTypes.findTypeArguments(processingEnv, this.realTypeFactory, expressionTree, methodElement, methodType); + AnnotatedTypes.findTypeArguments( + processingEnv, + this.realTypeFactory, + expressionTree, + methodElement, + methodType); if (typeVarMapping.isEmpty()) { - return new ParameterizedExecutableType(methodType, new LinkedList()); + return new ParameterizedExecutableType( + methodType, new LinkedList()); } // else // We take the type variables from the method element, not from the annotated method. // For some reason, this way works, the other one doesn't. // TODO: IS THAT TRUE? - final List foundTypeVars = new LinkedList<>(); + final List foundTypeVars = new LinkedList<>(); final List missingTypeVars = new LinkedList<>(); - for ( final TypeParameterElement typeParamElem : methodElement.getTypeParameters() ) { - final TypeVariable typeParam = (TypeVariable)typeParamElem.asType(); + for (final TypeParameterElement typeParamElem : methodElement.getTypeParameters()) { + final TypeVariable typeParam = (TypeVariable) typeParamElem.asType(); if (typeVarMapping.containsKey(typeParam)) { foundTypeVars.add(typeParam); } else { @@ -432,10 +468,11 @@ private ParameterizedExecutableType substitute if (!missingTypeVars.isEmpty()) { throw new BugInCF( - "InferenceAnnotatedTypeFactory.methodFromUse did not find a mapping for " + - "the following type params:\n" + InferenceUtil.join(missingTypeVars, "\n") + - "in the inferred type arguments: " + InferenceUtil.join(typeVarMapping) - ); + "InferenceAnnotatedTypeFactory.methodFromUse did not find a mapping for " + + "the following type params:\n" + + InferenceUtil.join(missingTypeVars, "\n") + + "in the inferred type arguments: " + + InferenceUtil.join(typeVarMapping)); } final List actualTypeArgs = new ArrayList<>(foundTypeVars.size()); @@ -443,12 +480,12 @@ private ParameterizedExecutableType substitute actualTypeArgs.add(typeVarMapping.get(found)); } - final AnnotatedExecutableType actualExeType = (AnnotatedExecutableType)typeVarSubstitutor.substitute(typeVarMapping, methodType); + final AnnotatedExecutableType actualExeType = + (AnnotatedExecutableType) typeVarSubstitutor.substitute(typeVarMapping, methodType); return new ParameterizedExecutableType(actualExeType, actualTypeArgs); } - @Override protected void performFlowAnalysis(final ClassTree classTree) { final InferenceMain inferenceMain = InferenceMain.getInstance(); @@ -458,15 +495,16 @@ protected void performFlowAnalysis(final ClassTree classTree) { } /** - * We override this to remove the extra isSubtype check when applying inferred annotations. - * (so we don't get those extra isSubtype constraints). + * We override this to remove the extra isSubtype check when applying inferred annotations. (so + * we don't get those extra isSubtype constraints). */ @Override - protected void applyInferredAnnotations(org.checkerframework.framework.type.AnnotatedTypeMirror type, CFValue as) { + protected void applyInferredAnnotations( + org.checkerframework.framework.type.AnnotatedTypeMirror type, CFValue as) { // TODO JB: Is this behavior different from what occured in inference? boolean skipSubtypingCheck = true; DefaultInferredTypesApplier applier = - new DefaultInferredTypesApplier(skipSubtypingCheck,getQualifierHierarchy(), this); + new DefaultInferredTypesApplier(skipSubtypingCheck, getQualifierHierarchy(), this); applier.applyInferredType(type, as.getAnnotations(), as.getUnderlyingType()); } @@ -474,9 +512,12 @@ protected void applyInferredAnnotations(org.checkerframework.framework.type.Anno * This is the same as the super method, but we do not want to use defaults or typeAnnotator. */ @Override - protected void addComputedTypeAnnotations(Tree tree, AnnotatedTypeMirror type, boolean iUseFlow) { - assert root != null : "GenericAnnotatedTypeFactory.annotateImplicit: " + - " root needs to be set when used on trees; factory: " + this.getClass(); + protected void addComputedTypeAnnotations( + Tree tree, AnnotatedTypeMirror type, boolean iUseFlow) { + assert root != null + : "GenericAnnotatedTypeFactory.annotateImplicit: " + + " root needs to be set when used on trees; factory: " + + this.getClass(); // Moving this here forces the type variables to be annotated as a declaration // before they are used and therefore ensures that they have annotations before use @@ -484,7 +525,7 @@ protected void addComputedTypeAnnotations(Tree tree, AnnotatedTypeMirror type, b // TODO: instead of removing these calls, add special do-nothing type annotators/defaults. // typeAnnotator.visit(type, null); - defaults.annotate(tree, type); + defaults.annotate(tree, type); if (iUseFlow) { CFValue as = getInferredValueFor(tree); @@ -505,26 +546,27 @@ public AnnotatedDeclaredType getBoxedType(AnnotatedPrimitiveType type) { } // TODO: I don't think this method is needed, but we should verify this. -// @Override -// public AnnotatedTypeMirror getAnnotatedTypeFromTypeTree(final Tree tree) { -// -// if (inferenceChecker.extImplsTreeCache.contains(tree)) { -// inferenceChecker.extImplsTreeCache(tree) -// -// } else { -// super.getAnnotatedTypeFromTypeTree(tree) -// -// } -// } + // @Override + // public AnnotatedTypeMirror getAnnotatedTypeFromTypeTree(final Tree tree) { + // + // if (inferenceChecker.extImplsTreeCache.contains(tree)) { + // inferenceChecker.extImplsTreeCache(tree) + // + // } else { + // super.getAnnotatedTypeFromTypeTree(tree) + // + // } + // } /** - * TODO: Expand - * If we have a cached AnnotatedTypeMirror for the element then copy its annotations to type - * else if we can get the source tree for the declaration of that element visit it with the tree annotator - * else get the AnnotatedTypeMirror from the real AnnotatedTypeFactory and copy its annotations to type + * TODO: Expand If we have a cached AnnotatedTypeMirror for the element then copy its + * annotations to type else if we can get the source tree for the declaration of that element + * visit it with the tree annotator else get the AnnotatedTypeMirror from the real + * AnnotatedTypeFactory and copy its annotations to type + * * @param element The element to annotate * @param type The AnnotatedTypeMirror corresponding to element - * */ + */ @Override public void addComputedTypeAnnotations(final Element element, final AnnotatedTypeMirror type) { if (!variableAnnotator.annotateElementFromStore(element, type)) { @@ -548,12 +590,17 @@ public void addComputedTypeAnnotations(final Element element, final AnnotatedTyp @Override public void setRoot(final CompilationUnitTree root) { - logger.fine("\nCHANGING COMPILATION UNIT ( " + compilationUnitsHandled + " ): " + root.getSourceFile().getName() + " \n"); + logger.fine( + "\nCHANGING COMPILATION UNIT ( " + + compilationUnitsHandled + + " ): " + + root.getSourceFile().getName() + + " \n"); // TODO: THERE MAY BE STORES WE WANT TO CLEAR, PERHAPS ELEMENTS FOR LOCAL VARIABLES // TODO: IN THE PREVIOUS COMPILATION UNIT IN VARIABLE ANNOTATOR compilationUnitsHandled += 1; - this.realTypeFactory.setRoot( root ); + this.realTypeFactory.setRoot(root); this.variableAnnotator.clearTreeInfo(); super.setRoot(root); } @@ -565,6 +612,7 @@ protected InferenceViewpointAdapter createViewpointAdapter() { /** * Get the annotation from the class declaration. + * * @param type a type * @return the singleton set with the {@link VarAnnot} on the class bound */ @@ -576,7 +624,8 @@ public AnnotationMirrorSet getTypeDeclarationBounds(TypeMirror type) { return AnnotationMirrorSet.singleton(vAnno); } - // This is to handle the special case of anonymous classes when the super class (or interface) + // This is to handle the special case of anonymous classes when the super class (or + // interface) // identifier is explicit annotated, e.g. // A a1 = new @OsUntrusted A() {}; // In such cases, the declaration bound of the anonymous class is the explicit annotation on @@ -594,9 +643,9 @@ public AnnotationMirrorSet getTypeDeclarationBounds(TypeMirror type) { } /** - * Unlike the cases in type checking, in inference we should: - * (1) if the clause tree contains explicit annotation, return the corresponding @VarAnnot - * (2) otherwise, return the primary variable created for the clause + * Unlike the cases in type checking, in inference we should: (1) if the clause tree contains + * explicit annotation, return the corresponding @VarAnnot (2) otherwise, return the primary + * variable created for the clause * * @param clause the tree that represents an extends or implements clause * @return the annotated type of the clause tree @@ -605,6 +654,4 @@ public AnnotationMirrorSet getTypeDeclarationBounds(TypeMirror type) { public AnnotatedTypeMirror getTypeOfExtendsImplements(Tree clause) { return getAnnotatedTypeFromTypeTree(clause); } - } - diff --git a/src/checkers/inference/InferenceChecker.java b/src/checkers/inference/InferenceChecker.java index b5bb56415..897bc77f5 100644 --- a/src/checkers/inference/InferenceChecker.java +++ b/src/checkers/inference/InferenceChecker.java @@ -14,9 +14,7 @@ public void initChecker() { this.visitor = InferenceMain.getInstance().getVisitor(); } - /** - * Called during super.initChecker(). We want it to do nothing. - */ + /** Called during super.initChecker(). We want it to do nothing. */ @Override protected BaseTypeVisitor createSourceVisitor() { return null; diff --git a/src/checkers/inference/InferenceCli.java b/src/checkers/inference/InferenceCli.java index 0f2c4129c..ee5762de5 100644 --- a/src/checkers/inference/InferenceCli.java +++ b/src/checkers/inference/InferenceCli.java @@ -1,22 +1,20 @@ package checkers.inference; +import org.plumelib.options.Option; +import org.plumelib.options.Options; + import java.io.IOException; import java.util.logging.ConsoleHandler; import java.util.logging.Handler; -import java.util.logging.Logger; import java.util.logging.Level; - -import org.plumelib.options.Option; -import org.plumelib.options.Options; +import java.util.logging.Logger; /** * Command line launcher for Checker-Framework-Inference. * - * Parses command line options and creates InferenceMain - * instance to start inference system. + *

Parses command line options and creates InferenceMain instance to start inference system. * * @author mcarthur - * */ public class InferenceCli { @@ -27,6 +25,7 @@ public class InferenceCli { // Modes @Option("-v print version") public static boolean version; + @Option("-h print help") public static boolean help; @@ -36,26 +35,37 @@ public class InferenceCli { @Option("[Level] set the log level") public static String log_level; + @Option("[InferenceSolver] solver to use on constraints") public static String solver; + @Option("[path] path to write jaif") public static String jaiffile = DEFAULT_JAIF; + @Option("encoding") public static String encoding; + @Option("[dir] directory to write dataflow diagrams") public static String flowdotdir; + @Option("Args to pass to javac compiler") public static String javac_args; + @Option("Args to pass to solver") public static String solver_args; + @Option("bootclasspath to use for compiling") public static String bootclasspath; + @Option("showchecks") public static boolean showchecks; + @Option("ignore logs of exceptions") public static boolean hackmode; + @Option("only perform type checking -- don't generate class files") public static boolean proconly = true; + @Option("[path] stubfiles to use for type checking") public static String stubs; @@ -68,7 +78,7 @@ public static void main(String[] args) throws IOException { inferenceMain.run(); } - public static void initCli(String [] args) { + public static void initCli(String[] args) { Options options = new Options("InferenceCli [options]", InferenceCli.class); otherOptions = options.parse(true, args); @@ -94,9 +104,7 @@ public static void initCli(String [] args) { } } - /** - * Set the root logging level and handler level. - */ + /** Set the root logging level and handler level. */ public static void setLoggingLevel(Level level) { Logger root = Logger.getLogger(""); root.setLevel(level); diff --git a/src/checkers/inference/InferenceDevelLauncher.java b/src/checkers/inference/InferenceDevelLauncher.java index f5e61e7e4..cdd808181 100644 --- a/src/checkers/inference/InferenceDevelLauncher.java +++ b/src/checkers/inference/InferenceDevelLauncher.java @@ -1,27 +1,26 @@ package checkers.inference; +import org.checkerframework.javacutil.BugInCF; + import java.io.File; import java.io.PrintStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import org.checkerframework.javacutil.BugInCF; - /** * Develop Launcher for checker-framework-inference developers. * - * Instead of using jar files of checker-framework-inference and checker-framework, - * {@code InferenceDevelLauncher} uses the eclipse build class files to invoke - * {@code InferenceMain}. Similar to {@code CheckerDevelMain}, this class is associated - * with a shell script called {@link inference-dev}, which set the proper class files - * locations that this class would use. + *

Instead of using jar files of checker-framework-inference and checker-framework, {@code + * InferenceDevelLauncher} uses the eclipse build class files to invoke {@code InferenceMain}. + * Similar to {@code CheckerDevelMain}, this class is associated with a shell script called {@link + * inference-dev}, which set the proper class files locations that this class would use. * - * TODO: We need to think how to enable {@code InferenceDevelLauncher} to find all necessary + *

TODO: We need to think how to enable {@code InferenceDevelLauncher} to find all necessary * locations by itself, so that we could remove the dependency of a shell script. After achieving * this, we could also apply the similar solution to {@code CheckerDevelMain}. - * @author charleszhuochen * + * @author charleszhuochen */ public class InferenceDevelLauncher extends InferenceLauncher { @@ -35,67 +34,82 @@ public InferenceDevelLauncher(PrintStream outStream, PrintStream errStream) { super(outStream, errStream); } - public static void main(String [] args) { - final String runtimeCp = System.getProperty( RUNTIME_CP ); - final String binaryDir = System.getProperty( BINARY ); - final String verbose = System.getProperty( VERBOSE ); - final String annotatedJDK = System.getProperty( ANNOTATED_JDK ); + public static void main(String[] args) { + final String runtimeCp = System.getProperty(RUNTIME_CP); + final String binaryDir = System.getProperty(BINARY); + final String verbose = System.getProperty(VERBOSE); + final String annotatedJDK = System.getProperty(ANNOTATED_JDK); if (verbose != null && verbose.equalsIgnoreCase("TRUE")) { - System.out.print("CheckerDevelMain:\n" + - "Prepended to runtime classpath: " + runtimeCp + "\n" + - "annotated jdk: " + annotatedJDK + "\n" + - "Binary Dir: " + binaryDir + "\n" - ); + System.out.print( + "CheckerDevelMain:\n" + + "Prepended to runtime classpath: " + + runtimeCp + + "\n" + + "annotated jdk: " + + annotatedJDK + + "\n" + + "Binary Dir: " + + binaryDir + + "\n"); } - assert (binaryDir != null) : - BINARY + " must specify a binary directory in which " + - "checker.jar, javac.jar, etc... are usually built"; + assert (binaryDir != null) + : BINARY + + " must specify a binary directory in which " + + "checker.jar, javac.jar, etc... are usually built"; - assert (runtimeCp != null) : RUNTIME_CP + " must specify a path entry to prepend to the Java classpath when running Javac"; // TODO: Fix the assert messages - assert (annotatedJDK != null) : ANNOTATED_JDK + " must specify a path entry to prepend to the annotated JDK"; + assert (runtimeCp != null) + : RUNTIME_CP + + " must specify a path entry to prepend to the Java classpath when running Javac"; // TODO: Fix the assert messages + assert (annotatedJDK != null) + : ANNOTATED_JDK + " must specify a path entry to prepend to the annotated JDK"; new InferenceDevelLauncher(System.out, System.err).launch(args); } @Override - protected void initInferenceOptions(String [] args) { + protected void initInferenceOptions(String[] args) { super.initInferenceOptions(args); - // overwrite distributed dirs and jars to the location that {@code InferenceDevelLauncher.BINARY} indicates. - InferenceOptions.pathToThisJar = null; // {@code InferenceDevelLauncher} should not be called from jar. set to null in case of wrong use. - InferenceOptions.distDir = new File(System.getProperty( BINARY )); + // overwrite distributed dirs and jars to the location that {@code + // InferenceDevelLauncher.BINARY} indicates. + InferenceOptions.pathToThisJar = + null; // {@code InferenceDevelLauncher} should not be called from jar. set to null + // in case of wrong use. + InferenceOptions.distDir = new File(System.getProperty(BINARY)); InferenceOptions.checkersInferenceDir = InferenceOptions.distDir.getParentFile(); - InferenceOptions.checkerJar = new File (InferenceOptions.distDir, "checker.jar"); + InferenceOptions.checkerJar = new File(InferenceOptions.distDir, "checker.jar"); } @Override /** - * return the eclipse output directory instead of jars. - * the eclipse output directory is set by {@code InferenceDevelLauncher.RUNTIME_BCP} + * return the eclipse output directory instead of jars. the eclipse output directory is set by + * {@code InferenceDevelLauncher.RUNTIME_BCP} */ - public List getInferenceRuntimeJars() { - return prependPathOpts(RUNTIME_CP, new ArrayList ()); + public List getInferenceRuntimeJars() { + return prependPathOpts(RUNTIME_CP, new ArrayList()); } @Override // return jdkFile path public String getInferenceCompilationBootclassPath() { - return System.getProperty( ANNOTATED_JDK ); + return System.getProperty(ANNOTATED_JDK); } /** - * TODO: we need to extract the utility methods in {@code CheckerMain} and {@code CheckerDevelMain} out to an Util Class, - * change their visibility to public, then we can reuse them in {@code InferenceLauncher}, {@code InferenceDevelLauncher} - * and {@code InferenceMain}. + * TODO: we need to extract the utility methods in {@code CheckerMain} and {@code + * CheckerDevelMain} out to an Util Class, change their visibility to public, then we can reuse + * them in {@code InferenceLauncher}, {@code InferenceDevelLauncher} and {@code InferenceMain}. + * + *

This method is copied from CheckerDevelMain * - * This method is copied from CheckerDevelMain * @param pathProp * @param pathOpts * @param otherPaths * @return */ - private static List prependPathOpts(final String pathProp, final List pathOpts, final String ... otherPaths) { + private static List prependPathOpts( + final String pathProp, final List pathOpts, final String... otherPaths) { final String cp = System.getProperty(pathProp); if (cp == null) { diff --git a/src/checkers/inference/InferenceLauncher.java b/src/checkers/inference/InferenceLauncher.java index 3d1fdce1a..4c03a1072 100644 --- a/src/checkers/inference/InferenceLauncher.java +++ b/src/checkers/inference/InferenceLauncher.java @@ -1,9 +1,9 @@ package checkers.inference; - import org.checkerframework.framework.util.CheckerMain; import org.checkerframework.framework.util.ExecUtil; import org.checkerframework.javacutil.SystemUtil; +import org.plumelib.util.StringsPlume; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; @@ -20,19 +20,16 @@ import java.util.regex.Pattern; import checkers.inference.InferenceOptions.InitStatus; -import org.plumelib.util.StringsPlume; - /** - * Main class used to execute inference and related tasks. It can be run from: - * The InferenceLauncher can be run from checker-framework-inference/scripts + * Main class used to execute inference and related tasks. It can be run from: The InferenceLauncher + * can be run from checker-framework-inference/scripts * - * InferenceLauncher parses a set of options (defined in InferenceOptions). - * Based on the options, InferenceLauncher will run 1 or more tasks. - * Use the --mode option to specify which tasks are run. The values that can - * be passed to this option are enumerated in InferenceLauncher.Mode + *

InferenceLauncher parses a set of options (defined in InferenceOptions). Based on the options, + * InferenceLauncher will run 1 or more tasks. Use the --mode option to specify which tasks are run. + * The values that can be passed to this option are enumerated in InferenceLauncher.Mode * - * See InferenceOptions.java for more information on arguments to InferenceLauncher + *

See InferenceOptions.java for more information on arguments to InferenceLauncher */ public class InferenceLauncher { @@ -47,13 +44,13 @@ public InferenceLauncher(PrintStream outStream, PrintStream errStream) { this.errStream = errStream; } - protected void initInferenceOptions(String [] args) { + protected void initInferenceOptions(String[] args) { InitStatus initStatus = InferenceOptions.init(args, true); initStatus.validateOrExit(); } - public void launch(String [] args) { + public void launch(String[] args) { initInferenceOptions(args); Mode mode = null; @@ -61,8 +58,12 @@ public void launch(String [] args) { mode = Mode.valueOf(InferenceOptions.mode); } catch (IllegalArgumentException iexc) { - outStream.println("Could not recognize mode: " + InferenceOptions.mode + "\n" - + "valid modes: " + StringsPlume.join(", ", Mode.values())); + outStream.println( + "Could not recognize mode: " + + InferenceOptions.mode + + "\n" + + "valid modes: " + + StringsPlume.join(", ", Mode.values())); System.exit(1); } @@ -82,49 +83,52 @@ public void launch(String [] args) { case ROUNDTRIP_TYPECHECK: infer(); - List updatedJavaFiles = insertJaif(); + List updatedJavaFiles = insertJaif(); typecheck(updatedJavaFiles.toArray(new String[updatedJavaFiles.size()])); break; } } - /** - * Mode describes what actions should be performed by the launcher. - */ + /** Mode describes what actions should be performed by the launcher. */ public enum Mode { - /** just run typechecking do not infer anything*/ + /** just run typechecking do not infer anything */ TYPECHECK, - /** run inference but do not typecheck or insert the result into source code*/ + /** run inference but do not typecheck or insert the result into source code */ INFER, - /** run inference and insert the result back into source code*/ + /** run inference and insert the result back into source code */ ROUNDTRIP, - /** run inference, insert the result back into source code, and typecheck*/ + /** run inference, insert the result back into source code, and typecheck */ ROUNDTRIP_TYPECHECK } - public static void main(String [] args) { + public static void main(String[] args) { new InferenceLauncher(System.out, System.err).launch(args); } /** - * Runs typechecking on the input set of files using the arguments passed - * to javacOptions on the command line. - * @param javaFiles Source files to typecheck, we use this argument instead of InferenceOptions.javaFiles - * because when we roundtrip we may or may not have inserted annotations in place. + * Runs typechecking on the input set of files using the arguments passed to javacOptions on the + * command line. + * + * @param javaFiles Source files to typecheck, we use this argument instead of + * InferenceOptions.javaFiles because when we roundtrip we may or may not have inserted + * annotations in place. */ - public void typecheck(String [] javaFiles) { + public void typecheck(String[] javaFiles) { printStep("Typechecking", outStream); - List options = new ArrayList<>(InferenceOptions.javacOptions.size() + javaFiles.length + 2); + List options = + new ArrayList<>(InferenceOptions.javacOptions.size() + javaFiles.length + 2); options.add("-processor"); options.add(InferenceOptions.checker); if (InferenceOptions.debug != null) { options.add("-J-Xdebug"); - options.add("-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=" + InferenceOptions.debug); + options.add( + "-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=" + + InferenceOptions.debug); } options.addAll(InferenceOptions.javacOptions); @@ -150,9 +154,9 @@ public void typecheck(String [] javaFiles) { } /** - * Infers annotations for the set of source files found in InferenceOptions.java - * This method creates a process that runs InferenceMain on the same options - * in InferenceOptions but excluding those that do not apply to the inference step + * Infers annotations for the set of source files found in InferenceOptions.java This method + * creates a process that runs InferenceMain on the same options in InferenceOptions but + * excluding those that do not apply to the inference step */ public void infer() { printStep("Inferring", outStream); @@ -168,32 +172,46 @@ public void infer() { if (SystemUtil.jreVersion > 8) { // Keep in sync with build.gradle - argList.addAll(Arrays.asList("--add-exports", "jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", - "--add-exports", "jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED", - "--add-exports", "jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", - "--add-exports", "jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", - "--add-exports", "jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED", - "--add-exports", "jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED", - "--add-exports", "jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", - "--add-exports", "jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", - "--add-opens", "jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED")); + argList.addAll( + Arrays.asList( + "--add-exports", + "jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", + "--add-exports", + "jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED", + "--add-exports", + "jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", + "--add-exports", + "jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", + "--add-exports", + "jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED", + "--add-exports", + "jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED", + "--add-exports", + "jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", + "--add-exports", + "jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", + "--add-opens", + "jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED")); } argList.add("-classpath"); argList.add(getInferenceRuntimeClassPath()); if (InferenceOptions.debug != null) { - argList.add("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=" + InferenceOptions.debug); + argList.add( + "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=" + + InferenceOptions.debug); } argList.addAll( Arrays.asList( - "-ea", "-ea:checkers.inference...", + "-ea", + "-ea:checkers.inference...", // TODO: enable assertions. "-da:org.checkerframework.framework.flow...", "checkers.inference.InferenceMain", - "--checker", InferenceOptions.checker) - ); + "--checker", + InferenceOptions.checker)); addIfNotNull("--jaifFile", InferenceOptions.jaifFile, argList); addIfNotNull("--logLevel", InferenceOptions.logLevel, argList); @@ -231,7 +249,9 @@ public void infer() { outStream.println(String.join(" ", argList)); } - int result = ExecUtil.execute(argList.toArray(new String[argList.size()]), outStream, System.err); + int result = + ExecUtil.execute( + argList.toArray(new String[argList.size()]), outStream, System.err); outStream.flush(); errStream.flush(); @@ -262,7 +282,8 @@ public static String getJavaCommand(final String javaHome, final PrintStream out } private void removeXmArgs(List argList, int preJavacOptsSize, int postJavacOptsSize) { - for (int i = preJavacOptsSize; i < argList.size() && i < postJavacOptsSize; /*incremented-below*/) { + for (int i = preJavacOptsSize; + i < argList.size() && i < postJavacOptsSize; /*incremented-below*/ ) { String current = argList.get(i); if (current.startsWith("-Xmx") || current.startsWith("-Xms")) { argList.remove(i); @@ -273,24 +294,28 @@ private void removeXmArgs(List argList, int preJavacOptsSize, int postJa } /** - * Inserts the Jaif resulting from Inference into the source code. - * TODO: Currently we have an InferenceOption.afuOptions field which should - * TODO: be piped into the isnert-annotation-to-source command but is not + * Inserts the Jaif resulting from Inference into the source code. TODO: Currently we have an + * InferenceOption.afuOptions field which should TODO: be piped into the + * isnert-annotation-to-source command but is not + * * @return The list of source files that were passed as arguments to the AFU and were - * potentially altered. This list is needed for subsequent typechecking. + * potentially altered. This list is needed for subsequent typechecking. */ public List insertJaif() { List outputJavaFiles = new ArrayList<>(InferenceOptions.javaFiles.length); printStep("Inserting annotations", outStream); int result; - String pathToAfuScripts = InferenceOptions.pathToAfuScripts == null ? "":InferenceOptions.pathToAfuScripts+File.separator; - String insertAnnotationsScript = pathToAfuScripts+"insert-annotations-to-source"; + String pathToAfuScripts = + InferenceOptions.pathToAfuScripts == null + ? "" + : InferenceOptions.pathToAfuScripts + File.separator; + String insertAnnotationsScript = pathToAfuScripts + "insert-annotations-to-source"; if (!InferenceOptions.inPlace) { final File outputDir = new File(InferenceOptions.afuOutputDir); ensureDirectoryExists(outputDir); - String jaifFile = getJaifFilePath (outputDir); + String jaifFile = getJaifFilePath(outputDir); List options = new ArrayList<>(); options.add(insertAnnotationsScript); @@ -309,10 +334,11 @@ public List insertJaif() { // this can get quite large for large projects and it is not advisable to run // roundtripping via the InferenceLauncher for these projects ByteArrayOutputStream insertOut = new ByteArrayOutputStream(); - result = ExecUtil.execute(options.toArray(new String[options.size()]), insertOut, errStream); + result = + ExecUtil.execute( + options.toArray(new String[options.size()]), insertOut, errStream); outStream.println(insertOut.toString()); - List newJavaFiles = findWrittenFiles(insertOut.toString()); for (File newJavaFile : newJavaFiles) { outputJavaFiles.add(newJavaFile.getAbsolutePath()); @@ -321,13 +347,14 @@ public List insertJaif() { } else { String jaifFile = getJaifFilePath(new File(".")); - String [] options = new String [4 + InferenceOptions.javaFiles.length]; + String[] options = new String[4 + InferenceOptions.javaFiles.length]; options[0] = insertAnnotationsScript; options[1] = "-v"; options[2] = "-i"; options[3] = jaifFile; - System.arraycopy(InferenceOptions.javaFiles, 0, options, 4, InferenceOptions.javaFiles.length); + System.arraycopy( + InferenceOptions.javaFiles, 0, options, 4, InferenceOptions.javaFiles.length); if (InferenceOptions.printCommands) { outStream.println("Running Insert Annotations Command:"); @@ -356,8 +383,8 @@ public static void ensureDirectoryExists(File path) { } /** - * This is a potentially brittle method to scan the output of the AFU - * for Java file paths. + * This is a potentially brittle method to scan the output of the AFU for Java file paths. + * * @param output The output of the Annotation File Utilities * @return The files that the AFU processed */ @@ -382,14 +409,13 @@ private static List findWrittenFiles(String output) { } catch (IOException e) { throw new RuntimeException(e); } - } - while (line != null); + } while (line != null); return writtenFiles; } /** - * @return InferenceOptions.jaifFile if it is non null, otherwise a path to "inference.jaif" in the - * output directory + * @return InferenceOptions.jaifFile if it is non null, otherwise a path to "inference.jaif" in + * the output directory */ private static String getJaifFilePath(File outputDir) { @@ -402,7 +428,8 @@ private static String getJaifFilePath(File outputDir) { } private static List getMemoryArgs() { - // this should instead read them from InferenceOptions and fall back to this if they are not present + // this should instead read them from InferenceOptions and fall back to this if they are not + // present // perhaps just find all -J String xmx = "-Xmx2048m"; String xms = "-Xms512m"; @@ -418,8 +445,8 @@ private static List getMemoryArgs() { } /** - * @return the paths to the set of jars that are needed to be placed on - * the classpath of the process running inference + * @return the paths to the set of jars that are needed to be placed on the classpath of the + * process running inference */ protected List getInferenceRuntimeJars() { final File distDir = InferenceOptions.pathToThisJar.getParentFile(); @@ -433,7 +460,7 @@ protected List getInferenceRuntimeJars() { // what used as bootclass to run the compiler protected String getInferenceRuntimeBootclassPath() { - return System.getProperty( RUNTIME_BCP_PROP ); + return System.getProperty(RUNTIME_BCP_PROP); } // what's used to run the compiler @@ -454,13 +481,13 @@ protected String getInferenceCompilationBootclassPath() { return ""; } - public static void printStep(String step, PrintStream out) { out.println("\n--- " + step + " ---" + "\n"); } public static void reportStatus(String prefix, int returnCode, PrintStream out) { - out.println("\n--- " + prefix + (returnCode == 0 ? " succeeded" : " failed") + " ---" + "\n"); + out.println( + "\n--- " + prefix + (returnCode == 0 ? " succeeded" : " failed") + " ---" + "\n"); } public static void exitOnNonZeroStatus(int result) { diff --git a/src/checkers/inference/InferenceMain.java b/src/checkers/inference/InferenceMain.java index ee792dee3..60791a44d 100644 --- a/src/checkers/inference/InferenceMain.java +++ b/src/checkers/inference/InferenceMain.java @@ -1,8 +1,10 @@ package checkers.inference; -import checkers.inference.model.SourceVariableSlot; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; +import org.checkerframework.javacutil.AnnotationUtils; +import org.checkerframework.javacutil.BugInCF; +import org.checkerframework.javacutil.SystemUtil; import java.io.FileOutputStream; import java.io.PrintWriter; @@ -24,48 +26,51 @@ import checkers.inference.model.AnnotationLocation; import checkers.inference.model.Constraint; import checkers.inference.model.ConstraintManager; +import checkers.inference.model.SourceVariableSlot; import checkers.inference.model.VariableSlot; import checkers.inference.qual.VarAnnot; import checkers.inference.util.InferenceUtil; import checkers.inference.util.JaifBuilder; -import org.checkerframework.javacutil.AnnotationUtils; -import org.checkerframework.javacutil.BugInCF; -import org.checkerframework.javacutil.SystemUtil; /** * InferenceMain is the central coordinator to the inference system. * - * The main method creates an instance of InferenceMain to handle the rest of the inference process. - * This InferenceMain instance is made accessible by the rest of Checker-Framework-Inference through a static method - * getInstance. - * InferenceMain uses the InferrableChecker of the target checker to instantiate components and wire them together. - * It creates and holds instances to the InferenceVisitor, the InferenceAnnotatedTypeFactory, the InferrableChecker, etc. + *

The main method creates an instance of InferenceMain to handle the rest of the inference + * process. This InferenceMain instance is made accessible by the rest of + * Checker-Framework-Inference through a static method getInstance. InferenceMain uses the + * InferrableChecker of the target checker to instantiate components and wire them together. It + * creates and holds instances to the InferenceVisitor, the InferenceAnnotatedTypeFactory, the + * InferrableChecker, etc. * - * InferenceMain invokes the Checker-Framework programmatically using the javac api to run the InferenceChecker. - * Checker-Framework runs the InferenceChecker as a normal checker. Since javac is running in the same JVM - * and with the same classloader as InferenceMain, the InferenceChecker can access the static InferenceMain instance. + *

InferenceMain invokes the Checker-Framework programmatically using the javac api to run the + * InferenceChecker. Checker-Framework runs the InferenceChecker as a normal checker. Since javac is + * running in the same JVM and with the same classloader as InferenceMain, the InferenceChecker can + * access the static InferenceMain instance. * - * During its initialization, InferenceChecker uses InferenceMain to get an instance of the InferenceVisitor. - * The Checker-Framework then uses this visitor to type-check the source code. For every compilation unit (source file) - * in the program, the InferenceVisitor scans the AST and generates constraints where each check would have occurred. - * InferenceMain manages a ConstraintManager instance to store all constraints generated. + *

During its initialization, InferenceChecker uses InferenceMain to get an instance of the + * InferenceVisitor. The Checker-Framework then uses this visitor to type-check the source code. For + * every compilation unit (source file) in the program, the InferenceVisitor scans the AST and + * generates constraints where each check would have occurred. InferenceMain manages a + * ConstraintManager instance to store all constraints generated. * - * After the last compilation unit has been scanned by the visitor, the Checker-Framework call completes and - * control returns to InferenceMain. InferenceMain checks the return code of javac. - * The Checker-Framework will return an error if no source files were specified, if the specified source files did not exist, - * or if the source files fail to compile. Error codes for other reasons generally result from bugs in Checker-Framework-Inference; - * inference only generates constraints, it does not enforce type-checking rules. + *

After the last compilation unit has been scanned by the visitor, the Checker-Framework call + * completes and control returns to InferenceMain. InferenceMain checks the return code of javac. + * The Checker-Framework will return an error if no source files were specified, if the specified + * source files did not exist, or if the source files fail to compile. Error codes for other reasons + * generally result from bugs in Checker-Framework-Inference; inference only generates constraints, + * it does not enforce type-checking rules. * - * If the Checker-Framework call does not return an error, Checker-Framework-Inference will then process the generated constraints. - * The constraints are solved using an InferenceSolver and then a JAIF is created to allow insertion of inferred annotations back into the input program. - * InferenceSolver is an interface that all solvers must implement. Checker-Framework-Inference can also serialize the constraints for processing later (by a solver or by Verigames). + *

If the Checker-Framework call does not return an error, Checker-Framework-Inference will then + * process the generated constraints. The constraints are solved using an InferenceSolver and then a + * JAIF is created to allow insertion of inferred annotations back into the input program. + * InferenceSolver is an interface that all solvers must implement. Checker-Framework-Inference can + * also serialize the constraints for processing later (by a solver or by Verigames). * - * In the future, Checker-Framework-Inference might be able to use the inferred annotations for type-checking without first inserting the annotations into the input program. + *

In the future, Checker-Framework-Inference might be able to use the inferred annotations for + * type-checking without first inserting the annotations into the input program. * * @author mcarthur - * */ - public class InferenceMain { public final Logger logger = Logger.getLogger(InferenceMain.class.getName()); @@ -73,21 +78,20 @@ public class InferenceMain { /** * Return the single instance of this class. * - * Consumers need an instance to look up - * Visitors/TypeFactories and to use the InferenceRunContext - * + *

Consumers need an instance to look up Visitors/TypeFactories and to use the + * InferenceRunContext */ private static InferenceMain inferenceMainInstance; private InferenceChecker inferenceChecker; /** - * When we are inferring annotations we do not generate all constraints because - * a type may not yet have it's flow-refined type (and therefore RefinementVariable) - * applied to it. This flag is set to true while flow is being performed. + * When we are inferring annotations we do not generate all constraints because a type may not + * yet have it's flow-refined type (and therefore RefinementVariable) applied to it. This flag + * is set to true while flow is being performed. * - * It is queried with isPerformingFlow. Every location from which this method is - * called is a location we omit from generating constraints during flow. + *

It is queried with isPerformingFlow. Every location from which this method is called is a + * location we omit from generating constraints during flow. */ private boolean performingFlow; @@ -112,7 +116,7 @@ public void setResultHandler(ResultHandler resultHandler) { this.resultHandler = resultHandler; } - public static void main(String [] args) { + public static void main(String[] args) { InitStatus status = InferenceOptions.init(args, false); status.validateOrExit(); @@ -120,10 +124,7 @@ public static void main(String [] args) { inferenceMain.run(); } - /** - * Create an InferenceMain instance. - * Options are pulled from InferenceCli static fields. - */ + /** Create an InferenceMain instance. Options are pulled from InferenceCli static fields. */ public InferenceMain() { if (inferenceMainInstance != null) { logger.warning("Only a single instance of InferenceMain should ever be created!"); @@ -138,9 +139,7 @@ public static InferenceMain resetInstance() { return inferenceMainInstance; } - /** - * Kick off the inference process. - */ + /** Kick off the inference process. */ public void run() { logger.finer("Starting InferenceMain"); @@ -156,16 +155,19 @@ public void run() { writeJaif(); } - /** - * Run the Checker-Framework using InferenceChecker - */ + /** Run the Checker-Framework using InferenceChecker */ private void startCheckerFramework() { - List checkerFrameworkArgs = new ArrayList<>(Arrays.asList( - "-processor", "checkers.inference.InferenceChecker", - "-Xmaxwarns", "1000", - "-Xmaxerrs", "1000", - "-XDignore.symbol.file", - "-Awarns")); + List checkerFrameworkArgs = + new ArrayList<>( + Arrays.asList( + "-processor", + "checkers.inference.InferenceChecker", + "-Xmaxwarns", + "1000", + "-Xmaxerrs", + "1000", + "-XDignore.symbol.file", + "-Awarns")); if (SystemUtil.jreVersion == 8) { checkerFrameworkArgs.addAll(Arrays.asList("-source", "8", "-target", "8")); @@ -193,19 +195,21 @@ private void startCheckerFramework() { checkerFrameworkArgs.addAll(Arrays.asList(InferenceOptions.javaFiles)); } - logger.fine(String.format("Starting checker framework with options: %s", checkerFrameworkArgs)); + logger.fine( + String.format("Starting checker framework with options: %s", checkerFrameworkArgs)); StringWriter javacoutput = new StringWriter(); - boolean success = CheckerFrameworkUtil.invokeCheckerFramework(checkerFrameworkArgs.toArray(new String[checkerFrameworkArgs.size()]), - new PrintWriter(javacoutput, true)); + boolean success = + CheckerFrameworkUtil.invokeCheckerFramework( + checkerFrameworkArgs.toArray(new String[checkerFrameworkArgs.size()]), + new PrintWriter(javacoutput, true)); resultHandler.handleCompilerResult(success, javacoutput.toString()); } - /** - * Give the InferenceMain instance a reference to the InferenceChecker - * that is being run by Checker-Framework. + * Give the InferenceMain instance a reference to the InferenceChecker that is being run by + * Checker-Framework. * * @param inferenceChecker The InferenceChecker being run by Checker Framework. */ @@ -215,12 +219,12 @@ public void recordInferenceCheckerInstance(InferenceChecker inferenceChecker) { } /** - * Create a jaif file that records the mapping of VariableSlots to their code positions. - * The output file can be configured by the command-line argument jaiffile. + * Create a jaif file that records the mapping of VariableSlots to their code positions. The + * output file can be configured by the command-line argument jaiffile. */ private void writeJaif() { - try (PrintWriter writer - = new PrintWriter(new FileOutputStream(InferenceOptions.jaifFile))) { + try (PrintWriter writer = + new PrintWriter(new FileOutputStream(InferenceOptions.jaifFile))) { List varSlots = slotManager.getVariableSlots(); Map values = new HashMap<>(); @@ -229,11 +233,14 @@ private void writeJaif() { if (solverResult == null) { annotationClasses.add(VarAnnot.class); } else { - for (Class annotation : realTypeFactory.getSupportedTypeQualifiers()) { + for (Class annotation : + realTypeFactory.getSupportedTypeQualifiers()) { annotationClasses.add(annotation); } - // add any custom annotations that must be inserted to the JAIF header, such as alias annotations - for (Class annotation : realChecker.additionalAnnotationsForJaifHeaderInsertion()) { + // add any custom annotations that must be inserted to the JAIF header, such as + // alias annotations + for (Class annotation : + realChecker.additionalAnnotationsForJaifHeaderInsertion()) { annotationClasses.add(annotation); } } @@ -248,7 +255,9 @@ private void writeJaif() { } } - JaifBuilder builder = new JaifBuilder(values, annotationClasses, realChecker.isInsertMainModOfLocalVar()); + JaifBuilder builder = + new JaifBuilder( + values, annotationClasses, realChecker.isInsertMainModOfLocalVar()); String jaif = builder.createJaif(); writer.println(jaif); @@ -257,14 +266,13 @@ private void writeJaif() { } } - /** - * Solve the generated constraints using the solver specified on the command line. - */ + /** Solve the generated constraints using the solver specified on the command line. */ private void solve() { // TODO: PERHAPS ALLOW SOLVERS TO DECIDE IF/HOW THEY WANT CONSTRAINTS NORMALIZED final ConstraintNormalizer constraintNormalizer = new ConstraintNormalizer(); - Set normalizedConstraints = constraintNormalizer.normalize(constraintManager.getConstraints()); + Set normalizedConstraints = + constraintNormalizer.normalize(constraintManager.getConstraints()); // TODO: Support multiple solvers or serialize before or after solving // TODO: Prune out unneeded variables @@ -272,12 +280,13 @@ private void solve() { if (InferenceOptions.solver != null) { InferenceSolver solver = getSolver(); - this.solverResult = solver.solve( - parseSolverArgs(), - slotManager.getSlots(), - normalizedConstraints, - getRealTypeFactory().getQualifierHierarchy(), - inferenceChecker.getProcessingEnvironment()); + this.solverResult = + solver.solve( + parseSolverArgs(), + slotManager.getSlots(), + normalizedConstraints, + getRealTypeFactory().getQualifierHierarchy(), + inferenceChecker.getProcessingEnvironment()); } } @@ -309,7 +318,9 @@ private void solve() { public InferenceVisitor getVisitor() { if (visitor == null) { - visitor = getRealChecker().createVisitor(inferenceChecker, getInferenceTypeFactory(), true); + visitor = + getRealChecker() + .createVisitor(inferenceChecker, getInferenceTypeFactory(), true); logger.finer("Created InferenceVisitor"); } return visitor; @@ -318,23 +329,37 @@ private void solve() { private InferrableChecker getRealChecker() { if (realChecker == null) { try { - realChecker = (InferrableChecker) Class.forName( - InferenceOptions.checker, true, ClassLoader.getSystemClassLoader()).getDeclaredConstructor().newInstance(); + realChecker = + (InferrableChecker) + Class.forName( + InferenceOptions.checker, + true, + ClassLoader.getSystemClassLoader()) + .getDeclaredConstructor() + .newInstance(); realChecker.init(inferenceChecker.getProcessingEnvironment()); realChecker.initChecker(); logger.finer(String.format("Created real checker: %s", realChecker)); } catch (Throwable e) { - logger.log(Level.SEVERE, "Error instantiating checker class \"" + InferenceOptions.checker + "\".", e); - System.exit(5); - } + logger.log( + Level.SEVERE, + "Error instantiating checker class \"" + InferenceOptions.checker + "\".", + e); + System.exit(5); + } } return realChecker; } private InferenceAnnotatedTypeFactory getInferenceTypeFactory() { if (inferenceTypeFactory == null) { - inferenceTypeFactory = realChecker.createInferenceATF(inferenceChecker, getRealChecker(), - getRealTypeFactory(), getSlotManager(), getConstraintManager()); + inferenceTypeFactory = + realChecker.createInferenceATF( + inferenceChecker, + getRealChecker(), + getRealTypeFactory(), + getSlotManager(), + getConstraintManager()); this.getConstraintManager().init(inferenceTypeFactory); logger.finer("Created InferenceAnnotatedTypeFactory"); } @@ -342,10 +367,11 @@ private InferenceAnnotatedTypeFactory getInferenceTypeFactory() { } /** - * This method is NOT deprecated but SHOULD NOT BE USED other than in getInferenceTypeFactory AND - * InferenceAnnotatedTypeFactory.getSupportedQualifierTypes. We have made it deprecated in order to bring - * this to the attention of future programmers. We would make it private if it weren't for the fact that - * we need the realTypeFactory qualifiers in getSupportedQualifierTypes and it is called in the super class. + * This method is NOT deprecated but SHOULD NOT BE USED other than in getInferenceTypeFactory + * AND InferenceAnnotatedTypeFactory.getSupportedQualifierTypes. We have made it deprecated in + * order to bring this to the attention of future programmers. We would make it private if it + * weren't for the fact that we need the realTypeFactory qualifiers in + * getSupportedQualifierTypes and it is called in the super class. */ public BaseAnnotatedTypeFactory getRealTypeFactory() { if (realTypeFactory == null) { @@ -356,18 +382,20 @@ public BaseAnnotatedTypeFactory getRealTypeFactory() { } public SlotManager getSlotManager() { - if (slotManager == null ) { - Set tops = realTypeFactory.getQualifierHierarchy().getTopAnnotations(); + if (slotManager == null) { + Set tops = + realTypeFactory.getQualifierHierarchy().getTopAnnotations(); if (tops.size() != 1) { - throw new BugInCF("Expected 1 real top qualifier, but received %d instead", tops.size()); + throw new BugInCF( + "Expected 1 real top qualifier, but received %d instead", tops.size()); } - slotManager = new DefaultSlotManager( - inferenceChecker.getProcessingEnvironment(), - tops.iterator().next(), - realTypeFactory.getSupportedTypeQualifiers(), - true - ); + slotManager = + new DefaultSlotManager( + inferenceChecker.getProcessingEnvironment(), + tops.iterator().next(), + realTypeFactory.getSupportedTypeQualifiers(), + true); logger.finer("Created slot manager" + slotManager); } return slotManager; @@ -375,20 +403,29 @@ public SlotManager getSlotManager() { protected InferenceSolver getSolver() { try { - InferenceSolver solver = (InferenceSolver) Class.forName( - InferenceOptions.solver, true, ClassLoader.getSystemClassLoader()).getDeclaredConstructor().newInstance(); + InferenceSolver solver = + (InferenceSolver) + Class.forName( + InferenceOptions.solver, + true, + ClassLoader.getSystemClassLoader()) + .getDeclaredConstructor() + .newInstance(); logger.finer("Created solver: " + solver); return solver; } catch (Throwable e) { - logger.log(Level.SEVERE, "Error instantiating solver class \"" + InferenceOptions.solver + "\".", e); + logger.log( + Level.SEVERE, + "Error instantiating solver class \"" + InferenceOptions.solver + "\".", + e); System.exit(5); return null; // Dead code } } /** - * Parse solver-args from a comma separated list of - * key=value pairs into a Map. + * Parse solver-args from a comma separated list of key=value pairs into a Map. + * * @return Map of string keys and values */ private Map parseSolverArgs() { @@ -400,7 +437,8 @@ private Map parseSolverArgs() { int index; part = part.trim(); if ((index = part.indexOf("=")) > 0) { - processed.put(part.substring(0, index), part.substring(index + 1, part.length())); + processed.put( + part.substring(0, index), part.substring(index + 1, part.length())); } else { processed.put(part, null); } @@ -410,10 +448,10 @@ private Map parseSolverArgs() { } /** - * Parse checker framework args from a space separated list of - * -Axxx=xxx,y=y -Azzz=zzz - * @return List of Strings, each string is a checker framework argument - * in the format: -Axxx=xxx,y=y or -Azzz or -Azzz=zzz + * Parse checker framework args from a space separated list of -Axxx=xxx,y=y -Azzz=zzz + * + * @return List of Strings, each string is a checker framework argument in the format: + * -Axxx=xxx,y=y or -Azzz or -Azzz=zzz */ private List parseCfArgs() { List argList = new ArrayList<>(); @@ -466,7 +504,7 @@ public static boolean isHackMode(boolean condition) { } } - public static abstract interface ResultHandler { + public abstract static interface ResultHandler { void handleCompilerResult(boolean success, String javacOutStr); } diff --git a/src/checkers/inference/InferenceOptions.java b/src/checkers/inference/InferenceOptions.java index 3f72dbfb1..e187161de 100644 --- a/src/checkers/inference/InferenceOptions.java +++ b/src/checkers/inference/InferenceOptions.java @@ -1,9 +1,10 @@ package checkers.inference; - import org.checkerframework.framework.util.CheckerMain; - -import interning.InterningChecker; +import org.plumelib.options.Option; +import org.plumelib.options.OptionGroup; +import org.plumelib.options.Options; +import org.plumelib.util.StringsPlume; import java.io.File; import java.util.ArrayList; @@ -12,30 +13,26 @@ import java.util.List; import java.util.Map; -import org.plumelib.util.StringsPlume; +import checkers.inference.InferenceLauncher.Mode; +import checkers.inference.model.serialization.JsonSerializerSolver; +import checkers.inference.solver.MaxSat2TypeSolver; +import interning.InterningChecker; import ostrusted.OsTrustedChecker; -import org.plumelib.options.Option; -import org.plumelib.options.OptionGroup; -import org.plumelib.options.Options; import sparta.checkers.IFlowSinkChecker; import sparta.checkers.IFlowSourceChecker; import sparta.checkers.propagation.IFlowSinkSolver; import sparta.checkers.propagation.IFlowSourceSolver; import sparta.checkers.sat.SinkSolver; import sparta.checkers.sat.SourceSolver; -import checkers.inference.InferenceLauncher.Mode; -import checkers.inference.model.serialization.JsonSerializerSolver; -import checkers.inference.solver.MaxSat2TypeSolver; /** - * Options for the InferenceLauncher and InferenceMain (though InferenceMain uses only the subset - * of options that apply to inference). + * Options for the InferenceLauncher and InferenceMain (though InferenceMain uses only the subset of + * options that apply to inference). */ public class InferenceOptions { public static final String VERSION = "2"; public static final String DEFAULT_JAIF = "default.jaif"; - // ------------------------------------------------------ // Command-line options // ------------------------------------------------------ @@ -50,29 +47,30 @@ public class InferenceOptions { public static boolean hacks; /** - * The type system to use for checker, solver, and related command-line - * options. If you use this option, all required command-line - * arguments except --mode will have values and the only other option - * you need to include is a list of source files.

+ * The type system to use for checker, solver, and related command-line options. If you use this + * option, all required command-line arguments except --mode will have values and the only other + * option you need to include is a list of source files. * - * All legal options are listed in InferenceOptions.typesystems.keySet() + *

All legal options are listed in InferenceOptions.typesystems.keySet() */ @Option("-t Type system whose checker and solver to use") public static String typesystem; // ------------------------------------------------------ @OptionGroup("Typechecking/Inference arguments") - @Option("[path] path to write jaif") public static String jaifFile = DEFAULT_JAIF; - @Option("[InferrableChecker] the fully-qualified name of the checker to run; overrides --typesystem.") + @Option( + "[InferrableChecker] the fully-qualified name of the checker to run; overrides --typesystem.") public static String checker; - @Option("[InferenceSolver] the fully-qualified name of the solver to use on constraints; overrides --typesystem.") + @Option( + "[InferenceSolver] the fully-qualified name of the solver to use on constraints; overrides --typesystem.") public static String solver; - @Option("The fully-qualified name of the classpath for target program; overrides --targetclasspath.") + @Option( + "The fully-qualified name of the classpath for target program; overrides --targetclasspath.") public static String targetclasspath = "."; @Option("Args to pass to solver, in the format key1=value,key2=value") @@ -82,16 +80,19 @@ public class InferenceOptions { public static String cfArgs; /** If jsonFile is specified this will be set to the JsonSerializerSolver */ - @Option("The JSON file to which constraints should be dumped. This field is mutually exclusive with solver.") + @Option( + "The JSON file to which constraints should be dumped. This field is mutually exclusive with solver.") public static String jsonFile; // ------------------------------------------------------ @OptionGroup("Annotation File Utilities options") - @Option(value = "Path to AFU scripts directory.") public static String pathToAfuScripts; - @Option(value = "Annotation file utilities output directory. WARNING: This directory must be empty.", aliases = "-afud") + @Option( + value = + "Annotation file utilities output directory. WARNING: This directory must be empty.", + aliases = "-afud") public static String afuOutputDir; @Option("Whether or not the annoations should be inserted in the original source code.") @@ -105,20 +106,20 @@ public class InferenceOptions { // ------------------------------------------------------ @OptionGroup("Help") - @Option("-v print version") public static boolean version; - @Option(value="-h Print a help message", aliases={"-help"}) + @Option( + value = "-h Print a help message", + aliases = {"-help"}) public static boolean help; // ------------------------------------------------------ @OptionGroup("Debugging") - @Option("[Level] set the log level (from Java logging)") public static String logLevel; - @Option(value="-p Print all commands before executing them") + @Option(value = "-p Print all commands before executing them") public static boolean printCommands; // TODO: change to int @@ -129,17 +130,18 @@ public class InferenceOptions { // ------------------------------------------------------ public static List javacOptions; - public static String [] javaFiles; + public static String[] javaFiles; - public static File pathToThisJar = new File(CheckerMain.findPathTo(InferenceOptions.class, true)); + public static File pathToThisJar = + new File(CheckerMain.findPathTo(InferenceOptions.class, true)); public static File checkersInferenceDir = pathToThisJar.getParentFile().getParentFile(); public static File distDir = new File(checkersInferenceDir, "dist"); public static File checkerJar = new File(distDir, "checker.jar"); - public static InitStatus init(String [] args, boolean requireMode) { + public static InitStatus init(String[] args, boolean requireMode) { List errors = new ArrayList<>(); Options options = new Options("inference [options]", InferenceOptions.class); - String [] otherArgs = options.parse(true, args); + String[] otherArgs = options.parse(true, args); int startOfJavaFilesIndex = -1; for (int i = 0; i < otherArgs.length; i++) { @@ -165,8 +167,9 @@ public static InitStatus init(String [] args, boolean requireMode) { if (typesystem != null) { TypeSystemSpec spec = typesystems.get(typesystem); if (spec == null) { - errors.add("Unrecognized typesystem. Current typesystems:\n" - + StringsPlume.join("\n", typesystems.keySet())); + errors.add( + "Unrecognized typesystem. Current typesystems:\n" + + StringsPlume.join("\n", typesystems.keySet())); } else { spec.apply(); } @@ -189,8 +192,12 @@ public static InitStatus init(String [] args, boolean requireMode) { modeEnum = Mode.valueOf(InferenceOptions.mode); } catch (IllegalArgumentException iexc) { - System.out.println("Could not recognize mode: " + InferenceOptions.mode + "\n" - + "valid modes: " + StringsPlume.join(", ", Mode.values())); + System.out.println( + "Could not recognize mode: " + + InferenceOptions.mode + + "\n" + + "valid modes: " + + StringsPlume.join(", ", Mode.values())); System.exit(1); } @@ -201,10 +208,15 @@ public static InitStatus init(String [] args, boolean requireMode) { if (solverArgs == null || solverArgs.isEmpty()) { solverArgs = "constraint-file=" + InferenceOptions.jsonFile; } else { - solverArgs = solverArgs + "," + "constraint-file=" + InferenceOptions.jsonFile; + solverArgs = + solverArgs + + "," + + "constraint-file=" + + InferenceOptions.jsonFile; } } else { - errors.add("You must specify a solver using --solver or a --jsonFile to write constraints in."); + errors.add( + "You must specify a solver using --solver or a --jsonFile to write constraints in."); } } else if (jsonFile != null) { errors.add("You may specify EITHER a solver or jsonFile but not both!"); @@ -214,14 +226,17 @@ public static InitStatus init(String [] args, boolean requireMode) { if (modeEnum.ordinal() >= Mode.ROUNDTRIP.ordinal()) { if (afuOutputDir == null) { if (!inPlace) { - errors.add("You must specify an Annotation File Utilities output directory (--afuOutputDir or -afud) or --inPlace."); + errors.add( + "You must specify an Annotation File Utilities output directory (--afuOutputDir or -afud) or --inPlace."); } } else if (inPlace) { - errors.add("You cannot specify both an Annotation File Utilities output directory (--afuOutputDir or -afud) and --inPlace."); + errors.add( + "You cannot specify both an Annotation File Utilities output directory (--afuOutputDir or -afud) and --inPlace."); } if (afuOptions != null && afuOptions.contains("\\s-d\\s")) { - errors.add("Annotation File Utilities output dir must be specified via (--afuOutputDir or -afud) not -d in AFU Options."); + errors.add( + "Annotation File Utilities output dir must be specified via (--afuOutputDir or -afud) not -d in AFU Options."); } } } @@ -230,51 +245,89 @@ public static InitStatus init(String [] args, boolean requireMode) { } public static final Map typesystems = new LinkedHashMap<>(); + static { final File srcDir = new File(checkersInferenceDir, "src"); - typesystems.put("ostrusted", - new TypeSystemSpec(OsTrustedChecker.class, - MaxSat2TypeSolver.class, - new File(srcDir, "ostrusted" + File.separator + "jdk.astub"))); - typesystems.put("interning", - new TypeSystemSpec(InterningChecker.class, - MaxSat2TypeSolver.class, - null)); - typesystems.put("sparta-source", - new TypeSystemSpec(IFlowSourceChecker.class, + typesystems.put( + "ostrusted", + new TypeSystemSpec( + OsTrustedChecker.class, + MaxSat2TypeSolver.class, + new File(srcDir, "ostrusted" + File.separator + "jdk.astub"))); + typesystems.put( + "interning", + new TypeSystemSpec(InterningChecker.class, MaxSat2TypeSolver.class, null)); + typesystems.put( + "sparta-source", + new TypeSystemSpec( + IFlowSourceChecker.class, IFlowSourceSolver.class, - new File(srcDir, "sparta"+ File.separator +"checkers" + File.separator + "information_flow.astub"))); - typesystems.put("sparta-sink", - new TypeSystemSpec(IFlowSinkChecker.class, + new File( + srcDir, + "sparta" + + File.separator + + "checkers" + + File.separator + + "information_flow.astub"))); + typesystems.put( + "sparta-sink", + new TypeSystemSpec( + IFlowSinkChecker.class, IFlowSinkSolver.class, - new File(srcDir, "sparta"+ File.separator +"checkers" + File.separator + "information_flow.astub"))); - typesystems.put("sparta-source-SAT", - new TypeSystemSpec(IFlowSourceChecker.class, + new File( + srcDir, + "sparta" + + File.separator + + "checkers" + + File.separator + + "information_flow.astub"))); + typesystems.put( + "sparta-source-SAT", + new TypeSystemSpec( + IFlowSourceChecker.class, SourceSolver.class, - new File(srcDir, "sparta"+ File.separator +"checkers" + File.separator + "information_flow.astub"))); - typesystems.put("sparta-sink-SAT", - new TypeSystemSpec(IFlowSinkChecker.class, + new File( + srcDir, + "sparta" + + File.separator + + "checkers" + + File.separator + + "information_flow.astub"))); + typesystems.put( + "sparta-sink-SAT", + new TypeSystemSpec( + IFlowSinkChecker.class, SinkSolver.class, - new File(srcDir, "sparta"+ File.separator +"checkers" + File.separator + "information_flow.astub"))); - + new File( + srcDir, + "sparta" + + File.separator + + "checkers" + + File.separator + + "information_flow.astub"))); } - /** - * Specifies the defaults a particular type system would use to run typechecking/inference. - */ + /** Specifies the defaults a particular type system would use to run typechecking/inference. */ private static class TypeSystemSpec { public final Class qualifiedChecker; public final Class defaultSolver; public final File defaultStubs; - public final String [] defaultJavacArgs; + public final String[] defaultJavacArgs; public final String defaultSolverArgs; - private TypeSystemSpec(Class qualifiedChecker, Class defaultSolver, File defaultStubs) { - this(qualifiedChecker, defaultSolver, defaultStubs, new String[0], ""); + private TypeSystemSpec( + Class qualifiedChecker, + Class defaultSolver, + File defaultStubs) { + this(qualifiedChecker, defaultSolver, defaultStubs, new String[0], ""); } - private TypeSystemSpec(Class qualifiedChecker, Class defaultSolver, File defaultStubs, - String[] defaultJavacArgs, String defaultSolverArgs) { + private TypeSystemSpec( + Class qualifiedChecker, + Class defaultSolver, + File defaultStubs, + String[] defaultJavacArgs, + String defaultSolverArgs) { this.qualifiedChecker = qualifiedChecker; this.defaultSolver = defaultSolver; this.defaultStubs = defaultStubs; @@ -338,6 +391,7 @@ public InitStatus(Options options, List errors, boolean printHelp) { public void validateOrExit() { validateOrExit("\n"); } + public void validateOrExit(String errorDelimiter) { if (!errors.isEmpty()) { System.out.println(StringsPlume.join(errorDelimiter, errors)); diff --git a/src/checkers/inference/InferenceQualifierHierarchy.java b/src/checkers/inference/InferenceQualifierHierarchy.java index 83e500ed7..a53c357f3 100644 --- a/src/checkers/inference/InferenceQualifierHierarchy.java +++ b/src/checkers/inference/InferenceQualifierHierarchy.java @@ -1,12 +1,7 @@ package checkers.inference; -import checkers.inference.model.ConstantSlot; -import checkers.inference.model.ConstraintManager; -import checkers.inference.model.LubVariableSlot; -import checkers.inference.model.Slot; -import checkers.inference.qual.VarAnnot; -import checkers.inference.util.InferenceUtil; import com.google.common.collect.ImmutableMap; + import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.framework.type.ElementQualifierHierarchy; import org.checkerframework.framework.type.GenericAnnotatedTypeFactory; @@ -19,17 +14,25 @@ import org.checkerframework.javacutil.BugInCF; import org.plumelib.util.StringsPlume; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.util.Elements; import java.lang.annotation.Annotation; import java.util.Collection; import java.util.Collections; import java.util.Map; import java.util.Set; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Elements; + +import checkers.inference.model.ConstantSlot; +import checkers.inference.model.ConstraintManager; +import checkers.inference.model.LubVariableSlot; +import checkers.inference.model.Slot; +import checkers.inference.qual.VarAnnot; +import checkers.inference.util.InferenceUtil; + /** - * A qualifier hierarchy that generates constraints rather than evaluating them. Calls to isSubtype + * A qualifier hierarchy that generates constraints rather than evaluating them. Calls to isSubtype * generates subtype and equality constraints between the input types based on the expected subtype * relationship (as described by the method signature). */ @@ -45,8 +48,7 @@ public class InferenceQualifierHierarchy extends ElementQualifierHierarchy { public InferenceQualifierHierarchy( Collection> qualifierClasses, Elements elements, - GenericAnnotatedTypeFactory atypeFactory - ) { + GenericAnnotatedTypeFactory atypeFactory) { super(qualifierClasses, elements, atypeFactory); slotMgr = inferenceMain.getSlotManager(); @@ -75,23 +77,21 @@ public static boolean isVarAnnot(AnnotationMirror anno) { /** * Overridden to prevent isSubtype call by just returning the first annotation. * - * There should at most be 1 annotation on a type. - * + *

There should at most be 1 annotation on a type. */ @Override public AnnotationMirror findAnnotationInSameHierarchy( Collection annos, AnnotationMirror annotationMirror) { if (!annos.isEmpty()) { - final AnnotationMirror anno = isVarAnnot(annotationMirror) ? findVarAnnot(annos) - : findNonVarAnnot(annos); + final AnnotationMirror anno = + isVarAnnot(annotationMirror) ? findVarAnnot(annos) : findNonVarAnnot(annos); if (anno != null) { return anno; } } return null; - } @Override @@ -99,8 +99,8 @@ public AnnotationMirror findAnnotationInHierarchy( Collection annos, AnnotationMirror top) { if (!annos.isEmpty()) { - final AnnotationMirror anno = isVarAnnot(top) ? findVarAnnot(annos) - : findNonVarAnnot(annos); + final AnnotationMirror anno = + isVarAnnot(top) ? findVarAnnot(annos) : findNonVarAnnot(annos); if (anno != null) { return anno; } @@ -112,7 +112,8 @@ public AnnotationMirror findAnnotationInHierarchy( /** * @return the first annotation in annos that is NOT an @VarAnnot */ - public static AnnotationMirror findNonVarAnnot(final Iterable annos) { + public static AnnotationMirror findNonVarAnnot( + final Iterable annos) { for (AnnotationMirror anno : annos) { if (!isVarAnnot(anno)) { return anno; @@ -140,41 +141,58 @@ public static AnnotationMirror findVarAnnot(final Iterable rhsAnnos, - TypeMirror subType, - final Collection lhsAnnos, - TypeMirror superType ) { + public boolean isSubtypeShallow( + final Collection rhsAnnos, + TypeMirror subType, + final Collection lhsAnnos, + TypeMirror superType) { final AnnotationMirror rhsVarAnnot = findVarAnnot(rhsAnnos); final AnnotationMirror lhsVarAnnot = findVarAnnot(lhsAnnos); if (InferenceMain.isHackMode(rhsVarAnnot == null || lhsVarAnnot == null)) { - InferenceMain.getInstance().logger.info( - "Hack:\n" - + " rhs=" + StringsPlume.join(", ", rhsAnnos) + "\n" - + " lhs=" + StringsPlume.join(", ", lhsAnnos )); - return true; + InferenceMain.getInstance() + .logger + .info( + "Hack:\n" + + " rhs=" + + StringsPlume.join(", ", rhsAnnos) + + "\n" + + " lhs=" + + StringsPlume.join(", ", lhsAnnos)); + return true; } - assert rhsVarAnnot != null && lhsVarAnnot != null : - "All types should have exactly 1 VarAnnot!\n" - + " rhs=" + StringsPlume.join(", ", rhsAnnos) + "\n" - + " lhs=" + StringsPlume.join(", ", lhsAnnos ); + assert rhsVarAnnot != null && lhsVarAnnot != null + : "All types should have exactly 1 VarAnnot!\n" + + " rhs=" + + StringsPlume.join(", ", rhsAnnos) + + "\n" + + " lhs=" + + StringsPlume.join(", ", lhsAnnos); return isSubtypeQualifiers(rhsVarAnnot, lhsVarAnnot); } @Override - public boolean isSubtypeQualifiers(final AnnotationMirror subtype, final AnnotationMirror supertype) { + public boolean isSubtypeQualifiers( + final AnnotationMirror subtype, final AnnotationMirror supertype) { - // NOTE: subtype and supertype are nullable because, for example, in BaseTypeVisitor::checkConstructorInvocation, - // findAnnotationInSameHierarchy may return null since @VarAnnot and some constant real qualifier + // NOTE: subtype and supertype are nullable because, for example, in + // BaseTypeVisitor::checkConstructorInvocation, + // findAnnotationInSameHierarchy may return null since @VarAnnot and some constant real + // qualifier // are not in the same qualifier hierarchy. - if (subtype == null || supertype == null || !isVarAnnot(subtype) || !isVarAnnot(supertype)) { + if (subtype == null + || supertype == null + || !isVarAnnot(subtype) + || !isVarAnnot(supertype)) { if (InferenceMain.isHackMode()) { return true; } else { - throw new BugInCF("Unexpected arguments for isSubtype: subtype=%s, supertype=%s", subtype, supertype); + throw new BugInCF( + "Unexpected arguments for isSubtype: subtype=%s, supertype=%s", + subtype, supertype); } } @@ -185,7 +203,7 @@ public boolean isSubtypeQualifiers(final AnnotationMirror subtype, final Annotat return true; } - final Slot subSlot = slotMgr.getSlot(subtype); + final Slot subSlot = slotMgr.getSlot(subtype); final Slot superSlot = slotMgr.getSlot(supertype); return constraintMgr.addSubtypeConstraintNoErrorMsg(subSlot, superSlot); @@ -218,24 +236,24 @@ public Set leastUpperBoundsShallow( } @Override - public AnnotationMirror leastUpperBoundQualifiers(final AnnotationMirror a1, final AnnotationMirror a2) { + public AnnotationMirror leastUpperBoundQualifiers( + final AnnotationMirror a1, final AnnotationMirror a2) { return merge(a1, a2, true); } - private AnnotationMirror merge(final AnnotationMirror a1, final AnnotationMirror a2, boolean isLub) { + private AnnotationMirror merge( + final AnnotationMirror a1, final AnnotationMirror a2, boolean isLub) { if (a1 == null || a2 == null) { if (!InferenceMain.isHackMode()) { throw new BugInCF("merge accepts only NonNull types! a1 (%s) a2 (%s)", a1, a2); } - InferenceMain.getInstance().logger.info( - "Hack:\n" - + "a1=" + a1 + "\n" - + "a2=" + a2); + InferenceMain.getInstance().logger.info("Hack:\n" + "a1=" + a1 + "\n" + "a2=" + a2); return a1 != null ? a1 : a2; } - final QualifierHierarchy realQualifierHierarchy = inferenceMain.getRealTypeFactory().getQualifierHierarchy(); + final QualifierHierarchy realQualifierHierarchy = + inferenceMain.getRealTypeFactory().getQualifierHierarchy(); final boolean isA1VarAnnot = isVarAnnot(a1); final boolean isA2VarAnnot = isVarAnnot(a2); @@ -260,28 +278,38 @@ private AnnotationMirror merge(final AnnotationMirror a1, final AnnotationMirror final Slot slot2 = slotMgr.getSlot(a2); if (slot1 != slot2) { if ((slot1 instanceof ConstantSlot) && (slot2 instanceof ConstantSlot)) { - // If both slots are constant slots, using real qualifier hierarchy to compute the merged type, + // If both slots are constant slots, using real qualifier hierarchy to compute the + // merged type, // then return a VarAnnot represent the constant result. - // (Because we passing in two VarAnnots that represent constant slots, so it is consistent - // to also return a VarAnnot that represents the constant merged type of these two constants.) + // (Because we passing in two VarAnnots that represent constant slots, so it is + // consistent + // to also return a VarAnnot that represents the constant merged type of these two + // constants.) AnnotationMirror realAnno1 = ((ConstantSlot) slot1).getValue(); AnnotationMirror realAnno2 = ((ConstantSlot) slot2).getValue(); AnnotationMirror mergedType; if (isLub) { - mergedType = realQualifierHierarchy.leastUpperBoundQualifiersOnly(realAnno1, realAnno2); + mergedType = + realQualifierHierarchy.leastUpperBoundQualifiersOnly( + realAnno1, realAnno2); } else { - mergedType = realQualifierHierarchy.greatestLowerBoundQualifiersOnly(realAnno1, realAnno2); + mergedType = + realQualifierHierarchy.greatestLowerBoundQualifiersOnly( + realAnno1, realAnno2); } Slot constantSlot = slotMgr.createConstantSlot(mergedType); return slotMgr.getAnnotation(constantSlot); } else if (!Collections.disjoint(slot1.getMergedToSlots(), slot2.getMergedToSlots())) { - // They have common merge variables, return the annotations on one of the common merged variables. - Slot commonMergedSlot = getOneIntersected(slot1.getMergedToSlots(), slot2.getMergedToSlots()); + // They have common merge variables, return the annotations on one of the common + // merged variables. + Slot commonMergedSlot = + getOneIntersected(slot1.getMergedToSlots(), slot2.getMergedToSlots()); return slotMgr.getAnnotation(commonMergedSlot); } else if (slot1.isMergedTo(slot2)) { - // var2 is a merge variable that var1 has been merged to. So just return annotation on var2. + // var2 is a merge variable that var1 has been merged to. So just return annotation + // on var2. return slotMgr.getAnnotation(slot2); } else if (slot2.isMergedTo(slot1)) { // Vice versa. @@ -332,8 +360,8 @@ private T getOneIntersected(Set set1, Set set2) { } /** - * Find the corresponding {@code VarAnnot} for the real top qualifier. - * Currently, there should only be one top qualifier. + * Find the corresponding {@code VarAnnot} for the real top qualifier. Currently, there should + * only be one top qualifier. * * @return the only VarAnnot corresponding to the real top qualifier */ @@ -341,7 +369,8 @@ private static AnnotationMirror findTopVarAnnot() { int numTops = 0; AnnotationMirror topVarAnnot = null; InferenceMain inferenceMain = InferenceMain.getInstance(); - Set realTops = inferenceMain.getRealTypeFactory().getQualifierHierarchy().getTopAnnotations(); + Set realTops = + inferenceMain.getRealTypeFactory().getQualifierHierarchy().getTopAnnotations(); SlotManager slotManager = inferenceMain.getSlotManager(); for (AnnotationMirror top : realTops) { @@ -359,8 +388,9 @@ private static AnnotationMirror findTopVarAnnot() { throw new BugInCF( "There should be exactly 1 top qualifier in inference hierarchy" + "( checkers.inference.qual.VarAnnot ).\n" - + "Real tops found ( " + InferenceUtil.join(realTops) + " )" - ); + + "Real tops found ( " + + InferenceUtil.join(realTops) + + " )"); } return topVarAnnot; } @@ -373,7 +403,8 @@ private static AnnotationMirror findTopVarAnnot() { private static AnnotationMirror findBottomVarAnnot() { AnnotationMirrorSet annos = new AnnotationMirrorSet(); InferenceMain inferenceMain = InferenceMain.getInstance(); - Set realBottoms = inferenceMain.getRealTypeFactory().getQualifierHierarchy().getBottomAnnotations(); + Set realBottoms = + inferenceMain.getRealTypeFactory().getQualifierHierarchy().getBottomAnnotations(); SlotManager slotManager = inferenceMain.getSlotManager(); assert slotManager.getSlots().size() > 0; for (AnnotationMirror bottom : realBottoms) { @@ -387,8 +418,9 @@ private static AnnotationMirror findBottomVarAnnot() { throw new BugInCF( "There should be exactly 1 bottom qualifier in inference hierarchy" + "( checkers.inference.qual.VarAnnot ).\n" - + "Bottoms found ( " + InferenceUtil.join(annos) + " )" - ); + + "Bottoms found ( " + + InferenceUtil.join(annos) + + " )"); } return annos.iterator().next(); } @@ -413,7 +445,10 @@ public AnnotationMirror getBottomAnnotation(final AnnotationMirror am) { } if (InferenceMain.isHackMode()) { - return inferenceMain.getRealTypeFactory().getQualifierHierarchy().getBottomAnnotation(am); + return inferenceMain + .getRealTypeFactory() + .getQualifierHierarchy() + .getBottomAnnotation(am); } else { throw new BugInCF("trying to get real bottom annotation from the inference hierarchy"); } @@ -421,8 +456,7 @@ public AnnotationMirror getBottomAnnotation(final AnnotationMirror am) { @Override protected QualifierKindHierarchy createQualifierKindHierarchy( - Collection> qualifierClasses - ) { + Collection> qualifierClasses) { return new InferenceQualifierKindHierarchy(qualifierClasses); } @@ -430,19 +464,23 @@ protected QualifierKindHierarchy createQualifierKindHierarchy( * Since {@link InferenceQualifierHierarchy} has its own implementations to compute LUB and GLB, * this class ensures we don't need any LUBs or GLBs for real qualifiers. */ - private static final class InferenceQualifierKindHierarchy extends DefaultQualifierKindHierarchy { - public InferenceQualifierKindHierarchy(Collection> qualifierClasses) { + private static final class InferenceQualifierKindHierarchy + extends DefaultQualifierKindHierarchy { + public InferenceQualifierKindHierarchy( + Collection> qualifierClasses) { super(qualifierClasses); } @Override public @Nullable QualifierKind leastUpperBound(QualifierKind q1, QualifierKind q2) { - throw new BugInCF("InferenceQualifierKindHierarchy.leastUpperBound should never be invoked"); + throw new BugInCF( + "InferenceQualifierKindHierarchy.leastUpperBound should never be invoked"); } @Override public @Nullable QualifierKind greatestLowerBound(QualifierKind q1, QualifierKind q2) { - throw new BugInCF("InferenceQualifierKindHierarchy.greatestLowerBound should never be invoked"); + throw new BugInCF( + "InferenceQualifierKindHierarchy.greatestLowerBound should never be invoked"); } @Override diff --git a/src/checkers/inference/InferenceQualifierPolymorphism.java b/src/checkers/inference/InferenceQualifierPolymorphism.java index c60a3eaf7..dd6bce563 100644 --- a/src/checkers/inference/InferenceQualifierPolymorphism.java +++ b/src/checkers/inference/InferenceQualifierPolymorphism.java @@ -1,6 +1,7 @@ package checkers.inference; -import checkers.inference.model.VariableSlot; +import com.sun.source.tree.Tree; + import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; import org.checkerframework.framework.type.AnnotatedTypeMirror; import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType; @@ -8,19 +9,16 @@ import javax.lang.model.element.AnnotationMirror; -import com.sun.source.tree.Tree; - import checkers.inference.model.ConstantSlot; import checkers.inference.model.Slot; -import checkers.inference.model.SourceVariableSlot; +import checkers.inference.model.VariableSlot; /** - * InferenceQualifierPolymorphism handle PolymorphicQualifiers for the Inference Framework. - * Per method call that contains a polymorphic qualifier, InferneceQualifierPolymorphism - * will create a single Variable and substitute all Polymorphic qualifiers with that - * variable. This means the locations that would normally generate constraints against - * the polymorphic qualifier will now generate them against the variable representing - * this instance of the polymorphic qualifier. + * InferenceQualifierPolymorphism handle PolymorphicQualifiers for the Inference Framework. Per + * method call that contains a polymorphic qualifier, InferneceQualifierPolymorphism will create a + * single Variable and substitute all Polymorphic qualifiers with that variable. This means the + * locations that would normally generate constraints against the polymorphic qualifier will now + * generate them against the variable representing this instance of the polymorphic qualifier. */ public class InferenceQualifierPolymorphism { @@ -30,11 +28,12 @@ public class InferenceQualifierPolymorphism { private final InferenceAnnotatedTypeFactory atypeFactory; private final BaseAnnotatedTypeFactory realTypeFactory; - public InferenceQualifierPolymorphism(final SlotManager slotManager, - final VariableAnnotator variableAnnotator, - final InferenceAnnotatedTypeFactory atypeFactory, - final BaseAnnotatedTypeFactory realTypeFactory, - final AnnotationMirror varAnnot) { + public InferenceQualifierPolymorphism( + final SlotManager slotManager, + final VariableAnnotator variableAnnotator, + final InferenceAnnotatedTypeFactory atypeFactory, + final BaseAnnotatedTypeFactory realTypeFactory, + final AnnotationMirror varAnnot) { this.slotManager = slotManager; this.variableAnnotator = variableAnnotator; this.atypeFactory = atypeFactory; @@ -52,16 +51,14 @@ public void replacePolys(Tree callTree, AnnotatedExecutableType methodType) { private class PolyReplacer extends AnnotatedTypeScanner { /** - * A method might be annotated twice, to avoid creating multiple variables representing - * the polymorphic qualifier for the same method call, we map the tree of the method call - * to the variable that was created for that tree. This map is contained - * in the VariableAnnotator because it contains other maps with similar purpose. + * A method might be annotated twice, to avoid creating multiple variables representing the + * polymorphic qualifier for the same method call, we map the tree of the method call to the + * variable that was created for that tree. This map is contained in the VariableAnnotator + * because it contains other maps with similar purpose. */ private final Tree methodCall; - /** - * The variable slot created for this method call - */ + /** The variable slot created for this method call */ private VariableSlot polyVar = null; private PolyReplacer(Tree methodCall) { @@ -85,7 +82,9 @@ public Void scan(AnnotatedTypeMirror type, Void v) { if (InferenceMain.isHackMode(slot == null)) { } else if (slot instanceof ConstantSlot) { AnnotationMirror constant = ((ConstantSlot) slot).getValue(); - if (realTypeFactory.getQualifierHierarchy().isPolymorphicQualifier(constant)) { + if (realTypeFactory + .getQualifierHierarchy() + .isPolymorphicQualifier(constant)) { type.replaceAnnotation(slotManager.getAnnotation(getOrCreatePolyVar())); } } @@ -96,5 +95,4 @@ public Void scan(AnnotatedTypeMirror type, Void v) { return null; } } - } diff --git a/src/checkers/inference/InferenceResult.java b/src/checkers/inference/InferenceResult.java index 405605037..2a32ab29c 100644 --- a/src/checkers/inference/InferenceResult.java +++ b/src/checkers/inference/InferenceResult.java @@ -1,22 +1,20 @@ package checkers.inference; -import checkers.inference.model.Constraint; - -import javax.lang.model.element.AnnotationMirror; import java.util.Collection; import java.util.Map; -/** - * Represents the result of inference. - */ +import javax.lang.model.element.AnnotationMirror; + +import checkers.inference.model.Constraint; + +/** Represents the result of inference. */ public interface InferenceResult { /** * Indicates if inference has solution or not. * - * @return true if inference result contains valid solutions for variable IDs. - * Returns false if underlying solver fails to give solution for {@link Constraint}s. - * + * @return true if inference result contains valid solutions for variable IDs. Returns false if + * underlying solver fails to give solution for {@link Constraint}s. * @see #getSolutions() * @see #containsSolutionForVariable(int) * @see #getSolutionForVariable(int) @@ -28,7 +26,6 @@ public interface InferenceResult { * Gets inference solutions from the result. * * @return inference solutions. Null if {{@link #hasSolution()}} is false. - * * @see #hasSolution() */ Map getSolutions(); @@ -38,8 +35,7 @@ public interface InferenceResult { * * @param varId id of a {@link checkers.inference.model.VariableSlot VariableSlot} * @return true iff {@link #hasSolution()} returns true and internal inferred - * result(implementation detail) contains solution for {@code varId} - * + * result(implementation detail) contains solution for {@code varId} * @see #hasSolution() * @see #getSolutionForVariable(int) */ @@ -49,9 +45,8 @@ public interface InferenceResult { * A method to get the inferred solution for the given slot ID. * * @param varId id of a {@link checkers.inference.model.Slot Slot} - * @return non-null solution iff {@link #hasSolution()} returns true and internal - * inferred result(implementation detail) contains solution for {@code varId} - * + * @return non-null solution iff {@link #hasSolution()} returns true and internal inferred + * result(implementation detail) contains solution for {@code varId} * @see #hasSolution() * @see #containsSolutionForVariable(int) */ @@ -60,14 +55,12 @@ public interface InferenceResult { /** * Access method to get set of {@link Constraint}s that are not solvable together. * - * Should be called only if {@link #hasSolution()} returns false. In this case, if - * an empty collection is returned, it means the underlying solver doesn't support - * explaning unsolvable reason. + *

Should be called only if {@link #hasSolution()} returns false. In this case, if an empty + * collection is returned, it means the underlying solver doesn't support explaning unsolvable + * reason. * * @return set of {@code Constraint}s that are not solvable together - * * @see #hasSolution() */ Collection getUnsatisfiableConstraints(); } - diff --git a/src/checkers/inference/InferenceSolver.java b/src/checkers/inference/InferenceSolver.java index 3131daef2..fa1974999 100644 --- a/src/checkers/inference/InferenceSolver.java +++ b/src/checkers/inference/InferenceSolver.java @@ -1,30 +1,31 @@ package checkers.inference; +import org.checkerframework.framework.type.QualifierHierarchy; + import java.util.Collection; import java.util.Map; import javax.annotation.processing.ProcessingEnvironment; -import org.checkerframework.framework.type.QualifierHierarchy; - import checkers.inference.model.Constraint; import checkers.inference.model.Slot; public interface InferenceSolver { /** - * Solve the constraints and return a mapping of slot id to an resulting - * AnnotationMirror. + * Solve the constraints and return a mapping of slot id to an resulting AnnotationMirror. * * @param configuration String key value pairs to configure the solver * @param slots List of all slots used in inference * @param constraints List of Constraints to be satisfied * @param qualHierarchy Target QualifierHierarchy - * @return an InferenceResult for the given slots/constraints or NULL if this solver does something besides solve + * @return an InferenceResult for the given slots/constraints or NULL if this solver does + * something besides solve */ - InferenceResult solve(Map configuration, - Collection slots, - Collection constraints, - QualifierHierarchy qualHierarchy, - ProcessingEnvironment processingEnvironment); + InferenceResult solve( + Map configuration, + Collection slots, + Collection constraints, + QualifierHierarchy qualHierarchy, + ProcessingEnvironment processingEnvironment); } diff --git a/src/checkers/inference/InferenceTreeAnnotator.java b/src/checkers/inference/InferenceTreeAnnotator.java index 1100b5bfb..15bd5bf2e 100644 --- a/src/checkers/inference/InferenceTreeAnnotator.java +++ b/src/checkers/inference/InferenceTreeAnnotator.java @@ -1,28 +1,5 @@ package checkers.inference; -import checkers.inference.model.ConstraintManager; -import checkers.inference.model.SourceVariableSlot; -import checkers.inference.model.Slot; - -import org.checkerframework.framework.type.AnnotatedTypeFactory; -import org.checkerframework.framework.type.AnnotatedTypeFactory.ParameterizedExecutableType; -import org.checkerframework.framework.type.AnnotatedTypeMirror; -import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType; -import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType; -import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType; -import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedNoType; -import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedPrimitiveType; -import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable; -import org.checkerframework.framework.type.treeannotator.TreeAnnotator; -import org.checkerframework.javacutil.BugInCF; -import org.checkerframework.javacutil.TreePathUtil; -import org.checkerframework.javacutil.TreeUtils; - -import java.util.List; - -import javax.lang.model.element.Element; -import javax.lang.model.type.TypeKind; - import com.sun.source.tree.AnnotatedTypeTree; import com.sun.source.tree.AnnotationTree; import com.sun.source.tree.AssignmentTree; @@ -46,32 +23,61 @@ import com.sun.source.tree.VariableTree; import com.sun.source.util.TreePath; +import org.checkerframework.framework.type.AnnotatedTypeFactory; +import org.checkerframework.framework.type.AnnotatedTypeFactory.ParameterizedExecutableType; +import org.checkerframework.framework.type.AnnotatedTypeMirror; +import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType; +import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType; +import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType; +import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedNoType; +import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedPrimitiveType; +import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable; +import org.checkerframework.framework.type.treeannotator.TreeAnnotator; +import org.checkerframework.javacutil.BugInCF; +import org.checkerframework.javacutil.TreePathUtil; +import org.checkerframework.javacutil.TreeUtils; + +import java.util.List; + +import javax.lang.model.element.Element; +import javax.lang.model.type.TypeKind; + +import checkers.inference.model.ConstraintManager; +import checkers.inference.model.Slot; +import checkers.inference.model.SourceVariableSlot; import checkers.inference.util.ConstantToVariableAnnotator; import checkers.inference.util.InferenceUtil; /** - * InferenceTreeAnnotator (a non-traversing visitor) determines which trees need to be annotated and then passes them - * (along with their types) to the VariableAnnotator which will do a deep traversal of the tree/type. - * VariableAnnotator will create the appropriate VariableSlots, store them via Tree -> VariableSlot, and place - * annotations representing the VariableSlots onto the AnnotateTypeMirror. + * InferenceTreeAnnotator (a non-traversing visitor) determines which trees need to be annotated and + * then passes them (along with their types) to the VariableAnnotator which will do a deep traversal + * of the tree/type. VariableAnnotator will create the appropriate VariableSlots, store them via + * Tree -> VariableSlot, and place annotations representing the VariableSlots onto the + * AnnotateTypeMirror. */ public class InferenceTreeAnnotator extends TreeAnnotator { // private final SlotManager slotManager; private final VariableAnnotator variableAnnotator; private final AnnotatedTypeFactory realTypeFactory; - // private final InferrableChecker realChecker; - // TODO: In the old InferenceAnnotatedTypeFactory there was a store between extends/implement identifier expressions - // TODO: used for getTypeFromTypeTree, I believe this is superfluous (since they will already be placed in - // TODO: AnnotatedTypeFactory) but I am unsure, therefore, we'll leave these todos and circle back - // private Map extendsAndImplementsTypes = new HashMap(); + // private final InferrableChecker realChecker; - public InferenceTreeAnnotator(final InferenceAnnotatedTypeFactory atypeFactory, - final InferrableChecker realChecker, - final AnnotatedTypeFactory realAnnotatedTypeFactory, - final VariableAnnotator variableAnnotator, - final SlotManager slotManager) { + // TODO: In the old InferenceAnnotatedTypeFactory there was a store between extends/implement + // identifier expressions + // TODO: used for getTypeFromTypeTree, I believe this is superfluous (since they will already be + // placed in + // TODO: AnnotatedTypeFactory) but I am unsure, therefore, we'll leave these todos and circle + // back + // private Map extendsAndImplementsTypes = new HashMap(); + + public InferenceTreeAnnotator( + final InferenceAnnotatedTypeFactory atypeFactory, + final InferrableChecker realChecker, + final AnnotatedTypeFactory realAnnotatedTypeFactory, + final VariableAnnotator variableAnnotator, + final SlotManager slotManager) { super(atypeFactory); // this.slotManager = slotManager; this.variableAnnotator = variableAnnotator; @@ -107,9 +113,12 @@ public Void visitAssignment(AssignmentTree assignmentTree, AnnotatedTypeMirror t /** * Add variables to class declarations of non-anonymous classes + * * @param classTree tree to visit, will be ignored if it's an anonymous class * @param classType AnnotatedDeclaredType, an Illegal argument exception will be throw otherwise - * @see checkers.inference.VariableAnnotator#handleClassDeclaration(checkers.types.AnnotatedTypeMirror.AnnotatedDeclaredType, com.sun.source.tree.ClassTree) + * @see + * checkers.inference.VariableAnnotator#handleClassDeclaration(checkers.types.AnnotatedTypeMirror.AnnotatedDeclaredType, + * com.sun.source.tree.ClassTree) * @return null */ @Override @@ -117,8 +126,13 @@ public Void visitClass(final ClassTree classTree, final AnnotatedTypeMirror clas // Apply Implicits super.visitClass(classTree, classType); - InferenceUtil.testArgument(classType instanceof AnnotatedDeclaredType, - "Unexpected type for ClassTree ( " + classTree + " ) AnnotatedTypeMirror ( " + classType + " ) "); + InferenceUtil.testArgument( + classType instanceof AnnotatedDeclaredType, + "Unexpected type for ClassTree ( " + + classTree + + " ) AnnotatedTypeMirror ( " + + classType + + " ) "); // Annotate the current class type variableAnnotator.visit(classType, classTree); @@ -150,7 +164,7 @@ public Void visitClass(final ClassTree classTree, final AnnotatedTypeMirror clas public Void visitIdentifier(IdentifierTree node, AnnotatedTypeMirror identifierType) { if (identifierType instanceof AnnotatedTypeVariable) { // note, variableAnnotator should already have a type for this tree at this point - variableAnnotator.visit(identifierType,node); + variableAnnotator.visit(identifierType, node); } else { TreePath path = atypeFactory.getPath(node); if (path != null) { @@ -163,7 +177,8 @@ public Void visitIdentifier(IdentifierTree node, AnnotatedTypeMirror identifierT // Note: This can happen when the explicit type argument to a method is // a type without type parameters. For types with type parameters, the node // is a parameterized type and is handled appropriately - // See Test: GenericMethodCall (compare the two cases where a type argument is expressly + // See Test: GenericMethodCall (compare the two cases where a type argument + // is expressly // provide) variableAnnotator.visit(identifierType, node); } @@ -172,7 +187,9 @@ public Void visitIdentifier(IdentifierTree node, AnnotatedTypeMirror identifierT // This case can indicate the identifier is wrapped in an annotation tree final Tree grandParent = parentPath.getParentPath().getLeaf(); if (grandParent.getKind() == Kind.METHOD_INVOCATION) { - if (((MethodInvocationTree) grandParent).getTypeArguments().contains(parentNode)) { + if (((MethodInvocationTree) grandParent) + .getTypeArguments() + .contains(parentNode)) { variableAnnotator.visit(identifierType, node); } } @@ -185,7 +202,8 @@ public Void visitIdentifier(IdentifierTree node, AnnotatedTypeMirror identifierT } else if (parentNode.getKind() == Kind.NEW_CLASS && ((NewClassTree) parentNode).getIdentifier() == node) { // This can happen in two cases related to NewClassTrees: - // (1) The type identifier of non-anonymous class instantiations, without explict + // (1) The type identifier of non-anonymous class instantiations, without + // explict // annotations, such as `A` of `new A()`; // (2) The type identifier of anonymous class instantiations, with or without // explicit annotations. @@ -195,15 +213,22 @@ public Void visitIdentifier(IdentifierTree node, AnnotatedTypeMirror identifierT NewClassTree newClassTree = (NewClassTree) parentNode; if (newClassTree.getClassBody() != null) { - // For case 2, get the explicit annotation if any exists so that no variable slot - // is created. Note the annotation cannot be retrieved from the identifier, but - // from the modifier of the anonymous class body. e.g. for the following case + // For case 2, get the explicit annotation if any exists so that no variable + // slot + // is created. Note the annotation cannot be retrieved from the identifier, + // but + // from the modifier of the anonymous class body. e.g. for the following + // case // new @HERE Class() {} - // @HERE is on the modifier of the anonymous class body, instead of on the type identifier. + // @HERE is on the modifier of the anonymous class body, instead of on the + // type identifier. List annos = newClassTree.getClassBody().getModifiers().getAnnotations(); - identifierType.addAnnotations(TreeUtils.annotationsFromTypeAnnotationTrees(annos)); - ((InferenceAnnotatedTypeFactory) atypeFactory).getConstantToVariableAnnotator().visit(identifierType); + identifierType.addAnnotations( + TreeUtils.annotationsFromTypeAnnotationTrees(annos)); + ((InferenceAnnotatedTypeFactory) atypeFactory) + .getConstantToVariableAnnotator() + .visit(identifierType); } variableAnnotator.visit(identifierType, node); } @@ -213,16 +238,20 @@ public Void visitIdentifier(IdentifierTree node, AnnotatedTypeMirror identifierT return null; } - /** - * Adds variables to the upper and lower bounds of a typeParameter - */ + /** Adds variables to the upper and lower bounds of a typeParameter */ @Override - public Void visitTypeParameter(final TypeParameterTree typeParamTree, final AnnotatedTypeMirror atm) { + public Void visitTypeParameter( + final TypeParameterTree typeParamTree, final AnnotatedTypeMirror atm) { // Apply Implicits super.visitTypeParameter(typeParamTree, atm); - InferenceUtil.testArgument(atm instanceof AnnotatedTypeVariable, - "Unexpected type for TypeParamTree ( " + typeParamTree + " ) AnnotatedTypeMirror ( " + atm + " ) "); + InferenceUtil.testArgument( + atm instanceof AnnotatedTypeVariable, + "Unexpected type for TypeParamTree ( " + + typeParamTree + + " ) AnnotatedTypeMirror ( " + + atm + + " ) "); variableAnnotator.visit(atm, typeParamTree); @@ -230,15 +259,22 @@ public Void visitTypeParameter(final TypeParameterTree typeParamTree, final Anno } /** - * @see checkers.inference.VariableAnnotator#handleMethodDeclaration(checkers.types.AnnotatedTypeMirror.AnnotatedExecutableType, com.sun.source.tree.MethodTree) + * @see + * checkers.inference.VariableAnnotator#handleMethodDeclaration(checkers.types.AnnotatedTypeMirror.AnnotatedExecutableType, + * com.sun.source.tree.MethodTree) */ @Override public Void visitMethod(final MethodTree methodTree, final AnnotatedTypeMirror atm) { // Apply Implicits super.visitMethod(methodTree, atm); - InferenceUtil.testArgument(atm instanceof AnnotatedExecutableType, - "Unexpected type for MethodTree ( " + methodTree + " ) AnnotatedTypeMirror ( " + atm + " ) "); + InferenceUtil.testArgument( + atm instanceof AnnotatedExecutableType, + "Unexpected type for MethodTree ( " + + methodTree + + " ) AnnotatedTypeMirror ( " + + atm + + " ) "); variableAnnotator.visit(atm, methodTree); @@ -246,11 +282,12 @@ public Void visitMethod(final MethodTree methodTree, final AnnotatedTypeMirror a } /** - * Adds variables to the methodTypeArguments - * // TODO: Verify that return types for generic methods work correctly + * Adds variables to the methodTypeArguments // TODO: Verify that return types for generic + * methods work correctly */ @Override - public Void visitMethodInvocation(final MethodInvocationTree methodInvocationTree, final AnnotatedTypeMirror atm) { + public Void visitMethodInvocation( + final MethodInvocationTree methodInvocationTree, final AnnotatedTypeMirror atm) { // Apply Implicits super.visitMethodInvocation(methodInvocationTree, atm); @@ -264,16 +301,17 @@ public Void visitMethodInvocation(final MethodInvocationTree methodInvocationTre return null; } - private void annotateMethodTypeArgs(final MethodInvocationTree methodInvocationTree) { if (!methodInvocationTree.getTypeArguments().isEmpty()) { final ParameterizedExecutableType methodFromUse = atypeFactory.methodFromUse(methodInvocationTree); - annotateMethodTypeArguments(methodInvocationTree.getTypeArguments(), methodFromUse.typeArgs); + annotateMethodTypeArguments( + methodInvocationTree.getTypeArguments(), methodFromUse.typeArgs); } else { - // TODO: annotate types if there are types but no trees, I think this will be taken care of by + // TODO: annotate types if there are types but no trees, I think this will be taken care + // of by // TODO: InferenceTypeArgumentInference which is not yet implemented } } @@ -284,7 +322,8 @@ private void annotateMethodTypeArgs(final NewClassTree newClassTree) { final ParameterizedExecutableType constructorFromUse = atypeFactory.constructorFromUse(newClassTree); - annotateMethodTypeArguments(newClassTree.getTypeArguments(), constructorFromUse.typeArgs); + annotateMethodTypeArguments( + newClassTree.getTypeArguments(), constructorFromUse.typeArgs); } else { // TODO: annotate types if there are types but no trees @@ -292,16 +331,19 @@ private void annotateMethodTypeArgs(final NewClassTree newClassTree) { } } - private void annotateMethodTypeArguments(final List typeArgTrees, - final List typeArgs) { + private void annotateMethodTypeArguments( + final List typeArgTrees, final List typeArgs) { if (!typeArgTrees.isEmpty()) { if (typeArgs.size() != typeArgTrees.size()) { throw new BugInCF( - "Number of type argument trees differs from number of types!\n" - + "Type arguments ( " + InferenceUtil.join(typeArgs) + " ) \n" - + "Trees ( " + InferenceUtil.join(typeArgTrees) + " )" - ); + "Number of type argument trees differs from number of types!\n" + + "Type arguments ( " + + InferenceUtil.join(typeArgs) + + " ) \n" + + "Trees ( " + + InferenceUtil.join(typeArgTrees) + + " )"); } for (int i = 0; i < Math.min(typeArgs.size(), typeArgTrees.size()); i++) { @@ -313,7 +355,7 @@ private void annotateMethodTypeArguments(final List typeArgTrees @Override public Void visitNewClass(final NewClassTree newClassTree, final AnnotatedTypeMirror atm) { // Apply Implicits - super.visitNewClass(newClassTree, atm); + super.visitNewClass(newClassTree, atm); // There used to be logic for finding the type based on implicit extends clause or // implements clauses for anonymous classes. This seems to work without it. @@ -322,26 +364,30 @@ public Void visitNewClass(final NewClassTree newClassTree, final AnnotatedTypeMi annotateMethodTypeArgs(newClassTree); - if (newClassTree.getClassBody() != null) { // For a fully annotated anonymous class instantiation as follows, // new @VarAnnot(1) A() @VarAnnot(2) {...} // create the implied equality constraint "1 == 2" - ConstraintManager constraintManager = InferenceMain.getInstance().getConstraintManager(); + ConstraintManager constraintManager = + InferenceMain.getInstance().getConstraintManager(); SlotManager slotManager = InferenceMain.getInstance().getSlotManager(); // Get the varSlot on the type identifier Slot identifierSlot = slotManager.getSlot(atm); - AnnotatedTypeMirror classType = atypeFactory.getAnnotatedType(newClassTree.getClassBody()); + AnnotatedTypeMirror classType = + atypeFactory.getAnnotatedType(newClassTree.getClassBody()); // Get the varSlot on the anonymous class body Slot classBodySlot = slotManager.getSlot(classType); - // When the NewClassTree is pre-annotated, the compiler automatically annotates the class body - // with the same annotation on the type identifier. In this case the slot on the class body is + // When the NewClassTree is pre-annotated, the compiler automatically annotates the + // class body + // with the same annotation on the type identifier. In this case the slot on the class + // body is // constant, and always equals to the slot on the type identifier if (classBodySlot instanceof SourceVariableSlot) { constraintManager.addEqualityConstraint(identifierSlot, classBodySlot); - // The location for `@VarAnnot(2)` in the above case is not syntactically valid, so the + // The location for `@VarAnnot(2)` in the above case is not syntactically valid, so + // the // slot for this location should not be inserted back to source code ((SourceVariableSlot) classBodySlot).setInsertable(false); } @@ -365,9 +411,12 @@ public Void visitVariable(final VariableTree varTree, final AnnotatedTypeMirror final Element varElem = TreeUtils.elementFromDeclaration(varTree); - // TODO: THIS AND THE VISIT BINARY COULD INSTEAD BE PUT AT THE TOP OF THE VISIT METHOD OF VariableAnnotator - // TODO: AS SPECIAL CASES, THIS WOULD MEAN WE COULD LEAVE storeElementType and addPrimaryCombVar AS PRIVATE - // This happens here, unlike all the other stores because then we would have to add this code + // TODO: THIS AND THE VISIT BINARY COULD INSTEAD BE PUT AT THE TOP OF THE VISIT METHOD OF + // VariableAnnotator + // TODO: AS SPECIAL CASES, THIS WOULD MEAN WE COULD LEAVE storeElementType and + // addPrimaryCombVar AS PRIVATE + // This happens here, unlike all the other stores because then we would have to add this + // code // to every atm/varTree combination, thoughts? switch (varElem.getKind()) { case RESOURCE_VARIABLE: @@ -380,7 +429,12 @@ public Void visitVariable(final VariableTree varTree, final AnnotatedTypeMirror break; default: - throw new BugInCF("Unexpected element of kind ( " + varElem.getKind() + " ) element ( " + varElem + " ) "); + throw new BugInCF( + "Unexpected element of kind ( " + + varElem.getKind() + + " ) element ( " + + varElem + + " ) "); } return null; } @@ -390,8 +444,13 @@ public Void visitNewArray(final NewArrayTree newArrayTree, final AnnotatedTypeMi // Do NOT call super method. // To match TreeAnnotator, we do not apply implicits - InferenceUtil.testArgument(atm instanceof AnnotatedArrayType, - "Unexpected type for NewArrayTree ( " + newArrayTree + " ) AnnotatedTypeMirror ( " + atm + " ) "); + InferenceUtil.testArgument( + atm instanceof AnnotatedArrayType, + "Unexpected type for NewArrayTree ( " + + newArrayTree + + " ) AnnotatedTypeMirror ( " + + atm + + " ) "); variableAnnotator.visit(atm, newArrayTree); return null; } @@ -406,26 +465,31 @@ public Void visitTypeCast(final TypeCastTree typeCast, final AnnotatedTypeMirror } @Override - public Void visitInstanceOf(final InstanceOfTree instanceOfTree, final AnnotatedTypeMirror atm) { + public Void visitInstanceOf( + final InstanceOfTree instanceOfTree, final AnnotatedTypeMirror atm) { // Apply Implicits super.visitInstanceOf(instanceOfTree, atm); if (atm.getKind() != TypeKind.BOOLEAN) { - throw new BugInCF("Unexpected type kind for instanceOfTree = " + instanceOfTree - + " atm=" + atm); + throw new BugInCF( + "Unexpected type kind for instanceOfTree = " + instanceOfTree + " atm=" + atm); } InferenceAnnotatedTypeFactory infTypeFactory = (InferenceAnnotatedTypeFactory) atypeFactory; - AnnotatedPrimitiveType instanceOfType = (AnnotatedPrimitiveType) realTypeFactory.getAnnotatedType(instanceOfTree); + AnnotatedPrimitiveType instanceOfType = + (AnnotatedPrimitiveType) realTypeFactory.getAnnotatedType(instanceOfTree); atm.replaceAnnotations(instanceOfType.getAnnotations()); - ConstantToVariableAnnotator constantToVarAnnotator = infTypeFactory.getConstantToVariableAnnotator(); + ConstantToVariableAnnotator constantToVarAnnotator = + infTypeFactory.getConstantToVariableAnnotator(); constantToVarAnnotator.visit(atm); // atm is always boolean, get actual tested type - final AnnotatedTypeMirror testedType = infTypeFactory.getAnnotatedType(instanceOfTree.getType()); + final AnnotatedTypeMirror testedType = + infTypeFactory.getAnnotatedType(instanceOfTree.getType()); - // Adding a varAnnot equal to the top of the qualifier hierarchy so the class on the right of + // Adding a varAnnot equal to the top of the qualifier hierarchy so the class on the right + // of // the instanceof will have annotations in both hierarchies. Adding top means that when the // resultant dataflow most-specific happens the annotation will not actually contribute // any meaningful constraints (because everything is more specific than top). @@ -447,8 +511,8 @@ public Void visitLiteral(final LiteralTree literalTree, final AnnotatedTypeMirro } /** - * The type returned from a unary operation is just the variable. - * This will have to change if we support refinement variables. + * The type returned from a unary operation is just the variable. This will have to change if we + * support refinement variables. */ @Override public Void visitUnary(UnaryTree node, AnnotatedTypeMirror type) { @@ -461,12 +525,10 @@ public Void visitUnary(UnaryTree node, AnnotatedTypeMirror type) { } /** - * The type returned from a compound operation is just the variable. - * The visitor will insure that the RHS is a subtype of the LHS of the - * compound assignment. + * The type returned from a compound operation is just the variable. The visitor will insure + * that the RHS is a subtype of the LHS of the compound assignment. * - * This will have to change if we support refinement variables. - * (See Issue 9) + *

This will have to change if we support refinement variables. (See Issue 9) */ @Override public Void visitCompoundAssignment(CompoundAssignmentTree node, AnnotatedTypeMirror type) { @@ -478,9 +540,7 @@ public Void visitCompoundAssignment(CompoundAssignmentTree node, AnnotatedTypeMi return null; } - /** - * We need to create a LUB and only create it once. - */ + /** We need to create a LUB and only create it once. */ @Override public Void visitBinary(BinaryTree node, AnnotatedTypeMirror type) { // Do NOT call super method. @@ -495,12 +555,12 @@ public Void visitBinary(BinaryTree node, AnnotatedTypeMirror type) { } @Override - public Void visitParameterizedType(final ParameterizedTypeTree param, final AnnotatedTypeMirror atm) { + public Void visitParameterizedType( + final ParameterizedTypeTree param, final AnnotatedTypeMirror atm) { // Do NOT call super method. // To match TreeAnnotator, we do not apply implicits variableAnnotator.visit(atm, param); return null; } - } diff --git a/src/checkers/inference/InferenceTypeHierarchy.java b/src/checkers/inference/InferenceTypeHierarchy.java index f39ebc5dc..cbcdbcd2f 100644 --- a/src/checkers/inference/InferenceTypeHierarchy.java +++ b/src/checkers/inference/InferenceTypeHierarchy.java @@ -13,32 +13,37 @@ import checkers.inference.model.Slot; /** - * The InferenceTypeHierarchy along with the InferenceQualifierHierarchy is responsible for - * creating a subtype and equality constraints. Normally the methods of these two classes are queried - * in order to verify that two types have a required subtype relationship or to determine what to do - * based on the relationship between the two types. However, in the InferenceQualifierHierarchy - * calls to isSubtype generate subtype/equality constraints between the input parameters and returns true. + * The InferenceTypeHierarchy along with the InferenceQualifierHierarchy is responsible for creating + * a subtype and equality constraints. Normally the methods of these two classes are queried in + * order to verify that two types have a required subtype relationship or to determine what to do + * based on the relationship between the two types. However, in the InferenceQualifierHierarchy + * calls to isSubtype generate subtype/equality constraints between the input parameters and returns + * true. * - * This class generally delegates calls to the InferenceQualifierHierarchy which in turn generates - * the correct constraints. + *

This class generally delegates calls to the InferenceQualifierHierarchy which in turn + * generates the correct constraints. */ public class InferenceTypeHierarchy extends DefaultTypeHierarchy { private final AnnotationMirror varAnnot; - // TODO: Think this through, add any missing constraints + // TODO: Think this through, add any missing constraints /** - * Constructs an instance of {@code TypeHierarchy} for the type system - * whose qualifiers represented in qualifierHierarchy. + * Constructs an instance of {@code TypeHierarchy} for the type system whose qualifiers + * represented in qualifierHierarchy. * * @param checker The type-checker to use * @param qualifierHierarchy The qualifier hierarchy to use */ - public InferenceTypeHierarchy(final BaseTypeChecker checker, final QualifierHierarchy qualifierHierarchy, - final AnnotationMirror varAnnot) { - super(checker, qualifierHierarchy, - checker.getOption("ignoreRawTypeArguments", "true").equals("true"), - checker.hasOption("invariantArrays")); + public InferenceTypeHierarchy( + final BaseTypeChecker checker, + final QualifierHierarchy qualifierHierarchy, + final AnnotationMirror varAnnot) { + super( + checker, + qualifierHierarchy, + checker.getOption("ignoreRawTypeArguments", "true").equals("true"), + checker.hasOption("invariantArrays")); this.varAnnot = varAnnot; } @@ -57,37 +62,48 @@ private static class InferenceEqualityComparer extends StructuralEqualityCompare private final AnnotationMirror varAnnot; - public InferenceEqualityComparer(StructuralEqualityVisitHistory typeargVisitHistory, AnnotationMirror varAnnot) { + public InferenceEqualityComparer( + StructuralEqualityVisitHistory typeargVisitHistory, AnnotationMirror varAnnot) { super(typeargVisitHistory); this.varAnnot = varAnnot; } @Override - protected boolean arePrimaryAnnosEqual(AnnotatedTypeMirror type1, AnnotatedTypeMirror type2) { + protected boolean arePrimaryAnnosEqual( + AnnotatedTypeMirror type1, AnnotatedTypeMirror type2) { final InferenceMain inferenceMain = InferenceMain.getInstance(); final AnnotationMirror varAnnot1 = type1.getAnnotationInHierarchy(varAnnot); final AnnotationMirror varAnnot2 = type2.getAnnotationInHierarchy(varAnnot); // TODO: HackMode if (InferenceMain.isHackMode((varAnnot1 == null || varAnnot2 == null))) { - InferenceMain.getInstance().logger.warning( - "Hack:InferenceTYpeHierarchy:66\n" - + "type1=" + type1 + "\n" - + "type2=" + type2 + "\n" - ); + InferenceMain.getInstance() + .logger + .warning( + "Hack:InferenceTYpeHierarchy:66\n" + + "type1=" + + type1 + + "\n" + + "type2=" + + type2 + + "\n"); return true; } if (varAnnot1 == null || varAnnot2 == null) { - throw new BugInCF("Calling InferenceTypeHierarchy.arePrimeAnnosEqual on type with" - + "no varAnnots.!\n" - + "type1=" + type1 + "\n" - + "type2=" + type2); + throw new BugInCF( + "Calling InferenceTypeHierarchy.arePrimeAnnosEqual on type with" + + "no varAnnots.!\n" + + "type1=" + + type1 + + "\n" + + "type2=" + + type2); } if (!inferenceMain.isPerformingFlow()) { - final Slot leftSlot = inferenceMain.getSlotManager().getSlot( varAnnot1 ); - final Slot rightSlot = inferenceMain.getSlotManager().getSlot( varAnnot2 ); + final Slot leftSlot = inferenceMain.getSlotManager().getSlot(varAnnot1); + final Slot rightSlot = inferenceMain.getSlotManager().getSlot(varAnnot2); inferenceMain.getConstraintManager().addEqualityConstraint(leftSlot, rightSlot); } diff --git a/src/checkers/inference/InferenceValidator.java b/src/checkers/inference/InferenceValidator.java index 6b39b76ca..6ffdb887c 100644 --- a/src/checkers/inference/InferenceValidator.java +++ b/src/checkers/inference/InferenceValidator.java @@ -1,32 +1,29 @@ package checkers.inference; - import com.sun.source.tree.Tree; + import org.checkerframework.common.basetype.BaseTypeChecker; import org.checkerframework.common.basetype.BaseTypeValidator; import org.checkerframework.framework.qual.TypeUseLocation; import org.checkerframework.framework.type.AnnotatedTypeFactory; import org.checkerframework.framework.type.AnnotatedTypeMirror; -import org.checkerframework.javacutil.AnnotationUtils; import javax.lang.model.element.AnnotationMirror; -/** - * A visitor to validate the types in a tree. - */ +/** A visitor to validate the types in a tree. */ public class InferenceValidator extends BaseTypeValidator { /** * Indicates whether the validator is in inference mode or not. * - * This field is intended to make implementations of subclasses easier. - * Instead of querying the {@link InferenceVisitor#infer}, subclasses can - * directly query this field to decide whether to generate constraints or - * perform typechecking. + *

This field is intended to make implementations of subclasses easier. Instead of querying + * the {@link InferenceVisitor#infer}, subclasses can directly query this field to decide + * whether to generate constraints or perform typechecking. */ protected boolean infer; - public InferenceValidator(BaseTypeChecker checker, + public InferenceValidator( + BaseTypeChecker checker, InferenceVisitor visitor, AnnotatedTypeFactory atypeFactory) { super(checker, visitor, atypeFactory); @@ -37,24 +34,37 @@ public void setInfer(boolean infer) { } @Override - protected void validateWildCardTargetLocation(AnnotatedTypeMirror.AnnotatedWildcardType type, Tree tree) { + protected void validateWildCardTargetLocation( + AnnotatedTypeMirror.AnnotatedWildcardType type, Tree tree) { - InferenceVisitor inferVisitor = (InferenceVisitor) visitor; + InferenceVisitor inferVisitor = (InferenceVisitor) visitor; if (inferVisitor.ignoreTargetLocations) { return; } AnnotationMirror[] mirrors = new AnnotationMirror[0]; for (AnnotationMirror am : type.getSuperBound().getAnnotations()) { - inferVisitor.annoIsNoneOf(type, am, - inferVisitor.locationToIllegalQuals.get(TypeUseLocation.LOWER_BOUND).toArray(mirrors), - "type.invalid.annotations.on.location", tree); + inferVisitor.annoIsNoneOf( + type, + am, + inferVisitor + .locationToIllegalQuals + .get(TypeUseLocation.LOWER_BOUND) + .toArray(mirrors), + "type.invalid.annotations.on.location", + tree); } for (AnnotationMirror am : type.getExtendsBound().getAnnotations()) { - inferVisitor.annoIsNoneOf(type, am, - inferVisitor.locationToIllegalQuals.get(TypeUseLocation.UPPER_BOUND).toArray(mirrors), - "type.invalid.annotations.on.location", tree); + inferVisitor.annoIsNoneOf( + type, + am, + inferVisitor + .locationToIllegalQuals + .get(TypeUseLocation.UPPER_BOUND) + .toArray(mirrors), + "type.invalid.annotations.on.location", + tree); } } } diff --git a/src/checkers/inference/InferenceVisitor.java b/src/checkers/inference/InferenceVisitor.java index 7ccd74518..9520acebf 100644 --- a/src/checkers/inference/InferenceVisitor.java +++ b/src/checkers/inference/InferenceVisitor.java @@ -1,7 +1,14 @@ package checkers.inference; +import com.sun.source.tree.CatchTree; import com.sun.source.tree.ClassTree; +import com.sun.source.tree.ExpressionTree; +import com.sun.source.tree.ThrowTree; +import com.sun.source.tree.Tree; +import com.sun.source.tree.Tree.Kind; +import com.sun.source.tree.VariableTree; import com.sun.source.util.TreePath; + import org.checkerframework.checker.compilermsgs.qual.CompilerMessageKey; import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; import org.checkerframework.common.basetype.BaseTypeVisitor; @@ -18,6 +25,7 @@ import org.checkerframework.framework.type.AnnotatedTypeParameterBounds; import org.checkerframework.framework.util.AnnotatedTypes; import org.checkerframework.javacutil.*; +import org.plumelib.util.ArraysPlume; import java.lang.annotation.Annotation; import java.util.Arrays; @@ -43,33 +51,22 @@ import checkers.inference.qual.VarAnnot; import checkers.inference.util.InferenceUtil; -import com.sun.source.tree.CatchTree; -import com.sun.source.tree.ExpressionTree; -import com.sun.source.tree.ThrowTree; -import com.sun.source.tree.Tree; -import com.sun.source.tree.Tree.Kind; -import com.sun.source.tree.VariableTree; - -import org.plumelib.util.ArraysPlume; - - /** - * InferenceVisitor visits trees in each compilation unit both in typecheck/inference mode. - * In typecheck mode, it functions nearly identically to BaseTypeVisitor, i.e. it - * enforces common assignment and other checks. However, it also defines a new - * API that may be more intuitive for checker writers (see mainIsNot). + * InferenceVisitor visits trees in each compilation unit both in typecheck/inference mode. In + * typecheck mode, it functions nearly identically to BaseTypeVisitor, i.e. it enforces common + * assignment and other checks. However, it also defines a new API that may be more intuitive for + * checker writers (see mainIsNot). * - * InferneceVisitor has an "infer" flag which indicates whether or not - * it is in typecheck or in inference mode. When true, this class replaces type checks - * with constraint generation. + *

InferneceVisitor has an "infer" flag which indicates whether or not it is in typecheck or in + * inference mode. When true, this class replaces type checks with constraint generation. * - * InferneceVisitor is intended to replace BaseTypeVisitor. - * That is, the methods from BaseTypeVisiotr should be migrated here and InferenceVisitor - * should replace it in the Visitor hierarchy. + *

InferneceVisitor is intended to replace BaseTypeVisitor. That is, the methods from + * BaseTypeVisiotr should be migrated here and InferenceVisitor should replace it in the Visitor + * hierarchy. */ // TODO(Zhiping): new logics from BaseTypeVisitor should be migrated here -public class InferenceVisitor +public class InferenceVisitor< + Checker extends InferenceChecker, Factory extends BaseAnnotatedTypeFactory> extends BaseTypeVisitor { private static final Logger logger = Logger.getLogger(InferenceVisitor.class.getName()); @@ -89,18 +86,19 @@ public class InferenceVisitor> locationToIllegalQuals; - public InferenceVisitor(Checker checker, InferenceChecker ichecker, Factory factory, boolean infer) { + public InferenceVisitor( + Checker checker, InferenceChecker ichecker, Factory factory, boolean infer) { super((infer) ? ichecker : checker, factory); this.realChecker = checker; this.infer = infer; - ((InferenceValidator)typeValidator).setInfer(infer); + ((InferenceValidator) typeValidator).setInfer(infer); locationToIllegalQuals = createMapForIllegalQuals(); } @SuppressWarnings("unchecked") @Override protected Factory createTypeFactory() { - return (Factory)((BaseInferrableChecker)checker).getTypeFactory(); + return (Factory) ((BaseInferrableChecker) checker).getTypeFactory(); } @Override @@ -112,17 +110,24 @@ public void visit(TreePath path) { super.visit(path); } - public void doesNotContain(AnnotatedTypeMirror ty, AnnotationMirror mod, String msgkey, Tree node) { + public void doesNotContain( + AnnotatedTypeMirror ty, AnnotationMirror mod, String msgkey, Tree node) { doesNotContain(ty, new AnnotationMirror[] {mod}, msgkey, node); } - public void doesNotContain(AnnotatedTypeMirror ty, AnnotationMirror[] mods, String msgkey, Tree node) { + public void doesNotContain( + AnnotatedTypeMirror ty, AnnotationMirror[] mods, String msgkey, Tree node) { if (infer) { doesNotContainInfer(ty, mods, node); } else { for (AnnotationMirror mod : mods) { if (AnnotatedTypes.containsModifier(ty, mod)) { - checker.reportError(node, msgkey, ty.getAnnotations().toString(), ty.toString(), node.toString()); + checker.reportError( + node, + msgkey, + ty.getAnnotations().toString(), + ty.toString(), + node.toString()); } } } @@ -132,8 +137,11 @@ private void doesNotContainInfer(AnnotatedTypeMirror ty, AnnotationMirror[] mods doesNotContainInferImpl(ty, mods, new java.util.LinkedList(), node); } - private void doesNotContainInferImpl(AnnotatedTypeMirror ty, AnnotationMirror[] mods, - java.util.List visited, Tree node) { + private void doesNotContainInferImpl( + AnnotatedTypeMirror ty, + AnnotationMirror[] mods, + java.util.List visited, + Tree node) { if (visited.contains(ty)) { return; } @@ -147,7 +155,8 @@ private void doesNotContainInferImpl(AnnotatedTypeMirror ty, AnnotationMirror[] logger.warning("InferenceVisitor::doesNotContain: no annotation in type: " + ty); } else { if (!InferenceMain.getInstance().isPerformingFlow()) { - logger.fine("InferenceVisitor::doesNotContain: Inequality constraint constructor invocation(s)."); + logger.fine( + "InferenceVisitor::doesNotContain: Inequality constraint constructor invocation(s)."); } ConstraintManager cm = InferenceMain.getInstance().getConstraintManager(); @@ -167,36 +176,43 @@ private void doesNotContainInferImpl(AnnotatedTypeMirror ty, AnnotationMirror[] doesNotContainInferImpl(arrayType.getComponentType(), mods, visited, node); } else if (ty.getKind() == TypeKind.TYPEVAR) { AnnotatedTypeVariable atv = (AnnotatedTypeVariable) ty; - if (atv.getUpperBound()!=null) { + if (atv.getUpperBound() != null) { doesNotContainInferImpl(atv.getUpperBound(), mods, visited, node); } - if (atv.getLowerBound()!=null) { + if (atv.getLowerBound() != null) { doesNotContainInferImpl(atv.getLowerBound(), mods, visited, node); } } } - private AnnotationMirror findEffectiveAnnotation(AnnotatedTypeMirror type, AnnotationMirror target) { + private AnnotationMirror findEffectiveAnnotation( + AnnotatedTypeMirror type, AnnotationMirror target) { if (infer) { - AnnotationMirror varAnnot = ((InferenceAnnotatedTypeFactory) atypeFactory).getVarAnnot(); - return AnnotatedTypes.findEffectiveAnnotationInHierarchy(atypeFactory.getQualifierHierarchy(), type, - varAnnot, InferenceMain.isHackMode()); + AnnotationMirror varAnnot = + ((InferenceAnnotatedTypeFactory) atypeFactory).getVarAnnot(); + return AnnotatedTypes.findEffectiveAnnotationInHierarchy( + atypeFactory.getQualifierHierarchy(), + type, + varAnnot, + InferenceMain.isHackMode()); } - return AnnotatedTypes.findEffectiveAnnotationInHierarchy(atypeFactory.getQualifierHierarchy(), type, target, - InferenceMain.isHackMode()); + return AnnotatedTypes.findEffectiveAnnotationInHierarchy( + atypeFactory.getQualifierHierarchy(), type, target, InferenceMain.isHackMode()); } private AnnotationMirror findMainAnnotation(AnnotatedTypeMirror type, AnnotationMirror target) { if (infer) { - AnnotationMirror varAnnot = ((InferenceAnnotatedTypeFactory) atypeFactory).getVarAnnot(); + AnnotationMirror varAnnot = + ((InferenceAnnotatedTypeFactory) atypeFactory).getVarAnnot(); return type.getAnnotationInHierarchy(varAnnot); } return type.getAnnotationInHierarchy(target); } - public void effectiveIs(AnnotatedTypeMirror ty, AnnotationMirror mod, String msgkey, Tree node) { + public void effectiveIs( + AnnotatedTypeMirror ty, AnnotationMirror mod, String msgkey, Tree node) { AnnotationMirror effective = findEffectiveAnnotation(ty, mod); if (InferenceMain.isHackMode(effective == null)) { return; @@ -205,7 +221,8 @@ public void effectiveIs(AnnotatedTypeMirror ty, AnnotationMirror mod, String msg annoIs(ty, effective, mod, msgkey, node); } - public void effectiveIsNot(AnnotatedTypeMirror ty, AnnotationMirror mod, String msgkey, Tree node) { + public void effectiveIsNot( + AnnotatedTypeMirror ty, AnnotationMirror mod, String msgkey, Tree node) { AnnotationMirror effective = findEffectiveAnnotation(ty, mod); annoIsNot(ty, effective, mod, msgkey, node); } @@ -219,7 +236,8 @@ public void mainIs(AnnotatedTypeMirror ty, AnnotationMirror mod, String msgkey, annoIs(ty, main, mod, msgkey, node); } - public void mainIsSubtype(AnnotatedTypeMirror ty, AnnotationMirror mod, String msgkey, Tree node) { + public void mainIsSubtype( + AnnotatedTypeMirror ty, AnnotationMirror mod, String msgkey, Tree node) { if (infer) { final SlotManager slotManager = InferenceMain.getInstance().getSlotManager(); @@ -230,13 +248,21 @@ public void mainIsSubtype(AnnotatedTypeMirror ty, AnnotationMirror mod, String m logger.warning("InferenceVisitor::mainIs: no annotation in type: " + ty); } else { if (!InferenceMain.getInstance().isPerformingFlow()) { - logger.fine("InferenceVisitor::mainIs: Subtype constraint constructor invocation(s)."); - InferenceMain.getInstance().getConstraintManager().addSubtypeConstraint(el, slotManager.getSlot(mod)); + logger.fine( + "InferenceVisitor::mainIs: Subtype constraint constructor invocation(s)."); + InferenceMain.getInstance() + .getConstraintManager() + .addSubtypeConstraint(el, slotManager.getSlot(mod)); } } } else { if (!ty.hasEffectiveAnnotation(mod)) { - checker.reportError(node, msgkey, ty.getAnnotations().toString(), ty.toString(), node.toString()); + checker.reportError( + node, + msgkey, + ty.getAnnotations().toString(), + ty.toString(), + node.toString()); } } } @@ -245,7 +271,8 @@ public void mainIsNot(AnnotatedTypeMirror ty, AnnotationMirror mod, String msgke mainIsNoneOf(ty, new AnnotationMirror[] {mod}, msgkey, node); } - public void mainIsNoneOf(AnnotatedTypeMirror ty, AnnotationMirror[] mods, String msgkey, Tree node) { + public void mainIsNoneOf( + AnnotatedTypeMirror ty, AnnotationMirror[] mods, String msgkey, Tree node) { if (infer) { final SlotManager slotManager = InferenceMain.getInstance().getSlotManager(); @@ -256,17 +283,25 @@ public void mainIsNoneOf(AnnotatedTypeMirror ty, AnnotationMirror[] mods, String logger.warning("InferenceVisitor::isNoneOf: no annotation in type: " + ty); } else { if (!InferenceMain.getInstance().isPerformingFlow()) { - logger.fine("InferenceVisitor::mainIsNoneOf: Inequality constraint constructor invocation(s)."); + logger.fine( + "InferenceVisitor::mainIsNoneOf: Inequality constraint constructor invocation(s)."); for (AnnotationMirror mod : mods) { - InferenceMain.getInstance().getConstraintManager().addInequalityConstraint(el, slotManager.getSlot(mod)); + InferenceMain.getInstance() + .getConstraintManager() + .addInequalityConstraint(el, slotManager.getSlot(mod)); } } } } else { for (AnnotationMirror mod : mods) { if (ty.hasEffectiveAnnotation(mod)) { - checker.reportError(node, msgkey, ty.getAnnotations().toString(), ty.toString(), node.toString()); + checker.reportError( + node, + msgkey, + ty.getAnnotations().toString(), + ty.toString(), + node.toString()); } } } @@ -280,13 +315,19 @@ public void addPreference(AnnotatedTypeMirror type, AnnotationMirror anno, int w if (vSlot instanceof ConstantSlot) { throw new BugInCF("Trying to add Preference to a constant target: " + vSlot); } - ConstantSlot cSlot = InferenceMain.getInstance().getSlotManager().createConstantSlot(anno); + ConstantSlot cSlot = + InferenceMain.getInstance().getSlotManager().createConstantSlot(anno); cManager.addPreferenceConstraint((VariableSlot) vSlot, cSlot, weight); } // Nothing to do in type check mode. } - protected void annoIs(AnnotatedTypeMirror sourceType, AnnotationMirror effectiveAnno, AnnotationMirror target, String msgKey, Tree node) { + protected void annoIs( + AnnotatedTypeMirror sourceType, + AnnotationMirror effectiveAnno, + AnnotationMirror target, + String msgKey, + Tree node) { if (infer) { final SlotManager slotManager = InferenceMain.getInstance().getSlotManager(); Slot el = slotManager.getSlot(effectiveAnno); @@ -296,38 +337,53 @@ protected void annoIs(AnnotatedTypeMirror sourceType, AnnotationMirror effective logger.warning("InferenceVisitor::mainIs: no annotation in type: " + sourceType); } else { if (!InferenceMain.getInstance().isPerformingFlow()) { - logger.fine("InferenceVisitor::mainIs: Equality constraint constructor invocation(s)."); - InferenceMain.getInstance().getConstraintManager() + logger.fine( + "InferenceVisitor::mainIs: Equality constraint constructor invocation(s)."); + InferenceMain.getInstance() + .getConstraintManager() .addEqualityConstraint(el, slotManager.getSlot(target)); } } } else { if (!AnnotationUtils.areSame(effectiveAnno, target)) { - checker.reportError(node, msgKey, effectiveAnno, sourceType.toString(), node.toString()); + checker.reportError( + node, msgKey, effectiveAnno, sourceType.toString(), node.toString()); } } } - protected void annoIsNot(AnnotatedTypeMirror sourceType, AnnotationMirror effectiveAnno, AnnotationMirror target, - String msgKey, Tree node) { - annoIsNoneOf(sourceType, effectiveAnno, new AnnotationMirror[]{target}, msgKey, node); + protected void annoIsNot( + AnnotatedTypeMirror sourceType, + AnnotationMirror effectiveAnno, + AnnotationMirror target, + String msgKey, + Tree node) { + annoIsNoneOf(sourceType, effectiveAnno, new AnnotationMirror[] {target}, msgKey, node); } - public void annoIsNoneOf(AnnotatedTypeMirror sourceType, AnnotationMirror effectiveAnno, - AnnotationMirror[] targets, String msgKey, Tree node) { + public void annoIsNoneOf( + AnnotatedTypeMirror sourceType, + AnnotationMirror effectiveAnno, + AnnotationMirror[] targets, + String msgKey, + Tree node) { if (infer) { final SlotManager slotManager = InferenceMain.getInstance().getSlotManager(); Slot el = slotManager.getSlot(effectiveAnno); if (el == null) { // TODO: prims not annotated in UTS, others might - logger.warning("InferenceVisitor::isNoneOf: no annotation in type: " + Arrays.toString(targets)); + logger.warning( + "InferenceVisitor::isNoneOf: no annotation in type: " + + Arrays.toString(targets)); } else { if (!InferenceMain.getInstance().isPerformingFlow()) { - logger.fine("InferenceVisitor::mainIsNoneOf: Inequality constraint constructor invocation(s)."); + logger.fine( + "InferenceVisitor::mainIsNoneOf: Inequality constraint constructor invocation(s)."); for (AnnotationMirror mod : targets) { - InferenceMain.getInstance().getConstraintManager() + InferenceMain.getInstance() + .getConstraintManager() .addInequalityConstraint(el, slotManager.getSlot(mod)); } } @@ -335,14 +391,15 @@ public void annoIsNoneOf(AnnotatedTypeMirror sourceType, AnnotationMirror effect } else { for (AnnotationMirror target : targets) { if (AnnotationUtils.areSame(target, effectiveAnno)) { - checker.reportError(node, msgKey, effectiveAnno, sourceType.toString(), node.toString()); + checker.reportError( + node, msgKey, effectiveAnno, sourceType.toString(), node.toString()); } } } } - - public void areComparable(AnnotatedTypeMirror ty1, AnnotatedTypeMirror ty2, String msgkey, Tree node) { + public void areComparable( + AnnotatedTypeMirror ty1, AnnotatedTypeMirror ty2, String msgkey, Tree node) { if (infer) { final SlotManager slotManager = InferenceMain.getInstance().getSlotManager(); Slot el1 = slotManager.getSlot(ty1); @@ -350,21 +407,30 @@ public void areComparable(AnnotatedTypeMirror ty1, AnnotatedTypeMirror ty2, Stri if (el1 == null || el2 == null) { // TODO: prims not annotated in UTS, others might - logger.warning("InferenceVisitor::areComparable: no annotation on type: " + ty1 + " or " + ty2); + logger.warning( + "InferenceVisitor::areComparable: no annotation on type: " + + ty1 + + " or " + + ty2); } else { if (!InferenceMain.getInstance().isPerformingFlow()) { - logger.fine("InferenceVisitor::areComparable: Comparable constraint constructor invocation."); - InferenceMain.getInstance().getConstraintManager().addComparableConstraint(el1, el2); + logger.fine( + "InferenceVisitor::areComparable: Comparable constraint constructor invocation."); + InferenceMain.getInstance() + .getConstraintManager() + .addComparableConstraint(el1, el2); } } } else { - if (!(atypeFactory.getTypeHierarchy().isSubtype(ty1, ty2) || atypeFactory.getTypeHierarchy().isSubtype(ty2, ty1))) { + if (!(atypeFactory.getTypeHierarchy().isSubtype(ty1, ty2) + || atypeFactory.getTypeHierarchy().isSubtype(ty2, ty1))) { checker.reportError(node, msgkey, ty1.toString(), ty2.toString(), node.toString()); } } } - public void areEqual(AnnotatedTypeMirror ty1, AnnotatedTypeMirror ty2, String msgkey, Tree node) { + public void areEqual( + AnnotatedTypeMirror ty1, AnnotatedTypeMirror ty2, String msgkey, Tree node) { if (infer) { final SlotManager slotManager = InferenceMain.getInstance().getSlotManager(); Slot el1 = slotManager.getSlot(ty1); @@ -372,11 +438,15 @@ public void areEqual(AnnotatedTypeMirror ty1, AnnotatedTypeMirror ty2, String ms if (el1 == null || el2 == null) { // TODO: prims not annotated in UTS, others might - logger.warning("InferenceVisitor::areEqual: no annotation on type: " + ty1 + " or " + ty2); + logger.warning( + "InferenceVisitor::areEqual: no annotation on type: " + ty1 + " or " + ty2); } else { if (!InferenceMain.getInstance().isPerformingFlow()) { - logger.fine("InferenceVisitor::areEqual: Equality constraint constructor invocation."); - InferenceMain.getInstance().getConstraintManager().addEqualityConstraint(el1, el2); + logger.fine( + "InferenceVisitor::areEqual: Equality constraint constructor invocation."); + InferenceMain.getInstance() + .getConstraintManager() + .addEqualityConstraint(el1, el2); } } } else { @@ -387,12 +457,13 @@ public void areEqual(AnnotatedTypeMirror ty1, AnnotatedTypeMirror ty2, String ms } @Override - protected void checkTypeArguments(Tree toptree, - List paramBounds, - List typeargs, - List typeargTrees, - CharSequence typeOrMethodName, - List paramNames) { + protected void checkTypeArguments( + Tree toptree, + List paramBounds, + List typeargs, + List typeargTrees, + CharSequence typeOrMethodName, + List paramNames) { // System.out.printf("BaseTypeVisitor.checkTypeArguments: %s, TVs: %s, TAs: %s, TATs: %s\n", // toptree, paramBounds, typeargs, typeargTrees); @@ -404,9 +475,9 @@ protected void checkTypeArguments(Tree toptree, int size = paramBounds.size(); assert size == typeargs.size() : "BaseTypeVisitor.checkTypeArguments: mismatch between type arguments: " - + typeargs - + " and type parameter bounds" - + paramBounds; + + typeargs + + " and type parameter bounds" + + paramBounds; for (int i = 0; i < size; i++) { @@ -417,11 +488,13 @@ protected void checkTypeArguments(Tree toptree, AnnotatedTypeMirror varUpperBound = bounds.getUpperBound(); final AnnotatedTypeMirror typeArgForUpperBoundCheck = typeArg; - if (typeArg.getKind() == TypeKind.WILDCARD ) { + if (typeArg.getKind() == TypeKind.WILDCARD) { if (bounds.getUpperBound().getKind() == TypeKind.WILDCARD) { - // TODO: When capture conversion is implemented, this special case should be removed. - // TODO: This may not occur only in places where capture conversion occurs but in those cases + // TODO: When capture conversion is implemented, this special case should be + // removed. + // TODO: This may not occur only in places where capture conversion occurs but + // in those cases // TODO: The containment check provided by this method should be enough continue; } @@ -429,18 +502,23 @@ protected void checkTypeArguments(Tree toptree, // If we have a declaration: // class MyClass ... // - // the javac compiler allows wildcard type arguments that have Java types OUTSIDE of the + // the javac compiler allows wildcard type arguments that have Java types OUTSIDE of + // the // bounds of T, i.e: // MyClass // - // This is sound because every NON-WILDCARD reference to MyClass MUST obey those bounds - // This leads to cases where varUpperBound is actually a subtype of typeArgForUpperBoundCheck + // This is sound because every NON-WILDCARD reference to MyClass MUST obey those + // bounds + // This leads to cases where varUpperBound is actually a subtype of + // typeArgForUpperBoundCheck final TypeMirror varUnderlyingUb = varUpperBound.getUnderlyingType(); - final TypeMirror argUnderlyingUb = ((AnnotatedWildcardType)typeArg).getExtendsBound().getUnderlyingType(); - if ( !types.isSubtype(argUnderlyingUb, varUnderlyingUb) - && types.isSubtype(varUnderlyingUb, argUnderlyingUb)) { - varUpperBound = AnnotatedTypes.asSuper(atypeFactory, - varUpperBound, typeArgForUpperBoundCheck); + final TypeMirror argUnderlyingUb = + ((AnnotatedWildcardType) typeArg).getExtendsBound().getUnderlyingType(); + if (!types.isSubtype(argUnderlyingUb, varUnderlyingUb) + && types.isSubtype(varUnderlyingUb, argUnderlyingUb)) { + varUpperBound = + AnnotatedTypes.asSuper( + atypeFactory, varUpperBound, typeArgForUpperBoundCheck); } } @@ -457,7 +535,8 @@ protected void checkTypeArguments(Tree toptree, curParamName, typeOrMethodName); } else { - commonAssignmentCheck(varUpperBound, + commonAssignmentCheck( + varUpperBound, typeArg, typeargTrees.get(typeargs.indexOf(typeArg)), "type.argument.type.incompatible", @@ -489,14 +568,13 @@ protected void checkTypeArguments(Tree toptree, } /** - * Checks the validity of an assignment (or pseudo-assignment) from a value - * to a variable and emits an error message (through the compiler's - * messaging interface) if it is not valid. + * Checks the validity of an assignment (or pseudo-assignment) from a value to a variable and + * emits an error message (through the compiler's messaging interface) if it is not valid. * * @param varTree the AST node for the variable * @param valueExp the AST node for the value - * @param errorKey the error message to use if the check fails (must be a - * compiler message key, see {@link org.checkerframework.checker.compilermsgs.qual.CompilerMessageKey}) + * @param errorKey the error message to use if the check fails (must be a compiler message key, + * see {@link org.checkerframework.checker.compilermsgs.qual.CompilerMessageKey}) * @param extraArgs arguments to the error message key, before "found" and "expected" types */ @Override @@ -518,8 +596,10 @@ protected boolean commonAssignmentCheck( // Since refinement variables come from flow inference, we must call "getAnnotatedType" // instead of "getAnnotatedTypeLhs". // TODO: use "getAnnotatedTypeLhs" uniformly when issue 316 is completely resolved. - // (In that way, the refinement constraints are uniformly created during dataflow analysis, so - // "commonAssignmentCheck" only needs to enforce the general type rule regarding assignment.) + // (In that way, the refinement constraints are uniformly created during dataflow + // analysis, so + // "commonAssignmentCheck" only needs to enforce the general type rule regarding + // assignment.) var = atypeFactory.getAnnotatedType(varTree); } else { var = atypeFactory.getAnnotatedTypeLhs(varTree); @@ -557,9 +637,12 @@ protected boolean commonAssignmentCheck( " %s (line %3d): %s %s%n actual: %s %s%n expected: %s %s%n", "About to test whether actual is a subtype of expected", (root.getLineMap() != null ? root.getLineMap().getLineNumber(valuePos) : -1), - valueTree.getKind(), valueTree, - valueType.getKind(), valueTypeString, - varType.getKind(), varTypeString); + valueTree.getKind(), + valueTree, + valueType.getKind(), + valueTypeString, + varType.getKind(), + varTypeString); } // ####### End Copied Code ######## @@ -580,20 +663,24 @@ protected boolean commonAssignmentCheck( // TODO: We should get rid of this if, but for now type variables will have their bounds // TODO: incorrectly inferred if we do not have it boolean success = true; - if (!infer || (varType.getKind() != TypeKind.TYPEVAR && valueType.getKind() != TypeKind.TYPEVAR)) { + if (!infer + || (varType.getKind() != TypeKind.TYPEVAR + && valueType.getKind() != TypeKind.TYPEVAR)) { success = atypeFactory.getTypeHierarchy().isSubtype(valueType, varType); } // ####### Copied Code ######## // TODO: integrate with subtype test. if (success) { - for (Class mono : atypeFactory.getSupportedMonotonicTypeQualifiers()) { - if (valueType.hasAnnotation(mono) - && varType.hasAnnotation(mono)) { - checker.reportError(valueTree, "monotonic.type.incompatible", - mono.getCanonicalName(), - mono.getCanonicalName(), - valueType.toString()); + for (Class mono : + atypeFactory.getSupportedMonotonicTypeQualifiers()) { + if (valueType.hasAnnotation(mono) && varType.hasAnnotation(mono)) { + checker.reportError( + valueTree, + "monotonic.type.incompatible", + mono.getCanonicalName(), + mono.getCanonicalName(), + valueType.toString()); // Assign success to false to report the error. success = false; } @@ -604,11 +691,16 @@ protected boolean commonAssignmentCheck( long valuePos = positions.getStartPosition(root, valueTree); System.out.printf( " %s (line %3d): %s %s%n actual: %s %s%n expected: %s %s%n", - (success ? "success: actual is subtype of expected" : "FAILURE: actual is not subtype of expected"), + (success + ? "success: actual is subtype of expected" + : "FAILURE: actual is not subtype of expected"), (root.getLineMap() != null ? root.getLineMap().getLineNumber(valuePos) : -1), - valueTree.getKind(), valueTree, - valueType.getKind(), valueTypeString, - varType.getKind(), varTypeString); + valueTree.getKind(), + valueTree, + valueType.getKind(), + valueTypeString, + varType.getKind(), + varTypeString); } // Use an error key only if it's overridden by a checker. @@ -622,13 +714,18 @@ protected boolean commonAssignmentCheck( // ####### End Copied Code ######## } - private void addRefinementVariableConstraints(final AnnotatedTypeMirror varType, - final AnnotatedTypeMirror valueType, - final SlotManager slotManager, - final ConstraintManager constraintManager) { + private void addRefinementVariableConstraints( + final AnnotatedTypeMirror varType, + final AnnotatedTypeMirror valueType, + final SlotManager slotManager, + final ConstraintManager constraintManager) { Slot sup = slotManager.getSlot(varType); Slot sub = slotManager.getSlot(valueType); - logger.fine("InferenceVisitor::commonAssignmentCheck: Equality constraint for qualifiers sub: " + sub + " sup: " + sup); + logger.fine( + "InferenceVisitor::commonAssignmentCheck: Equality constraint for qualifiers sub: " + + sub + + " sup: " + + sup); // Equality between the refvar and the value constraintManager.addEqualityConstraint(sup, sub); @@ -638,24 +735,28 @@ private void addRefinementVariableConstraints(final AnnotatedTypeMirror varType, } /** - * A refinement variable generally has two constraints that must be enforce. It must be a subtype of the - * declared type it refines and it must be equal to the type on the right-hand side of the assignment or - * pseudo-assignment that created it. + * A refinement variable generally has two constraints that must be enforce. It must be a + * subtype of the declared type it refines and it must be equal to the type on the right-hand + * side of the assignment or pseudo-assignment that created it. * - * This method detects the assignments that cause refinements and generates the above constraints. + *

This method detects the assignments that cause refinements and generates the above + * constraints. * - * For declared type, we create the refinement constraint once the refinement variable is created in - * {@link checkers.inference.dataflow.InferenceTransfer#createRefinementVar} during dataflow analysis. - * Therefore nothing needs to be done here. - * TODO: handle type variables and wildcards the same way as declared types, so that finally all - * refinement-related constraints are created in the dataflow analysis, and this method is removed. + *

For declared type, we create the refinement constraint once the refinement variable is + * created in {@link checkers.inference.dataflow.InferenceTransfer#createRefinementVar} during + * dataflow analysis. Therefore nothing needs to be done here. TODO: handle type variables and + * wildcards the same way as declared types, so that finally all refinement-related constraints + * are created in the dataflow analysis, and this method is removed. */ - public boolean maybeAddRefinementVariableConstraints(final AnnotatedTypeMirror varType, final AnnotatedTypeMirror valueType) { + public boolean maybeAddRefinementVariableConstraints( + final AnnotatedTypeMirror varType, final AnnotatedTypeMirror valueType) { boolean inferenceRefinementVariable = false; final SlotManager slotManager = InferenceMain.getInstance().getSlotManager(); - final ConstraintManager constraintManager = InferenceMain.getInstance().getConstraintManager(); + final ConstraintManager constraintManager = + InferenceMain.getInstance().getConstraintManager(); - // type variables have two refinement variables (one on the upper bound and one on the lower bound) + // type variables have two refinement variables (one on the upper bound and one on the lower + // bound) if (varType.getKind() == TypeKind.TYPEVAR) { if (valueType.getKind() == TypeKind.TYPEVAR) { final AnnotatedTypeVariable varTypeTv = (AnnotatedTypeVariable) varType; @@ -667,7 +768,7 @@ public boolean maybeAddRefinementVariableConstraints(final AnnotatedTypeMirror v varUpperBoundAtm = InferenceUtil.findUpperBoundType(varTypeTv); varLowerBoundAtm = InferenceUtil.findLowerBoundType(varTypeTv); - } catch(Throwable exc) { + } catch (Throwable exc) { if (InferenceMain.isHackMode()) { return false; } else { @@ -685,17 +786,18 @@ public boolean maybeAddRefinementVariableConstraints(final AnnotatedTypeMirror v try { valUpperBoundAtm = InferenceUtil.findUpperBoundType(valueTypeTv); valLowerBoundAtm = InferenceUtil.findLowerBoundType(valueTypeTv); - } catch(Throwable exc) { + } catch (Throwable exc) { if (InferenceMain.isHackMode()) { return false; } else { throw exc; } } - addRefinementVariableConstraints(varUpperBoundAtm, valUpperBoundAtm, slotManager, constraintManager); + addRefinementVariableConstraints( + varUpperBoundAtm, valUpperBoundAtm, slotManager, constraintManager); - constraintManager.addEqualityConstraint(lowerBoundSlot, - slotManager.getSlot(valLowerBoundAtm)); + constraintManager.addEqualityConstraint( + lowerBoundSlot, slotManager.getSlot(valLowerBoundAtm)); constraintManager.addSubtypeConstraint(lowerBoundSlot, upperBoundSlot); inferenceRefinementVariable = true; @@ -706,7 +808,10 @@ public boolean maybeAddRefinementVariableConstraints(final AnnotatedTypeMirror v } else { if (!InferenceMain.isHackMode()) { - throw new BugInCF("Unexpected assignment to type variable"); // TODO: Either more detail, or remove because of type args? + throw new BugInCF( + "Unexpected assignment to type variable"); // TODO: Either more detail, + // or remove because of type + // args? // TODO: OR A DIFFERENT SET OF CONSTRAINTS? } } @@ -715,7 +820,8 @@ public boolean maybeAddRefinementVariableConstraints(final AnnotatedTypeMirror v return inferenceRefinementVariable; } - protected Set filterThrowCatchBounds(Set originals) { + protected Set filterThrowCatchBounds( + Set originals) { Set throwBounds = new HashSet<>(); for (AnnotationMirror throwBound : originals) { @@ -726,7 +832,8 @@ protected Set filterThrowCatchBounds(Set filterThrowCatchBounds(Set throwBounds = filterThrowCatchBounds(getThrowUpperBoundAnnotations()); + AnnotatedTypeMirror throwType = atypeFactory.getAnnotatedType(node.getExpression()); + Set throwBounds = + filterThrowCatchBounds(getThrowUpperBoundAnnotations()); - final AnnotationMirror varAnnot =new AnnotationBuilder(atypeFactory.getProcessingEnv(), VarAnnot.class).build(); + final AnnotationMirror varAnnot = + new AnnotationBuilder(atypeFactory.getProcessingEnv(), VarAnnot.class).build(); final SlotManager slotManager = InferenceMain.getInstance().getSlotManager(); - final ConstraintManager constraintManager = InferenceMain.getInstance().getConstraintManager(); + final ConstraintManager constraintManager = + InferenceMain.getInstance().getConstraintManager(); for (AnnotationMirror throwBound : throwBounds) { switch (throwType.getKind()) { case NULL: case DECLARED: - constraintManager.addSubtypeConstraint(slotManager.getSlot(throwType), - slotManager.getSlot(throwBound) - ); + constraintManager.addSubtypeConstraint( + slotManager.getSlot(throwType), slotManager.getSlot(throwBound)); break; case TYPEVAR: case WILDCARD: - AnnotationMirror foundEffective = AnnotatedTypes.findEffectiveAnnotationInHierarchy( - atypeFactory.getQualifierHierarchy(), throwType, varAnnot); - constraintManager.addSubtypeConstraint(slotManager.getSlot(foundEffective), - slotManager.getSlot(throwBound) - ); + AnnotationMirror foundEffective = + AnnotatedTypes.findEffectiveAnnotationInHierarchy( + atypeFactory.getQualifierHierarchy(), throwType, varAnnot); + constraintManager.addSubtypeConstraint( + slotManager.getSlot(foundEffective), + slotManager.getSlot(throwBound)); break; case UNION: AnnotatedUnionType unionType = (AnnotatedUnionType) throwType; AnnotationMirror primary = unionType.getAnnotationInHierarchy(varAnnot); if (primary != null) { - constraintManager.addSubtypeConstraint(slotManager.getSlot(primary), - slotManager.getSlot(throwBound) - ); + constraintManager.addSubtypeConstraint( + slotManager.getSlot(primary), slotManager.getSlot(throwBound)); } for (AnnotatedTypeMirror altern : unionType.getAlternatives()) { AnnotationMirror alternAnno = altern.getAnnotationInHierarchy(varAnnot); if (alternAnno != null) { - constraintManager.addSubtypeConstraint(slotManager.getSlot(alternAnno), - slotManager.getSlot(throwBound) - ); + constraintManager.addSubtypeConstraint( + slotManager.getSlot(alternAnno), + slotManager.getSlot(throwBound)); } } break; default: - throw new BugInCF("Unexpected throw expression type: " - + throwType.getKind()); + throw new BugInCF( + "Unexpected throw expression type: " + throwType.getKind()); } } - - } else { + } else { super.checkThrownExpression(node); } - } // TODO: TEMPORARY HACK UNTIL WE SUPPORT UNIONS @@ -809,7 +915,8 @@ protected void checkExceptionParameter(CatchTree node) { if (infer) { // TODO: Unify with BaseTypeVisitor implementation - Set requiredAnnotations = filterThrowCatchBounds(getExceptionParameterLowerBoundAnnotations()); + Set requiredAnnotations = + filterThrowCatchBounds(getExceptionParameterLowerBoundAnnotations()); AnnotatedTypeMirror exPar = atypeFactory.getAnnotatedType(node.getParameter()); for (AnnotationMirror required : requiredAnnotations) { @@ -817,22 +924,30 @@ protected void checkExceptionParameter(CatchTree node) { assert found != null; if (exPar.getKind() != TypeKind.UNION) { - if (!atypeFactory.getQualifierHierarchy() + if (!atypeFactory + .getQualifierHierarchy() .isSubtypeQualifiersOnly(required, found)) { - checker.reportError(node.getParameter(), "exception.parameter.invalid", - found, required); + checker.reportError( + node.getParameter(), + "exception.parameter.invalid", + found, + required); } } else { AnnotatedUnionType aut = (AnnotatedUnionType) exPar; for (AnnotatedTypeMirror alterntive : aut.getAlternatives()) { - AnnotationMirror foundAltern = alterntive - .getAnnotationInHierarchy(required); - if (!atypeFactory.getQualifierHierarchy().isSubtypeQualifiersOnly( - required, foundAltern)) { - checker.reportError(node.getParameter(), "exception.parameter.invalid", foundAltern, + AnnotationMirror foundAltern = + alterntive.getAnnotationInHierarchy(required); + if (!atypeFactory + .getQualifierHierarchy() + .isSubtypeQualifiersOnly(required, foundAltern)) { + checker.reportError( + node.getParameter(), + "exception.parameter.invalid", + foundAltern, required); } - } + } } } @@ -847,11 +962,11 @@ protected InferenceValidator createTypeValidator() { } /** - * The super method issues a warning if the result type of the constructor is not top. - * If we keep the same logic in inference, a hard constraint "classBound == top" will be - * created, which is not what we want. Therefore, skip this checking when it's in the - * inference mode. - * TODO: consider using preference constraints where warnings are issued in the type-checking mode. + * The super method issues a warning if the result type of the constructor is not top. If we + * keep the same logic in inference, a hard constraint "classBound == top" will be created, + * which is not what we want. Therefore, skip this checking when it's in the inference mode. + * TODO: consider using preference constraints where warnings are issued in the type-checking + * mode. */ @Override protected void checkConstructorResult( @@ -862,17 +977,21 @@ protected void checkConstructorResult( } /** - * This method creates a mapping from type-use locations to a set of qualifiers which cannot be applied to that location. + * This method creates a mapping from type-use locations to a set of qualifiers which cannot be + * applied to that location. * - * @return a mapping from type-use locations to a set of qualifiers which cannot be applied to that location + * @return a mapping from type-use locations to a set of qualifiers which cannot be applied to + * that location */ protected Map> createMapForIllegalQuals() { Map> locationToIllegalQuals = new HashMap<>(); // First, init each type-use location to contain all type qualifiers. - Set> supportQualifiers = atypeFactory.getSupportedTypeQualifiers(); + Set> supportQualifiers = + atypeFactory.getSupportedTypeQualifiers(); Set supportedAnnos = new AnnotationMirrorSet(); - for (Class qual: supportQualifiers) { - supportedAnnos.add(new AnnotationBuilder(atypeFactory.getProcessingEnv(), qual).build()); + for (Class qual : supportQualifiers) { + supportedAnnos.add( + new AnnotationBuilder(atypeFactory.getProcessingEnv(), qual).build()); } for (TypeUseLocation location : TypeUseLocation.values()) { locationToIllegalQuals.put(location, new HashSet<>(supportedAnnos)); @@ -887,7 +1006,9 @@ protected Map> createMapForIllegalQuals() if (tls == null) { for (TypeUseLocation location : TypeUseLocation.values()) { Set amSet = locationToIllegalQuals.get(location); - amSet.remove(AnnotationUtils.getAnnotationByName(supportedAnnos, qual.getCanonicalName())); + amSet.remove( + AnnotationUtils.getAnnotationByName( + supportedAnnos, qual.getCanonicalName())); } continue; } @@ -895,12 +1016,16 @@ protected Map> createMapForIllegalQuals() if (location == TypeUseLocation.ALL) { for (TypeUseLocation val : TypeUseLocation.values()) { Set amSet = locationToIllegalQuals.get(val); - amSet.remove(AnnotationUtils.getAnnotationByName(supportedAnnos, qual.getCanonicalName())); + amSet.remove( + AnnotationUtils.getAnnotationByName( + supportedAnnos, qual.getCanonicalName())); } break; } Set amSet = locationToIllegalQuals.get(location); - amSet.remove(AnnotationUtils.getAnnotationByName(supportedAnnos, qual.getCanonicalName())); + amSet.remove( + AnnotationUtils.getAnnotationByName( + supportedAnnos, qual.getCanonicalName())); } } return locationToIllegalQuals; @@ -948,8 +1073,11 @@ protected void validateVariablesTargetLocation(Tree tree, AnnotatedTypeMirror ty throw new BugInCF("Location not matched"); } AnnotationMirror[] mirrors = new AnnotationMirror[0]; - mainIsNoneOf(type, locationToIllegalQuals.get(location).toArray(mirrors), - "type.invalid.annotations.on.location", tree); + mainIsNoneOf( + type, + locationToIllegalQuals.get(location).toArray(mirrors), + "type.invalid.annotations.on.location", + tree); } } @@ -962,8 +1090,11 @@ protected void validateTargetLocation( if (ignoreTargetLocations) { return; } - mainIsNoneOf(type, locationToIllegalQuals.get(required).toArray(new AnnotationMirror[0]), - "type.invalid.annotations.on.location", tree); + mainIsNoneOf( + type, + locationToIllegalQuals.get(required).toArray(new AnnotationMirror[0]), + "type.invalid.annotations.on.location", + tree); } } } diff --git a/src/checkers/inference/InferrableChecker.java b/src/checkers/inference/InferrableChecker.java index c5f99e6fc..09e08015d 100644 --- a/src/checkers/inference/InferrableChecker.java +++ b/src/checkers/inference/InferrableChecker.java @@ -1,51 +1,56 @@ package checkers.inference; +import com.sun.source.tree.Tree; + import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; import org.checkerframework.framework.flow.CFAnalysis; import org.checkerframework.framework.flow.CFStore; import org.checkerframework.framework.flow.CFTransfer; import org.checkerframework.framework.flow.CFValue; import org.checkerframework.framework.type.GenericAnnotatedTypeFactory; + import java.lang.annotation.Annotation; import java.util.Set; + import javax.annotation.processing.ProcessingEnvironment; import checkers.inference.dataflow.InferenceAnalysis; import checkers.inference.model.ConstraintManager; -import com.sun.source.tree.Tree; - /** * Interface for all checkers that wish to be used with Checker-Framework-Inference * - * This interface allows a checker to configure is inference behavior. + *

This interface allows a checker to configure is inference behavior. * - * Some methods are from BaseTypeChecker as convenience to Inference classes so they do not need to have multiple - * references to the same class. + *

Some methods are from BaseTypeChecker as convenience to Inference classes so they do not need + * to have multiple references to the same class. * * @author mcarthur - * */ - public interface InferrableChecker { // Initialize the underlying checker void init(ProcessingEnvironment processingEnv); + void initChecker(); // Instantiate the real type factory BaseInferenceRealTypeFactory createRealTypeFactory(boolean infer); - public InferenceAnnotatedTypeFactory createInferenceATF(InferenceChecker inferenceChecker, - InferrableChecker realChecker, BaseAnnotatedTypeFactory realTypeFactory, - SlotManager slotManager, ConstraintManager constraintManager); + public InferenceAnnotatedTypeFactory createInferenceATF( + InferenceChecker inferenceChecker, + InferrableChecker realChecker, + BaseAnnotatedTypeFactory realTypeFactory, + SlotManager slotManager, + ConstraintManager constraintManager); // Instantiate a visitor based on parameters - InferenceVisitor createVisitor(InferenceChecker checker, BaseAnnotatedTypeFactory factory, boolean infer); + InferenceVisitor createVisitor( + InferenceChecker checker, BaseAnnotatedTypeFactory factory, boolean infer); /** - * Should inference generate variables and constraints for - * viewpoint adaption when accessing instance members. + * Should inference generate variables and constraints for viewpoint adaption when accessing + * instance members. */ boolean withCombineConstraints(); @@ -54,36 +59,36 @@ public InferenceAnnotatedTypeFactory createInferenceATF(InferenceChecker inferen CFAnalysis createInferenceAnalysis( InferenceChecker checker, GenericAnnotatedTypeFactory factory, - SlotManager slotManager, ConstraintManager constraintManager, + SlotManager slotManager, + ConstraintManager constraintManager, InferrableChecker realChecker); /** * Should this node be treated as having a constant value. * - * If true, the underlying ATF will be used to look up the type of the node - * and an equality constraint will be generated for between the VarAnnot - * and the annotation from the underlying ATF. + *

If true, the underlying ATF will be used to look up the type of the node and an equality + * constraint will be generated for between the VarAnnot and the annotation from the underlying + * ATF. * * @param node the node * @return true if the node should be treated as constant */ boolean isConstant(Tree node); - /** * @return true whether or not the SlotManager should try to maintain a store of - * AnnotationMirror -> ConstantSlot in order to avoid creating multiple constants - * for the same annotation. For parameterized qualifiers this should return false. + * AnnotationMirror -> ConstantSlot in order to avoid creating multiple constants for the + * same annotation. For parameterized qualifiers this should return false. */ boolean shouldStoreConstantSlots(); /** - * should the inference annotations of main modifier of local variables also insert - * into source code + * should the inference annotations of main modifier of local variables also insert into source + * code * - * Generally a checker would not want insert annotations of main modifier of local vars - * because they can inferred by flow refinement. For some specific checkers, e.g. Ontology, - * they may not want ignore those information. + *

Generally a checker would not want insert annotations of main modifier of local vars + * because they can inferred by flow refinement. For some specific checkers, e.g. Ontology, they + * may not want ignore those information. * * @return true if should insert annotations of main modifier of local variables */ @@ -94,15 +99,15 @@ CFAnalysis createInferenceAnalysis( * qualifiers set) into source code, then the class literals for these alias annotations should * be returned in an override of this method. * - * For example, in Units Checker, it is preferred to insert {@code @m}, an alias annotation, + *

For example, in Units Checker, it is preferred to insert {@code @m}, an alias annotation, * into source code instead of the corresponding internal representation annotation * {@code @UnitsInternal(...)} as the alias annotation is easier to understand for users. * - * The default implementation of this method in {@ + *

The default implementation of this method in {@ * BaseInferrableChecker#additionalAnnotationsForJaifHeaderInsertion()} returns an empty set. * * @return a set of any additional annotations that need to be inserted as annotation headers - * into Jaif files. + * into Jaif files. */ Set> additionalAnnotationsForJaifHeaderInsertion(); -} \ No newline at end of file +} diff --git a/src/checkers/inference/SlotManager.java b/src/checkers/inference/SlotManager.java index 57a1c432e..1838b8e7e 100644 --- a/src/checkers/inference/SlotManager.java +++ b/src/checkers/inference/SlotManager.java @@ -1,8 +1,7 @@ package checkers.inference; -import checkers.inference.model.LubVariableSlot; import com.sun.source.tree.ClassTree; -import com.sun.source.tree.CompilationUnitTree; + import org.checkerframework.framework.type.AnnotatedTypeMirror; import java.util.List; @@ -16,15 +15,16 @@ import checkers.inference.model.ComparisonVariableSlot; import checkers.inference.model.ConstantSlot; import checkers.inference.model.ExistentialVariableSlot; +import checkers.inference.model.LubVariableSlot; import checkers.inference.model.RefinementVariableSlot; import checkers.inference.model.Slot; -import checkers.inference.model.VariableSlot; import checkers.inference.model.SourceVariableSlot; +import checkers.inference.model.VariableSlot; /** - * SlotManager stores variables for later access, provides ids for creating variables and - * provides helper method for converting back and forth between Slots and the AnnotationMirrors - * that represent them. + * SlotManager stores variables for later access, provides ids for creating variables and provides + * helper method for converting back and forth between Slots and the AnnotationMirrors that + * represent them. */ public interface SlotManager { @@ -36,125 +36,107 @@ public interface SlotManager { int getNumberOfSlots(); /** - * Create new SourceVariableSlot and return the reference to it if no SourceVariableSlot - * on this location exists. Otherwise return the reference to existing SourceVariableSlot - * on this location. Each location uniquely identifies a SourceVariableSlot + * Create new SourceVariableSlot and return the reference to it if no SourceVariableSlot on this + * location exists. Otherwise return the reference to existing SourceVariableSlot on this + * location. Each location uniquely identifies a SourceVariableSlot * - * @param location - * used to locate this variable in code + * @param location used to locate this variable in code * @return SourceVariableSlot that corresponds to this location */ SourceVariableSlot createSourceVariableSlot(AnnotationLocation location, TypeMirror type); /** - * Create new VariableSlot and return the reference to it if no VariableSlot - * on this location exists. Otherwise return the reference to existing VariableSlot - * on this location. Each location uniquely identifies a polymorphic instance. - * For now, there's no dedicated slot for polymorphic instance, but we may add one - * in the future. + * Create new VariableSlot and return the reference to it if no VariableSlot on this location + * exists. Otherwise return the reference to existing VariableSlot on this location. Each + * location uniquely identifies a polymorphic instance. For now, there's no dedicated slot for + * polymorphic instance, but we may add one in the future. * - * @param location - * used to locate this variable in code + * @param location used to locate this variable in code * @return VariableSlot that corresponds to this location */ VariableSlot createPolymorphicInstanceSlot(AnnotationLocation location, TypeMirror type); /** - * Create new RefinementVariableSlot (as well as the refinement constraint if - * possible) and return the reference to it if no RefinementVariableSlot on this - * location exists. Otherwise return the reference to existing RefinementVariableSlot - * on this location. Each location uniquely identifies a RefinementVariableSlot - * - * @param location - * used to locate this refinement variable in code - * @param declarationSlot - * the VariableSlot for the lhs that gets refined - * @param valueSlot - * the value that the given lhs VariableSlot is refined to. If it is - * non-null, an equality constraint "declarationSlot == valueSlot" is - * created. Otherwise such constraint is created in - * {@link InferenceVisitor#maybeAddRefinementVariableConstraints} - * Currently we pass in non-null valueSlot only when lhs is a declared type. - * TODO: handle wildcards/type variables in the same way as declared - * type, so that this parameter is always non-null + * Create new RefinementVariableSlot (as well as the refinement constraint if possible) and + * return the reference to it if no RefinementVariableSlot on this location exists. Otherwise + * return the reference to existing RefinementVariableSlot on this location. Each location + * uniquely identifies a RefinementVariableSlot * + * @param location used to locate this refinement variable in code + * @param declarationSlot the VariableSlot for the lhs that gets refined + * @param valueSlot the value that the given lhs VariableSlot is refined to. If it is non-null, + * an equality constraint "declarationSlot == valueSlot" is created. Otherwise such + * constraint is created in {@link InferenceVisitor#maybeAddRefinementVariableConstraints} + * Currently we pass in non-null valueSlot only when lhs is a declared type. TODO: handle + * wildcards/type variables in the same way as declared type, so that this parameter is + * always non-null * @return RefinementVariableSlot that corresponds to this refinement */ - RefinementVariableSlot createRefinementVariableSlot(AnnotationLocation location, Slot declarationSlot, Slot valueSlot); + RefinementVariableSlot createRefinementVariableSlot( + AnnotationLocation location, Slot declarationSlot, Slot valueSlot); /** - * Create new ConstrantSlot and returns the reference to it if no - * ConstantSlot representing this AnnotationMirror exists. Otherwise, return - * the reference to existing ConstantSlot. An AnnotationMirror uniquely - * identifies a ConstantSlot + * Create new ConstrantSlot and returns the reference to it if no ConstantSlot representing this + * AnnotationMirror exists. Otherwise, return the reference to existing ConstantSlot. An + * AnnotationMirror uniquely identifies a ConstantSlot * - * @param value - * The actual AnnotationMirror that this ConstantSlot represents. - * This AnnotationMirror should be valid within the type system - * for which we are inferring values. + * @param value The actual AnnotationMirror that this ConstantSlot represents. This + * AnnotationMirror should be valid within the type system for which we are inferring + * values. * @return the ConstantSlot that represents this AnnotationMirror */ ConstantSlot createConstantSlot(AnnotationMirror value); /** - * Create new CombVariableSlot using receiver slot and declared slot, and - * return reference to it if no CombVariableSlot representing result of - * adapting declared slot to receiver slot exists. Otherwise, returns the - * existing CombVariableSlot. Receiver slot and declared slot can uniquely - * identify a CombVariableSlot + * Create new CombVariableSlot using receiver slot and declared slot, and return reference to it + * if no CombVariableSlot representing result of adapting declared slot to receiver slot exists. + * Otherwise, returns the existing CombVariableSlot. Receiver slot and declared slot can + * uniquely identify a CombVariableSlot * - * @param receiver - * receiver slot - * @param declared - * declared slot - * @return CombVariableSlot that represents the viewpoint adaptation result - * of adapting declared slot to receiver slot + * @param receiver receiver slot + * @param declared declared slot + * @return CombVariableSlot that represents the viewpoint adaptation result of adapting declared + * slot to receiver slot */ CombVariableSlot createCombVariableSlot(Slot receiver, Slot declared); // TODO(Zhiping): will rename LubVariableSlot to MergeVariableSlot /** - * Creates new LubVariableSlot using left slot and right slot, and returns - * reference to it if no LubVariableSlot representing least upper bound of - * left slot and right slot exists. Otherwise, returns the existing LubVariableSlot. - * Left slot and right slot can uniquely identify a slot that stores their - * least upper bound. + * Creates new LubVariableSlot using left slot and right slot, and returns reference to it if no + * LubVariableSlot representing least upper bound of left slot and right slot exists. Otherwise, + * returns the existing LubVariableSlot. Left slot and right slot can uniquely identify a slot + * that stores their least upper bound. * * @param left left side of merge operation * @param right right side of merge operation - * @return LubVariableSlot that represents the least upper bound result - * of left slot and right slot + * @return LubVariableSlot that represents the least upper bound result of left slot and right + * slot */ LubVariableSlot createLubMergeVariableSlot(Slot left, Slot right); /** - * Creates new LubVariableSlot using left slot and right slot, and returns - * reference to it if no LubVariableSlot representing greatest lower bound of - * left slot and right slot exists. Otherwise, returns the existing LubVariableSlot. - * Left slot and right slot can uniquely identify a slot that stores their - * greatest lower bound. + * Creates new LubVariableSlot using left slot and right slot, and returns reference to it if no + * LubVariableSlot representing greatest lower bound of left slot and right slot exists. + * Otherwise, returns the existing LubVariableSlot. Left slot and right slot can uniquely + * identify a slot that stores their greatest lower bound. * * @param left left side of merge operation * @param right right side of merge operation - * @return LubVariableSlot that represents the greatest lower bound result - * of left slot and right slot + * @return LubVariableSlot that represents the greatest lower bound result of left slot and + * right slot */ LubVariableSlot createGlbMergeVariableSlot(Slot left, Slot right); /** - * Create new ExistentialVariableSlot using potential slot and alternative - * slot, and return reference to it if no ExistentialVariableSlot that wraps - * this potentialSlot and alternativeSlot exists. Otherwise, returns the - * existing ExistentialVariableSlot. Potential slot and alternative slot can - * uniquely identify an ExistentialVariableSlot + * Create new ExistentialVariableSlot using potential slot and alternative slot, and return + * reference to it if no ExistentialVariableSlot that wraps this potentialSlot and + * alternativeSlot exists. Otherwise, returns the existing ExistentialVariableSlot. Potential + * slot and alternative slot can uniquely identify an ExistentialVariableSlot * - * @param potentialSlot - * a slot whose annotation may or may not exist in source - * @param alternativeSlot - * the slot which would take part in a constraint if - * {@code potentialSlot} does not exist - * @return the ExistentialVariableSlot that wraps this potentialSlot and - * alternativeSlot + * @param potentialSlot a slot whose annotation may or may not exist in source + * @param alternativeSlot the slot which would take part in a constraint if {@code + * potentialSlot} does not exist + * @return the ExistentialVariableSlot that wraps this potentialSlot and alternativeSlot */ ExistentialVariableSlot createExistentialVariableSlot(Slot potentialSlot, Slot alternativeSlot); @@ -180,54 +162,60 @@ ArithmeticVariableSlot createArithmeticVariableSlot( * @param thenBranch true if is for the then store, false if is for the else store * @return the ComparisonVariableSlot for the given location */ - ComparisonVariableSlot createComparisonVariableSlot(AnnotationLocation location, Slot refined, boolean thenBranch); + ComparisonVariableSlot createComparisonVariableSlot( + AnnotationLocation location, Slot refined, boolean thenBranch); /** * Create a VarAnnot equivalent to the given realQualifier. * * @return a VarAnnot equivalent to the given realQualifier. - * */ - AnnotationMirror createEquivalentVarAnno(final AnnotationMirror realQualifier); + AnnotationMirror createEquivalentVarAnno(final AnnotationMirror realQualifier); /** Return the slot identified by the given id or null if no such slot has been added */ - Slot getSlot( int id ); + Slot getSlot(int id); /** - * Given a slot return an annotation that represents the slot when added to an AnnotatedTypeMirror. - * If A is the annotation returned by getAnnotation( S ) where is a slot. Then getSlot( A ) will - * return S (or an equivalent Slot in case of Constants ). - * For {@code ConstantSlot}, this method should return the {@code VariableAnnotation} that represents - * the underlying constant, and one should use {@link ConstantSlot#getValue()} to get the real annotation. + * Given a slot return an annotation that represents the slot when added to an + * AnnotatedTypeMirror. If A is the annotation returned by getAnnotation( S ) where is a slot. + * Then getSlot( A ) will return S (or an equivalent Slot in case of Constants ). For {@code + * ConstantSlot}, this method should return the {@code VariableAnnotation} that represents the + * underlying constant, and one should use {@link ConstantSlot#getValue()} to get the real + * annotation. + * * @param slot A slot to convert to an annotation * @return An annotation representing the slot */ - AnnotationMirror getAnnotation( Slot slot ); + AnnotationMirror getAnnotation(Slot slot); /** - * Return the Slot (or an equivalent Slot) that is represented by the given AnnotationMirror. A RuntimeException - * is thrown if the annotation isn't a VarAnnot, RefVarAnnot, CombVarAnnot or a member of one of the - * REAL_QUALIFIER set provided by InferenceChecker. + * Return the Slot (or an equivalent Slot) that is represented by the given AnnotationMirror. A + * RuntimeException is thrown if the annotation isn't a VarAnnot, RefVarAnnot, CombVarAnnot or a + * member of one of the REAL_QUALIFIER set provided by InferenceChecker. + * * @param am The annotationMirror representing a Slot * @return The Slot (on an equivalent Slot) represented by annotationMirror */ - Slot getSlot( AnnotationMirror am ); + Slot getSlot(AnnotationMirror am); /** - * Return the Slot in the primary annotation location of annotated type mirror. If - * there is no Slot this method throws an exception + * Return the Slot in the primary annotation location of annotated type mirror. If there is no + * Slot this method throws an exception + * * @param atm An annotated type mirror with a VarAnnot in its primary annotations list */ Slot getSlot(AnnotatedTypeMirror atm); /** * Return all slots collected by this SlotManager + * * @return a list of slots */ List getSlots(); /** * Return all VariableSlots collected by this SlotManager + * * @return a lit of VariableSlots */ List getVariableSlots(); @@ -235,13 +223,13 @@ ArithmeticVariableSlot createArithmeticVariableSlot( List getConstantSlots(); /** - * This method informs slot manager of the current top level class tree that's being type processed. - * Slot manager can then preprocess this information by clearing caches, resolving slot default - * types, etc. + * This method informs slot manager of the current top level class tree that's being type + * processed. Slot manager can then preprocess this information by clearing caches, resolving + * slot default types, etc. * - * Note that trees that are not within this tree may be missing some information - * (in the JCTree implementation), and this is because they are either not fully - * initialized or being garbage-recycled. + *

Note that trees that are not within this tree may be missing some information (in the + * JCTree implementation), and this is because they are either not fully initialized or being + * garbage-recycled. */ void setTopLevelClass(ClassTree classTree); } diff --git a/src/checkers/inference/SolutionJaifUpdater.java b/src/checkers/inference/SolutionJaifUpdater.java index c49d05d73..ef3d65b93 100644 --- a/src/checkers/inference/SolutionJaifUpdater.java +++ b/src/checkers/inference/SolutionJaifUpdater.java @@ -1,5 +1,9 @@ package checkers.inference; +import org.json.simple.parser.ParseException; +import org.plumelib.options.Option; +import org.plumelib.options.Options; + import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; @@ -14,23 +18,20 @@ import java.util.Scanner; import java.util.Set; -import org.json.simple.parser.ParseException; - import checkers.inference.model.serialization.JsonDeserializer; -import org.plumelib.options.Option; -import org.plumelib.options.Options; /** - * * SolutionJaifUpdater takes in a solved json constraints file and a JAIF that contains - * {@link @VarAnnot} annotations and creates a new JAIF by replacing the @VarAnnots - * with the annotation for that @VarAnnot's id in the solution. + * {@link @VarAnnot} annotations and creates a new JAIF by replacing the @VarAnnots with the + * annotation for that @VarAnnot's id in the solution. * * @author mcarthur */ public class SolutionJaifUpdater { - public static final String CHECKERS_INFERENCE_QUALS_VAR_ANNOT = "@checkers.inference.qual.VarAnnot("; + public static final String CHECKERS_INFERENCE_QUALS_VAR_ANNOT = + "@checkers.inference.qual.VarAnnot("; + @Option("[filename] the input jaif.") public static String jaifFilename = "default.jaif"; @@ -52,7 +53,11 @@ public class SolutionJaifUpdater { public static void main(String[] args) throws IOException, ParseException { Options options = new Options("SolutionJaifUpdator [options]", SolutionJaifUpdater.class); options.parse(true, args); - if (solvedJson == null || originalJson == null || outputFilename == null || topAnnotation == null || botAnnotation == null) { + if (solvedJson == null + || originalJson == null + || outputFilename == null + || topAnnotation == null + || botAnnotation == null) { System.out.println("A required argument was not found."); options.printUsage(); System.exit(1); @@ -61,29 +66,36 @@ public static void main(String[] args) throws IOException, ParseException { String solvedJsonStr = readFile(solvedJson); JsonDeserializer solvedDeserializer = new JsonDeserializer(null, solvedJsonStr); - Map existentialValues = getExistentialValues(originalJson, solvedDeserializer); - Map solvedValues = getSolvedValues(solvedDeserializer, topAnnotation, botAnnotation); + Map existentialValues = + getExistentialValues(originalJson, solvedDeserializer); + Map solvedValues = + getSolvedValues(solvedDeserializer, topAnnotation, botAnnotation); updateJaif(solvedValues, existentialValues, jaifFilename, outputFilename); } /** - * Parses the inference.jaif file provided by verigames.jar and updates the variable values - * with a boolean of true/false depending on the results obtained from the updates xml file - * after the user plays the game. - * @param values Map where the integer is the variable id and the boolean - * is the value to replace the variable id with. + * Parses the inference.jaif file provided by verigames.jar and updates the variable values with + * a boolean of true/false depending on the results obtained from the updates xml file after the + * user plays the game. + * + * @param values Map where the integer is the variable id and the boolean is + * the value to replace the variable id with. * @param existentialValues * @throws FileNotFoundException thrown if the file inference.jaif is not found in the current - * directory. + * directory. */ - private static void updateJaif(Map values, Map existentialValues, - String jaifPath, String outputFile) throws FileNotFoundException { + private static void updateJaif( + Map values, + Map existentialValues, + String jaifPath, + String outputFile) + throws FileNotFoundException { if (values == null) { throw new IllegalArgumentException("Map passed must not be null"); } try (Scanner in = new Scanner(new File(jaifPath)); - PrintStream out = new PrintStream(new File(outputFile))) { + PrintStream out = new PrintStream(new File(outputFile))) { while (in.hasNextLine()) { String line = in.nextLine(); @@ -94,7 +106,10 @@ private static void updateJaif(Map values, Map String key = line.substring(end, line.length() - 1); if (values.get(key) == null) { - System.out.println("Warning: Could not find value for " + key + " using supertype, skipping"); + System.out.println( + "Warning: Could not find value for " + + key + + " using supertype, skipping"); } else { Boolean exists = existentialValues.get(key); if (exists == null || exists) { @@ -103,13 +118,14 @@ private static void updateJaif(Map values, Map } } - } else - out.println(line); + } else out.println(line); } } } - private static final Map getExistentialValues(String originalJsonFilename, JsonDeserializer solvedDeserializer) throws IOException, ParseException { + private static final Map getExistentialValues( + String originalJsonFilename, JsonDeserializer solvedDeserializer) + throws IOException, ParseException { String json = readFile(originalJsonFilename); JsonDeserializer deserializer = new JsonDeserializer(null, json); List allPotentialVariables = deserializer.getPotentialVariables(); @@ -123,10 +139,12 @@ private static final Map getExistentialValues(String originalJs return out; } - private static final Map getSolvedValues(JsonDeserializer deserializer, String top, String bottom) throws IOException, ParseException { + private static final Map getSolvedValues( + JsonDeserializer deserializer, String top, String bottom) + throws IOException, ParseException { Map values = deserializer.getAnnotationValues(); Map results = new HashMap<>(); - for (Map.Entry entry: values.entrySet()) { + for (Map.Entry entry : values.entrySet()) { String value = entry.getValue().equals("0") ? bottom : top; results.put(entry.getKey(), value); } diff --git a/src/checkers/inference/VariableAnnotator.java b/src/checkers/inference/VariableAnnotator.java index b4b48df17..4ad2ee9da 100644 --- a/src/checkers/inference/VariableAnnotator.java +++ b/src/checkers/inference/VariableAnnotator.java @@ -1,5 +1,30 @@ package checkers.inference; +import com.sun.source.tree.AnnotatedTypeTree; +import com.sun.source.tree.ArrayTypeTree; +import com.sun.source.tree.BinaryTree; +import com.sun.source.tree.ClassTree; +import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.tree.ExpressionTree; +import com.sun.source.tree.IntersectionTypeTree; +import com.sun.source.tree.MemberSelectTree; +import com.sun.source.tree.MethodTree; +import com.sun.source.tree.NewArrayTree; +import com.sun.source.tree.ParameterizedTypeTree; +import com.sun.source.tree.Tree; +import com.sun.source.tree.Tree.Kind; +import com.sun.source.tree.TypeParameterTree; +import com.sun.source.tree.UnionTypeTree; +import com.sun.source.tree.VariableTree; +import com.sun.source.tree.WildcardTree; +import com.sun.source.util.TreePath; +import com.sun.tools.javac.code.Symbol.ClassSymbol; +import com.sun.tools.javac.code.Symbol.MethodSymbol; +import com.sun.tools.javac.tree.JCTree; + +import org.checkerframework.afu.scenelib.io.ASTIndex; +import org.checkerframework.afu.scenelib.io.ASTPath; +import org.checkerframework.afu.scenelib.io.ASTRecord; import org.checkerframework.framework.type.AnnotatedTypeFactory; import org.checkerframework.framework.type.AnnotatedTypeMirror; import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType; @@ -14,11 +39,12 @@ import org.checkerframework.framework.type.visitor.AnnotatedTypeScanner; import org.checkerframework.javacutil.AnnotationBuilder; import org.checkerframework.javacutil.AnnotationMirrorSet; -import org.checkerframework.javacutil.ElementUtils; import org.checkerframework.javacutil.BugInCF; +import org.checkerframework.javacutil.ElementUtils; import org.checkerframework.javacutil.TreePathUtil; import org.checkerframework.javacutil.TreeUtils; import org.checkerframework.javacutil.TypesUtils; +import org.plumelib.util.IPair; import java.util.ArrayList; import java.util.HashMap; @@ -39,57 +65,31 @@ import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; -import com.sun.source.tree.AnnotatedTypeTree; -import com.sun.source.tree.ArrayTypeTree; -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.ClassTree; -import com.sun.source.tree.CompilationUnitTree; -import com.sun.source.tree.ExpressionTree; -import com.sun.source.tree.IntersectionTypeTree; -import com.sun.source.tree.MemberSelectTree; -import com.sun.source.tree.MethodTree; -import com.sun.source.tree.NewArrayTree; -import com.sun.source.tree.ParameterizedTypeTree; -import com.sun.source.tree.Tree; -import com.sun.source.tree.Tree.Kind; -import com.sun.source.tree.TypeParameterTree; -import com.sun.source.tree.UnionTypeTree; -import com.sun.source.tree.VariableTree; -import com.sun.source.tree.WildcardTree; -import com.sun.source.util.TreePath; -import com.sun.tools.javac.code.Symbol.ClassSymbol; -import com.sun.tools.javac.code.Symbol.MethodSymbol; -import com.sun.tools.javac.tree.JCTree; - -import org.checkerframework.afu.scenelib.io.ASTIndex; -import org.checkerframework.afu.scenelib.io.ASTPath; -import org.checkerframework.afu.scenelib.io.ASTRecord; import checkers.inference.model.AnnotationLocation; import checkers.inference.model.AnnotationLocation.AstPathLocation; import checkers.inference.model.AnnotationLocation.ClassDeclLocation; import checkers.inference.model.ConstantSlot; import checkers.inference.model.ConstraintManager; import checkers.inference.model.ExistentialVariableSlot; -import checkers.inference.model.SourceVariableSlot; import checkers.inference.model.Slot; +import checkers.inference.model.SourceVariableSlot; import checkers.inference.model.VariableSlot; import checkers.inference.model.tree.ArtificialExtendsBoundTree; import checkers.inference.qual.VarAnnot; import checkers.inference.util.ASTPathUtil; import checkers.inference.util.CopyUtil; import checkers.inference.util.InferenceUtil; -import org.plumelib.util.IPair; /** - * VariableAnnotator takes a type and the tree that the type represents. It determines what locations on the tree - * should contain a slot (i.e. locations over which we are doing inference). For each one of these locations - * it: - * 1. Checks to see if that tree has been given a VariableSlot previously, if so skip to 3 - * 2. Creates the appropriate VariableSlot or ConstantSlot for the location - * 3. Adds an annotation representing that slot to the AnnotatedTypeMirror that corresponds to the given tree - * 4. Stores a mapping of tree -> VariableSlot for the given tree if it contains a VariableSlot + * VariableAnnotator takes a type and the tree that the type represents. It determines what + * locations on the tree should contain a slot (i.e. locations over which we are doing inference). + * For each one of these locations it: 1. Checks to see if that tree has been given a VariableSlot + * previously, if so skip to 3 2. Creates the appropriate VariableSlot or ConstantSlot for the + * location 3. Adds an annotation representing that slot to the AnnotatedTypeMirror that corresponds + * to the given tree 4. Stores a mapping of tree -> VariableSlot for the given tree if it contains a + * VariableSlot */ -public class VariableAnnotator extends AnnotatedTypeScanner { +public class VariableAnnotator extends AnnotatedTypeScanner { private static final Logger logger = Logger.getLogger(VariableAnnotator.class.getName()); @@ -101,17 +101,16 @@ public class VariableAnnotator extends AnnotatedTypeScanner { protected final ConstraintManager constraintManager; /** - * Store the corresponding slot and annotation mirrors for each - * tree. The second parameter of pair is needed because sometimes the - * annotation mirror for a tree is calculated (i.e least upper bound for - * binary tree), and the calculated result is cached in the set. - **/ + * Store the corresponding slot and annotation mirrors for each tree. The second parameter of + * pair is needed because sometimes the annotation mirror for a tree is calculated (i.e least + * upper bound for binary tree), and the calculated result is cached in the set. + */ protected final Map>> treeToVarAnnoPair; - /** Store elements that have already been annotated **/ + /** Store elements that have already been annotated * */ private final Map elementToAtm; - private final Map, ExistentialVariableSlot> idsToExistentialSlots; + private final Map, ExistentialVariableSlot> idsToExistentialSlots; private final AnnotatedTypeFactory realTypeFactory; private final InferrableChecker realChecker; @@ -121,17 +120,20 @@ public class VariableAnnotator extends AnnotatedTypeScanner { // The key is the most specific identifiable object. /** Element is that class Element that we are storing. */ private final Map extendsMissingTrees; + /** Element is the method for the implicit receiver we are storing. */ private final Map receiverMissingTrees; + /** Key is the NewArray Tree */ private final Map newArrayMissingTrees; + /** Class declarations may (or may not) have annotations that act as bound. */ private final Map classDeclAnnos; - /** When inferring the type of polymorphic qualifiers we create one new Variable to - * represent the call-site value of that qualifier. This map keeps track of - * methodCall -> variable created to represent Poly qualifiers - * See InferenceQualifierPolymorphism. + /** + * When inferring the type of polymorphic qualifiers we create one new Variable to represent the + * call-site value of that qualifier. This map keeps track of methodCall -> variable created to + * represent Poly qualifiers See InferenceQualifierPolymorphism. */ private final Map treeToPolyVar; @@ -144,15 +146,17 @@ public class VariableAnnotator extends AnnotatedTypeScanner { private final ExistentialVariableInserter existentialInserter; private final ImpliedTypeAnnotator impliedTypeAnnotator; - public VariableAnnotator(final InferenceAnnotatedTypeFactory typeFactory, - final AnnotatedTypeFactory realTypeFactory, - final InferrableChecker realChecker, - final SlotManager slotManager, ConstraintManager constraintManager) { + public VariableAnnotator( + final InferenceAnnotatedTypeFactory typeFactory, + final AnnotatedTypeFactory realTypeFactory, + final InferrableChecker realChecker, + final SlotManager slotManager, + ConstraintManager constraintManager) { this.realTypeFactory = realTypeFactory; this.inferenceTypeFactory = typeFactory; this.slotManager = slotManager; this.treeToVarAnnoPair = new HashMap<>(); - this.elementToAtm = new HashMap<>(); + this.elementToAtm = new HashMap<>(); this.extendsMissingTrees = new HashMap<>(); this.receiverMissingTrees = new HashMap<>(); this.newArrayMissingTrees = new HashMap<>(); @@ -161,16 +165,19 @@ public VariableAnnotator(final InferenceAnnotatedTypeFactory typeFactory, this.classDeclAnnos = new HashMap<>(); this.realChecker = realChecker; this.constraintManager = constraintManager; - this.varAnnot = new AnnotationBuilder(typeFactory.getProcessingEnv(), VarAnnot.class).build(); - this.realTop = realTypeFactory.getQualifierHierarchy().getTopAnnotations().iterator().next(); + this.varAnnot = + new AnnotationBuilder(typeFactory.getProcessingEnv(), VarAnnot.class).build(); + this.realTop = + realTypeFactory.getQualifierHierarchy().getTopAnnotations().iterator().next(); - this.existentialInserter = new ExistentialVariableInserter(slotManager, constraintManager, this.realTop, - varAnnot, this); + this.existentialInserter = + new ExistentialVariableInserter( + slotManager, constraintManager, this.realTop, varAnnot, this); - this.impliedTypeAnnotator = new ImpliedTypeAnnotator(inferenceTypeFactory, slotManager, existentialInserter); + this.impliedTypeAnnotator = + new ImpliedTypeAnnotator(inferenceTypeFactory, slotManager, existentialInserter); } - public static AnnotationLocation treeToLocation(AnnotatedTypeFactory typeFactory, Tree tree) { final TreePath path = typeFactory.getPath(tree); @@ -179,10 +186,12 @@ public static AnnotationLocation treeToLocation(AnnotatedTypeFactory typeFactory } // else ASTPathUtil.getASTRecordForPath(typeFactory, path); - if (tree.getKind() == Kind.CLASS || tree.getKind() == Kind.INTERFACE - || tree.getKind() == Kind.ENUM || tree.getKind() == Kind.ANNOTATION_TYPE) { + if (tree.getKind() == Kind.CLASS + || tree.getKind() == Kind.INTERFACE + || tree.getKind() == Kind.ENUM + || tree.getKind() == Kind.ANNOTATION_TYPE) { TypeElement typeElement = TreeUtils.elementFromDeclaration((ClassTree) tree); - return new ClassDeclLocation(((ClassSymbol)typeElement).flatName().toString()); + return new ClassDeclLocation(((ClassSymbol) typeElement).flatName().toString()); } // else ASTRecord record = ASTPathUtil.getASTRecordForPath(typeFactory, path); @@ -191,7 +200,6 @@ public static AnnotationLocation treeToLocation(AnnotatedTypeFactory typeFactory } return new AstPathLocation(record); - } protected AnnotationLocation treeToLocation(Tree tree) { @@ -199,16 +207,20 @@ protected AnnotationLocation treeToLocation(Tree tree) { } /** - * For each method call that uses a method with a polymorphic qualifier, we replace all uses of that polymorphic - * qualifier with a Variable. Sometimes we might have to later retrieve that qualifier for a given invocation - * tree. This method will return a previously created variable for a given invocation tree OR create a new - * one and return it, if we haven't created one for the given tree. see InferenceQualifierPolymorphism + * For each method call that uses a method with a polymorphic qualifier, we replace all uses of + * that polymorphic qualifier with a Variable. Sometimes we might have to later retrieve that + * qualifier for a given invocation tree. This method will return a previously created variable + * for a given invocation tree OR create a new one and return it, if we haven't created one for + * the given tree. see InferenceQualifierPolymorphism + * * @return The Variable representing PolymorphicQualifier for the given tree */ public VariableSlot getOrCreatePolyVar(Tree tree) { VariableSlot polyVar = treeToPolyVar.get(tree); if (polyVar == null) { - polyVar = slotManager.createPolymorphicInstanceSlot(treeToLocation(tree), TreeUtils.typeOf(tree)); + polyVar = + slotManager.createPolymorphicInstanceSlot( + treeToLocation(tree), TreeUtils.typeOf(tree)); treeToPolyVar.put(tree, polyVar); } @@ -216,64 +228,66 @@ public VariableSlot getOrCreatePolyVar(Tree tree) { } /** - * Creates a variable for the given tree, adds it to the slotManager, and returns it. The - * only variables not created by this method should be those that are attached to an "implied tree", - * (e.g. the "extends Object" that is implied in the declaration class MyClass {}). In those - * cases the ASTPath should be created in the calling method and the createVariable(ASTPath astPat) - * method should be used. + * Creates a variable for the given tree, adds it to the slotManager, and returns it. The only + * variables not created by this method should be those that are attached to an "implied tree", + * (e.g. the "extends Object" that is implied in the declaration class MyClass {}). In those + * cases the ASTPath should be created in the calling method and the createVariable(ASTPath + * astPat) method should be used. * - * @param tree The tree to create a variable for. Tree will be converted to an ASTPath that will - * be passed to the created variable + * @param tree The tree to create a variable for. Tree will be converted to an ASTPath that will + * be passed to the created variable * @return A new VariableSlot corresponding to tree */ private SourceVariableSlot createVariable(final Tree tree) { - final SourceVariableSlot varSlot = createVariable(treeToLocation(tree), TreeUtils.typeOf(tree)); - -// if (path != null) { -// Element element = inferenceTypeFactory.getTreeUtils().getElement(path); -// if ( (!element.getKind().isClass() && element.getKind().isInterface() && element.getKind().isField())) { -// -// } -// } - - final IPair> varATMPair = IPair - .> of(varSlot, - new AnnotationMirrorSet()); + final SourceVariableSlot varSlot = + createVariable(treeToLocation(tree), TreeUtils.typeOf(tree)); + + // if (path != null) { + // Element element = inferenceTypeFactory.getTreeUtils().getElement(path); + // if ( (!element.getKind().isClass() && element.getKind().isInterface() && + // element.getKind().isField())) { + // + // } + // } + + final IPair> varATMPair = + IPair.>of(varSlot, new AnnotationMirrorSet()); treeToVarAnnoPair.put(tree, varATMPair); logger.fine("Created variable for tree:\n" + varSlot.getId() + " => " + tree); return varSlot; } /** - * Creates a variable with the given ASTPath, adds it to the slotManager, and returns it. This method - * should be used ONLY for "implied trees". That is, locations that don't exist in the source code - * but are implied by other trees. The created variable is also added to the SlotManager - * (e.g. the "extends Object" bound that is implied by in the declaration class MyClass extends List{}). + * Creates a variable with the given ASTPath, adds it to the slotManager, and returns it. This + * method should be used ONLY for "implied trees". That is, locations that don't exist in the + * source code but are implied by other trees. The created variable is also added to the + * SlotManager (e.g. the "extends Object" bound that is implied by in the declaration class + * MyClass extends List{}). * - * @param location The path to the "missing tree". That is, the path to the parent tree with the path to the - * actual implied tree appended to it. + * @param location The path to the "missing tree". That is, the path to the parent tree with the + * path to the actual implied tree appended to it. * @return A new VariableSlot corresponding to tree */ private SourceVariableSlot createVariable(final AnnotationLocation location, TypeMirror type) { - final SourceVariableSlot variableSlot = slotManager - .createSourceVariableSlot(location, type); + final SourceVariableSlot variableSlot = + slotManager.createSourceVariableSlot(location, type); return variableSlot; } public ConstantSlot createConstant(final AnnotationMirror value, final Tree tree) { final ConstantSlot constantSlot = slotManager.createConstantSlot(value); -// if (path != null) { -// Element element = inferenceTypeFactory.getTreeUtils().getElement(path); -// if ( (!element.getKind().isClass() && element.getKind().isInterface() && element.getKind().isField())) { -// -// } -// } + // if (path != null) { + // Element element = inferenceTypeFactory.getTreeUtils().getElement(path); + // if ( (!element.getKind().isClass() && element.getKind().isInterface() && + // element.getKind().isField())) { + // + // } + // } Set annotations = new AnnotationMirrorSet(); annotations.add(constantSlot.getValue()); - final IPair> varATMPair = IPair - .> of(constantSlot, - annotations); + final IPair> varATMPair = + IPair.>of(constantSlot, annotations); treeToVarAnnoPair.put(tree, varATMPair); logger.fine("Created constant for tree:\n" + constantSlot.getId() + " => " + tree); return constantSlot; @@ -281,39 +295,43 @@ public ConstantSlot createConstant(final AnnotationMirror value, final Tree tree /** * ExistentialVariableSlot are used when a constraint should appear in an ExistentialConstraint. - * Between two variable slots (a potential and alternative) we only ever need to create - * 1 existential variable slot which we can then reuse. + * Between two variable slots (a potential and alternative) we only ever need to create 1 + * existential variable slot which we can then reuse. * - * If one does not already exist, this method creates an existential variable slot between - * potentialVariable and alternative and stores it. - * Otherwise, it returns the previously stored ExistentialVariableSlot + *

If one does not already exist, this method creates an existential variable slot between + * potentialVariable and alternative and stores it. Otherwise, it returns the previously stored + * ExistentialVariableSlot * - * This method then applies the existential variable as a primary annotation on atm + *

This method then applies the existential variable as a primary annotation on atm */ - ExistentialVariableSlot getOrCreateExistentialVariable(final AnnotatedTypeMirror atm, - final Slot potentialVariable, - final Slot alternativeSlot) { - ExistentialVariableSlot existentialVariable = getOrCreateExistentialVariable(potentialVariable, alternativeSlot); + ExistentialVariableSlot getOrCreateExistentialVariable( + final AnnotatedTypeMirror atm, + final Slot potentialVariable, + final Slot alternativeSlot) { + ExistentialVariableSlot existentialVariable = + getOrCreateExistentialVariable(potentialVariable, alternativeSlot); atm.replaceAnnotation(slotManager.getAnnotation(existentialVariable)); return existentialVariable; } /** * ExistentialVariableSlot are used when a constraint should appear in an ExistentialConstraint. - * Between two variable slots (a potential and alternative) we only ever need to create - * 1 existential variable slot which we can then reuse. + * Between two variable slots (a potential and alternative) we only ever need to create 1 + * existential variable slot which we can then reuse. * - * If one does not already exist, this method creates an existential variable slot between - * potentialVariable and alternative and stores it. - * Otherwise, it returns the previously stored ExistentialVariableSlot + *

If one does not already exist, this method creates an existential variable slot between + * potentialVariable and alternative and stores it. Otherwise, it returns the previously stored + * ExistentialVariableSlot */ - ExistentialVariableSlot getOrCreateExistentialVariable(final Slot potentialVariable, - final Slot alternativeSlot) { - final IPair idPair = IPair.of(potentialVariable.getId(), alternativeSlot.getId()); + ExistentialVariableSlot getOrCreateExistentialVariable( + final Slot potentialVariable, final Slot alternativeSlot) { + final IPair idPair = + IPair.of(potentialVariable.getId(), alternativeSlot.getId()); ExistentialVariableSlot existentialVariable = idsToExistentialSlots.get(idPair); if (existentialVariable == null) { - existentialVariable = slotManager.createExistentialVariableSlot(potentialVariable, alternativeSlot); + existentialVariable = + slotManager.createExistentialVariableSlot(potentialVariable, alternativeSlot); idsToExistentialSlots.put(idPair, existentialVariable); } // else @@ -321,45 +339,48 @@ ExistentialVariableSlot getOrCreateExistentialVariable(final Slot potentialVaria } /** - * When getting trees to annotate types we sometimes need them from other compilation units (this occurs - * in calls to directSupertypes for instance). TypeFactory.getPath will NOT find these trees - * instead use getPath. Note, this call should not be made often since we do not cache any of the tree - * lookups and we re-traverse from the root everytime. + * When getting trees to annotate types we sometimes need them from other compilation units + * (this occurs in calls to directSupertypes for instance). TypeFactory.getPath will NOT find + * these trees instead use getPath. Note, this call should not be made often since we do not + * cache any of the tree lookups and we re-traverse from the root everytime. */ - public static TreePath expensiveBackupGetPath(final Element element, final Tree tree, final InferenceAnnotatedTypeFactory inferenceTypeFactory) { + public static TreePath expensiveBackupGetPath( + final Element element, + final Tree tree, + final InferenceAnnotatedTypeFactory inferenceTypeFactory) { TypeElement typeElement = ElementUtils.enclosingTypeElement(element); - CompilationUnitTree compilationUnitTree = inferenceTypeFactory.getTreeUtils().getPath(typeElement).getCompilationUnit(); + CompilationUnitTree compilationUnitTree = + inferenceTypeFactory.getTreeUtils().getPath(typeElement).getCompilationUnit(); return inferenceTypeFactory.getTreeUtils().getPath(compilationUnitTree, tree); } /** - * Adds existential variables to a USE of a type parameter. - * Note: See ExistentialVariableSlot for a key to the shorthand used below. + * Adds existential variables to a USE of a type parameter. Note: See ExistentialVariableSlot + * for a key to the shorthand used below. * - * E.g. if we have a type parameter: {@code - * <@0 T extends @1 Object> - * } - * And we have a use of T: {@code - * T t; - * } - * Then the type of t should be: {@code - * <(@2 (@3 | @0)) T extends (@4 (@3 | @1)) Object - * } + *

E.g. if we have a type parameter: {@code <@0 T extends @1 Object> } And we have a use of + * T: {@code T t; } Then the type of t should be: {@code <(@2 (@3 | @0)) T extends (@4 (@3 + * | @1)) Object } * - * @param typeVar A use of a type parameter + * @param typeVar A use of a type parameter * @param tree The tree corresponding to the use of the type parameter */ - private void addExistentialVariable(final AnnotatedTypeVariable typeVar, final Tree tree, boolean isUpperBoundOfTypeParam) { + private void addExistentialVariable( + final AnnotatedTypeVariable typeVar, final Tree tree, boolean isUpperBoundOfTypeParam) { // TODO: THINK THROUGH POLY QUALS - // Leave polymorphic qualifiers on the type. They will be replaced during methodFromUse/constructorFromUse. -// if (typeVar.getAnnotations().size() > 0) { -// for (AnnotationMirror aa : typeVar.getAnnotations().iterator().next().getAnnotationType().asElement().getAnnotationMirrors()) { -// if (aa.getAnnotationType().toString().equals(PolymorphicQualifier.class.getCanonicalName())) { -// return; -// } -// } -// } + // Leave polymorphic qualifiers on the type. They will be replaced during + // methodFromUse/constructorFromUse. + // if (typeVar.getAnnotations().size() > 0) { + // for (AnnotationMirror aa : + // typeVar.getAnnotations().iterator().next().getAnnotationType().asElement().getAnnotationMirrors()) { + // if + // (aa.getAnnotationType().toString().equals(PolymorphicQualifier.class.getCanonicalName())) + // { + // return; + // } + // } + // } final Slot potentialVariable; final Element varElem; @@ -375,20 +396,31 @@ private void addExistentialVariable(final AnnotatedTypeVariable typeVar, final T final boolean isReturn; if (tree.getKind() == Kind.IDENTIFIER) { - // so this can happen when we call direct supertypes on a type for which we have the class's source - // file. The tree here is a type variable in that file and therefore cannot be found from + // so this can happen when we call direct supertypes on a type for which we have the + // class's source + // file. The tree here is a type variable in that file and therefore cannot be found + // from // the root of the current compilation unit via the type factory. TreePath pathToTree = inferenceTypeFactory.getPath(tree); if (pathToTree == null) { - pathToTree = expensiveBackupGetPath(varElem, tree, inferenceTypeFactory).getParentPath(); + pathToTree = + expensiveBackupGetPath(varElem, tree, inferenceTypeFactory).getParentPath(); if (pathToTree == null) { - throw new BugInCF("Could not find path to tree: " + tree + "\n" - + "typeVar=" + typeVar + "\n" - + "tree=" + tree + "\n" - + "isUpperBoundOfTypeParam=" + isUpperBoundOfTypeParam); + throw new BugInCF( + "Could not find path to tree: " + + tree + + "\n" + + "typeVar=" + + typeVar + + "\n" + + "tree=" + + tree + + "\n" + + "isUpperBoundOfTypeParam=" + + isUpperBoundOfTypeParam); } } @@ -405,10 +437,9 @@ private void addExistentialVariable(final AnnotatedTypeVariable typeVar, final T isReturn = false; } // TODO: I think this was to guard against declarations getting here but I think - // TODO: we might want to remove this check and just always add them (because declarations shouldn't get here?) - if (elementToAtm.containsKey(varElem) - && !isUpperBoundOfTypeParam - && !isReturn) { + // TODO: we might want to remove this check and just always add them (because declarations + // shouldn't get here?) + if (elementToAtm.containsKey(varElem) && !isUpperBoundOfTypeParam && !isReturn) { typeVar.clearAnnotations(); annotateElementFromStore(varElem, typeVar); return; @@ -426,22 +457,28 @@ private void addExistentialVariable(final AnnotatedTypeVariable typeVar, final T // if(tree.getKind() == ) // TODO: GOTTA FIGURE OUT IDENTIFIER STUFF if (!typeVar.getAnnotations().isEmpty()) { if (typeVar.getAnnotations().size() > 2) { - throw new BugInCF("There should be only 1 or 2 primary annotation on the typevar: \n" - + "typeVar=" + typeVar + "\n" - + "tree=" + tree + "\n"); + throw new BugInCF( + "There should be only 1 or 2 primary annotation on the typevar: \n" + + "typeVar=" + + typeVar + + "\n" + + "tree=" + + tree + + "\n"); } typeVar.clearAnnotations(); } potentialVariable = createVariable(typeTree); - final IPair> varATMPair = IPair - .> of( - potentialVariable, typeVar.getAnnotations()); + final IPair> varATMPair = + IPair.>of( + potentialVariable, typeVar.getAnnotations()); treeToVarAnnoPair.put(typeTree, varATMPair); // TODO: explicitPrimary is null at this point! Someone needs to set it. if (explicitPrimary != null) { - constraintManager.addEqualityConstraint(potentialVariable, slotManager.getSlot(explicitPrimary)); + constraintManager.addEqualityConstraint( + potentialVariable, slotManager.getSlot(explicitPrimary)); } } @@ -454,11 +491,13 @@ private void addExistentialVariable(final AnnotatedTypeVariable typeVar, final T } else { typeVarDecl = elementToAtm.get(typeVarDeclElem); // TODO: I THINK THIS IS UNNECESSARY DUE TO InferenceVisitor.visitVariable -// if(tree instanceof VariableTree && !treeToVariable.containsKey(tree)) { // if it's a declaration of a variable, store it -// final Element varElement = TreeUtils.elementFromDeclaration((VariableTree) tree); -// storeElementType(varElement, typeVar); -// treeToVariable.put(tree, potentialVariable); -// } + // if(tree instanceof VariableTree && !treeToVariable.containsKey(tree)) { // + // if it's a declaration of a variable, store it + // final Element varElement = + // TreeUtils.elementFromDeclaration((VariableTree) tree); + // storeElementType(varElement, typeVar); + // treeToVariable.put(tree, potentialVariable); + // } } existentialInserter.insert(potentialVariable, typeVar, typeVarDecl); @@ -478,19 +517,20 @@ private boolean isInUpperBound(TreePath path) { } } while (parent.getKind() == Kind.PARAMETERIZED_TYPE - || parent.getKind() == Kind.ANNOTATED_TYPE); + || parent.getKind() == Kind.ANNOTATED_TYPE); return false; } /** - * If treeToVariable contains tree, add the stored variable as a primary annotation to atm - * If treeToVariable does not contain tree, create a new variable as a primary annotation to atm + * If treeToVariable contains tree, add the stored variable as a primary annotation to atm If + * treeToVariable does not contain tree, create a new variable as a primary annotation to atm + * + *

If any annotation exist on Atm already create an EqualityConstraint between that + * annotation and the one added to atm. The original annotation is cleared from atm * - * If any annotation exist on Atm already create an EqualityConstraint between that annotation and - * the one added to atm. The original annotation is cleared from atm - * @param atm Annotation mirror representing tree, atm will have a VarAnnot as its primary annotation - * after this method completes + * @param atm Annotation mirror representing tree, atm will have a VarAnnot as its primary + * annotation after this method completes * @param tree Tree for which we want to create variables */ private Slot addPrimaryVariable(AnnotatedTypeMirror atm, final Tree tree) { @@ -499,25 +539,26 @@ private Slot addPrimaryVariable(AnnotatedTypeMirror atm, final Tree tree) { if (treeToVarAnnoPair.containsKey(tree)) { variable = treeToVarAnnoPair.get(tree).first; - // The record will be null if we created a variable for a tree in a different compilation unit. + // The record will be null if we created a variable for a tree in a different + // compilation unit. // When that compilation unit is visited we will be able to get the record. - if ((variable instanceof VariableSlot) && ((VariableSlot) variable).getLocation() == null) { + if ((variable instanceof VariableSlot) + && ((VariableSlot) variable).getLocation() == null) { ((VariableSlot) variable).setLocation(treeToLocation(tree)); } } else { AnnotationLocation location = treeToLocation(tree); variable = replaceOrCreateEquivalentVarAnno(atm, tree, location); - MethodTree enclosingMethod = TreePathUtil.enclosingMethod(inferenceTypeFactory.getPath(tree)); - if (enclosingMethod != null - && TreeUtils.isAnonymousConstructor(enclosingMethod)) { + MethodTree enclosingMethod = + TreePathUtil.enclosingMethod(inferenceTypeFactory.getPath(tree)); + if (enclosingMethod != null && TreeUtils.isAnonymousConstructor(enclosingMethod)) { // Slots created for anonymous constructors should not be inserted to source code ((SourceVariableSlot) variable).setInsertable(false); } - final IPair> varATMPair = IPair - .of(variable, - new AnnotationMirrorSet()); + final IPair> varATMPair = + IPair.of(variable, new AnnotationMirrorSet()); treeToVarAnnoPair.put(tree, varATMPair); } @@ -529,19 +570,17 @@ private Slot addPrimaryVariable(AnnotatedTypeMirror atm, final Tree tree) { } /** - * If we have a tree to a type use that is implied, such as:{@code - * extends String - * } - * Create a variable for the primary annotation on the type. For the above example, - * the record argument would be an ASTRecord that points to the annotation @1 below: {@code - * extends @1 String - * } + * If we have a tree to a type use that is implied, such as:{@code extends String } Create a + * variable for the primary annotation on the type. For the above example, the record argument + * would be an ASTRecord that points to the annotation @1 below: {@code extends @1 String } * - * We create a variable annotation for @1 and place it in the primary annotation position of + *

We create a variable annotation for @1 and place it in the primary annotation position of * the type. */ - public SourceVariableSlot addImpliedPrimaryVariable(AnnotatedTypeMirror atm, final AnnotationLocation location) { - SourceVariableSlot variable = slotManager.createSourceVariableSlot(location, atm.getUnderlyingType()); + public SourceVariableSlot addImpliedPrimaryVariable( + AnnotatedTypeMirror atm, final AnnotationLocation location) { + SourceVariableSlot variable = + slotManager.createSourceVariableSlot(location, atm.getUnderlyingType()); atm.addAnnotation(slotManager.getAnnotation(variable)); AnnotationMirror realAnno = atm.getAnnotationInHierarchy(realTop); @@ -555,10 +594,12 @@ public SourceVariableSlot addImpliedPrimaryVariable(AnnotatedTypeMirror atm, fin } /** - * Given an atm, replace its real annotation from pre-annotated code and implicit from the underlying type system - * by the equivalent varAnnotation, or creating a new VarAnnotation for it if doesn't have any existing annotations. + * Given an atm, replace its real annotation from pre-annotated code and implicit from the + * underlying type system by the equivalent varAnnotation, or creating a new VarAnnotation for + * it if doesn't have any existing annotations. */ - private Slot replaceOrCreateEquivalentVarAnno(AnnotatedTypeMirror atm, Tree tree, final AnnotationLocation location) { + private Slot replaceOrCreateEquivalentVarAnno( + AnnotatedTypeMirror atm, Tree tree, final AnnotationLocation location) { Slot varSlot = null; AnnotationMirror realQualifier = null; @@ -568,13 +609,18 @@ private Slot replaceOrCreateEquivalentVarAnno(AnnotatedTypeMirror atm, Tree tree } else if (!atm.getAnnotations().isEmpty()) { realQualifier = atm.getAnnotationInHierarchy(realTop); if (realQualifier == null) { - throw new BugInCF("The annotation(s) on the given type is neither VarAnno nor real qualifier!" - + "Atm is: " + atm + " annotations: " + atm.getAnnotations()); + throw new BugInCF( + "The annotation(s) on the given type is neither VarAnno nor real qualifier!" + + "Atm is: " + + atm + + " annotations: " + + atm.getAnnotations()); } varSlot = slotManager.createConstantSlot(realQualifier); - } else if (tree != null && realChecker.isConstant(tree) ) { + } else if (tree != null && realChecker.isConstant(tree)) { // Considered constant by real type system - realQualifier = realTypeFactory.getAnnotatedType(tree).getAnnotationInHierarchy(realTop); + realQualifier = + realTypeFactory.getAnnotatedType(tree).getAnnotationInHierarchy(realTop); varSlot = slotManager.createConstantSlot(realQualifier); } else { varSlot = createVariable(location, atm.getUnderlyingType()); @@ -595,6 +641,7 @@ public ConstantSlot getTopConstant() { /** * Stores the given AnnotatedTypeMirror with element as a key. + * * @see checkers.inference.VariableAnnotator#annotateElementFromStore */ public void storeElementType(final Element element, final AnnotatedTypeMirror atm) { @@ -602,14 +649,13 @@ public void storeElementType(final Element element, final AnnotatedTypeMirror at } /** - * For the given tree, create or retrieve variable or constant annotations and place - * them on the AnnotatedDeclaredType. Note, often AnnotatedDeclaredTypes are associated with VariableTrees - * but they should NOT be passed as a tree here. Instead pass their identifier. + * For the given tree, create or retrieve variable or constant annotations and place them on the + * AnnotatedDeclaredType. Note, often AnnotatedDeclaredTypes are associated with VariableTrees + * but they should NOT be passed as a tree here. Instead pass their identifier. * * @param adt A type to annotate - * @param tree A tree of kind: - * ANNOTATION_TYPE, CLASS, INTERFACE, ENUM, STRING_LITERAL, IDENTIFIER, - * ANNOTATED_TYPE, TYPE_PARAMETER, MEMBER_SELECT, PARAMETERIZED_TYPE + * @param tree A tree of kind: ANNOTATION_TYPE, CLASS, INTERFACE, ENUM, STRING_LITERAL, + * IDENTIFIER, ANNOTATED_TYPE, TYPE_PARAMETER, MEMBER_SELECT, PARAMETERIZED_TYPE * @return null */ @Override @@ -618,7 +664,7 @@ public Void visitDeclared(final AnnotatedDeclaredType adt, final Tree tree) { if (tree instanceof BinaryTree) { // Since there are so many kinds of binary trees // handle these with an if instead of in the switch. - handleBinaryTree(adt, (BinaryTree)tree); + handleBinaryTree(adt, (BinaryTree) tree); return null; } @@ -626,109 +672,122 @@ public Void visitDeclared(final AnnotatedDeclaredType adt, final Tree tree) { // TODO: and make a constraint between it switch (tree.getKind()) { - case ANNOTATION_TYPE: - case CLASS: - case INTERFACE: - case ENUM: // TODO: MORE TO DO HERE? - handleClassDeclaration(adt, (ClassTree) tree); - break; - - case ANNOTATED_TYPE: // We need to do this for Identifiers that are - // already annotated. - case STRING_LITERAL: - case IDENTIFIER: - Slot primary = addPrimaryVariable(adt, tree); - handleWasRawDeclaredTypes(adt); - addDeclarationConstraints(getOrCreateDeclBound(adt), primary); - break; - - case VARIABLE: - final Element varElement = TreeUtils.elementFromDeclaration((VariableTree) tree); - if (varElement.getKind() == ElementKind.ENUM_CONSTANT) { - AnnotatedTypeMirror realType = realTypeFactory.getAnnotatedType(tree); - CopyUtil.copyAnnotations(realType, adt); - inferenceTypeFactory.getConstantToVariableAnnotator().visit(adt); - } else { - // calls this method again but with a ParameterizedTypeTree - visitDeclared(adt, ((VariableTree) tree).getType()); - } - break; + case ANNOTATION_TYPE: + case CLASS: + case INTERFACE: + case ENUM: // TODO: MORE TO DO HERE? + handleClassDeclaration(adt, (ClassTree) tree); + break; - case TYPE_PARAMETER: - // TODO: I assume that the only way a TypeParameterTree is going to - // have an ADT as its - // TODO: AnnotatedTypeMirror is through either a - // getEffectiveAnnotation call or some other - // TODO: call that will treat the type parameter as it's upper bound - // but we should probably - // TODO: inspect this in order to have an idea of when this happens + case ANNOTATED_TYPE: // We need to do this for Identifiers that are + // already annotated. + case STRING_LITERAL: + case IDENTIFIER: + Slot primary = addPrimaryVariable(adt, tree); + handleWasRawDeclaredTypes(adt); + addDeclarationConstraints(getOrCreateDeclBound(adt), primary); + break; + + case VARIABLE: + final Element varElement = TreeUtils.elementFromDeclaration((VariableTree) tree); + if (varElement.getKind() == ElementKind.ENUM_CONSTANT) { + AnnotatedTypeMirror realType = realTypeFactory.getAnnotatedType(tree); + CopyUtil.copyAnnotations(realType, adt); + inferenceTypeFactory.getConstantToVariableAnnotator().visit(adt); + } else { + // calls this method again but with a ParameterizedTypeTree + visitDeclared(adt, ((VariableTree) tree).getType()); + } + break; - final TypeParameterTree typeParamTree = (TypeParameterTree) tree; + case TYPE_PARAMETER: + // TODO: I assume that the only way a TypeParameterTree is going to + // have an ADT as its + // TODO: AnnotatedTypeMirror is through either a + // getEffectiveAnnotation call or some other + // TODO: call that will treat the type parameter as it's upper bound + // but we should probably + // TODO: inspect this in order to have an idea of when this happens + + final TypeParameterTree typeParamTree = (TypeParameterTree) tree; + + if (typeParamTree.getBounds().isEmpty()) { + primary = addPrimaryVariable(adt, tree); + addDeclarationConstraints(getOrCreateDeclBound(adt), primary); + // TODO: HANDLE MISSING EXTENDS BOUND? + } else { + visit(adt, typeParamTree.getBounds().get(0)); + } + break; - if (typeParamTree.getBounds().isEmpty()) { + case MEMBER_SELECT: primary = addPrimaryVariable(adt, tree); + // We only need to dive into the expression if it is not an + // identifier. + // Otherwise we may try to annotate the outer class for a + // Outer.Inner static class. + if (adt.getEnclosingType() != null + && ((MemberSelectTree) tree).getExpression().getKind() + != Tree.Kind.IDENTIFIER) { + visit(adt.getEnclosingType(), ((MemberSelectTree) tree).getExpression()); + } addDeclarationConstraints(getOrCreateDeclBound(adt), primary); - // TODO: HANDLE MISSING EXTENDS BOUND? - } else { - visit(adt, typeParamTree.getBounds().get(0)); - } - break; - - case MEMBER_SELECT: - primary = addPrimaryVariable(adt, tree); - // We only need to dive into the expression if it is not an - // identifier. - // Otherwise we may try to annotate the outer class for a - // Outer.Inner static class. - if (adt.getEnclosingType() != null - && ((MemberSelectTree) tree).getExpression().getKind() != Tree.Kind.IDENTIFIER) { - visit(adt.getEnclosingType(), ((MemberSelectTree) tree).getExpression()); - } - addDeclarationConstraints(getOrCreateDeclBound(adt), primary); - break; - - case PARAMETERIZED_TYPE: - final ParameterizedTypeTree parameterizedTypeTree = (ParameterizedTypeTree) tree; - primary = addPrimaryVariable(adt, parameterizedTypeTree.getType()); - // visit(adt, parameterizedTypeTree.getType()); - - AnnotatedDeclaredType newAdt = adt; - - if (!handleWasRawDeclaredTypes(newAdt) - && !parameterizedTypeTree.getTypeArguments().isEmpty()) { - if (TypesUtils.isAnonymous(newAdt.getUnderlyingType())) { - // There are multiple super classes for an anonymous class - // if the name following new keyword specifies an interface, - // and the anonymous class implements that interface and - // extends Object. In this case, we need the following for - // loop to find out the AnnotatedTypeMirror for the - // interface. - for (AnnotatedDeclaredType adtSuper : newAdt.directSupertypes()) { - if (TreeUtils.typeOf(parameterizedTypeTree).equals( - adtSuper.getUnderlyingType())) { - newAdt = adtSuper; - } + break; + + case PARAMETERIZED_TYPE: + final ParameterizedTypeTree parameterizedTypeTree = (ParameterizedTypeTree) tree; + primary = addPrimaryVariable(adt, parameterizedTypeTree.getType()); + // visit(adt, parameterizedTypeTree.getType()); + + AnnotatedDeclaredType newAdt = adt; + + if (!handleWasRawDeclaredTypes(newAdt) + && !parameterizedTypeTree.getTypeArguments().isEmpty()) { + if (TypesUtils.isAnonymous(newAdt.getUnderlyingType())) { + // There are multiple super classes for an anonymous class + // if the name following new keyword specifies an interface, + // and the anonymous class implements that interface and + // extends Object. In this case, we need the following for + // loop to find out the AnnotatedTypeMirror for the + // interface. + for (AnnotatedDeclaredType adtSuper : newAdt.directSupertypes()) { + if (TreeUtils.typeOf(parameterizedTypeTree) + .equals(adtSuper.getUnderlyingType())) { + newAdt = adtSuper; + } + } } - } - final List treeArgs = parameterizedTypeTree.getTypeArguments(); - final List typeArgs = newAdt.getTypeArguments(); + final List treeArgs = parameterizedTypeTree.getTypeArguments(); + final List typeArgs = newAdt.getTypeArguments(); - if (treeArgs.size() != typeArgs.size()) { - throw new BugInCF("Raw type? Tree(" + parameterizedTypeTree + "), Atm(" + newAdt + ")"); - } + if (treeArgs.size() != typeArgs.size()) { + throw new BugInCF( + "Raw type? Tree(" + + parameterizedTypeTree + + "), Atm(" + + newAdt + + ")"); + } - for (int i = 0; i < typeArgs.size(); i++) { - final AnnotatedTypeMirror typeArg = typeArgs.get(i); - visit(typeArg, treeArgs.get(i)); + for (int i = 0; i < typeArgs.size(); i++) { + final AnnotatedTypeMirror typeArg = typeArgs.get(i); + visit(typeArg, treeArgs.get(i)); + } } - } - addDeclarationConstraints(getOrCreateDeclBound(newAdt), primary); - break; + addDeclarationConstraints(getOrCreateDeclBound(newAdt), primary); + break; - default: - throw new IllegalArgumentException("Unexpected tree type ( kind=" + tree.getKind() + " tree= " + tree - + " ) when visiting " + "AnnotatedDeclaredType( " + adt + " )"); + default: + throw new IllegalArgumentException( + "Unexpected tree type ( kind=" + + tree.getKind() + + " tree= " + + tree + + " ) when visiting " + + "AnnotatedDeclaredType( " + + adt + + " )"); } return null; @@ -746,7 +805,8 @@ private boolean handleWasRawDeclaredTypes(AnnotatedDeclaredType adt) { final List rawTypeArgs = adt.getTypeArguments(); for (int i = 0; i < declarationTypeArgs.size(); i++) { - final AnnotatedTypeVariable declArg = (AnnotatedTypeVariable) declarationTypeArgs.get(i); + final AnnotatedTypeVariable declArg = + (AnnotatedTypeVariable) declarationTypeArgs.get(i); if (InferenceMain.isHackMode(rawTypeArgs.get(i).getKind() != TypeKind.WILDCARD)) { return false; @@ -754,8 +814,12 @@ private boolean handleWasRawDeclaredTypes(AnnotatedDeclaredType adt) { final AnnotatedWildcardType rawArg = (AnnotatedWildcardType) rawTypeArgs.get(i); - rawArg.getExtendsBound().replaceAnnotation(declArg.getUpperBound().getAnnotationInHierarchy(varAnnot)); - rawArg.getSuperBound().replaceAnnotation(declArg.getLowerBound().getAnnotationInHierarchy(varAnnot)); + rawArg.getExtendsBound() + .replaceAnnotation( + declArg.getUpperBound().getAnnotationInHierarchy(varAnnot)); + rawArg.getSuperBound() + .replaceAnnotation( + declArg.getLowerBound().getAnnotationInHierarchy(varAnnot)); } return true; } else { @@ -765,7 +829,8 @@ private boolean handleWasRawDeclaredTypes(AnnotatedDeclaredType adt) { /** * Handle implicit extends clauses and type parameters of the given class type and tree. - * Explicit extends and implements clauses are handled by {@link checkers.inference.InferenceAnnotatedTypeFactory#getTypeOfExtendsImplements} + * Explicit extends and implements clauses are handled by {@link + * checkers.inference.InferenceAnnotatedTypeFactory#getTypeOfExtendsImplements} */ private void handleClassDeclaration(AnnotatedDeclaredType classType, ClassTree classTree) { final Tree extendsTree = classTree.getExtendsClause(); @@ -778,8 +843,12 @@ private void handleClassDeclaration(AnnotatedDeclaredType classType, ClassTree c AnnotationLocation location = createImpliedExtendsLocation(classTree); extendsSlot = createVariable(location, classType.getUnderlyingType()); extendsMissingTrees.put(classElement, extendsSlot); - logger.fine("Created variable for implicit extends on class:\n" + - extendsSlot.getId() + " => " + classElement + " (extends Object)"); + logger.fine( + "Created variable for implicit extends on class:\n" + + extendsSlot.getId() + + " => " + + classElement + + " (extends Object)"); } else { // Add annotation @@ -787,7 +856,6 @@ private void handleClassDeclaration(AnnotatedDeclaredType classType, ClassTree c } List superTypes = classType.directSupertypes(); superTypes.get(0).replaceAnnotation(slotManager.getAnnotation(extendsSlot)); - } if (InferenceMain.isHackMode( @@ -805,27 +873,31 @@ private void handleClassDeclaration(AnnotatedDeclaredType classType, ClassTree c // when the compiler moves on to the next class Element classElement = classType.getUnderlyingType().asElement(); storeElementType(classElement, classType); - } /** - * I BELIEVE THIS METHOD IS NO LONGER NEEDED BECAUSE WE DON'T HAVE SEMANTICS FOR the extends LOCATION - * ON A CLASS IN THE CHECKER FRAMEWORK. Mike Ernst, Javier Thaine, Werner Deitl, and Suzanne Millstein have an - * email entitled "Annotation on Class Name" that covers this. But the gist is, Werner does not see the - * need for an annotation on the extends bound and we currently have no semantics for it. + * I BELIEVE THIS METHOD IS NO LONGER NEEDED BECAUSE WE DON'T HAVE SEMANTICS FOR the extends + * LOCATION ON A CLASS IN THE CHECKER FRAMEWORK. Mike Ernst, Javier Thaine, Werner Deitl, and + * Suzanne Millstein have an email entitled "Annotation on Class Name" that covers this. But the + * gist is, Werner does not see the need for an annotation on the extends bound and we currently + * have no semantics for it. * - * Note, if we have on on the extends bound, you can also have one on every implemented interface. Which - * are other locations we don't have sematnics for. + *

Note, if we have on on the extends bound, you can also have one on every implemented + * interface. Which are other locations we don't have sematnics for. */ private AnnotationLocation createImpliedExtendsLocation(ClassTree classTree) { - // TODO: THIS CAN BE CREATED ONCE THIS IS FIXED: https://github.com/typetools/annotation-tools/issues/100 - InferenceMain.getInstance().logger.warning("Hack:VariableAnnotator::createImpliedExtendsLocation(classTree) not implemented"); + // TODO: THIS CAN BE CREATED ONCE THIS IS FIXED: + // https://github.com/typetools/annotation-tools/issues/100 + InferenceMain.getInstance() + .logger + .warning( + "Hack:VariableAnnotator::createImpliedExtendsLocation(classTree) not implemented"); return AnnotationLocation.MISSING_LOCATION; } /** * Creates an AnnotationLocation that represents the implied (missing bound) on a type parameter - * that extends object. E.g. {@code } the "extends Object" on T is implied but not written. + * that extends object. E.g. {@code } the "extends Object" on T is implied but not written. */ private AnnotationLocation createImpliedExtendsLocation(TypeParameterTree typeParamTree) { AnnotationLocation parentLoc = treeToLocation(typeParamTree); @@ -842,8 +914,11 @@ private AnnotationLocation createImpliedExtendsLocation(TypeParameterTree typePa break; default: - throw new RuntimeException("Unexpected location " + parentLoc.getKind() + " location kind for tree:\n" - + typeParamTree); + throw new RuntimeException( + "Unexpected location " + + parentLoc.getKind() + + " location kind for tree:\n" + + typeParamTree); } return result; @@ -851,8 +926,10 @@ private AnnotationLocation createImpliedExtendsLocation(TypeParameterTree typePa /** * Visit each bound on the intersection type + * * @param intersectionType type to annotate - * @param tree An AnnotatedIntersectionTypeTree, an IllegalArgumentException will be thrown otherwise + * @param tree An AnnotatedIntersectionTypeTree, an IllegalArgumentException will be thrown + * otherwise * @return null */ @Override @@ -866,33 +943,45 @@ public Void visitIntersection(AnnotatedIntersectionType intersectionType, Tree t // TODO: AND DO GENERAL TESTING/THINKING ABOUT WHAT WE WANT TO DO WITH INTERSECTIONS switch (tree.getKind()) { - case INTERSECTION_TYPE: - assert ((IntersectionTypeTree) tree).getBounds().size() == intersectionType.directSupertypes().size(); - visitTogether(intersectionType.directSupertypes(), ((IntersectionTypeTree) tree).getBounds()); + assert ((IntersectionTypeTree) tree).getBounds().size() + == intersectionType.directSupertypes().size(); + visitTogether( + intersectionType.directSupertypes(), + ((IntersectionTypeTree) tree).getBounds()); break; case TYPE_PARAMETER: - assert ((TypeParameterTree) tree).getBounds().size() == intersectionType.directSupertypes().size(); - visitTogether(intersectionType.directSupertypes(), ((TypeParameterTree) tree).getBounds()); + assert ((TypeParameterTree) tree).getBounds().size() + == intersectionType.directSupertypes().size(); + visitTogether( + intersectionType.directSupertypes(), + ((TypeParameterTree) tree).getBounds()); break; - // TODO: IN JAVA 8, LAMBDAS CAN HAVE INTERSECTION ARGUMENTS + // TODO: IN JAVA 8, LAMBDAS CAN HAVE INTERSECTION ARGUMENTS default: - InferenceUtil.testArgument(false, - "Unexpected tree type ( " + tree + " ) when visiting AnnotatedIntersectionType( " + intersectionType + " )"); + InferenceUtil.testArgument( + false, + "Unexpected tree type ( " + + tree + + " ) when visiting AnnotatedIntersectionType( " + + intersectionType + + " )"); } // TODO: So in Java 8 the Ast the "A & B" tree in T extends A & B is an IntersectionTypeTree // TODO: but there are also casts of type (A & B) I believe -// visitTogether(intersectionType.directSuperTypes(), ((IntersectionTypeTree) tree).getBounds()); + // visitTogether(intersectionType.directSuperTypes(), ((IntersectionTypeTree) + // tree).getBounds()); return null; } /** * Visit each alternative in the union type + * * @param unionType type to be annotated * @param tree must be a UnionTypeTree * @return null @@ -900,16 +989,21 @@ public Void visitIntersection(AnnotatedIntersectionType intersectionType, Tree t @Override public Void visitUnion(final AnnotatedUnionType unionType, final Tree tree) { - InferenceUtil.testArgument(tree instanceof UnionTypeTree || tree instanceof VariableTree, - "Unexpected tree type ( " + tree + " ) for AnnotatedUnionType (" + unionType + ")"); - + InferenceUtil.testArgument( + tree instanceof UnionTypeTree || tree instanceof VariableTree, + "Unexpected tree type ( " + tree + " ) for AnnotatedUnionType (" + unionType + ")"); UnionTypeTree unionTree; if (tree instanceof VariableTree) { VariableTree varTree = (VariableTree) tree; Tree typeTree = varTree.getType(); - InferenceUtil.testArgument(typeTree instanceof UnionTypeTree, - "Unexpected tree type ( " + tree + " ) for variable tree of type AnnotatedUnionType (" + unionType + ")"); + InferenceUtil.testArgument( + typeTree instanceof UnionTypeTree, + "Unexpected tree type ( " + + tree + + " ) for variable tree of type AnnotatedUnionType (" + + unionType + + ")"); unionTree = (UnionTypeTree) typeTree; } else { unionTree = (UnionTypeTree) tree; @@ -928,8 +1022,8 @@ public Void visitUnion(final AnnotatedUnionType unionType, final Tree tree) { * Annotates the array type of the given AnnotatedArrayType. * * @param type The type to be annotated - * @param tree A tree of kind: ARRAY_TYPE, NEW_ARRAY, ANNOTATION_TYPE - * an IllegalArgumentException is thrown otherwise + * @param tree A tree of kind: ARRAY_TYPE, NEW_ARRAY, ANNOTATION_TYPE an + * IllegalArgumentException is thrown otherwise * @return null */ @Override @@ -940,7 +1034,8 @@ public Void visitArray(AnnotatedArrayType type, Tree tree) { Tree effectiveTree = tree; // This is a while loop because variable declarations may have ANNOTATED_TYPE as their type, // unwrap till we get an ARRAY_TYPE - while (effectiveTree.getKind() == Kind.ANNOTATED_TYPE || effectiveTree.getKind() == Kind.VARIABLE) { + while (effectiveTree.getKind() == Kind.ANNOTATED_TYPE + || effectiveTree.getKind() == Kind.VARIABLE) { if (effectiveTree.getKind() == Kind.ANNOTATED_TYPE) { // This happens for arrays that are already annotated. effectiveTree = ((JCTree.JCAnnotatedType) effectiveTree).getUnderlyingType(); @@ -971,8 +1066,10 @@ public Void visitArray(AnnotatedArrayType type, Tree tree) { // When dealing with AnnotatedArrayTypes for a NewArrayTree, // some of the annotatable positions will not have any corresponding tree - // so we can't just use addPrimaryVariable since there is no tree associated with it. - // Instead, we cache the entire AnnotatedArrayType and return it the next time this method + // so we can't just use addPrimaryVariable since there is no tree associated with + // it. + // Instead, we cache the entire AnnotatedArrayType and return it the next time this + // method // is called for that tree. if (newArrayMissingTrees.containsKey(effectiveTree)) { CopyUtil.copyAnnotations(newArrayMissingTrees.get(effectiveTree), type); @@ -982,7 +1079,7 @@ public Void visitArray(AnnotatedArrayType type, Tree tree) { boolean isArrayLiteral = (((NewArrayTree) effectiveTree).getType() == null); if (isArrayLiteral) { // {"1", "2", "3"} - annotateArrayLiteral(type, (NewArrayTree)effectiveTree); + annotateArrayLiteral(type, (NewArrayTree) effectiveTree); } else { // new Array[1][] // new Array[1][1] @@ -1002,13 +1099,13 @@ public Void visitArray(AnnotatedArrayType type, Tree tree) { addPrimaryVariable(type, effectiveTree); break; default: - throw new IllegalArgumentException("Unexpected tree (" + tree + ") for type (" + type + ")"); + throw new IllegalArgumentException( + "Unexpected tree (" + tree + ") for type (" + type + ")"); } return null; } - public boolean enclosedByAnnotation(TreePath path) { Set treeKinds = new HashSet<>(); @@ -1020,21 +1117,20 @@ public boolean enclosedByAnnotation(TreePath path) { treeKinds.add(Kind.INTERFACE); Tree enclosure = TreePathUtil.enclosingOfKind(path, treeKinds); return enclosure.getKind() == Kind.ANNOTATION - || enclosure.getKind() == Kind.ANNOTATION_TYPE - || enclosure.getKind() == Kind.TYPE_ANNOTATION; + || enclosure.getKind() == Kind.ANNOTATION_TYPE + || enclosure.getKind() == Kind.TYPE_ANNOTATION; } /** * Create VariableSlots to a NewArrayTree. * - * An array literal like the RHS of this - * String[][] = {{"a", "b"}, {}, null} + *

An array literal like the RHS of this String[][] = {{"a", "b"}, {}, null} * - * is really - * String[][] = new @A String @B [] @C [] { new @D String @E []{"a", "b"}, new @F String @G []{}, null} + *

is really String[][] = new @A String @B [] @C [] { new @D String @E []{"a", "b"}, new @F + * String @G []{}, null} * - * This method adds variables for the @A,@B,@C. - * The intializers will be annotated when their ATM is created. + *

This method adds variables for the @A,@B,@C. The intializers will be annotated when their + * ATM is created. * * @param type the type corresponding to the array literal * @param tree The tree corresponding to an array literal @@ -1073,7 +1169,7 @@ private void annotateArrayLiteral(AnnotatedArrayType type, NewArrayTree tree) { int level = 0; while (loopType instanceof AnnotatedArrayType) { loopType = ((AnnotatedArrayType) loopType).getComponentType(); - level ++; + level++; ASTRecord astRec = astRecord.newArrayLevel(level); replaceOrCreateEquivalentVarAnno(loopType, tree, new AstPathLocation(astRec)); @@ -1083,43 +1179,46 @@ private void annotateArrayLiteral(AnnotatedArrayType type, NewArrayTree tree) { /** * Recursively creates annotations for an Array. * - * This needs special handling to correctly - * number the ASTRecord entries, and because these two expressions correspond to different trees. - * (Is this a compiler bug?) + *

This needs special handling to correctly number the ASTRecord entries, and because these + * two expressions correspond to different trees. (Is this a compiler bug?) * - * new Array[1][] - * new Array[1][1] + *

new Array[1][] new Array[1][1] * - * The latter is missing a tree for the nested string array; the component tree for new String[1][1] - * is just String. This means there is no tree to associate the @VarAnnot type with. - * This assigns an @VarAnnot to the missing tree, and the full result will be cached by newArrayMissingTrees. + *

The latter is missing a tree for the nested string array; the component tree for new + * String[1][1] is just String. This means there is no tree to associate the @VarAnnot type + * with. This assigns an @VarAnnot to the missing tree, and the full result will be cached by + * newArrayMissingTrees. * * @param type * @param tree * @param level * @param topLevelTree */ - private void annotateNewArray(AnnotatedTypeMirror type, Tree tree, int level, Tree topLevelTree) { + private void annotateNewArray( + AnnotatedTypeMirror type, Tree tree, int level, Tree topLevelTree) { if (type instanceof AnnotatedArrayType && (tree.getKind() == Tree.Kind.NEW_ARRAY - || tree.getKind() == Tree.Kind.ARRAY_TYPE)) { + || tree.getKind() == Tree.Kind.ARRAY_TYPE)) { // The tree is an array type. // The outer if check is needed because sometimes the tree might be a declared type. shallowAnnotateArray(type, tree, level, topLevelTree); } else if (type instanceof AnnotatedArrayType) { - // The tree is a declared type, which happens, although is unintuitive. Might be a compiler bug. + // The tree is a declared type, which happens, although is unintuitive. Might be a + // compiler bug. // The tree doesn't correspond to the type, so it is effectively missing. // This is one reason for having newArrayMissingTrees // Create a variable from an ASTPath final TreePath pathToTree = inferenceTypeFactory.getPath(topLevelTree); - ASTRecord astRec = ASTPathUtil.getASTRecordForPath(inferenceTypeFactory, pathToTree).newArrayLevel(level); + ASTRecord astRec = + ASTPathUtil.getASTRecordForPath(inferenceTypeFactory, pathToTree) + .newArrayLevel(level); replaceOrCreateEquivalentVarAnno(type, tree, new AstPathLocation(astRec)); } else if (!(tree.getKind() == Tree.Kind.NEW_ARRAY - || tree.getKind() == Tree.Kind.ARRAY_TYPE)) { + || tree.getKind() == Tree.Kind.ARRAY_TYPE)) { // Annotate the declared type for the component tree. // The inner most component type always has a corresponding tree. @@ -1142,16 +1241,20 @@ private void annotateNewArray(AnnotatedTypeMirror type, Tree tree, int level, Tr componentTree = tree; } level += 1; - annotateNewArray(((AnnotatedArrayType) type).getComponentType(), componentTree, level, topLevelTree); + annotateNewArray( + ((AnnotatedArrayType) type).getComponentType(), + componentTree, + level, + topLevelTree); } - } /** - * Add a primary annotation to the top level of an array. Special handling is needed to create the ASTRecord - * correctly. + * Add a primary annotation to the top level of an array. Special handling is needed to create + * the ASTRecord correctly. */ - private void shallowAnnotateArray(AnnotatedTypeMirror type, Tree tree, int level, Tree topLevelTree) { + private void shallowAnnotateArray( + AnnotatedTypeMirror type, Tree tree, int level, Tree topLevelTree) { if (treeToVarAnnoPair.containsKey(tree)) { addPrimaryVariable(type, tree); } else { @@ -1160,12 +1263,14 @@ private void shallowAnnotateArray(AnnotatedTypeMirror type, Tree tree, int level AnnotationLocation location; assert pathToTopLevelTree != null; - ASTRecord astRecord = ASTPathUtil.getASTRecordForPath(inferenceTypeFactory, pathToTopLevelTree); + ASTRecord astRecord = + ASTPathUtil.getASTRecordForPath(inferenceTypeFactory, pathToTopLevelTree); if (astRecord != null) { astRecord = astRecord.newArrayLevel(level); location = new AstPathLocation(astRecord); } else { - // astRecord for `pathToTopLevelTree` is null when `topLevelTree` is an artificial array creation + // astRecord for `pathToTopLevelTree` is null when `topLevelTree` is an artificial + // array creation // tree like for varargs, as the following case shows // // void foo() { @@ -1176,10 +1281,14 @@ private void shallowAnnotateArray(AnnotatedTypeMirror type, Tree tree, int level // // At the method invocation of `bar`, an artificial new array is created as // "new Object[]{new String("a"), new String("b")}" - // There's no exclusive AST path (i.e. AnnotationLocation) for the artificial tree. Currently we - // create slots for the array primary type and component types all on MISSING_LOCATION. - // TODO: consider an appropriate AST path for the artificial array creation or other ways to get - // rid of MISSING_LOCATION. See https://github.com/opprop/checker-framework-inference/issues/346 + // There's no exclusive AST path (i.e. AnnotationLocation) for the artificial tree. + // Currently we + // create slots for the array primary type and component types all on + // MISSING_LOCATION. + // TODO: consider an appropriate AST path for the artificial array creation or other + // ways to get + // rid of MISSING_LOCATION. See + // https://github.com/opprop/checker-framework-inference/issues/346 location = AnnotationLocation.MISSING_LOCATION; } @@ -1188,20 +1297,22 @@ private void shallowAnnotateArray(AnnotatedTypeMirror type, Tree tree, int level } /** - * If the given typeVar represents a declaration (TypeParameterTree), the adds annotations to the upper and - * lower bounds of the given type variable. If the given typeVar reperesents a typeUse, adds a primary annotation - * to the type variable and stores the element -> typeVa + * If the given typeVar represents a declaration (TypeParameterTree), the adds annotations to + * the upper and lower bounds of the given type variable. If the given typeVar reperesents a + * typeUse, adds a primary annotation to the type variable and stores the element -> typeVa + * * @param typeVar type variable to annotate - * @param tree A tree of kind TYPE_PARAMETER leads to creation of bounds variable, other tree kinds are treated as - * type uses + * @param tree A tree of kind TYPE_PARAMETER leads to creation of bounds variable, other tree + * kinds are treated as type uses * @return null */ @Override public Void visitTypeVariable(AnnotatedTypeVariable typeVar, Tree tree) { if (tree.getKind() == Tree.Kind.TYPE_PARAMETER) { - final TypeParameterElement typeParamElement = (TypeParameterElement) typeVar.getUnderlyingType().asElement(); - final TypeParameterTree typeParameterTree = (TypeParameterTree) tree; + final TypeParameterElement typeParamElement = + (TypeParameterElement) typeVar.getUnderlyingType().asElement(); + final TypeParameterTree typeParameterTree = (TypeParameterTree) tree; if (!elementToAtm.containsKey(typeParamElement)) { storeElementType(typeParamElement, typeVar); @@ -1213,14 +1324,17 @@ public Void visitTypeVariable(AnnotatedTypeVariable typeVar, Tree tree) { if (typeParameterTree.getBounds().size() > 0) { final AnnotatedTypeMirror upperBound = typeVar.getUpperBound(); if (upperBound.getKind() == TypeKind.TYPEVAR) { - addExistentialVariable((AnnotatedTypeVariable) upperBound, - typeParameterTree.getBounds().get(0), true); + addExistentialVariable( + (AnnotatedTypeVariable) upperBound, + typeParameterTree.getBounds().get(0), + true); } else { Tree bound = typeParameterTree.getBounds().get(0); if (upperBound.getKind() == TypeKind.INTERSECTION) { - // sometimes all of the bounds are in the bound list and sometimes there seem to be + // sometimes all of the bounds are in the bound list and sometimes there + // seem to be // nested intersection type trees. if (bound.getKind() != Kind.INTERSECTION_TYPE) { visit(upperBound, typeParameterTree); @@ -1232,15 +1346,20 @@ public Void visitTypeVariable(AnnotatedTypeVariable typeVar, Tree tree) { } } } else { - final TypeParameterElement typeVarElement = (TypeParameterElement) typeVar.getUnderlyingType().asElement(); + final TypeParameterElement typeVarElement = + (TypeParameterElement) typeVar.getUnderlyingType().asElement(); final SourceVariableSlot extendsSlot; if (!extendsMissingTrees.containsKey(typeVarElement)) { AnnotationLocation location = createImpliedExtendsLocation(typeParameterTree); extendsSlot = createVariable(location, typeVar.getUnderlyingType()); extendsMissingTrees.put(typeVarElement, extendsSlot); - logger.fine("Created variable for implicit extends on type parameter:\n" + - extendsSlot.getId() + " => " + typeVarElement + " (extends Object)"); + logger.fine( + "Created variable for implicit extends on type parameter:\n" + + extendsSlot.getId() + + " => " + + typeVarElement + + " (extends Object)"); } else { // Add annotation @@ -1251,7 +1370,7 @@ public Void visitTypeVariable(AnnotatedTypeVariable typeVar, Tree tree) { upperBound.addAnnotation(slotManager.getAnnotation(extendsSlot)); } - } else { + } else { addExistentialVariable(typeVar, tree, false); } @@ -1261,6 +1380,7 @@ public Void visitTypeVariable(AnnotatedTypeVariable typeVar, Tree tree) { /** * Add a variable to the given primitiveType + * * @param primitiveType Type to annotate * @param tree Any tree type * @return null @@ -1270,7 +1390,7 @@ public Void visitPrimitive(AnnotatedPrimitiveType primitiveType, Tree tree) { if (tree instanceof BinaryTree) { // Since there are so many kinds of binary trees // handle these with an if instead of in the switch. - handleBinaryTree(primitiveType, (BinaryTree)tree); + handleBinaryTree(primitiveType, (BinaryTree) tree); return null; } @@ -1284,7 +1404,8 @@ public Void visitPrimitive(AnnotatedPrimitiveType primitiveType, Tree tree) { } /** - * Add super/extends variable slots to the wildcardType. Visits whatever bounds are available. + * Add super/extends variable slots to the wildcardType. Visits whatever bounds are available. + * * @param wildcardType type to annotate * @param tree A WildcardTree of kind: UNBOUNDED_WILDCARD, EXTENDS_WILDCARD, SUPER_WILDCARD * @return null @@ -1297,22 +1418,32 @@ public Void visitWildcard(AnnotatedWildcardType wildcardType, Tree tree) { tree = ((AnnotatedTypeTree) tree).getUnderlyingType(); } if (!(tree instanceof WildcardTree)) { - throw new IllegalArgumentException("Wildcard type ( " + wildcardType + " ) associated " + - "with non-WildcardTree ( " + tree + " ) "); + throw new IllegalArgumentException( + "Wildcard type ( " + + wildcardType + + " ) associated " + + "with non-WildcardTree ( " + + tree + + " ) "); } } - // TODO: Despite what the framework docs say, if this WILDCARD is UNBOUNDED or EXTENDS bounded - // TODO: then I believe the primary annotation is ignored. Check this, if so then we might want to - // TODO: either make it used (i.e. create a superBound) or just not generate the variable in this case + // TODO: Despite what the framework docs say, if this WILDCARD is UNBOUNDED or EXTENDS + // bounded + // TODO: then I believe the primary annotation is ignored. Check this, if so then we might + // want to + // TODO: either make it used (i.e. create a superBound) or just not generate the variable in + // this case final WildcardTree wildcardTree = (WildcardTree) tree; final Tree.Kind wildcardKind = wildcardTree.getKind(); if (wildcardKind == Tree.Kind.UNBOUNDED_WILDCARD) { // Visit super bound, use the wild card type tree to represents the superbound. addPrimaryVariable(wildcardType.getSuperBound(), tree); - // Visit extend bound, construct an artificial extends bound tree to represent the extendbound. - ArtificialExtendsBoundTree artificialExtendsBoundTree = new ArtificialExtendsBoundTree(wildcardTree); + // Visit extend bound, construct an artificial extends bound tree to represent the + // extendbound. + ArtificialExtendsBoundTree artificialExtendsBoundTree = + new ArtificialExtendsBoundTree(wildcardTree); addPrimaryVariable(wildcardType.getExtendsBound(), artificialExtendsBoundTree); } else if (wildcardKind == Tree.Kind.EXTENDS_WILDCARD) { @@ -1328,21 +1459,28 @@ public Void visitWildcard(AnnotatedWildcardType wildcardType, Tree tree) { } /** - * Annotates the given methodType as a method declaration. The return type, parameters, and type parameters of - * the declaration are annotated but the body is NOT visited. + * Annotates the given methodType as a method declaration. The return type, parameters, and type + * parameters of the declaration are annotated but the body is NOT visited. + * * @param methodType A type to be annotated * @param tree A tree of METHOD kind, an IllegalArgumentException will be thrown otherwise * @return null */ @Override public Void visitExecutable(AnnotatedExecutableType methodType, Tree tree) { - InferenceUtil.testArgument(tree.getKind() == Tree.Kind.METHOD, - "Unexpected tree type (" + tree + ") when visiting AnnotatedExecutableType (" + methodType + ")"); + InferenceUtil.testArgument( + tree.getKind() == Tree.Kind.METHOD, + "Unexpected tree type (" + + tree + + ") when visiting AnnotatedExecutableType (" + + methodType + + ")"); - boolean isFromAnonymousClass = ((MethodSymbol) methodType.getElement()).getEnclosingElement().isAnonymous(); + boolean isFromAnonymousClass = + ((MethodSymbol) methodType.getElement()).getEnclosingElement().isAnonymous(); // This is so we do not add annotations the the parameters of a anonymous class invocation. - if (((MethodSymbol)methodType.getElement()).isConstructor() && isFromAnonymousClass) { + if (((MethodSymbol) methodType.getElement()).isConstructor() && isFromAnonymousClass) { final MethodTree methodTree = (MethodTree) tree; final ExecutableElement methodElem = TreeUtils.elementFromDeclaration(methodTree); handleConstructorReturn(methodType, methodElem, (MethodTree) tree); @@ -1362,36 +1500,42 @@ public Void visitNull(AnnotatedNullType type, Tree tree) { return null; } - private void handleConstructorReturn(AnnotatedExecutableType methodType, - ExecutableElement methodElem, MethodTree tree) { + private void handleConstructorReturn( + AnnotatedExecutableType methodType, ExecutableElement methodElem, MethodTree tree) { addPrimaryVariable(methodType.getReturnType(), tree); final AnnotatedDeclaredType returnType = (AnnotatedDeclaredType) methodType.getReturnType(); // Use the element, don't try to use the tree // (since it might be in a different compilation unit, getting the path wont work) - final AnnotatedDeclaredType classType = inferenceTypeFactory.getAnnotatedType(ElementUtils.enclosingTypeElement(methodElem)); + final AnnotatedDeclaredType classType = + inferenceTypeFactory.getAnnotatedType( + ElementUtils.enclosingTypeElement(methodElem)); // TODO: TEST THIS // Copy the annotations from the class declaration type parameter to the return type params // although this might be handled by a methodFromUse etc... final List returnTypeParams = returnType.getTypeArguments(); - final List classTypeParams = classType.getTypeArguments(); - assert returnTypeParams.size() == classTypeParams.size() : "Constructor type param size != class type param size"; + final List classTypeParams = classType.getTypeArguments(); + assert returnTypeParams.size() == classTypeParams.size() + : "Constructor type param size != class type param size"; for (int i = 0; i < returnTypeParams.size(); i++) { CopyUtil.copyAnnotations(classTypeParams.get(i), returnTypeParams.get(i)); } } - private void handleReceiver(AnnotatedExecutableType methodType, - ExecutableElement methodElem, MethodTree methodTree, boolean anonymousClassReceiver) { + private void handleReceiver( + AnnotatedExecutableType methodType, + ExecutableElement methodElem, + MethodTree methodTree, + boolean anonymousClassReceiver) { final AnnotatedTypeMirror receiverType = methodType.getReceiverType(); - if (receiverType!= null && methodTree.getReceiverParameter() != null) { + if (receiverType != null && methodTree.getReceiverParameter() != null) { visit(methodType.getReceiverType(), methodTree.getReceiverParameter().getType()); } else if (receiverType != null) { - if (InferenceMain.isHackMode( ((MethodSymbol) methodElem).isConstructor())) { + if (InferenceMain.isHackMode(((MethodSymbol) methodElem).isConstructor())) { TypeElement enclosingClass = (TypeElement) methodElem.getEnclosingElement(); if (((ClassSymbol) enclosingClass).isInner()) { @@ -1401,24 +1545,27 @@ private void handleReceiver(AnnotatedExecutableType methodType, } } - if (isAnnotatedFromBytecode(receiverType)) { return; - // annotate missing tree if it's not a constructor or static + // annotate missing tree if it's not a constructor or static } else if (!receiverMissingTrees.containsKey(methodElem)) { - TreePath pathToMethod = inferenceTypeFactory.getPath(methodTree); + TreePath pathToMethod = inferenceTypeFactory.getPath(methodTree); if (pathToMethod == null) { - pathToMethod = expensiveBackupGetPath(methodElem, methodTree, inferenceTypeFactory); + pathToMethod = + expensiveBackupGetPath(methodElem, methodTree, inferenceTypeFactory); } - ASTRecord astRecord = ASTPathUtil.getASTRecordForPath(inferenceTypeFactory, pathToMethod); + ASTRecord astRecord = + ASTPathUtil.getASTRecordForPath(inferenceTypeFactory, pathToMethod); if (astRecord == null) { if (!anonymousClassReceiver) { TreePath path = inferenceTypeFactory.getPath(methodTree); if (path != null) { - ASTRecord parent = ASTIndex.indexOf(path.getCompilationUnit()).get(path.getParentPath().getLeaf()); + ASTRecord parent = + ASTIndex.indexOf(path.getCompilationUnit()) + .get(path.getParentPath().getLeaf()); if (parent != null) { astRecord = ASTPathUtil.getConstructorRecord(parent); @@ -1430,7 +1577,8 @@ private void handleReceiver(AnnotatedExecutableType methodType, } if (astRecord == null) { - throw new BugInCF("Missing path to receiver: " + methodElem + " => " + methodType); + throw new BugInCF( + "Missing path to receiver: " + methodElem + " => " + methodType); } } @@ -1446,8 +1594,11 @@ private void handleReceiver(AnnotatedExecutableType methodType, } receiverMissingTrees.put(methodElem, receiverType.deepCopy()); - logger.fine("Created variable for implicit receiver on method:\n" + methodElem + "=>" + receiverType); - + logger.fine( + "Created variable for implicit receiver on method:\n" + + methodElem + + "=>" + + receiverType); } else { // Add annotation @@ -1458,23 +1609,26 @@ private void handleReceiver(AnnotatedExecutableType methodType, public void addAnonymousClassReceiverAnnos(AnnotatedTypeMirror receiverType) { - // the receiver of an anonymous inner class method (including constructors) is the declared type of the - // receiver type's class. Use the receiver type to get this type. Get the variable annotations from it + // the receiver of an anonymous inner class method (including constructors) is the declared + // type of the + // receiver type's class. Use the receiver type to get this type. Get the variable + // annotations from it // and copy them to the receiver since there is no way to write annotations that will // override the declaration - final AnnotatedDeclaredType receiverDt = (AnnotatedDeclaredType)receiverType; + final AnnotatedDeclaredType receiverDt = (AnnotatedDeclaredType) receiverType; final Element receiverClass = receiverDt.getUnderlyingType().asElement(); - final AnnotatedTypeMirror declarationType = inferenceTypeFactory.getAnnotatedType(receiverClass); + final AnnotatedTypeMirror declarationType = + inferenceTypeFactory.getAnnotatedType(receiverClass); // Note: We do not apply a primary annotation to the declaration of a class but we do // apply it to it's extends bound and therefore it's supertype. Apply that AnnotationMirror variableAnno = declarationType.directSupertypes().get(0).getAnnotationInHierarchy(varAnnot); - if (variableAnno == null) { if (!InferenceMain.isHackMode()) { - throw new BugInCF("Missing receiver annotation: " + receiverType + " " + declarationType); + throw new BugInCF( + "Missing receiver annotation: " + receiverType + " " + declarationType); } } else { receiverType.replaceAnnotation(variableAnno); @@ -1487,21 +1641,26 @@ public void addAnonymousClassReceiverAnnos(AnnotatedTypeMirror receiverType) { } /** - * TODO: ADD TESTS FOR <> - * Annotates the return type, parameters, and type parameter of the given method declaration. - * methodElement -> methodType + * TODO: ADD TESTS FOR <> Annotates the return type, parameters, and type parameter of the given + * method declaration. methodElement -> methodType + * * @param methodType * @param tree */ - private void handleMethodDeclaration(final AnnotatedExecutableType methodType, final MethodTree tree, - boolean isFromAnonymousClass) { + private void handleMethodDeclaration( + final AnnotatedExecutableType methodType, + final MethodTree tree, + boolean isFromAnonymousClass) { // TODO: DOES THIS CHANGE WITH JAVA 8 AND CLOSURES? final MethodTree methodTree = tree; final ExecutableElement methodElem = TreeUtils.elementFromDeclaration(methodTree); final boolean isConstructor = TreeUtils.isConstructor(tree); - // this needs to happen before anythinge els because they might be referred to in other types - visitTogether(methodType.getTypeVariables(), methodTree.getTypeParameters()); // TODO: STORE THESE TYPES? + // this needs to happen before anythinge els because they might be referred to in other + // types + visitTogether( + methodType.getTypeVariables(), + methodTree.getTypeParameters()); // TODO: STORE THESE TYPES? if (isConstructor) { handleConstructorReturn(methodType, methodElem, tree); @@ -1517,7 +1676,7 @@ private void handleMethodDeclaration(final AnnotatedExecutableType methodType, f for (final VariableTree paramTree : methodTree.getParameters()) { paramTrees.add(paramTree); } - visitTogether(methodType.getParameterTypes(), paramTrees); // TODO: STORE THESE TYPES? + visitTogether(methodType.getParameterTypes(), paramTrees); // TODO: STORE THESE TYPES? storeElementType(methodElem, methodType); } @@ -1529,6 +1688,7 @@ private ASTRecord recreateImpliedReceiverASTRecord(MethodTree methodTree) { /** * Annotate a BinaryTree by creating and storing the LUB of the elemtns. + * * @param atm the type of the binary tree to annotate * @param binaryTree the binary tree */ @@ -1537,16 +1697,24 @@ public void handleBinaryTree(AnnotatedTypeMirror atm, BinaryTree binaryTree) { if (treeToVarAnnoPair.containsKey(binaryTree)) { atm.replaceAnnotations(treeToVarAnnoPair.get(binaryTree).second); } else { - AnnotatedTypeMirror a = inferenceTypeFactory.getAnnotatedType(binaryTree.getLeftOperand()); - AnnotatedTypeMirror b = inferenceTypeFactory.getAnnotatedType(binaryTree.getRightOperand()); - Set lubs = inferenceTypeFactory - .getQualifierHierarchy().leastUpperBoundsShallow(a.getEffectiveAnnotations(), a.getUnderlyingType(), - b.getEffectiveAnnotations(), b.getUnderlyingType()); + AnnotatedTypeMirror a = + inferenceTypeFactory.getAnnotatedType(binaryTree.getLeftOperand()); + AnnotatedTypeMirror b = + inferenceTypeFactory.getAnnotatedType(binaryTree.getRightOperand()); + Set lubs = + inferenceTypeFactory + .getQualifierHierarchy() + .leastUpperBoundsShallow( + a.getEffectiveAnnotations(), + a.getUnderlyingType(), + b.getEffectiveAnnotations(), + b.getUnderlyingType()); atm.clearAnnotations(); atm.addAnnotations(lubs); if (slotManager.getSlot(atm) instanceof VariableSlot) { - final IPair> varATMPair = IPair.>of( - slotManager.getSlot(atm), lubs); + final IPair> varATMPair = + IPair.>of( + slotManager.getSlot(atm), lubs); treeToVarAnnoPair.put(binaryTree, varATMPair); } else { // The slot returned was a constant. Regenerating it is ok. @@ -1555,13 +1723,16 @@ public void handleBinaryTree(AnnotatedTypeMirror atm, BinaryTree binaryTree) { } /** - * If the given declaration tree of element has been previously annotated by the VariableAnnotator - * then copy the annotations from a stored AnnotatedTypeMirror onto destAtm - * @param element The element which may or may not correspond to a tree which has already been annotated + * If the given declaration tree of element has been previously annotated by the + * VariableAnnotator then copy the annotations from a stored AnnotatedTypeMirror onto destAtm + * + * @param element The element which may or may not correspond to a tree which has already been + * annotated * @param destAtm The type of element * @return True if destAtm was annotated, false otherwise */ - public boolean annotateElementFromStore(final Element element, final AnnotatedTypeMirror destAtm) { + public boolean annotateElementFromStore( + final Element element, final AnnotatedTypeMirror destAtm) { if (!elementToAtm.containsKey(element)) { return false; } @@ -1577,12 +1748,14 @@ public void annotateImpliedType(AnnotatedTypeMirror type, boolean isUse, ASTReco } /** - * Given a list of types and tree, visit them pairwise with this VariableAnnotator. The sizes of types and - * trees MUST be equal + * Given a list of types and tree, visit them pairwise with this VariableAnnotator. The sizes of + * types and trees MUST be equal + * * @param types A list of types to visit * @param trees A list of trees to visit */ - private void visitTogether(final List types, final List trees) { + private void visitTogether( + final List types, final List trees) { assert types.size() == trees.size(); for (int i = 0; i < types.size(); ++i) { @@ -1617,7 +1790,9 @@ protected Boolean scan(AnnotatedTypeMirror type, Void aVoid) { return true; } Boolean superCall = super.scan(type, aVoid); - if (superCall == null) { // handles null returns from things like scanning an empty list of type args + if (superCall + == null) { // handles null returns from things like scanning an empty list + // of type args return false; } @@ -1634,12 +1809,13 @@ protected Boolean scan(AnnotatedTypeMirror type, Void aVoid) { } /** - * This method returns the annotation that may or may not be placed on the class declaration for type. - * If it does not already exist, this method creates the annotation and stores it in classDeclAnnos. - * - * This method can be overridden if a type system wants to use a fixed annotation for class declarations. - * For example, using the top annotation effectively disables declaration bound checks. + * This method returns the annotation that may or may not be placed on the class declaration for + * type. If it does not already exist, this method creates the annotation and stores it in + * classDeclAnnos. * + *

This method can be overridden if a type system wants to use a fixed annotation for class + * declarations. For example, using the top annotation effectively disables declaration bound + * checks. */ protected Slot getOrCreateDeclBound(AnnotatedDeclaredType type) { TypeElement classElt = (TypeElement) type.getUnderlyingType().asElement(); @@ -1650,7 +1826,9 @@ protected Slot getOrCreateDeclBound(AnnotatedDeclaredType type) { Tree classTree = inferenceTypeFactory.declarationFromElement(classElt); if (classTree != null) { final AnnotatedDeclaredType declType = inferenceTypeFactory.fromElement(classElt); - declSlot = replaceOrCreateEquivalentVarAnno(declType, classTree, treeToLocation(classTree)); + declSlot = + replaceOrCreateEquivalentVarAnno( + declType, classTree, treeToLocation(classTree)); classDeclAnnos.put(classElt, declSlot); } else { @@ -1663,10 +1841,11 @@ protected Slot getOrCreateDeclBound(AnnotatedDeclaredType type) { /** * Get the {@link VarAnnot} on the class declaration of the TypeElement. + * * @param ele a type element - * @return the {@link VarAnnot} on the class declaration, - * or {@code null} if the class declaration of the TypeElement is not handled by the - * {@link VariableAnnotator#getOrCreateDeclBound(AnnotatedDeclaredType)}. + * @return the {@link VarAnnot} on the class declaration, or {@code null} if the class + * declaration of the TypeElement is not handled by the {@link + * VariableAnnotator#getOrCreateDeclBound(AnnotatedDeclaredType)}. */ public AnnotationMirror getClassDeclVarAnnot(TypeElement ele) { final Slot slot = classDeclAnnos.get(ele); @@ -1676,7 +1855,6 @@ public AnnotationMirror getClassDeclVarAnnot(TypeElement ele) { return null; } - private void addDeclarationConstraints(Slot declSlot, Slot instanceSlot) { constraintManager.addSubtypeConstraint(instanceSlot, declSlot); } diff --git a/src/checkers/inference/VariableSlotReplacer.java b/src/checkers/inference/VariableSlotReplacer.java index 1195dc8b9..f02d602ce 100644 --- a/src/checkers/inference/VariableSlotReplacer.java +++ b/src/checkers/inference/VariableSlotReplacer.java @@ -14,23 +14,15 @@ import checkers.inference.model.Slot; /** - * Given a set of replacement mappings (oldSlot -> newSlot), - * SlotReplacer will replace each oldSlot in an AnnotatedTypeMirror with newSlot. + * Given a set of replacement mappings (oldSlot -> newSlot), SlotReplacer will replace each oldSlot + * in an AnnotatedTypeMirror with newSlot. * - * Usage: - * new SlotReplacer(slotManager) - * .addReplacement(oldSlot1, newSlot1) - * .addReplacement(oldSlot2, newSlot2) - * .addReplacement(oldSlot3, newSlot3) - * .replaceSlots(atmToUpdate) + *

Usage: new SlotReplacer(slotManager) .addReplacement(oldSlot1, newSlot1) + * .addReplacement(oldSlot2, newSlot2) .addReplacement(oldSlot3, newSlot3) + * .replaceSlots(atmToUpdate) * - * or - * new SlotReplacer(slotManager, - * Arrays.asList( - * new Replacement(oldSlot1, newSlot2), - * new Replacement(oldSlot2, newSlot2), - * new Replacement(oldSlot3, newSlot3) - * ) + *

or new SlotReplacer(slotManager, Arrays.asList( new Replacement(oldSlot1, newSlot2), new + * Replacement(oldSlot2, newSlot2), new Replacement(oldSlot3, newSlot3) ) * ).replaceSlots(atmToUpdate) */ public class VariableSlotReplacer { @@ -40,17 +32,23 @@ public class VariableSlotReplacer { private final boolean replaceInExistentials; private final VariableAnnotator varAnnotator; - public VariableSlotReplacer(final SlotManager slotManager, final VariableAnnotator varAnnotator, - final AnnotationMirror varAnnot, boolean replaceInExistentials) { + public VariableSlotReplacer( + final SlotManager slotManager, + final VariableAnnotator varAnnotator, + final AnnotationMirror varAnnot, + boolean replaceInExistentials) { this.slotManager = slotManager; this.varAnnotator = varAnnotator; this.varAnnot = varAnnot; this.replaceInExistentials = replaceInExistentials; } - public VariableSlotReplacer(final Collection initialReplacements, final SlotManager slotManager, - final VariableAnnotator varAnnotator, final AnnotationMirror varAnnot, - final boolean replaceInExistentials) { + public VariableSlotReplacer( + final Collection initialReplacements, + final SlotManager slotManager, + final VariableAnnotator varAnnotator, + final AnnotationMirror varAnnot, + final boolean replaceInExistentials) { this(slotManager, varAnnotator, varAnnot, replaceInExistentials); replacements.addAll(initialReplacements); } @@ -61,8 +59,9 @@ public VariableSlotReplacer addReplacement(final Slot oldSlot, final Slot newSlo } /** - * For each replacement mapping (oldSlot -> newSlot) configured in this slotReplacer, - * replace each oldSlot in type with its corresponding newSlot + * For each replacement mapping (oldSlot -> newSlot) configured in this slotReplacer, replace + * each oldSlot in type with its corresponding newSlot + * * @param type */ public void replaceSlots(final AnnotatedTypeMirror type) { @@ -70,8 +69,9 @@ public void replaceSlots(final AnnotatedTypeMirror type) { } /** - * Create a copy of type then for each replacement mapping (oldSlot -> newSlot) - * configured in this slotReplacer, replace each oldSlot in type with its corresponding newSlot + * Create a copy of type then for each replacement mapping (oldSlot -> newSlot) configured in + * this slotReplacer, replace each oldSlot in type with its corresponding newSlot + * * @param type * @return */ @@ -81,13 +81,11 @@ public AnnotatedTypeMirror copyAndReplaceSlots(final AnnotatedTypeMirror type) { return copy; } - private class BoundReplacementVisitor extends AnnotatedTypeScanner> { @Override protected Void scan(AnnotatedTypeMirror type, Set replacements) { - // If we have a lot of Replacements it would make a lot more sense to put them in a // map and test them all at once rather than re-traversing. For now, we use it only // with single annotations so I am not worried @@ -104,24 +102,26 @@ protected void testAndReplace(Replacement replacement, AnnotatedTypeMirror type) Slot variable = slotManager.getSlot(anno); if (slotManager.getSlot(type).equals(replacement.oldSlot)) { - final AnnotationMirror newAnnotation = slotManager.getAnnotation(replacement.newSlot); + final AnnotationMirror newAnnotation = + slotManager.getAnnotation(replacement.newSlot); type.replaceAnnotation(newAnnotation); } else if (replaceInExistentials && variable instanceof ExistentialVariableSlot) { Slot existentialReplacement = - constructExistentialReplacement(replacement, (ExistentialVariableSlot) variable); + constructExistentialReplacement( + replacement, (ExistentialVariableSlot) variable); if (existentialReplacement != null) { - final AnnotationMirror newAnnotation = slotManager.getAnnotation(existentialReplacement); + final AnnotationMirror newAnnotation = + slotManager.getAnnotation(existentialReplacement); type.replaceAnnotation(newAnnotation); } } } } - - protected Slot constructExistentialReplacement(Replacement replacement, - ExistentialVariableSlot variable) { + protected Slot constructExistentialReplacement( + Replacement replacement, ExistentialVariableSlot variable) { Slot potential = variable.getPotentialSlot(); AnnotationMirror potentialAnno = null; @@ -141,7 +141,8 @@ protected Slot constructExistentialReplacement(Replacement replacement, } else if (alternative instanceof ExistentialVariableSlot) { Slot existentialAlternative = - constructExistentialReplacement(replacement, (ExistentialVariableSlot) alternative); + constructExistentialReplacement( + replacement, (ExistentialVariableSlot) alternative); if (existentialAlternative != null) { alternative = existentialAlternative; @@ -166,8 +167,7 @@ public Replacement(final Slot oldSlot, final Slot newSlot) { this.newSlot = newSlot; if (oldSlot == null || newSlot == null) { - throw new BugInCF("Replacement includes null Slot: \n" - + this.toString()); + throw new BugInCF("Replacement includes null Slot: \n" + this.toString()); } } @@ -178,15 +178,14 @@ public String toString() { @Override public boolean equals(Object obj) { - if (this == obj ) return true; + if (this == obj) return true; if (obj == null || !(obj.getClass().equals(Replacement.class))) { return false; } final Replacement that = (Replacement) obj; - return this.oldSlot.equals(that.oldSlot) - && this.newSlot.equals(that.newSlot); + return this.oldSlot.equals(that.oldSlot) && this.newSlot.equals(that.newSlot); } @Override @@ -194,5 +193,4 @@ public int hashCode() { return 31 * (oldSlot.hashCode() + newSlot.hashCode()); } } - } diff --git a/src/checkers/inference/dataflow/InferenceAnalysis.java b/src/checkers/inference/dataflow/InferenceAnalysis.java index 6f8aa2811..3f62ed94a 100644 --- a/src/checkers/inference/dataflow/InferenceAnalysis.java +++ b/src/checkers/inference/dataflow/InferenceAnalysis.java @@ -1,10 +1,5 @@ package checkers.inference.dataflow; -import java.util.logging.Logger; - -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; - import org.checkerframework.framework.flow.CFAbstractAnalysis; import org.checkerframework.framework.flow.CFAnalysis; import org.checkerframework.framework.flow.CFStore; @@ -13,31 +8,35 @@ import org.checkerframework.framework.type.GenericAnnotatedTypeFactory; import org.checkerframework.javacutil.AnnotationMirrorSet; import org.checkerframework.javacutil.BugInCF; +import org.plumelib.util.StringsPlume; + +import java.util.logging.Logger; + +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; import checkers.inference.InferenceChecker; import checkers.inference.InferrableChecker; import checkers.inference.SlotManager; import checkers.inference.model.ConstraintManager; -import org.plumelib.util.StringsPlume; /** * InferenceAnalysis tweaks dataflow for Checker-Framework-Inference. * - * Checker-Framework-Inference's dataflow is primarily concerned with the creation - * and maintenance of RefinementVariableSlots. (See RefinementVariableSlots). + *

Checker-Framework-Inference's dataflow is primarily concerned with the creation and + * maintenance of RefinementVariableSlots. (See RefinementVariableSlots). * - * InferenceAnalysis returns InferenceStore for createEmptyStore and createCopiedStore. - * This is what makes the InferenceStore be the store used when the dataflow algorithm is - * executed by the type factory. + *

InferenceAnalysis returns InferenceStore for createEmptyStore and createCopiedStore. This is + * what makes the InferenceStore be the store used when the dataflow algorithm is executed by the + * type factory. * - * InferenceAnalysis also holds references to other inference components (SlotManager, ConstraintManager, etc.) - * to make them available to other inference dataflow components. + *

InferenceAnalysis also holds references to other inference components (SlotManager, + * ConstraintManager, etc.) to make them available to other inference dataflow components. * - * Finally, InferenceAnalysis make analysis' nodeValues field available outside of the class. InferenceTransfer - * uses nodeValue to override values for nodes. + *

Finally, InferenceAnalysis make analysis' nodeValues field available outside of the class. + * InferenceTransfer uses nodeValue to override values for nodes. * * @author mcarthur - * */ public class InferenceAnalysis extends CFAnalysis { @@ -62,26 +61,29 @@ public InferenceAnalysis( /** * Validate that a type has at most 1 annotation. * - * Null types will be returned when a type has no annotations. This happens currently when getting - * the declaration of a class. + *

Null types will be returned when a type has no annotations. This happens currently when + * getting the declaration of a class. */ @Override - public CFValue defaultCreateAbstractValue(CFAbstractAnalysis analysis, - AnnotationMirrorSet annos, - TypeMirror underlyingType) { + public CFValue defaultCreateAbstractValue( + CFAbstractAnalysis analysis, + AnnotationMirrorSet annos, + TypeMirror underlyingType) { if (annos.size() == 0 && underlyingType.getKind() != TypeKind.TYPEVAR) { // This happens for currently for class declarations. - logger.fine("Found type with no inferenceAnnotations. Returning null. Type found: " - + underlyingType.toString()); + logger.fine( + "Found type with no inferenceAnnotations. Returning null. Type found: " + + underlyingType.toString()); return null; } else if (annos.size() > 2) { // Canary for bugs with VarAnnots // Note: You can have 1 annotation if a primary annotation in the real type system is // present for a type variable use or wildcard - throw new BugInCF("Found type in inference with the wrong number of " - + "annotations. Should always have 0, 1, or 2: " + StringsPlume.join(", ", - annos)); + throw new BugInCF( + "Found type in inference with the wrong number of " + + "annotations. Should always have 0, 1, or 2: " + + StringsPlume.join(", ", annos)); } else { return new InferenceValue((InferenceAnalysis) analysis, annos, underlyingType); } diff --git a/src/checkers/inference/dataflow/InferenceStore.java b/src/checkers/inference/dataflow/InferenceStore.java index f170dee32..db57102ff 100644 --- a/src/checkers/inference/dataflow/InferenceStore.java +++ b/src/checkers/inference/dataflow/InferenceStore.java @@ -7,10 +7,9 @@ /** * InferenceStore extends CFStore for inference. * - * Currently it does not change the behaviour of CFStore. + *

Currently it does not change the behaviour of CFStore. * * @author mcarthur - * */ public class InferenceStore extends CFStore { @@ -21,5 +20,4 @@ public InferenceStore(InferenceAnalysis analysis, boolean sequentialSemantics) { public InferenceStore(CFAbstractStore other) { super(other); } - -} \ No newline at end of file +} diff --git a/src/checkers/inference/dataflow/InferenceValue.java b/src/checkers/inference/dataflow/InferenceValue.java index 9d9843b79..f1e8bc7b2 100644 --- a/src/checkers/inference/dataflow/InferenceValue.java +++ b/src/checkers/inference/dataflow/InferenceValue.java @@ -1,7 +1,5 @@ package checkers.inference.dataflow; -import checkers.inference.util.InferenceUtil; -import javax.lang.model.type.TypeVariable; import org.checkerframework.framework.flow.CFValue; import org.checkerframework.framework.type.AnnotatedTypeMirror; import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable; @@ -10,35 +8,35 @@ import org.checkerframework.javacutil.AnnotationMirrorSet; import org.checkerframework.javacutil.TypesUtils; -import java.util.Collections; import java.util.Iterator; -import java.util.Set; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.TypeVariable; import javax.lang.model.util.Types; import checkers.inference.InferenceMain; import checkers.inference.SlotManager; +import checkers.inference.model.ConstantSlot; import checkers.inference.model.RefinementVariableSlot; import checkers.inference.model.Slot; import checkers.inference.model.VariableSlot; -import checkers.inference.model.ConstantSlot; +import checkers.inference.util.InferenceUtil; /** * InferenceValue extends CFValue for inference. * - * leastUpperBound, creates CombVariables to represent - * the join of two VarAnnots. + *

leastUpperBound, creates CombVariables to represent the join of two VarAnnots. * * @author mcarthur - * */ public class InferenceValue extends CFValue { - - public InferenceValue(InferenceAnalysis analysis, AnnotationMirrorSet annotations, TypeMirror underlyingType) { + public InferenceValue( + InferenceAnalysis analysis, + AnnotationMirrorSet annotations, + TypeMirror underlyingType) { super(analysis, annotations, underlyingType); } @@ -47,9 +45,8 @@ private InferenceAnalysis getInferenceAnalysis() { } /** - * If values for a variable are not the same, create a merge variable to - * represent the join of the two variables. - * + * If values for a variable are not the same, create a merge variable to represent the join of + * the two variables. */ @Override public CFValue upperBound(CFValue other, TypeMirror upperBoundTypeMirror, boolean shouldWiden) { @@ -58,7 +55,8 @@ public CFValue upperBound(CFValue other, TypeMirror upperBoundTypeMirror, boolea } final SlotManager slotManager = getInferenceAnalysis().getSlotManager(); - final QualifierHierarchy qualifierHierarchy = analysis.getTypeFactory().getQualifierHierarchy(); + final QualifierHierarchy qualifierHierarchy = + analysis.getTypeFactory().getQualifierHierarchy(); Slot slot1 = getEffectiveSlot(this); Slot slot2 = getEffectiveSlot(other); @@ -70,15 +68,18 @@ public CFValue upperBound(CFValue other, TypeMirror upperBoundTypeMirror, boolea // the two VarAnnos getting from slotManager. final AnnotationMirror lub = qualifierHierarchy.leastUpperBoundQualifiersOnly(anno1, anno2); - return analysis.createAbstractValue(AnnotationMirrorSet.singleton(lub), getLubType(other, null)); + return analysis.createAbstractValue( + AnnotationMirrorSet.singleton(lub), getLubType(other, null)); } public Slot getEffectiveSlot(final CFValue value) { if (value.getUnderlyingType().getKind() == TypeKind.TYPEVAR) { TypeVariable typevar = ((TypeVariable) value.getUnderlyingType()); AnnotatedTypeVariable type = - (AnnotatedTypeVariable) analysis.getTypeFactory().getAnnotatedType(typevar.asElement()); - AnnotatedTypeMirror ubType = InferenceUtil.findUpperBoundType(type, InferenceMain.isHackMode()); + (AnnotatedTypeVariable) + analysis.getTypeFactory().getAnnotatedType(typevar.asElement()); + AnnotatedTypeMirror ubType = + InferenceUtil.findUpperBoundType(type, InferenceMain.isHackMode()); return getInferenceAnalysis().getSlotManager().getSlot(ubType); } Iterator iterator = value.getAnnotations().iterator(); @@ -105,21 +106,22 @@ public CFValue mostSpecific(CFValue other, CFValue backup) { } /** - * When inference looks up an identifier, it uses mostSpecific to determine - * if the store value or the factory value should be used. + * When inference looks up an identifier, it uses mostSpecific to determine if the store value + * or the factory value should be used. * - * Most specific must be overridden to ensure the correct annotation for a - * variable for the block that it is in is used. + *

Most specific must be overridden to ensure the correct annotation for a variable for the + * block that it is in is used. * - * With a declared type and its refinement variable, we want to use the refinement variable. + *

With a declared type and its refinement variable, we want to use the refinement variable. * - * If one variable has been merged to a comb variable, we want to use the comb - * variable that was merged to. - * - * If any refinement variables for one variable has been merged to the other, we want the other. + *

If one variable has been merged to a comb variable, we want to use the comb variable that + * was merged to. * + *

If any refinement variables for one variable has been merged to the other, we want the + * other. */ - public CFValue mostSpecificFromSlot(final Slot thisSlot, final Slot otherSlot, final CFValue other, final CFValue backup) { + public CFValue mostSpecificFromSlot( + final Slot thisSlot, final Slot otherSlot, final CFValue other, final CFValue backup) { if (thisSlot.isMergedTo(otherSlot)) { return other; } @@ -140,12 +142,16 @@ public CFValue mostSpecificFromSlot(final Slot thisSlot, final Slot otherSlot, f if (thisSlot instanceof RefinementVariableSlot && otherSlot instanceof RefinementVariableSlot - && ((RefinementVariableSlot) thisSlot).getRefined().equals(((RefinementVariableSlot) otherSlot).getRefined())) { - // This happens when a local variable is declared with initializer, and is reassigned afterwards. E.g. + && ((RefinementVariableSlot) thisSlot) + .getRefined() + .equals(((RefinementVariableSlot) otherSlot).getRefined())) { + // This happens when a local variable is declared with initializer, and is reassigned + // afterwards. E.g. // Object obj = null; // obj = new Object(); // return obj; - // Suppose RefinementVar(1) is created at variable declaration, RefinementVar(2) is created at re-assignment. + // Suppose RefinementVar(1) is created at variable declaration, RefinementVar(2) is + // created at re-assignment. // Then at the return point, when getting the most specific type of obj, // "thisSlot" is RefinementVar(1), coming from "getValueFromFactory". // "otherSlot" is RefinementVar(2), coming from the store value. @@ -187,7 +193,7 @@ public CFValue mostSpecificTypeVariable(TypeMirror resultType, CFValue other, CF } // result is type var T and the mostSpecific is type var T - if (types.isSameType(resultType, mostSpecificValue.getUnderlyingType())) { + if (types.isSameType(resultType, mostSpecificValue.getUnderlyingType())) { return mostSpecificValue; } @@ -195,11 +201,11 @@ public CFValue mostSpecificTypeVariable(TypeMirror resultType, CFValue other, CF // copy primary of U over to T final AnnotationMirror mostSpecificAnno = getInferenceAnalysis() - .getSlotManager() - .getAnnotation(mostSpecificValue == this ? thisSlot : otherSlot); - + .getSlotManager() + .getAnnotation(mostSpecificValue == this ? thisSlot : otherSlot); - AnnotatedTypeMirror resultAtm = AnnotatedTypeMirror.createType(resultType, analysis.getTypeFactory(), false); + AnnotatedTypeMirror resultAtm = + AnnotatedTypeMirror.createType(resultType, analysis.getTypeFactory(), false); resultAtm.addAnnotation(mostSpecificAnno); return analysis.createAbstractValue(resultAtm); } @@ -209,8 +215,8 @@ private TypeMirror getLubType(final CFValue other, final CFValue backup) { // Create new full type (with the same underlying type), and then add // the appropriate annotations. TypeMirror underlyingType = - TypesUtils.leastUpperBound(getUnderlyingType(), - other.getUnderlyingType(), analysis.getEnv()); + TypesUtils.leastUpperBound( + getUnderlyingType(), other.getUnderlyingType(), analysis.getEnv()); if (underlyingType.getKind() == TypeKind.ERROR || underlyingType.getKind() == TypeKind.NONE) { @@ -230,8 +236,8 @@ private TypeMirror getGlbType(final CFValue other, final CFValue backup) { // Create new full type (with the same underlying type), and then add // the appropriate annotations. TypeMirror underlyingType = - TypesUtils.greatestLowerBound(getUnderlyingType(), - other.getUnderlyingType(), analysis.getEnv()); + TypesUtils.greatestLowerBound( + getUnderlyingType(), other.getUnderlyingType(), analysis.getEnv()); if (underlyingType.getKind() == TypeKind.ERROR || underlyingType.getKind() == TypeKind.NONE) { diff --git a/src/checkers/inference/model/AlwaysFalseConstraint.java b/src/checkers/inference/model/AlwaysFalseConstraint.java index 5a1ec6d5f..0c7060589 100644 --- a/src/checkers/inference/model/AlwaysFalseConstraint.java +++ b/src/checkers/inference/model/AlwaysFalseConstraint.java @@ -1,8 +1,9 @@ package checkers.inference.model; -import java.util.Collections; import org.checkerframework.javacutil.BugInCF; +import java.util.Collections; + /** * This "constraint" is the result of normalizing another constraint, where that constraint is * always false (evaluates to contradiction). This class is implemented as a singleton. @@ -28,7 +29,8 @@ protected static AlwaysFalseConstraint create() { @Override public T serialize(Serializer serializer) { throw new BugInCF( - "Attempting to serialize an " + AlwaysFalseConstraint.class.getCanonicalName() + "Attempting to serialize an " + + AlwaysFalseConstraint.class.getCanonicalName() + ". This constraint should never be serialized."); } } diff --git a/src/checkers/inference/model/AlwaysTrueConstraint.java b/src/checkers/inference/model/AlwaysTrueConstraint.java index a2e82120c..1450d96a9 100644 --- a/src/checkers/inference/model/AlwaysTrueConstraint.java +++ b/src/checkers/inference/model/AlwaysTrueConstraint.java @@ -1,8 +1,9 @@ package checkers.inference.model; -import java.util.Collections; import org.checkerframework.javacutil.BugInCF; +import java.util.Collections; + /** * This "constraint" is the result of normalizing another constraint, where that constraint is * always true (evaluates to tautology). This class is implemented as a singleton. @@ -28,7 +29,8 @@ protected static AlwaysTrueConstraint create() { @Override public T serialize(Serializer serializer) { throw new BugInCF( - "Attempting to serialize an " + AlwaysTrueConstraint.class.getCanonicalName() + "Attempting to serialize an " + + AlwaysTrueConstraint.class.getCanonicalName() + ". This constraint should never be serialized."); } } diff --git a/src/checkers/inference/model/AnnotationLocation.java b/src/checkers/inference/model/AnnotationLocation.java index 803edc832..b12b87fa7 100644 --- a/src/checkers/inference/model/AnnotationLocation.java +++ b/src/checkers/inference/model/AnnotationLocation.java @@ -3,30 +3,26 @@ import org.checkerframework.afu.scenelib.io.ASTPath; import org.checkerframework.afu.scenelib.io.ASTRecord; -/** - * Describes a location in Java Source Code. - */ +/** Describes a location in Java Source Code. */ public abstract class AnnotationLocation { /** - * The default instance of MISSING_LOCATION, the constructor is private. - * TODO: Maybe we should have MISSING_LOCATION information that contains strings or even - * TODO: path information that identifies the locations that cannot be inserted BUT can - * TODO: can be + * The default instance of MISSING_LOCATION, the constructor is private. TODO: Maybe we should + * have MISSING_LOCATION information that contains strings or even TODO: path information that + * identifies the locations that cannot be inserted BUT can TODO: can be */ public static AnnotationLocation MISSING_LOCATION = new MissingLocation(); /** - * Annotation locations can be of 3 kinds: - * a) a general location described by an Annotation File Utilities AST Path, - * this covers all locations except or annotations on class declarations + * Annotation locations can be of 3 kinds: a) a general location described by an Annotation File + * Utilities AST Path, this covers all locations except or annotations on class declarations * - * b) class declaration annotations (e.g. @HERE class MyClass {...} + *

b) class declaration annotations (e.g. @HERE class MyClass {...} * - * c) missing, that is there is no source code location for a specified annotation + *

c) missing, that is there is no source code location for a specified annotation */ public enum Kind { - /** The most common Annotation kind specified by an AstPath, see AstPathLocation*/ + /** The most common Annotation kind specified by an AstPath, see AstPathLocation */ AST_PATH, /** Applicable only for annotations in front of class declarations, see ClassDeclLocation */ @@ -49,7 +45,8 @@ public Kind getKind() { } /** - * Associates an annotation with an exact location in source using Annotation File Utilities ASTRecords + * Associates an annotation with an exact location in source using Annotation File Utilities + * ASTRecords */ public static class AstPathLocation extends AnnotationLocation { private final ASTRecord astRecord; @@ -91,14 +88,19 @@ public int hashCode() { @Override public String toString() { - return "AstPathLocation( " + astRecord.className + "." + astRecord.methodName + "." - + astRecord.varName + ":" + astRecord.toString() + " )"; + return "AstPathLocation( " + + astRecord.className + + "." + + astRecord.methodName + + "." + + astRecord.varName + + ":" + + astRecord.toString() + + " )"; } } - /** - * Associates an annotation on a class declaration in source using class and package names - */ + /** Associates an annotation on a class declaration in source using class and package names */ public static class ClassDeclLocation extends AnnotationLocation { private final String fullyQualifiedClassName; @@ -140,10 +142,10 @@ public String toString() { } /** - * Indicates that a annotation is not insertable in source. It is also used in location - * where we haven't yet created the code to create an "implied tree", i.e. a place - * where the AFU will create source code and insert annotations there but we haven't - * created the code to make the AFU String to place in the output JAIF + * Indicates that a annotation is not insertable in source. It is also used in location where we + * haven't yet created the code to create an "implied tree", i.e. a place where the AFU will + * create source code and insert annotations there but we haven't created the code to make the + * AFU String to place in the output JAIF */ private static class MissingLocation extends AnnotationLocation { diff --git a/src/checkers/inference/model/ArithmeticConstraint.java b/src/checkers/inference/model/ArithmeticConstraint.java index e588a6ad0..3836d1c53 100644 --- a/src/checkers/inference/model/ArithmeticConstraint.java +++ b/src/checkers/inference/model/ArithmeticConstraint.java @@ -1,10 +1,11 @@ package checkers.inference.model; -import java.util.Arrays; -import java.util.Objects; +import com.sun.source.tree.Tree; import org.checkerframework.javacutil.BugInCF; -import com.sun.source.tree.Tree; + +import java.util.Arrays; +import java.util.Objects; /** * Represents a constraint between the result of an arithmetic operation and its two operands. @@ -34,10 +35,13 @@ private ArithmeticOperationKind(String opSymbol) { } /** - * Get the {@link ArithmeticOperationKind} corresponding to a {@link Tree.Kind}. For a compound - * assignment tree, get the {@link ArithmeticOperationKind} for the arithmetic operation of the RHS. + * Get the {@link ArithmeticOperationKind} corresponding to a {@link Tree.Kind}. For a + * compound assignment tree, get the {@link ArithmeticOperationKind} for the arithmetic + * operation of the RHS. + * * @param kind a {@link Tree.Kind} for an arithmetic operation - * @return the corresponding {@link ArithmeticOperationKind} for the given arithmetic operation + * @return the corresponding {@link ArithmeticOperationKind} for the given arithmetic + * operation */ public static ArithmeticOperationKind fromTreeKind(Tree.Kind kind) { switch (kind) { @@ -75,8 +79,10 @@ public static ArithmeticOperationKind fromTreeKind(Tree.Kind kind) { case XOR_ASSIGNMENT: return XOR; default: - throw new BugInCF("There are no defined ArithmeticOperationKinds " - + "for the given com.sun.source.tree.Tree.Kind: " + kind); + throw new BugInCF( + "There are no defined ArithmeticOperationKinds " + + "for the given com.sun.source.tree.Tree.Kind: " + + kind); } } @@ -90,8 +96,12 @@ public String getSymbol() { private final Slot rightOperand; // either a {@link ConstantSlot} or a {@link VariableSlot} private final ArithmeticVariableSlot result; - private ArithmeticConstraint(ArithmeticOperationKind operation, Slot leftOperand, - Slot rightOperand, ArithmeticVariableSlot result, AnnotationLocation location) { + private ArithmeticConstraint( + ArithmeticOperationKind operation, + Slot leftOperand, + Slot rightOperand, + ArithmeticVariableSlot result, + AnnotationLocation location) { super(Arrays.asList(leftOperand, rightOperand, result), location); this.operation = operation; this.leftOperand = leftOperand; @@ -99,13 +109,23 @@ private ArithmeticConstraint(ArithmeticOperationKind operation, Slot leftOperand this.result = result; } - protected static ArithmeticConstraint create(ArithmeticOperationKind operation, - Slot leftOperand, Slot rightOperand, ArithmeticVariableSlot result, + protected static ArithmeticConstraint create( + ArithmeticOperationKind operation, + Slot leftOperand, + Slot rightOperand, + ArithmeticVariableSlot result, AnnotationLocation location) { if (operation == null || leftOperand == null || rightOperand == null || result == null) { - throw new BugInCF("Create arithmetic constraint with null argument. " - + "Operation: " + operation + " LeftOperand: " + leftOperand + " RightOperand: " - + rightOperand + " Result: " + result); + throw new BugInCF( + "Create arithmetic constraint with null argument. " + + "Operation: " + + operation + + " LeftOperand: " + + leftOperand + + " RightOperand: " + + rightOperand + + " Result: " + + result); } if (location == null || location.getKind() == AnnotationLocation.Kind.MISSING) { throw new BugInCF( @@ -152,7 +172,9 @@ public boolean equals(Object obj) { return false; } ArithmeticConstraint other = (ArithmeticConstraint) obj; - return operation.equals(other.operation) && leftOperand.equals(other.leftOperand) - && rightOperand.equals(other.rightOperand) && result.equals(other.result); + return operation.equals(other.operation) + && leftOperand.equals(other.leftOperand) + && rightOperand.equals(other.rightOperand) + && result.equals(other.result); } } diff --git a/src/checkers/inference/model/ArithmeticVariableSlot.java b/src/checkers/inference/model/ArithmeticVariableSlot.java index 373568050..556786c9d 100644 --- a/src/checkers/inference/model/ArithmeticVariableSlot.java +++ b/src/checkers/inference/model/ArithmeticVariableSlot.java @@ -3,19 +3,19 @@ import javax.lang.model.type.TypeKind; /** - * ArithmeticVariableSlot represent the result of an arithmetic operation between two other - * {@link Slot}s. Note that this slot is serialized identically to a {@link Slot}. + * ArithmeticVariableSlot represent the result of an arithmetic operation between two other {@link + * Slot}s. Note that this slot is serialized identically to a {@link Slot}. */ public class ArithmeticVariableSlot extends VariableSlot { /** - * The value kind of the arithmetic operation, which indicates the value range. - * (i) If one operand is long => long - * (ii) otherwise => int + * The value kind of the arithmetic operation, which indicates the value range. (i) If one + * operand is long => long (ii) otherwise => int */ private final TypeKind valueTypeKind; /** * Constructor + * * @param id slot id * @param location location of the slot * @param valueTypeKind the type kind of the arithmetic operation diff --git a/src/checkers/inference/model/BinaryConstraint.java b/src/checkers/inference/model/BinaryConstraint.java index 63931c4a7..97522dbe6 100644 --- a/src/checkers/inference/model/BinaryConstraint.java +++ b/src/checkers/inference/model/BinaryConstraint.java @@ -1,24 +1,20 @@ package checkers.inference.model; /** - * Implemented by constraints between two variables. Make is provided to be able to make a copy of - * the constraint without knowing the concrete base class. getFirst and getSecond are provided - * so that users can either copy through a slot to a constraint made by make or substitute out a - * variable. E.g., + * Implemented by constraints between two variables. Make is provided to be able to make a copy of + * the constraint without knowing the concrete base class. getFirst and getSecond are provided so + * that users can either copy through a slot to a constraint made by make or substitute out a + * variable. E.g., * - * // this call makes a copy of the constraint - * make(getFirst(), getSecond()) + *

// this call makes a copy of the constraint make(getFirst(), getSecond()) * - * // this call modifies the first slot - * make(mutate(getFirst()), getSecond()) + *

// this call modifies the first slot make(mutate(getFirst()), getSecond()) */ public interface BinaryConstraint { Slot getFirst(); + Slot getSecond(); - /** - * Make a constraint that has the same class as this constraint but using the input - * slots. - */ + /** Make a constraint that has the same class as this constraint but using the input slots. */ Constraint make(final Slot first, final Slot second); } diff --git a/src/checkers/inference/model/CombVariableSlot.java b/src/checkers/inference/model/CombVariableSlot.java index 27280fbc1..f0ae6c7eb 100644 --- a/src/checkers/inference/model/CombVariableSlot.java +++ b/src/checkers/inference/model/CombVariableSlot.java @@ -3,13 +3,13 @@ /** * CombVariableSlots represent locations whose values depend on two other VariableSlots. * - * CombVariableSlots are used to model viewpoint adaptation result of two slots. + *

CombVariableSlots are used to model viewpoint adaptation result of two slots. * - * TODO: Wener uses this class for Viewpoint adaptation. All other locations are intended to be - * TODO: used to represent LUBS. Those uses should be replaced either with a new LubVariableSlot - * TODO: or just a new VariableSlot with subtype constraints - * TODO: One thing to note, is the viewpoint adaptation locations I believe should be - * TODO: accompanied with a CombineConstraint where as the LUBs only use the subtype constraints + *

TODO: Wener uses this class for Viewpoint adaptation. All other locations are intended to be + * TODO: used to represent LUBS. Those uses should be replaced either with a new LubVariableSlot + * TODO: or just a new VariableSlot with subtype constraints TODO: One thing to note, is the + * viewpoint adaptation locations I believe should be TODO: accompanied with a CombineConstraint + * where as the LUBs only use the subtype constraints */ public class CombVariableSlot extends VariableSlot { @@ -41,8 +41,8 @@ public Slot getSecond() { } /** - * CombVariables should never be re-inserted into the source code. record - * does not correspond to an annotatable position. + * CombVariables should never be re-inserted into the source code. record does not correspond to + * an annotatable position. * * @return false */ @@ -62,23 +62,16 @@ public int hashCode() { @Override public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; CombVariableSlot other = (CombVariableSlot) obj; if (first == null) { - if (other.first != null) - return false; - } else if (!first.equals(other.first)) - return false; + if (other.first != null) return false; + } else if (!first.equals(other.first)) return false; if (second == null) { - if (other.second != null) - return false; - } else if (!second.equals(other.second)) - return false; + if (other.second != null) return false; + } else if (!second.equals(other.second)) return false; return true; } } diff --git a/src/checkers/inference/model/CombineConstraint.java b/src/checkers/inference/model/CombineConstraint.java index 7087ab141..aec8c72c9 100644 --- a/src/checkers/inference/model/CombineConstraint.java +++ b/src/checkers/inference/model/CombineConstraint.java @@ -1,13 +1,13 @@ package checkers.inference.model; -import java.util.Arrays; import org.checkerframework.javacutil.BugInCF; +import java.util.Arrays; + /** - * Represents a constraint that the viewpoint adaptation between - * target and decl gives result. + * Represents a constraint that the viewpoint adaptation between target and decl gives result. * - * TODO: clarify relation to CombVariableSlot. Should we add separate types? + *

TODO: clarify relation to CombVariableSlot. Should we add separate types? */ public class CombineConstraint extends Constraint { @@ -15,18 +15,24 @@ public class CombineConstraint extends Constraint { private final Slot decl; private final CombVariableSlot result; - private CombineConstraint(Slot target, Slot decl, CombVariableSlot result, AnnotationLocation location) { + private CombineConstraint( + Slot target, Slot decl, CombVariableSlot result, AnnotationLocation location) { super(Arrays.asList(target, decl, result), location); this.target = target; this.decl = decl; this.result = result; } - protected static CombineConstraint create(Slot target, Slot decl, CombVariableSlot result, - AnnotationLocation location) { + protected static CombineConstraint create( + Slot target, Slot decl, CombVariableSlot result, AnnotationLocation location) { if (target == null || decl == null || result == null) { - throw new BugInCF("Create combine constraint with null argument. Target: " - + target + " Decl: " + decl + " Result: " + result); + throw new BugInCF( + "Create combine constraint with null argument. Target: " + + target + + " Decl: " + + decl + + " Result: " + + result); } return new CombineConstraint(target, decl, result, location); @@ -60,16 +66,11 @@ public int hashCode() { @Override public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; CombineConstraint other = (CombineConstraint) obj; - if (target.equals(other.target) && - decl.equals(other.decl) && - result.equals(other.result)) { + if (target.equals(other.target) && decl.equals(other.decl) && result.equals(other.result)) { return true; } else { return false; diff --git a/src/checkers/inference/model/ComparableConstraint.java b/src/checkers/inference/model/ComparableConstraint.java index 0c58e32f1..75e4223ce 100644 --- a/src/checkers/inference/model/ComparableConstraint.java +++ b/src/checkers/inference/model/ComparableConstraint.java @@ -1,14 +1,15 @@ package checkers.inference.model; -import java.util.Arrays; - import org.checkerframework.framework.type.QualifierHierarchy; import org.checkerframework.javacutil.BugInCF; +import java.util.Arrays; + /** - * Represents a constraint that two slots must be comparable, i.e. one type can be cast to the other. + * Represents a constraint that two slots must be comparable, i.e. one type can be cast to the + * other. * - * In contrast, a {@link ComparisonConstraint} is created when two expressions are compared. + *

In contrast, a {@link ComparisonConstraint} is created when two expressions are compared. */ public class ComparableConstraint extends Constraint implements BinaryConstraint { @@ -27,11 +28,17 @@ private ComparableConstraint(Slot first, Slot second) { this.second = second; } - protected static Constraint create(Slot first, Slot second, AnnotationLocation location, + protected static Constraint create( + Slot first, + Slot second, + AnnotationLocation location, QualifierHierarchy realQualHierarchy) { if (first == null || second == null) { - throw new BugInCF("Create comparable constraint with null argument. Subtype: " - + first + " Supertype: " + second); + throw new BugInCF( + "Create comparable constraint with null argument. Subtype: " + + first + + " Supertype: " + + second); } // Normalization cases: @@ -44,10 +51,12 @@ protected static Constraint create(Slot first, Slot second, AnnotationLocation l ConstantSlot firstConst = (ConstantSlot) first; ConstantSlot secondConst = (ConstantSlot) second; - return realQualHierarchy.isSubtypeQualifiersOnly(firstConst.getValue(), secondConst.getValue()) - || realQualHierarchy.isSubtypeQualifiersOnly(secondConst.getValue(), firstConst.getValue()) - ? AlwaysTrueConstraint.create() - : AlwaysFalseConstraint.create(); + return realQualHierarchy.isSubtypeQualifiersOnly( + firstConst.getValue(), secondConst.getValue()) + || realQualHierarchy.isSubtypeQualifiersOnly( + secondConst.getValue(), firstConst.getValue()) + ? AlwaysTrueConstraint.create() + : AlwaysFalseConstraint.create(); } // V <~> V => TRUE (every type is always comparable to itself) @@ -89,12 +98,9 @@ public int hashCode() { @Override public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; ComparableConstraint other = (ComparableConstraint) obj; if ((first.equals(other.first) && second.equals(other.second)) || (first.equals(other.second) && (second.equals(other.first)))) { @@ -103,4 +109,4 @@ public boolean equals(Object obj) { return false; } } -} \ No newline at end of file +} diff --git a/src/checkers/inference/model/ComparisonConstraint.java b/src/checkers/inference/model/ComparisonConstraint.java index 97a55da28..63c372b0d 100644 --- a/src/checkers/inference/model/ComparisonConstraint.java +++ b/src/checkers/inference/model/ComparisonConstraint.java @@ -1,20 +1,19 @@ package checkers.inference.model; -import java.util.Arrays; -import java.util.Objects; +import com.sun.source.tree.Tree.Kind; import org.checkerframework.framework.type.QualifierHierarchy; import org.checkerframework.javacutil.BugInCF; -import com.sun.source.tree.Tree.Kind; +import java.util.Arrays; +import java.util.Objects; /** - * Represents constraints created for: - * (1) numerical comparison ("==", "!=", ">", ">=", "<", "<=") - * (2) comparison between references/null ("==", "!=") + * Represents constraints created for: (1) numerical comparison ("==", "!=", ">", ">=", "<", "<=") + * (2) comparison between references/null ("==", "!=") * - * In contrast, a {@link ComparableConstraint} describes two types are compatible, - * i.e. one type can be cast to the other. + *

In contrast, a {@link ComparableConstraint} describes two types are compatible, i.e. one type + * can be cast to the other. */ public class ComparisonConstraint extends Constraint { @@ -22,7 +21,7 @@ public class ComparisonConstraint extends Constraint { private final Slot left; private final Slot right; private final ComparisonVariableSlot result; - + public enum ComparisonOperationKind { EQUAL_TO("=="), NOT_EQUAL_TO("!="), @@ -41,20 +40,22 @@ private ComparisonOperationKind(String opSymbol) { public static ComparisonOperationKind fromTreeKind(Kind kind) { switch (kind) { case EQUAL_TO: - return EQUAL_TO; + return EQUAL_TO; case NOT_EQUAL_TO: - return NOT_EQUAL_TO; + return NOT_EQUAL_TO; case GREATER_THAN: - return GREATER_THAN; + return GREATER_THAN; case GREATER_THAN_EQUAL: - return GREATER_THAN_EQUAL; + return GREATER_THAN_EQUAL; case LESS_THAN: - return LESS_THAN; + return LESS_THAN; case LESS_THAN_EQUAL: - return LESS_THAN_EQUAL; + return LESS_THAN_EQUAL; default: - throw new BugInCF("There are no defined ComparableOperationKind " - + "for the given com.sun.source.tree.Tree.Kind: " + kind); + throw new BugInCF( + "There are no defined ComparableOperationKind " + + "for the given com.sun.source.tree.Tree.Kind: " + + kind); } } @@ -63,8 +64,12 @@ public String getSymbol() { } } - private ComparisonConstraint(ComparisonOperationKind operation, Slot left, Slot right, - ComparisonVariableSlot result, AnnotationLocation location) { + private ComparisonConstraint( + ComparisonOperationKind operation, + Slot left, + Slot right, + ComparisonVariableSlot result, + AnnotationLocation location) { super(Arrays.asList(left, right, result), location); this.left = left; this.right = right; @@ -72,12 +77,22 @@ private ComparisonConstraint(ComparisonOperationKind operation, Slot left, Slot this.result = result; } - protected static Constraint create(ComparisonOperationKind operation, Slot left, Slot right, - ComparisonVariableSlot result, AnnotationLocation location, QualifierHierarchy realQualHierarchy) { + protected static Constraint create( + ComparisonOperationKind operation, + Slot left, + Slot right, + ComparisonVariableSlot result, + AnnotationLocation location, + QualifierHierarchy realQualHierarchy) { if (operation == null || left == null || right == null) { - throw new BugInCF("Create comparable constraint with null argument. " - + "Operation: " + operation + " Subtype: " - + left + " Supertype: " + right); + throw new BugInCF( + "Create comparable constraint with null argument. " + + "Operation: " + + operation + + " Subtype: " + + left + + " Supertype: " + + right); } if (location == null || location.getKind() == AnnotationLocation.Kind.MISSING) { throw new BugInCF( @@ -103,7 +118,7 @@ public Slot getLeft() { public Slot getRight() { return right; } - + public ComparisonVariableSlot getResult() { return result; } @@ -125,7 +140,8 @@ public boolean equals(Object obj) { return false; } ComparisonConstraint other = (ComparisonConstraint) obj; - return left.equals(other.left) && right.equals(other.right) - && operation.equals(other.operation); + return left.equals(other.left) + && right.equals(other.right) + && operation.equals(other.operation); } } diff --git a/src/checkers/inference/model/ComparisonVariableSlot.java b/src/checkers/inference/model/ComparisonVariableSlot.java index d5261cde3..e13bafbf0 100644 --- a/src/checkers/inference/model/ComparisonVariableSlot.java +++ b/src/checkers/inference/model/ComparisonVariableSlot.java @@ -1,10 +1,9 @@ package checkers.inference.model; /** - * ComparisonVariableSlot represent the left side refinement of an comparison operation between two other - * {@link VariableSlot}s. - * e.g., for a comparison constraint c := x < y, the comparison variable slot c is the refined value of - * x where x < y is always when x = c. + * ComparisonVariableSlot represent the left side refinement of an comparison operation between two + * other {@link VariableSlot}s. e.g., for a comparison constraint c := x < y, the comparison + * variable slot c is the refined value of x where x < y is always when x = c. */ public class ComparisonVariableSlot extends VariableSlot { private final Slot refined; diff --git a/src/checkers/inference/model/ConstantSlot.java b/src/checkers/inference/model/ConstantSlot.java index 14e1eca6d..8e34c6e7f 100644 --- a/src/checkers/inference/model/ConstantSlot.java +++ b/src/checkers/inference/model/ConstantSlot.java @@ -1,34 +1,30 @@ package checkers.inference.model; -import checkers.inference.InferenceMain; -import checkers.inference.InferenceQualifierHierarchy; import org.checkerframework.javacutil.AnnotationUtils; import org.checkerframework.javacutil.BugInCF; -import checkers.inference.qual.VarAnnot; - import javax.lang.model.element.AnnotationMirror; +import checkers.inference.InferenceQualifierHierarchy; + /** * Represents a real qualifier of the type system. * - * Constant slots are used for elements with fixed types, e.g. literals. + *

Constant slots are used for elements with fixed types, e.g. literals. */ public class ConstantSlot extends Slot { - /** - * The annotation in the real type system that this slot is equivalent to - */ + /** The annotation in the real type system that this slot is equivalent to */ private final AnnotationMirror value; /** - * - * @param value The actual AnnotationMirror that this ConstantSlot represents. This AnnotationMirror should - * be valid within the type system for which we are inferring values. - * @param id Exactly like a variable id, this will uniquely identify this constant in the entirey of the - * program - * - * The location for slots constructed using this constructor will be AnnotationLocation.MISSING_LOCATION + * @param value The actual AnnotationMirror that this ConstantSlot represents. This + * AnnotationMirror should be valid within the type system for which we are inferring + * values. + * @param id Exactly like a variable id, this will uniquely identify this constant in the + * entirey of the program + *

The location for slots constructed using this constructor will be + * AnnotationLocation.MISSING_LOCATION */ public ConstantSlot(int id, AnnotationMirror value) { super(id); @@ -38,7 +34,8 @@ public ConstantSlot(int id, AnnotationMirror value) { private void checkValue(AnnotationMirror value) { if (InferenceQualifierHierarchy.isVarAnnot(value)) { - throw new BugInCF("Invalid attempt to create a ConstantSlot with VarAnnot as value: " + value); + throw new BugInCF( + "Invalid attempt to create a ConstantSlot with VarAnnot as value: " + value); } } @@ -79,18 +76,13 @@ public int hashCode() { @Override public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; ConstantSlot other = (ConstantSlot) obj; if (value == null) { - if (other.value != null) - return false; - } else if (!AnnotationUtils.areSame(value,other.value)) - return false; + if (other.value != null) return false; + } else if (!AnnotationUtils.areSame(value, other.value)) return false; return true; } } diff --git a/src/checkers/inference/model/Constraint.java b/src/checkers/inference/model/Constraint.java index faaefea08..7e3d6fbbf 100644 --- a/src/checkers/inference/model/Constraint.java +++ b/src/checkers/inference/model/Constraint.java @@ -3,20 +3,16 @@ import java.util.List; /** - * A Constraint represents a logical relationship between two or more Slots of any type. ConstraintSolvers - * assign values to VariableSlots such that the resulting assignments, if possible, satisfy all the given - * Constraints. + * A Constraint represents a logical relationship between two or more Slots of any type. + * ConstraintSolvers assign values to VariableSlots such that the resulting assignments, if + * possible, satisfy all the given Constraints. */ public abstract class Constraint { - /** - * The slots constrained by this object - */ + /** The slots constrained by this object */ private final List slots; - /** - * Used to locate this constraint in source code. - */ + /** Used to locate this constraint in source code. */ private final AnnotationLocation location; public Constraint(List slots, AnnotationLocation location) { diff --git a/src/checkers/inference/model/ConstraintManager.java b/src/checkers/inference/model/ConstraintManager.java index d6fa6c927..bbaca4101 100644 --- a/src/checkers/inference/model/ConstraintManager.java +++ b/src/checkers/inference/model/ConstraintManager.java @@ -1,13 +1,15 @@ package checkers.inference.model; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - import com.sun.source.util.TreePath; + import org.checkerframework.framework.source.SourceChecker; import org.checkerframework.framework.type.QualifierHierarchy; import org.checkerframework.javacutil.BugInCF; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + import checkers.inference.InferenceAnnotatedTypeFactory; import checkers.inference.VariableAnnotator; import checkers.inference.model.ArithmeticConstraint.ArithmeticOperationKind; @@ -17,7 +19,6 @@ * Constraint manager holds constraints that are generated by InferenceVisitor. * * @author mcarthur - * */ public class ConstraintManager { @@ -52,8 +53,7 @@ public Set getConstraints() { private void add(Constraint constraint) { if (!ignoreConstraints) { if (constraint instanceof AlwaysFalseConstraint) { - throw new BugInCF( - "An AlwaysFalseConstraint is being added to the constraint set."); + throw new BugInCF("An AlwaysFalseConstraint is being added to the constraint set."); } else if (!(constraint instanceof AlwaysTrueConstraint)) { constraints.add(constraint); } @@ -61,11 +61,10 @@ private void add(Constraint constraint) { } /** - * Allows {@link ImplicationConstraint} to add its component assumptions - * directly to the manager as part of one of its normalization cases. + * Allows {@link ImplicationConstraint} to add its component assumptions directly to the manager + * as part of one of its normalization cases. * - * @param constraints - * a collection of (possibly normalized) constraints + * @param constraints a collection of (possibly normalized) constraints */ protected void addAll(Iterable constraints) { for (Constraint c : constraints) { @@ -85,12 +84,12 @@ public void stopIgnoringConstraints() { // slots. It does not issue errors for unsatisfiable constraints. /** - * Creates a {@link SubtypeConstraint} between the two slots, which may be normalized to - * {@link AlwaysTrueConstraint}, {@link AlwaysFalseConstraint}, or {@link EqualityConstraint}. + * Creates a {@link SubtypeConstraint} between the two slots, which may be normalized to {@link + * AlwaysTrueConstraint}, {@link AlwaysFalseConstraint}, or {@link EqualityConstraint}. */ public Constraint createSubtypeConstraint(Slot subtype, Slot supertype) { - return SubtypeConstraint.create(subtype, supertype, getCurrentLocation(), - realQualHierarchy); + return SubtypeConstraint.create( + subtype, supertype, getCurrentLocation(), realQualHierarchy); } /** @@ -117,49 +116,50 @@ public Constraint createComparableConstraint(Slot first, Slot second) { return ComparableConstraint.create(first, second, getCurrentLocation(), realQualHierarchy); } - /** - * Creates a {@link ComparisonConstraint} between the two slots. - */ - public Constraint createComparisonConstraint(ComparisonOperationKind operation, Slot first, - Slot second, ComparisonVariableSlot result) { - return ComparisonConstraint.create(operation, first, second, result, getCurrentLocation(), realQualHierarchy); + /** Creates a {@link ComparisonConstraint} between the two slots. */ + public Constraint createComparisonConstraint( + ComparisonOperationKind operation, + Slot first, + Slot second, + ComparisonVariableSlot result) { + return ComparisonConstraint.create( + operation, first, second, result, getCurrentLocation(), realQualHierarchy); } - /** - * Creates a {@link CombineConstraint} between the three slots. - */ - public CombineConstraint createCombineConstraint(Slot target, Slot decl, CombVariableSlot result) { + /** Creates a {@link CombineConstraint} between the three slots. */ + public CombineConstraint createCombineConstraint( + Slot target, Slot decl, CombVariableSlot result) { return CombineConstraint.create(target, decl, result, getCurrentLocation()); } - /** - * Creates a {@link PreferenceConstraint} for the given slots with the given weight. - */ - public PreferenceConstraint createPreferenceConstraint(VariableSlot variable, ConstantSlot goal, - int weight) { + /** Creates a {@link PreferenceConstraint} for the given slots with the given weight. */ + public PreferenceConstraint createPreferenceConstraint( + VariableSlot variable, ConstantSlot goal, int weight) { return PreferenceConstraint.create(variable, goal, weight, getCurrentLocation()); } - /** - * Creates an {@link ExistentialConstraint} for the given slot and lists of constraints. - */ - public ExistentialConstraint createExistentialConstraint(Slot slot, - List ifExistsConstraints, List ifNotExistsConstraints) { - return ExistentialConstraint.create(slot, ifExistsConstraints, - ifNotExistsConstraints, getCurrentLocation()); + /** Creates an {@link ExistentialConstraint} for the given slot and lists of constraints. */ + public ExistentialConstraint createExistentialConstraint( + Slot slot, + List ifExistsConstraints, + List ifNotExistsConstraints) { + return ExistentialConstraint.create( + slot, ifExistsConstraints, ifNotExistsConstraints, getCurrentLocation()); } - public Constraint createImplicationConstraint(List assumptions, Constraint conclusion) { + public Constraint createImplicationConstraint( + List assumptions, Constraint conclusion) { return ImplicationConstraint.create(assumptions, conclusion, getCurrentLocation()); } - /** - * Create an {@link ArithmeticConstraint} for the given operation and slots. - */ - public ArithmeticConstraint createArithmeticConstraint(ArithmeticOperationKind operation, - Slot leftOperand, Slot rightOperand, ArithmeticVariableSlot result) { - return ArithmeticConstraint.create(operation, leftOperand, rightOperand, result, - getCurrentLocation()); + /** Create an {@link ArithmeticConstraint} for the given operation and slots. */ + public ArithmeticConstraint createArithmeticConstraint( + ArithmeticOperationKind operation, + Slot leftOperand, + Slot rightOperand, + ArithmeticVariableSlot result) { + return ArithmeticConstraint.create( + operation, leftOperand, rightOperand, result, getCurrentLocation()); } // TODO: give location directly in Constraint.create() methods @@ -216,8 +216,8 @@ public boolean addSubtypeConstraintNoErrorMsg(Slot subtype, Slot supertype) { /** * Creates and adds an {@link EqualityConstraint} between the two slots to the constraint set, - * which may be normalized to {@link AlwaysTrueConstraint}. An error is issued if the - * {@link EqualityConstraint} is always unsatisfiable. + * which may be normalized to {@link AlwaysTrueConstraint}. An error is issued if the {@link + * EqualityConstraint} is always unsatisfiable. */ public void addEqualityConstraint(Slot first, Slot second) { Constraint constraint = createEqualityConstraint(first, second); @@ -234,8 +234,8 @@ public void addEqualityConstraint(Slot first, Slot second) { /** * Creates and adds an {@link InequalityConstraint} between the two slots to the constraint set, - * which may be normalized to {@link AlwaysTrueConstraint}. An error is issued if the - * {@link InequalityConstraint} is always unsatisfiable. + * which may be normalized to {@link AlwaysTrueConstraint}. An error is issued if the {@link + * InequalityConstraint} is always unsatisfiable. */ public void addInequalityConstraint(Slot first, Slot second) { Constraint constraint = createInequalityConstraint(first, second); @@ -252,8 +252,8 @@ public void addInequalityConstraint(Slot first, Slot second) { /** * Creates and adds a {@link ComparableConstraint} between the two slots to the constraint set, - * which may be normalized to {@link AlwaysTrueConstraint}. An error is issued if the - * {@link ComparableConstraint} is always unsatisfiable. + * which may be normalized to {@link AlwaysTrueConstraint}. An error is issued if the {@link + * ComparableConstraint} is always unsatisfiable. */ public void addComparableConstraint(Slot first, Slot second) { Constraint constraint = createComparableConstraint(first, second); @@ -271,35 +271,37 @@ public void addComparableConstraint(Slot first, Slot second) { /** * Creates and adds a {@link ComparisonConstraint} between the two slots to the constraint set. */ - public void addComparisonConstraint(ComparisonOperationKind operation, Slot first, Slot second, - ComparisonVariableSlot result) { + public void addComparisonConstraint( + ComparisonOperationKind operation, + Slot first, + Slot second, + ComparisonVariableSlot result) { add(createComparisonConstraint(operation, first, second, result)); } - /** - * Creates and adds a {@link CombineConstraint} to the constraint set. - */ + /** Creates and adds a {@link CombineConstraint} to the constraint set. */ public void addCombineConstraint(Slot target, Slot decl, CombVariableSlot result) { add(createCombineConstraint(target, decl, result)); } - /** - * Creates and adds a {@link PreferenceConstraint} to the constraint set. - */ + /** Creates and adds a {@link PreferenceConstraint} to the constraint set. */ public void addPreferenceConstraint(VariableSlot variable, ConstantSlot goal, int weight) { add(createPreferenceConstraint(variable, goal, weight)); } - /** - * Creates and adds a {@link ExistentialConstraint} to the constraint set. - */ - public void addExistentialConstraint(Slot slot, List ifExistsConstraints, + /** Creates and adds a {@link ExistentialConstraint} to the constraint set. */ + public void addExistentialConstraint( + Slot slot, + List ifExistsConstraints, List ifNotExistsConstraints) { add(createExistentialConstraint(slot, ifExistsConstraints, ifNotExistsConstraints)); } - public void addArithmeticConstraint(ArithmeticOperationKind operation, Slot leftOperand, - Slot rightOperand, ArithmeticVariableSlot result) { + public void addArithmeticConstraint( + ArithmeticOperationKind operation, + Slot leftOperand, + Slot rightOperand, + ArithmeticVariableSlot result) { add(createArithmeticConstraint(operation, leftOperand, rightOperand, result)); } diff --git a/src/checkers/inference/model/EqualityConstraint.java b/src/checkers/inference/model/EqualityConstraint.java index d72ba9bcf..035a3e10f 100644 --- a/src/checkers/inference/model/EqualityConstraint.java +++ b/src/checkers/inference/model/EqualityConstraint.java @@ -1,29 +1,25 @@ package checkers.inference.model; -import java.util.Arrays; - import org.checkerframework.javacutil.BugInCF; +import java.util.Arrays; + /** - * Represents an equality relationship between two slots. - * E.g. - * List ls = new ArrayList(); + * Represents an equality relationship between two slots. E.g. List ls = new + * ArrayList(); * - * If, in any type system: - * // vls represents the variable corresponding to the annotation on the first type String - * // located on the left-hand side of the assignment in List ls ... - * vs = VariableSlot( astPathToVls, 0 ) + *

If, in any type system: // vls represents the variable corresponding to the annotation on the + * first type String // located on the left-hand side of the assignment in List ls ... vs = + * VariableSlot( astPathToVls, 0 ) * - * // als represents the variable corresponding to the annotation on the second type String - * // located on the right-hand side of the assignment in ArrayList() - * va = VariableSlot( astPathToAls, 1 ) + *

// als represents the variable corresponding to the annotation on the second type String // + * located on the right-hand side of the assignment in ArrayList() va = VariableSlot( + * astPathToAls, 1 ) * - * Then: - * The above statements would result in the following EqualityConstraints: - * logical representation: in Java: - * vls == als new EqualityConstraint( vls, als ) + *

Then: The above statements would result in the following EqualityConstraints: logical + * representation: in Java: vls == als new EqualityConstraint( vls, als ) * - * Note: The equality relationship is commutative so order should not matter, though in practice + *

Note: The equality relationship is commutative so order should not matter, though in practice * it is up to the given ConstraintSolver to treat them this way. */ public class EqualityConstraint extends Constraint implements BinaryConstraint { @@ -45,8 +41,11 @@ private EqualityConstraint(Slot first, Slot second, AnnotationLocation location) protected static Constraint create(Slot first, Slot second, AnnotationLocation location) { if (first == null || second == null) { - throw new BugInCF("Create equality constraint with null argument. Subtype: " - + first + " Supertype: " + second); + throw new BugInCF( + "Create equality constraint with null argument. Subtype: " + + first + + " Supertype: " + + second); } // Normalization cases: @@ -103,12 +102,9 @@ public int hashCode() { @Override public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; EqualityConstraint other = (EqualityConstraint) obj; if ((first.equals(other.first) && second.equals(other.second)) || (first.equals(other.second) && (second.equals(other.first)))) { diff --git a/src/checkers/inference/model/ExistentialConstraint.java b/src/checkers/inference/model/ExistentialConstraint.java index f23678843..3937ea38c 100644 --- a/src/checkers/inference/model/ExistentialConstraint.java +++ b/src/checkers/inference/model/ExistentialConstraint.java @@ -9,18 +9,15 @@ /** * An ExistentialConstraint indicates that solvers need to determine if a variable's annotation - * exists or not. If that variable annotations exists then one set of constraints should be - * enforced by the output solution, otherwise a different set of constraints should be enforce. - * That is, they are constraints of the form: + * exists or not. If that variable annotations exists then one set of constraints should be enforced + * by the output solution, otherwise a different set of constraints should be enforce. That is, they + * are constraints of the form: * - * if (potentialVariable exists) { - * // enforce potentialConstraints - * } else { - * // enforce alternateConstraints - * } + *

if (potentialVariable exists) { // enforce potentialConstraints } else { // enforce + * alternateConstraints } * - * At the time of this writing, these constraints are used for uses of - * generic type parameters exclusively. + *

At the time of this writing, these constraints are used for uses of generic type parameters + * exclusively. */ public class ExistentialConstraint extends Constraint { @@ -33,24 +30,34 @@ public class ExistentialConstraint extends Constraint { // the constraints to enforce if potentialVariable DOES NOT exist private final List alternateConstraints; - public ExistentialConstraint(Slot potentialVariable, - List potentialConstraints, - List alternateConstraints, AnnotationLocation location) { - super(combineSlots(potentialVariable, potentialConstraints, alternateConstraints), location); + public ExistentialConstraint( + Slot potentialVariable, + List potentialConstraints, + List alternateConstraints, + AnnotationLocation location) { + super( + combineSlots(potentialVariable, potentialConstraints, alternateConstraints), + location); this.potentialVariable = potentialVariable; this.potentialConstraints = Collections.unmodifiableList(potentialConstraints); this.alternateConstraints = Collections.unmodifiableList(alternateConstraints); } - protected static ExistentialConstraint create(Slot potentialVariable, - List potentialConstraints, List alternateConstraints, + protected static ExistentialConstraint create( + Slot potentialVariable, + List potentialConstraints, + List alternateConstraints, AnnotationLocation location) { - if (potentialVariable == null || potentialConstraints == null + if (potentialVariable == null + || potentialConstraints == null || alternateConstraints == null) { throw new BugInCF( "Create existential constraint with null argument. potentialVariable: " - + potentialVariable + " potentialConstraints: " + potentialConstraints - + " alternateConstraints: " + alternateConstraints); + + potentialVariable + + " potentialConstraints: " + + potentialConstraints + + " alternateConstraints: " + + alternateConstraints); } return new ExistentialConstraint( @@ -58,7 +65,7 @@ protected static ExistentialConstraint create(Slot potentialVariable, } @SafeVarargs - private static List combineSlots(Slot potential, final List ... constraints) { + private static List combineSlots(Slot potential, final List... constraints) { final List slots = new ArrayList<>(); slots.add(potential); for (final List constraintList : constraints) { @@ -91,11 +98,20 @@ public String toString() { String tab = " "; String doubleTab = tab + tab; return "ExistentialConstraint[\n" - + tab + "if( " + potentialVariable + " ) {\n" - + doubleTab + StringsPlume.join("\n" + doubleTab, potentialConstraints) + "\n" - + tab + "} else {\n" - + doubleTab + StringsPlume.join("\n" + doubleTab, alternateConstraints ) + "\n" - + tab + "}\n" + + tab + + "if( " + + potentialVariable + + " ) {\n" + + doubleTab + + StringsPlume.join("\n" + doubleTab, potentialConstraints) + + "\n" + + tab + + "} else {\n" + + doubleTab + + StringsPlume.join("\n" + doubleTab, alternateConstraints) + + "\n" + + tab + + "}\n" + "]"; } } diff --git a/src/checkers/inference/model/ImplicationConstraint.java b/src/checkers/inference/model/ImplicationConstraint.java index b0eab12a2..d8e527c7c 100644 --- a/src/checkers/inference/model/ImplicationConstraint.java +++ b/src/checkers/inference/model/ImplicationConstraint.java @@ -2,8 +2,6 @@ import org.checkerframework.javacutil.BugInCF; -import checkers.inference.InferenceMain; - import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -11,42 +9,37 @@ import java.util.Objects; import java.util.Set; +import checkers.inference.InferenceMain; + /** - * Constraint that models implication logic. If all the assumptions are - * satisfied, then conclusion should also be satisfied. - *

- * Suppose one needs to enforce this restriction: if {@code @A} is inferred as - * on declaration of class {@code MyClass}, then every usage of class - * {@code MyClass} needs to be inferred to {@code @A}. - * {@link ImplicationConstraint} can express this restriction: - *

- * {@code @1 == @A -> @2 == @A}, in which {@code @1} is the slot inserted on the - * class tree and {@code @2} is the slot that represents one usage of - * {@code MyClass}. + * Constraint that models implication logic. If all the assumptions are satisfied, then conclusion + * should also be satisfied. + * + *

Suppose one needs to enforce this restriction: if {@code @A} is inferred as on declaration of + * class {@code MyClass}, then every usage of class {@code MyClass} needs to be inferred to + * {@code @A}. {@link ImplicationConstraint} can express this restriction: + * + *

{@code @1 == @A -> @2 == @A}, in which {@code @1} is the slot inserted on the class tree and + * {@code @2} is the slot that represents one usage of {@code MyClass}. */ public class ImplicationConstraint extends Constraint { - /** - * An immutable set of {@link Constraint}s that are conjuncted together. - */ + /** An immutable set of {@link Constraint}s that are conjuncted together. */ private final Set assumptions; - /** - * A single {@link Constraint} that is implicated by the - * {@link #assumptions}. - */ + /** A single {@link Constraint} that is implicated by the {@link #assumptions}. */ private final Constraint conclusion; - public ImplicationConstraint(Set assumptions, - Constraint conclusion, AnnotationLocation location) { + public ImplicationConstraint( + Set assumptions, Constraint conclusion, AnnotationLocation location) { super(extractAllSlots(assumptions, conclusion), location); this.assumptions = Collections.unmodifiableSet(assumptions); this.conclusion = conclusion; } - private static List extractAllSlots(Iterable assumptions, - Constraint conclusion) { + private static List extractAllSlots( + Iterable assumptions, Constraint conclusion) { List slots = new ArrayList<>(); for (Constraint a : assumptions) { slots.addAll(a.getSlots()); @@ -57,12 +50,16 @@ private static List extractAllSlots(Iterable assumptions, // TODO: the input should be a set of constraints instead of a list. This // requires modifying the constraint manager and PICO. - public static Constraint create(List assumptions, - Constraint conclusion, AnnotationLocation currentLocation) { + public static Constraint create( + List assumptions, + Constraint conclusion, + AnnotationLocation currentLocation) { if (assumptions == null || conclusion == null) { throw new BugInCF( "Adding implication constraint with null argument. assumptions: " - + assumptions + " conclusion: " + conclusion); + + assumptions + + " conclusion: " + + conclusion); } // Normalization cases: @@ -117,8 +114,7 @@ public static Constraint create(List assumptions, if (conclusion instanceof AlwaysFalseConstraint) { // Instead of creating a "conjunction constraint", here we directly // add the set of constraints to the constraint manager - InferenceMain.getInstance().getConstraintManager() - .addAll(refinedAssumptions); + InferenceMain.getInstance().getConstraintManager().addAll(refinedAssumptions); // since all assumptions are added to the constraint manager, we // return a dummy always true constraint as the normalized result return AlwaysTrueConstraint.create(); @@ -126,8 +122,7 @@ public static Constraint create(List assumptions, // 6) refinedAssumptions != empty && conclusion != TRUE && conclusion != // FALSE ==> CREATE_REAL_IMPLICATION_CONSTRAINT - return new ImplicationConstraint(refinedAssumptions, conclusion, - currentLocation); + return new ImplicationConstraint(refinedAssumptions, conclusion, currentLocation); } @Override @@ -157,7 +152,6 @@ public boolean equals(Object obj) { return false; } ImplicationConstraint other = (ImplicationConstraint) obj; - return assumptions.equals(other.assumptions) - && conclusion.equals(other.conclusion); + return assumptions.equals(other.assumptions) && conclusion.equals(other.conclusion); } } diff --git a/src/checkers/inference/model/InequalityConstraint.java b/src/checkers/inference/model/InequalityConstraint.java index a4bd71381..11981c4c4 100644 --- a/src/checkers/inference/model/InequalityConstraint.java +++ b/src/checkers/inference/model/InequalityConstraint.java @@ -1,9 +1,9 @@ package checkers.inference.model; -import java.util.Arrays; - import org.checkerframework.javacutil.BugInCF; +import java.util.Arrays; + public class InequalityConstraint extends Constraint implements BinaryConstraint { private final Slot first; @@ -23,8 +23,11 @@ private InequalityConstraint(Slot first, Slot second, AnnotationLocation locatio protected static Constraint create(Slot first, Slot second, AnnotationLocation location) { if (first == null || second == null) { - throw new BugInCF("Create inequality constraint with null argument. Subtype: " - + first + " Supertype: " + second); + throw new BugInCF( + "Create inequality constraint with null argument. Subtype: " + + first + + " Supertype: " + + second); } // Normalization cases: @@ -81,12 +84,9 @@ public int hashCode() { @Override public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; InequalityConstraint other = (InequalityConstraint) obj; if ((first.equals(other.first) && second.equals(other.second)) || (first.equals(other.second) && (second.equals(other.first)))) { diff --git a/src/checkers/inference/model/LubVariableSlot.java b/src/checkers/inference/model/LubVariableSlot.java index 2e1032416..94d53c71d 100644 --- a/src/checkers/inference/model/LubVariableSlot.java +++ b/src/checkers/inference/model/LubVariableSlot.java @@ -1,9 +1,9 @@ package checkers.inference.model; /** - * LubVariableSlot models the least-upper-bounds of two other slots. - * TODO(Zhiping): Rename this to MergeVariableSlot, also consider the difference - * TODO(Zhiping): between this class and CombVariableSlot + * LubVariableSlot models the least-upper-bounds of two other slots. TODO(Zhiping): Rename this to + * MergeVariableSlot, also consider the difference TODO(Zhiping): between this class and + * CombVariableSlot */ public class LubVariableSlot extends VariableSlot { @@ -35,8 +35,8 @@ public Slot getRight() { } /** - * LubVariableSlot should never be inserted into the source code. record - * does not correspond to an annotatable position. + * LubVariableSlot should never be inserted into the source code. record does not correspond to + * an annotatable position. * * @return false */ @@ -56,23 +56,16 @@ public int hashCode() { @Override public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; LubVariableSlot other = (LubVariableSlot) obj; if (left == null) { - if (other.left != null) - return false; - } else if (!left.equals(other.left)) - return false; + if (other.left != null) return false; + } else if (!left.equals(other.left)) return false; if (right == null) { - if (other.right != null) - return false; - } else if (!right.equals(other.right)) - return false; + if (other.right != null) return false; + } else if (!right.equals(other.right)) return false; return true; } } diff --git a/src/checkers/inference/model/PreferenceConstraint.java b/src/checkers/inference/model/PreferenceConstraint.java index feb89caf5..95ef6d885 100644 --- a/src/checkers/inference/model/PreferenceConstraint.java +++ b/src/checkers/inference/model/PreferenceConstraint.java @@ -1,30 +1,32 @@ package checkers.inference.model; -import java.util.Arrays; import org.checkerframework.javacutil.BugInCF; -/** - * Represents a preference for a particular qualifier. - */ +import java.util.Arrays; + +/** Represents a preference for a particular qualifier. */ public class PreferenceConstraint extends Constraint { private final VariableSlot variable; private final ConstantSlot goal; private final int weight; - private PreferenceConstraint(VariableSlot variable, ConstantSlot goal, int weight, - AnnotationLocation location) { - super(Arrays. asList(variable, goal), location); + private PreferenceConstraint( + VariableSlot variable, ConstantSlot goal, int weight, AnnotationLocation location) { + super(Arrays.asList(variable, goal), location); this.variable = variable; this.goal = goal; this.weight = weight; } - protected static PreferenceConstraint create(VariableSlot variable, ConstantSlot goal, - int weight, AnnotationLocation location) { + protected static PreferenceConstraint create( + VariableSlot variable, ConstantSlot goal, int weight, AnnotationLocation location) { if (variable == null || goal == null) { - throw new BugInCF("Create preference constraint with null argument. Variable: " - + variable + " Goal: " + goal); + throw new BugInCF( + "Create preference constraint with null argument. Variable: " + + variable + + " Goal: " + + goal); } return new PreferenceConstraint(variable, goal, weight, location); @@ -52,20 +54,16 @@ public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((variable == null) ? 0 : variable.hashCode()); - result = prime * result - + ((goal == null) ? 0 : goal.hashCode()); + result = prime * result + ((goal == null) ? 0 : goal.hashCode()); result = prime * result + weight; return result; } @Override public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; PreferenceConstraint other = (PreferenceConstraint) obj; if (variable == null) { if (other.variable != null) { diff --git a/src/checkers/inference/model/RefinementVariableSlot.java b/src/checkers/inference/model/RefinementVariableSlot.java index 0881a0dc2..55f23795b 100644 --- a/src/checkers/inference/model/RefinementVariableSlot.java +++ b/src/checkers/inference/model/RefinementVariableSlot.java @@ -1,62 +1,50 @@ package checkers.inference.model; /** - * RefinementVariableSlots represent a potential downward refinement of an existing VariableSlot. For each - * RefinementVariableSlot, R, there exists a VariableSlot, V, with which it shares the following subtype - * relationship: - * R <: V + * RefinementVariableSlots represent a potential downward refinement of an existing VariableSlot. + * For each RefinementVariableSlot, R, there exists a VariableSlot, V, with which it shares the + * following subtype relationship: R <: V * - * Refinement variables are used to model the semantics of flow-sensitive type refinement + *

Refinement variables are used to model the semantics of flow-sensitive type refinement * (http://types.cs.washington.edu/checker-framework/current/checkers-manual.html#type-refinement). * - * Within methods, the values of fields, parameters, and local variables are all refined downward when possible ( e.g. - * after an assignment ). To model this behavior, every time a variable could possibly be refined downward we generate - * a RefinementVariableSlot which is then used in all constraints for which the refinement holds. + *

Within methods, the values of fields, parameters, and local variables are all refined downward + * when possible ( e.g. after an assignment ). To model this behavior, every time a variable could + * possibly be refined downward we generate a RefinementVariableSlot which is then used in all + * constraints for which the refinement holds. * - * E.g. - * The notation @X where X is an integer is used to identify individual VariableSlots below. Each @X - * corresponds to locations where @VarAnnot(X) would be placed and identifies trees corresponding to the - * Variable slot with id X. + *

E.g. The notation @X where X is an integer is used to identify individual VariableSlots below. + * Each @X corresponds to locations where @VarAnnot(X) would be placed and identifies trees + * corresponding to the Variable slot with id X. * - * Using the Nullness type-system: + *

Using the Nullness type-system: * - * class RefVarExample { + *

class RefVarExample { * - * private @0 String myField = null; + *

private @0 String myField = null; * - * void method( ) { - * @1 String s = myField; - * myField = "not null"; // This line results in a RefinementVariable @2 - * s = myField; // This line results in a RefinementVariable @3 - * } - * } + *

void method( ) { @1 String s = myField; myField = "not null"; // This line results in a + * RefinementVariable @2 s = myField; // This line results in a RefinementVariable @3 } } * - * In the example above the statement: - * @1 String s = myField; - * will generate the following subtype constraint: - * @0 <: @1 + *

In the example above the statement: @1 String s = myField; will generate the following subtype + * constraint: @0 <: @1 * - * At this point in method, nothing is known about myField except for the information given by it's declaration. - * However, after the statement: - * myField = "not null"; - * we know explicitly that myField is now not null and data-flow would refine @0 to @NonNull. Any location in - * which this type of refinement is possible, usually at all method local assignments and potentially at the - * branches of if statements, we generate refinement variables. + *

At this point in method, nothing is known about myField except for the information given by + * it's declaration. However, after the statement: myField = "not null"; we know explicitly that + * myField is now not null and data-flow would refine @0 to @NonNull. Any location in which this + * type of refinement is possible, usually at all method local assignments and potentially at the + * branches of if statements, we generate refinement variables. * - * Therefore, the assignment - * myField = "not null" - * results in a refinement variable @2 with the following constraints: - * @2 <: @0 - * @2 <: ConstantSlot( NonNull ) + *

Therefore, the assignment myField = "not null" results in a refinement variable @2 with the + * following constraints: @2 <: @0 @2 <: ConstantSlot( NonNull ) * - * Note, that even though @2 and @0 represent annotations on the same declared variable, @2's value might be different - * than @1 as they represent the possible type of the variable in different locations. For instance, the line: - * s = myField; - * generates the following subtype constraints: - * @2 <: @1 + *

Note, that even though @2 and @0 represent annotations on the same declared variable, @2's + * value might be different than @1 as they represent the possible type of the variable in different + * locations. For instance, the line: s = myField; generates the following subtype constraints: @2 + * <: @1 * - * Essentially, RefinementVariableSlots allow us to generate constraints as if the code were written in - * SSA form ( http://en.wikipedia.org/wiki/Static_single_assignment_form ). + *

Essentially, RefinementVariableSlots allow us to generate constraints as if the code were + * written in SSA form ( http://en.wikipedia.org/wiki/Static_single_assignment_form ). */ public class RefinementVariableSlot extends VariableSlot { @@ -82,8 +70,8 @@ public Kind getKind() { } /** - * Refinement variables should never be re-inserted into the source code. record - * does not correspond to an annotatable position. + * Refinement variables should never be re-inserted into the source code. record does not + * correspond to an annotatable position. * * @return false */ diff --git a/src/checkers/inference/model/Serializer.java b/src/checkers/inference/model/Serializer.java index 4a318a198..fbbd46195 100644 --- a/src/checkers/inference/model/Serializer.java +++ b/src/checkers/inference/model/Serializer.java @@ -3,18 +3,15 @@ /** * Interface for serializing constraints and variables. * - * Serialization will occur for all variables and constraints either - * before or instead of Constraint solving. + *

Serialization will occur for all variables and constraints either before or instead of + * Constraint solving. * - * This allows us to avoid re-generating constraints for a piece of - * source code every time we wish to solve (for instance when a new - * solver is written or an existing one is modified). + *

This allows us to avoid re-generating constraints for a piece of source code every time we + * wish to solve (for instance when a new solver is written or an existing one is modified). * - * Type parameters S and T are used to adapt the return type of the - * XXXSlot visitor methods (S) and the XXXConstraint visitor methods - * (T). - * Implementing classes can use the same or different types for these - * type parameters. + *

Type parameters S and T are used to adapt the return type of the XXXSlot visitor methods (S) + * and the XXXConstraint visitor methods (T). Implementing classes can use the same or different + * types for these type parameters. */ public interface Serializer { diff --git a/src/checkers/inference/model/Slot.java b/src/checkers/inference/model/Slot.java index 7e2ce83ac..f9c349cad 100644 --- a/src/checkers/inference/model/Slot.java +++ b/src/checkers/inference/model/Slot.java @@ -5,29 +5,26 @@ import java.util.Set; /** - * Slots represent constraint variables that represent either - * (1) the qualifiers of the real type system {@link ConstantSlot} or - * (2) placeholders for which a solution needs to be inferred {@link VariableSlot}. + * Slots represent constraint variables that represent either (1) the qualifiers of the real type + * system {@link ConstantSlot} or (2) placeholders for which a solution needs to be inferred {@link + * VariableSlot}. * - * Each Slot has a unique identification number. + *

Each Slot has a unique identification number. * - * Slots are represented by {@code @VarAnnot( slot id )} annotations in AnnotatedTypeMirrors. - * The {@link checkers.inference.VariableAnnotator} generates the Slots for source code. + *

Slots are represented by {@code @VarAnnot( slot id )} annotations in AnnotatedTypeMirrors. The + * {@link checkers.inference.VariableAnnotator} generates the Slots for source code. * - * A slot maintains the set of {@link LubVariableSlot}s of least-upper bound computations it is + *

A slot maintains the set of {@link LubVariableSlot}s of least-upper bound computations it is * involved in. - * */ public abstract class Slot implements Comparable { /** - * Uniquely identifies this Slot. id's are monotonically increasing in value by the order they + * Uniquely identifies this Slot. id's are monotonically increasing in value by the order they * are generated */ protected final int id; - /** - * Slots this variable has been merged to. - */ + /** Slots this variable has been merged to. */ private final Set mergedToSlots = new HashSet<>(); public Slot(int id) { @@ -53,7 +50,7 @@ public void addMergedToSlot(LubVariableSlot mergedSlot) { } public boolean isMergedTo(Slot other) { - for (LubVariableSlot mergedTo: mergedToSlots) { + for (LubVariableSlot mergedTo : mergedToSlots) { if (mergedTo.equals(other)) { return true; } else { @@ -72,15 +69,11 @@ public int hashCode() { @Override public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; Slot other = (Slot) obj; - if (id != other.id) - return false; + if (id != other.id) return false; return true; } diff --git a/src/checkers/inference/model/SourceVariableSlot.java b/src/checkers/inference/model/SourceVariableSlot.java index 95df9f779..efe0ce5ea 100644 --- a/src/checkers/inference/model/SourceVariableSlot.java +++ b/src/checkers/inference/model/SourceVariableSlot.java @@ -1,13 +1,15 @@ package checkers.inference.model; -import checkers.inference.InferenceOptions; import org.checkerframework.checker.nullness.qual.Nullable; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.type.TypeMirror; +import checkers.inference.InferenceOptions; + /** - * SourceVariableSlot is a VariableSlot representing a type use in the source code with undetermined value. + * SourceVariableSlot is a VariableSlot representing a type use in the source code with undetermined + * value. */ public class SourceVariableSlot extends VariableSlot { @@ -15,16 +17,15 @@ public class SourceVariableSlot extends VariableSlot { protected final TypeMirror actualType; /** - * The default annotation for this slot from the real type factory. - * This field is nullable because we find the default annotation only - * if {@link InferenceOptions#makeDefaultsExplicit} is true. + * The default annotation for this slot from the real type factory. This field is nullable + * because we find the default annotation only if {@link InferenceOptions#makeDefaultsExplicit} + * is true. */ protected final @Nullable AnnotationMirror defaultAnnotation; /** - * Should this slot be inserted back into the source code. - * This should be false for types that have an implicit annotation - * and slots for pre-annotated code. + * Should this slot be inserted back into the source code. This should be false for types that + * have an implicit annotation and slots for pre-annotated code. */ private boolean insertable; @@ -32,8 +33,8 @@ public class SourceVariableSlot extends VariableSlot { * @param location used to locate this variable in code, see @AnnotationLocation * @param id unique identifier for this variable * @param type the underlying type - * @param defaultAnnotation the default annotation (solution) for this slot, which can be null when - * {@link InferenceOptions#makeDefaultsExplicit} returns true + * @param defaultAnnotation the default annotation (solution) for this slot, which can be null + * when {@link InferenceOptions#makeDefaultsExplicit} returns true * @param insertable indicates whether this slot should be inserted back into the source code */ public SourceVariableSlot( @@ -41,8 +42,7 @@ public SourceVariableSlot( AnnotationLocation location, TypeMirror type, @Nullable AnnotationMirror defaultAnnotation, - boolean insertable - ) { + boolean insertable) { super(id, location); this.actualType = type; this.defaultAnnotation = defaultAnnotation; @@ -68,20 +68,18 @@ public TypeMirror getUnderlyingType() { return actualType; } - /** - * Should this VariableSlot be inserted back into the source code. - */ + /** Should this VariableSlot be inserted back into the source code. */ @Override public boolean isInsertable() { return insertable; } /** - * This method is not encouraged to use, since whether a specific {@code SourceVariableSlot} - * is insertable should be determined at creation depending on the type use location, while - * sometime it's more convenient to set this flag of a {@code SourceVariableSlot} when it's - * use. + * This method is not encouraged to use, since whether a specific {@code SourceVariableSlot} is + * insertable should be determined at creation depending on the type use location, while + * sometime it's more convenient to set this flag of a {@code SourceVariableSlot} when it's use. * TODO: determine whether the slot is insertable at creation and remove this method + * * @param insertable whether this slot should be inserted back into the source code */ public void setInsertable(boolean insertable) { diff --git a/src/checkers/inference/model/SubtypeConstraint.java b/src/checkers/inference/model/SubtypeConstraint.java index b2f787372..a2011efef 100644 --- a/src/checkers/inference/model/SubtypeConstraint.java +++ b/src/checkers/inference/model/SubtypeConstraint.java @@ -1,32 +1,25 @@ package checkers.inference.model; -import java.util.Arrays; - import org.checkerframework.framework.type.QualifierHierarchy; import org.checkerframework.javacutil.BugInCF; +import java.util.Arrays; + /** - * Represents a subtyping relationship between two slots. - * E.g. - * String s = "yo"; - * String a = s; - * - * If, using the Nullness type system: - * // vs represents the variable corresponding to the annotation on s - * vs = VariableSlot( astPathToS, 0 ) + * Represents a subtyping relationship between two slots. E.g. String s = "yo"; String a = s; * - * // va represents the variable corresponding to the annotation on a - * va = VariableSlot( astPathToA, 1 ) + *

If, using the Nullness type system: // vs represents the variable corresponding to the + * annotation on s vs = VariableSlot( astPathToS, 0 ) * - * // cn represents the constant NonNull value (which "yo" inherently has) - * cnn = ConstantSlot( NonNull ) + *

// va represents the variable corresponding to the annotation on a va = VariableSlot( + * astPathToA, 1 ) * - * Then: - * The above statements would result in the following SubtypeConstraints: - * logical representation: in Java: - * vs <: cnn new SubtypeConstraint( vs, cnn ) - * va <: vs new SubtypeConstraint( va, vs ) + *

// cn represents the constant NonNull value (which "yo" inherently has) cnn = ConstantSlot( + * NonNull ) * + *

Then: The above statements would result in the following SubtypeConstraints: logical + * representation: in Java: vs <: cnn new SubtypeConstraint( vs, cnn ) va <: vs new + * SubtypeConstraint( va, vs ) */ public class SubtypeConstraint extends Constraint implements BinaryConstraint { @@ -45,11 +38,17 @@ private SubtypeConstraint(Slot subtype, Slot supertype) { this.supertype = supertype; } - protected static Constraint create(Slot subtype, Slot supertype, AnnotationLocation location, + protected static Constraint create( + Slot subtype, + Slot supertype, + AnnotationLocation location, QualifierHierarchy realQualHierarchy) { if (subtype == null || supertype == null) { - throw new BugInCF("Create subtype constraint with null argument. Subtype: " - + subtype + " Supertype: " + supertype); + throw new BugInCF( + "Create subtype constraint with null argument. Subtype: " + + subtype + + " Supertype: " + + supertype); } // Normalization cases: @@ -66,7 +65,8 @@ protected static Constraint create(Slot subtype, Slot supertype, AnnotationLocat ConstantSlot subConstant = (ConstantSlot) subtype; ConstantSlot superConstant = (ConstantSlot) supertype; - return realQualHierarchy.isSubtypeQualifiersOnly(subConstant.getValue(), superConstant.getValue()) + return realQualHierarchy.isSubtypeQualifiersOnly( + subConstant.getValue(), superConstant.getValue()) ? AlwaysTrueConstraint.create() : AlwaysFalseConstraint.create(); } @@ -129,30 +129,22 @@ public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((subtype == null) ? 0 : subtype.hashCode()); - result = prime * result - + ((supertype == null) ? 0 : supertype.hashCode()); + result = prime * result + ((supertype == null) ? 0 : supertype.hashCode()); return result; } @Override public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; SubtypeConstraint other = (SubtypeConstraint) obj; if (subtype == null) { - if (other.subtype != null) - return false; - } else if (!subtype.equals(other.subtype)) - return false; + if (other.subtype != null) return false; + } else if (!subtype.equals(other.subtype)) return false; if (supertype == null) { - if (other.supertype != null) - return false; - } else if (!supertype.equals(other.supertype)) - return false; + if (other.supertype != null) return false; + } else if (!supertype.equals(other.supertype)) return false; return true; } diff --git a/src/checkers/inference/model/VariableSlot.java b/src/checkers/inference/model/VariableSlot.java index 2c7e0b0a6..bbc0fa17d 100644 --- a/src/checkers/inference/model/VariableSlot.java +++ b/src/checkers/inference/model/VariableSlot.java @@ -1,32 +1,29 @@ package checkers.inference.model; - -import javax.lang.model.type.TypeMirror; import java.util.HashSet; import java.util.Set; /** * VariableSlot is a Slot representing an undetermined value (i.e. a variable we are solving for). - * After the Solver is run, each VariableSlot has an assigned value which is then written - * to the output Jaif file for later insertion into the original source code. + * After the Solver is run, each VariableSlot has an assigned value which is then written to the + * output Jaif file for later insertion into the original source code. * - * The {@link checkers.inference.InferenceVisitor} and other code can convert between VarAnnots in - * AnnotatedTypeMirrors and VariableSlots, which are then used to generate constraints. + *

The {@link checkers.inference.InferenceVisitor} and other code can convert between VarAnnots + * in AnnotatedTypeMirrors and VariableSlots, which are then used to generate constraints. * - * E.g. @VarAnnot(0) String s; + *

E.g. @VarAnnot(0) String s; * - * The above example implies that a VariableSlot with id 0 represents the possible annotations - * on the declaration of s. + *

The above example implies that a VariableSlot with id 0 represents the possible annotations on + * the declaration of s. * - * Every VariableSlot has an {@link AnnotationLocation} and the {@link RefinementVariableSlot}s + *

Every VariableSlot has an {@link AnnotationLocation} and the {@link RefinementVariableSlot}s * it is refined by. - * */ public abstract class VariableSlot extends Slot { /** - * Used to locate this Slot in source code. {@code AnnotationLocation}s are written to Jaif files - * along with the annotations determined for this slot by the Solver. + * Used to locate this Slot in source code. {@code AnnotationLocation}s are written to Jaif + * files along with the annotations determined for this slot by the Solver. */ private AnnotationLocation location; diff --git a/src/checkers/inference/model/serialization/AnnotationMirrorSerializer.java b/src/checkers/inference/model/serialization/AnnotationMirrorSerializer.java index 824b7a8da..41ccd1c2e 100644 --- a/src/checkers/inference/model/serialization/AnnotationMirrorSerializer.java +++ b/src/checkers/inference/model/serialization/AnnotationMirrorSerializer.java @@ -6,7 +6,6 @@ * Interface to handle serialization and deserialization of AnnotationMirrors to Strings. * * @author mcarthur - * */ public interface AnnotationMirrorSerializer { diff --git a/src/checkers/inference/model/serialization/CnfSerializerSolver.java b/src/checkers/inference/model/serialization/CnfSerializerSolver.java index 3e42c99ba..9f44c6558 100644 --- a/src/checkers/inference/model/serialization/CnfSerializerSolver.java +++ b/src/checkers/inference/model/serialization/CnfSerializerSolver.java @@ -2,6 +2,7 @@ import org.checkerframework.framework.type.QualifierHierarchy; import org.checkerframework.javacutil.AnnotationUtils; +import org.sat4j.core.VecInt; import java.io.BufferedWriter; import java.io.File; @@ -16,8 +17,6 @@ import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.AnnotationMirror; -import org.sat4j.core.VecInt; - import checkers.inference.InferenceMain; import checkers.inference.InferenceResult; import checkers.inference.InferenceSolver; @@ -26,9 +25,7 @@ import checkers.inference.model.Constraint; import checkers.inference.model.Slot; -/** - * TODO: THIS IS NOT USEFUL UNTIL WE MAP EXISTENTIALVARIABLEIDS to POTENTIAL VAR - */ +/** TODO: THIS IS NOT USEFUL UNTIL WE MAP EXISTENTIALVARIABLEIDS to POTENTIAL VAR */ public class CnfSerializerSolver implements InferenceSolver { private static final String FILE_KEY = "constraint-file"; @@ -37,41 +34,45 @@ public class CnfSerializerSolver implements InferenceSolver { @Override public InferenceResult solve( - Map configuration, - Collection slots, - Collection constraints, - QualifierHierarchy qualHierarchy, - ProcessingEnvironment processingEnvironment) { + Map configuration, + Collection slots, + Collection constraints, + QualifierHierarchy qualHierarchy, + ProcessingEnvironment processingEnvironment) { final AnnotationMirror top = qualHierarchy.getTopAnnotations().iterator().next(); // AnnotationMirror bottom = // qualHierarchy.getBottomAnnotations().iterator().next(); this.slotManager = InferenceMain.getInstance().getSlotManager(); - CnfVecIntSerializer cnfSerializer = new CnfVecIntSerializer(slotManager) { - @Override - protected boolean isTop(ConstantSlot constantSlot) { - return AnnotationUtils.areSame(constantSlot.getValue(), top); - } - }; - - String outFile = configuration.containsKey(FILE_KEY) ? configuration.get(FILE_KEY) - : DEFAULT_FILE; + CnfVecIntSerializer cnfSerializer = + new CnfVecIntSerializer(slotManager) { + @Override + protected boolean isTop(ConstantSlot constantSlot) { + return AnnotationUtils.areSame(constantSlot.getValue(), top); + } + }; + + String outFile = + configuration.containsKey(FILE_KEY) ? configuration.get(FILE_KEY) : DEFAULT_FILE; printCnf(new File(outFile), constraints, cnfSerializer); return null; } - protected void printCnf(File outputFile, Collection constraints, CnfVecIntSerializer serializer) { + protected void printCnf( + File outputFile, Collection constraints, CnfVecIntSerializer serializer) { try { int totalVars = slotManager.getNumberOfSlots(); int totalConstraints = constraints.size(); final BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile)); - String header = makeComment( - "CNF File Generated by checkers.inference.serialization.CnfSerializerSolver\n" - + "http://types.cs.washington.edu/checker-framework/\n" - + "Generated: " + getDateString() + "\n" - + "File Format: DIMACS CNF - http://www.satcompetition.org/2009/format-benchmarks2009.html" - ); + String header = + makeComment( + "CNF File Generated by checkers.inference.serialization.CnfSerializerSolver\n" + + "http://types.cs.washington.edu/checker-framework/\n" + + "Generated: " + + getDateString() + + "\n" + + "File Format: DIMACS CNF - http://www.satcompetition.org/2009/format-benchmarks2009.html"); writer.write(header); writer.newLine(); @@ -90,9 +91,9 @@ protected void printCnf(File outputFile, Collection constraints, Cnf writer.close(); } catch (IOException ioExc) { - throw new RuntimeException("Error writing CNF File: " + outputFile.getAbsolutePath(), ioExc); + throw new RuntimeException( + "Error writing CNF File: " + outputFile.getAbsolutePath(), ioExc); } - } private String getDateString() { @@ -102,7 +103,7 @@ private String getDateString() { } private String makeComment(String commentBlock) { - String [] lines = commentBlock.split("\\r?\\n"); + String[] lines = commentBlock.split("\\r?\\n"); StringBuilder sb = new StringBuilder(); for (String line : lines) { diff --git a/src/checkers/inference/model/serialization/CnfVecIntSerializer.java b/src/checkers/inference/model/serialization/CnfVecIntSerializer.java index 65ca0e6ae..c38e90477 100644 --- a/src/checkers/inference/model/serialization/CnfVecIntSerializer.java +++ b/src/checkers/inference/model/serialization/CnfVecIntSerializer.java @@ -1,16 +1,13 @@ package checkers.inference.model.serialization; +import org.checkerframework.javacutil.BugInCF; +import org.sat4j.core.VecInt; + import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; -import checkers.inference.model.LubVariableSlot; -import checkers.inference.model.ImplicationConstraint; -import checkers.inference.model.VariableSlot; -import org.checkerframework.javacutil.BugInCF; -import org.sat4j.core.VecInt; - import checkers.inference.SlotManager; import checkers.inference.model.ArithmeticConstraint; import checkers.inference.model.ArithmeticVariableSlot; @@ -24,21 +21,26 @@ import checkers.inference.model.EqualityConstraint; import checkers.inference.model.ExistentialConstraint; import checkers.inference.model.ExistentialVariableSlot; +import checkers.inference.model.ImplicationConstraint; import checkers.inference.model.InequalityConstraint; +import checkers.inference.model.LubVariableSlot; import checkers.inference.model.PreferenceConstraint; import checkers.inference.model.RefinementVariableSlot; import checkers.inference.model.Serializer; import checkers.inference.model.Slot; -import checkers.inference.model.SubtypeConstraint; import checkers.inference.model.SourceVariableSlot; +import checkers.inference.model.SubtypeConstraint; +import checkers.inference.model.VariableSlot; -/** - */ +/** */ public abstract class CnfVecIntSerializer implements Serializer { private final SlotManager slotManager; - /** var representing whether or not some potential var exists mapped to that potential var - *

var exists -> var

**/ + /** + * var representing whether or not some potential var exists mapped to that potential var + * + *

var exists -> var* + */ private final Map existentialToPotentialVar = new HashMap<>(); public CnfVecIntSerializer(SlotManager slotManager) { @@ -54,7 +56,8 @@ public VecInt[] serialize(SubtypeConstraint constraint) { return new VariableCombos() { @Override - protected VecInt[] constant_variable(ConstantSlot subtype, VariableSlot supertype, SubtypeConstraint constraint) { + protected VecInt[] constant_variable( + ConstantSlot subtype, VariableSlot supertype, SubtypeConstraint constraint) { if (isTop(subtype)) { return asVecArray(-supertype.getId()); @@ -64,7 +67,8 @@ protected VecInt[] constant_variable(ConstantSlot subtype, VariableSlot supertyp } @Override - protected VecInt[] variable_constant(VariableSlot subtype, ConstantSlot supertype, SubtypeConstraint constraint) { + protected VecInt[] variable_constant( + VariableSlot subtype, ConstantSlot supertype, SubtypeConstraint constraint) { if (!isTop(supertype)) { return asVecArray(subtype.getId()); } @@ -73,12 +77,12 @@ protected VecInt[] variable_constant(VariableSlot subtype, ConstantSlot supertyp } @Override - protected VecInt[] variable_variable(VariableSlot subtype, VariableSlot supertype, SubtypeConstraint constraint) { + protected VecInt[] variable_variable( + VariableSlot subtype, VariableSlot supertype, SubtypeConstraint constraint) { // this is supertype => subtype which is the equivalent of (!supertype v subtype) return asVecArray(-supertype.getId(), subtype.getId()); } - }.accept(constraint.getSubtype(), constraint.getSupertype(), constraint); } @@ -88,7 +92,8 @@ public VecInt[] serialize(EqualityConstraint constraint) { return new VariableCombos() { @Override - protected VecInt[] constant_variable(ConstantSlot slot1, VariableSlot slot2, EqualityConstraint constraint) { + protected VecInt[] constant_variable( + ConstantSlot slot1, VariableSlot slot2, EqualityConstraint constraint) { if (isTop(slot1)) { return asVecArray(-slot2.getId()); @@ -98,22 +103,21 @@ protected VecInt[] constant_variable(ConstantSlot slot1, VariableSlot slot2, Equ } @Override - protected VecInt[] variable_constant(VariableSlot slot1, ConstantSlot slot2, EqualityConstraint constraint) { + protected VecInt[] variable_constant( + VariableSlot slot1, ConstantSlot slot2, EqualityConstraint constraint) { return constant_variable(slot2, slot1, constraint); } @Override - protected VecInt[] variable_variable(VariableSlot slot1, VariableSlot slot2, EqualityConstraint constraint) { + protected VecInt[] variable_variable( + VariableSlot slot1, VariableSlot slot2, EqualityConstraint constraint) { // a <=> b which is the same as (!a v b) & (!b v a) - return new VecInt[]{ - asVec(-slot1.getId(), slot2.getId()), - asVec( slot1.getId(), -slot2.getId()) + return new VecInt[] { + asVec(-slot1.getId(), slot2.getId()), asVec(slot1.getId(), -slot2.getId()) }; } - }.accept(constraint.getFirst(), constraint.getSecond(), constraint); - } @Override @@ -121,7 +125,8 @@ public VecInt[] serialize(InequalityConstraint constraint) { return new VariableCombos() { @Override - protected VecInt[] constant_variable(ConstantSlot slot1, VariableSlot slot2, InequalityConstraint constraint) { + protected VecInt[] constant_variable( + ConstantSlot slot1, VariableSlot slot2, InequalityConstraint constraint) { if (isTop(slot1)) { return asVecArray(slot2.getId()); @@ -131,24 +136,23 @@ protected VecInt[] constant_variable(ConstantSlot slot1, VariableSlot slot2, Ine } @Override - protected VecInt[] variable_constant(VariableSlot slot1, ConstantSlot slot2, InequalityConstraint constraint) { + protected VecInt[] variable_constant( + VariableSlot slot1, ConstantSlot slot2, InequalityConstraint constraint) { return constant_variable(slot2, slot1, constraint); } @Override - protected VecInt[] variable_variable(VariableSlot slot1, VariableSlot slot2, InequalityConstraint constraint) { + protected VecInt[] variable_variable( + VariableSlot slot1, VariableSlot slot2, InequalityConstraint constraint) { // a <=> !b which is the same as (!a v !b) & (b v a) - return new VecInt[]{ - asVec(-slot1.getId(), -slot2.getId()), - asVec( slot1.getId(), slot2.getId()) + return new VecInt[] { + asVec(-slot1.getId(), -slot2.getId()), asVec(slot1.getId(), slot2.getId()) }; } - }.accept(constraint.getFirst(), constraint.getSecond(), constraint); } - @Override public VecInt[] serialize(ExistentialConstraint constraint) { // holds a list of Integers that should be prepended to the current set of constraints @@ -157,38 +161,35 @@ public VecInt[] serialize(ExistentialConstraint constraint) { // TODO: THIS ONLY WORKS IF THE CONSTRAINTS ARE NORMALIZED // TODO: WE SHOULD INSTEAD PIPE THROUGH THE ExistentialVariable ID - Integer existentialId = existentialToPotentialVar.get(constraint.getPotentialVariable().getId()); + Integer existentialId = + existentialToPotentialVar.get(constraint.getPotentialVariable().getId()); if (existentialId == null) { // existentialId should not overlap with the Id of real slots in slot manager // thus by computing sum of total slots number in slot manager - // and the size of existentialToPotentialVar and plus 1 to get next id of existential Id here + // and the size of existentialToPotentialVar and plus 1 to get next id of existential Id + // here existentialId = slotManager.getNumberOfSlots() + existentialToPotentialVar.size() + 1; - this.existentialToPotentialVar.put(Integer.valueOf(existentialId), Integer.valueOf(constraint.getPotentialVariable().getId())); + this.existentialToPotentialVar.put( + Integer.valueOf(existentialId), + Integer.valueOf(constraint.getPotentialVariable().getId())); } /** - * if we have an existential constraint of the form: - * if (a exists) { - * a <: b - * } else { - * c <: b + * if we have an existential constraint of the form: if (a exists) { a <: b } else { c <: b * } * - * Let E be a new variable that implies that a exists - * The above existential constraint becomes: - * (E => a <: b) && (!E => c <: b) + *

Let E be a new variable that implies that a exists The above existential constraint + * becomes: (E => a <: b) && (!E => c <: b) * - * Recall: x <: y <=> !x | y - * Then the existential constraint becomes: - * (E => a | !b) && (!E => c | !b) + *

Recall: x <: y <=> !x | y Then the existential constraint becomes: (E => a | !b) && + * (!E => c | !b) * - * We then convert => using material implication we get: - * (!E | a | !b) && (E | c | !b) + *

We then convert => using material implication we get: (!E | a | !b) && (E | c | !b) * - * So, we do this for every constraint in the if block (i.e. the potentialConstraints) + *

So, we do this for every constraint in the if block (i.e. the potentialConstraints) * and for every constraint in the else block (i.e. the alternativeConstraints) */ - List potentialClauses = convertAll(constraint.potentialConstraints()); + List potentialClauses = convertAll(constraint.potentialConstraints()); List alternativeClauses = convertAll(constraint.getAlternateConstraints()); for (VecInt clause : potentialClauses) { @@ -211,7 +212,7 @@ public VecInt[] serialize(ExistentialConstraint constraint) { return clauses; } - public boolean emptyClause(VecInt ... clauses) { + public boolean emptyClause(VecInt... clauses) { for (VecInt clause : clauses) { if (clause.size() == 0) { return true; @@ -248,7 +249,7 @@ public VecInt[] serialize(CombVariableSlot slot) { public VecInt[] serialize(LubVariableSlot slot) { return null; } - + @Override public VecInt[] serialize(ArithmeticVariableSlot slot) { // doesn't really mean anything @@ -263,7 +264,8 @@ public VecInt[] serialize(ComparisonVariableSlot slot) { @Override public VecInt[] serialize(ExistentialVariableSlot slot) { // See checkers.inference.ConstraintNormalizer.normalize() - throw new UnsupportedOperationException("Existential slots should be normalized away before serialization."); + throw new UnsupportedOperationException( + "Existential slots should be normalized away before serialization."); } @Override @@ -274,7 +276,7 @@ public VecInt[] serialize(ComparableConstraint comparableConstraint) { @Override public VecInt[] serialize(ComparisonConstraint comparisonConstraint) { - throw new UnsupportedOperationException( + throw new UnsupportedOperationException( "Serializing ComparisonConstraint is unsupported in CnfVecIntSerializer"); } @@ -298,16 +300,17 @@ public VecInt[] serialize(PreferenceConstraint preferenceConstraint) { @Override public VecInt[] serialize(ImplicationConstraint implicationConstraint) { - throw new UnsupportedOperationException("ImplicationConstraint is supported in more-advanced" + - "MaxSAT backend. Use MaxSATSolver instead!"); + throw new UnsupportedOperationException( + "ImplicationConstraint is supported in more-advanced" + + "MaxSAT backend. Use MaxSATSolver instead!"); } /** - * Convert all the given mandatory constraints into hard clauses. A BugInCF exception is - * raised if the given constraints contain any {@link PreferenceConstraint}. + * Convert all the given mandatory constraints into hard clauses. A BugInCF exception is raised + * if the given constraints contain any {@link PreferenceConstraint}. * - * For conversion of constraints containing {@link PreferenceConstraint}, use - * {@link CnfVecIntSerializer#convertAll(Iterable, List, List)} + *

For conversion of constraints containing {@link PreferenceConstraint}, use {@link + * CnfVecIntSerializer#convertAll(Iterable, List, List)} * * @param constraints the constraints to convert * @return the output clauses for the given constraints @@ -317,11 +320,11 @@ public List convertAll(Iterable constraints) { } /** - * Convert all the given mandatory constraints into hard clauses. A BugInCF exception is - * raised if the given constraints contains any {@link PreferenceConstraint}. + * Convert all the given mandatory constraints into hard clauses. A BugInCF exception is raised + * if the given constraints contains any {@link PreferenceConstraint}. * - * For conversion of constraints containing {@link PreferenceConstraint}, use - * {@link CnfVecIntSerializer#convertAll(Iterable, List, List)} + *

For conversion of constraints containing {@link PreferenceConstraint}, use {@link + * CnfVecIntSerializer#convertAll(Iterable, List, List)} * * @param constraints the constraints to convert * @param results the output clauses for the given constraints @@ -330,8 +333,10 @@ public List convertAll(Iterable constraints) { public List convertAll(Iterable constraints, List results) { for (Constraint constraint : constraints) { if (constraint instanceof PreferenceConstraint) { - throw new BugInCF("CnfVecIntSerializer: adding PreferenceConstraint ( " + constraint + - " ) to hard clauses is forbidden"); + throw new BugInCF( + "CnfVecIntSerializer: adding PreferenceConstraint ( " + + constraint + + " ) to hard clauses is forbidden"); } for (VecInt res : constraint.serialize(this)) { if (res.size() != 0) { @@ -344,14 +349,15 @@ public List convertAll(Iterable constraints, List re } /** - * Convert all the given mandatory constraints to hard clauses, and preference constraints - * to soft clauses. + * Convert all the given mandatory constraints to hard clauses, and preference constraints to + * soft clauses. * * @param constraints the constraints to convert * @param hardClauses the output hard clauses for the mandatory constraints * @param softClauses the output soft clauses for {@link PreferenceConstraint} */ - public void convertAll(Iterable constraints, List hardClauses, List softClauses) { + public void convertAll( + Iterable constraints, List hardClauses, List softClauses) { for (Constraint constraint : constraints) { for (VecInt res : constraint.serialize(this)) { if (res.size() != 0) { @@ -367,22 +373,23 @@ public void convertAll(Iterable constraints, List hardClause protected abstract boolean isTop(ConstantSlot constantSlot); - VecInt asVec(int ... vars) { + VecInt asVec(int... vars) { return new VecInt(vars); } /** * Creates a single clause using integers and then wraps that clause in an array + * * @param vars The positive/negative literals of the clause * @return A VecInt array containing just 1 element */ - VecInt[] asVecArray(int ... vars) { - return new VecInt[]{new VecInt(vars)}; + VecInt[] asVecArray(int... vars) { + return new VecInt[] {new VecInt(vars)}; } /** - * Takes 2 slots and constraints, down casts them to the right VariableSlot or ConstantSlot - * and passes them to the corresponding method. + * Takes 2 slots and constraints, down casts them to the right VariableSlot or ConstantSlot and + * passes them to the corresponding method. */ class VariableCombos { @@ -410,9 +417,13 @@ public VecInt[] accept(Slot slot1, Slot slot2, T constraint) { final VecInt[] result; if (slot1 instanceof ConstantSlot) { if (slot2 instanceof ConstantSlot) { - result = constant_constant((ConstantSlot) slot1, (ConstantSlot) slot2, constraint); + result = + constant_constant( + (ConstantSlot) slot1, (ConstantSlot) slot2, constraint); } else { - result = constant_variable((ConstantSlot) slot1, (VariableSlot) slot2, constraint); + result = + constant_variable( + (ConstantSlot) slot1, (VariableSlot) slot2, constraint); } } else if (slot2 instanceof ConstantSlot) { result = variable_constant((VariableSlot) slot1, (ConstantSlot) slot2, constraint); diff --git a/src/checkers/inference/model/serialization/JsonDeserializer.java b/src/checkers/inference/model/serialization/JsonDeserializer.java index 77aca6d7a..8ec9c68a5 100644 --- a/src/checkers/inference/model/serialization/JsonDeserializer.java +++ b/src/checkers/inference/model/serialization/JsonDeserializer.java @@ -1,29 +1,8 @@ package checkers.inference.model.serialization; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.lang.model.element.AnnotationMirror; - -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; -import org.json.simple.parser.ParseException; - -import checkers.inference.InferenceMain; -import checkers.inference.model.AnnotationLocation; -import checkers.inference.model.Constraint; -import checkers.inference.model.ConstraintManager; -import checkers.inference.model.Slot; -import checkers.inference.model.SourceVariableSlot; import static checkers.inference.model.serialization.JsonSerializer.COMPARABLE_CONSTRAINT_KEY; -import static checkers.inference.model.serialization.JsonSerializer.COMPARISON_CONSTRAINT_KEY; +import static checkers.inference.model.serialization.JsonSerializer.COMPARABLE_LHS; +import static checkers.inference.model.serialization.JsonSerializer.COMPARABLE_RHS; import static checkers.inference.model.serialization.JsonSerializer.CONSTRAINTS_KEY; import static checkers.inference.model.serialization.JsonSerializer.CONSTRAINT_KEY; import static checkers.inference.model.serialization.JsonSerializer.EQUALITY_CONSTRAINT_KEY; @@ -37,8 +16,6 @@ import static checkers.inference.model.serialization.JsonSerializer.INEQUALITY_CONSTRAINT_KEY; import static checkers.inference.model.serialization.JsonSerializer.INEQUALITY_LHS; import static checkers.inference.model.serialization.JsonSerializer.INEQUALITY_RHS; -import static checkers.inference.model.serialization.JsonSerializer.COMPARABLE_LHS; -import static checkers.inference.model.serialization.JsonSerializer.COMPARABLE_RHS; import static checkers.inference.model.serialization.JsonSerializer.SUBTYPE_CONSTRAINT_KEY; import static checkers.inference.model.serialization.JsonSerializer.SUBTYPE_SUB_KEY; import static checkers.inference.model.serialization.JsonSerializer.SUBTYPE_SUPER_KEY; @@ -46,15 +23,38 @@ import static checkers.inference.model.serialization.JsonSerializer.VARIABLES_VALUE_KEY; import static checkers.inference.model.serialization.JsonSerializer.VAR_PREFIX; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.lang.model.element.AnnotationMirror; + +import checkers.inference.InferenceMain; +import checkers.inference.model.AnnotationLocation; +import checkers.inference.model.Constraint; +import checkers.inference.model.ConstraintManager; +import checkers.inference.model.Slot; +import checkers.inference.model.SourceVariableSlot; + /** - * Class to convert a String (this is a formatted json constraint file) into a list of inference Constraints. + * Class to convert a String (this is a formatted json constraint file) into a list of inference + * Constraints. * - * The format of the json constraint file is documented in JsonSerializer.java. + *

The format of the json constraint file is documented in JsonSerializer.java. * - * TODO: Support nested constraints + *

TODO: Support nested constraints * * @author mcarthur - * */ public class JsonDeserializer { @@ -66,7 +66,8 @@ public class JsonDeserializer { private ConstraintManager constraintManager; - public JsonDeserializer(AnnotationMirrorSerializer annotationSerializer, String json) throws ParseException { + public JsonDeserializer(AnnotationMirrorSerializer annotationSerializer, String json) + throws ParseException { this.annotationSerializer = annotationSerializer; JSONParser parser = new JSONParser(); this.root = (JSONObject) parser.parse(json); @@ -82,14 +83,16 @@ public List parseConstraints() throws ParseException { public List jsonArrayToConstraints(final JSONArray jsonConstraints) { List results = new LinkedList(); - for (Object obj: jsonConstraints) { + for (Object obj : jsonConstraints) { if (obj instanceof String) { String constraintStr = (String) obj; String[] parts = constraintStr.trim().split(" "); if (parts.length != 3) { - throw new IllegalArgumentException("Parse error: could not parse constraint: " + obj); + throw new IllegalArgumentException( + "Parse error: could not parse constraint: " + obj); } else if (!SUBTYPE_STR.equals(parts[1])) { - throw new IllegalArgumentException("Parse error: found unexpected constraint operation: " + obj); + throw new IllegalArgumentException( + "Parse error: found unexpected constraint operation: " + obj); } Slot sub = parseSlot(parts[0]); Slot sup = parseSlot(parts[2]); @@ -119,10 +122,12 @@ public List jsonArrayToConstraints(final JSONArray jsonConstraints) jsonArrayToConstraints((JSONArray) constraint.get(EXISTENTIAL_THEN)); List elseConstraints = jsonArrayToConstraints((JSONArray) constraint.get(EXISTENTIAL_ELSE)); - results.add(constraintManager.createExistentialConstraint(potential, - thenConstraints, elseConstraints)); - } else { - throw new IllegalArgumentException("Parse error: unknown constraint type: " + obj); + results.add( + constraintManager.createExistentialConstraint( + potential, thenConstraints, elseConstraints)); + } else { + throw new IllegalArgumentException( + "Parse error: unknown constraint type: " + obj); } // TODO: map.get, enabled_check, selection_check } else { @@ -133,9 +138,10 @@ public List jsonArrayToConstraints(final JSONArray jsonConstraints) } public List getPotentialVariables() { - Set potentialVars = findPotentialVars((JSONArray) root.get(CONSTRAINTS_KEY), new LinkedHashSet()); + Set potentialVars = + findPotentialVars( + (JSONArray) root.get(CONSTRAINTS_KEY), new LinkedHashSet()); return new ArrayList<>(potentialVars); - } private Set findPotentialVars(JSONArray constraints, Set potentialVariableIds) { @@ -189,7 +195,8 @@ public Map getAnnotationValues() { for (Map.Entry e : entries) { String variableId = (String) e.getKey(); - // in the first results from v.12 the output solved JSON had two different formats in the Variables section + // in the first results from v.12 the output solved JSON had two different formats in + // the Variables section String variableType; if (e.getValue() instanceof JSONObject) { variableType = (String) ((JSONObject) e.getValue()).get(VARIABLES_VALUE_KEY); @@ -210,7 +217,8 @@ private Slot parseSlot(String slot) { int id = Integer.valueOf(slot.split(":")[1]); // TODO: Here we are creating a SourceVariableSlot without any detailed information. // We should consider refactor this implementation. - return new SourceVariableSlot(id, AnnotationLocation.MISSING_LOCATION, null, null, true); + return new SourceVariableSlot( + id, AnnotationLocation.MISSING_LOCATION, null, null, true); } else { // TODO: THIS NEEDS FIXING AnnotationMirror value = annotationSerializer.deserialize(slot); diff --git a/src/checkers/inference/model/serialization/JsonSerializer.java b/src/checkers/inference/model/serialization/JsonSerializer.java index f8eaf0873..162195d80 100644 --- a/src/checkers/inference/model/serialization/JsonSerializer.java +++ b/src/checkers/inference/model/serialization/JsonSerializer.java @@ -1,5 +1,8 @@ package checkers.inference.model.serialization; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; + import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -7,10 +10,6 @@ import javax.lang.model.element.AnnotationMirror; -import checkers.inference.model.LubVariableSlot; -import checkers.inference.model.ImplicationConstraint; -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; import checkers.inference.model.ArithmeticConstraint; import checkers.inference.model.ArithmeticVariableSlot; import checkers.inference.model.CombVariableSlot; @@ -23,7 +22,9 @@ import checkers.inference.model.EqualityConstraint; import checkers.inference.model.ExistentialConstraint; import checkers.inference.model.ExistentialVariableSlot; +import checkers.inference.model.ImplicationConstraint; import checkers.inference.model.InequalityConstraint; +import checkers.inference.model.LubVariableSlot; import checkers.inference.model.PreferenceConstraint; import checkers.inference.model.RefinementVariableSlot; import checkers.inference.model.Serializer; @@ -32,75 +33,36 @@ import checkers.inference.model.SubtypeConstraint; /** + * // Scores are numeric // Everything else is a string (including version and qualifier ids) // + * Game side ignores any key in a map prefixed with "system-" // Variables are prefixed with "var:" + * // Types are prefixed with "type:" * - -// Scores are numeric -// Everything else is a string (including version and qualifier ids) -// Game side ignores any key in a map prefixed with "system-" -// Variables are prefixed with "var:" -// Types are prefixed with "type:" - -// Variable values are set in the "variables": "var:ID": "type_value": key. - -{ - "version": "1", - - "scoring": { - "constraints": 1000, - "variables": { "type:0" : 0, "type:1": 100 } - }, - - // Extra configurations on variables - // Listing variables here is optional - "variables": { - "var:10" : { - "type_value": "type:0", - "keyfor_value" : [],' - "score": { "type:0" : 0, "type:1": 1000 }, - "possible_keyfor": ["mymap1", "mymap2"] - } - }, - - "constraints": [ - // Format 1 - "var:10 <= type:0", - - // Subtype - { "constraint" : "subtype", // subtype, equality, inequality - "lhs" : "var:1", - "rhs": "var:2" - "score": 100 - }, - - // Map.get - { "constraint": "map.get", - "name": "mymap1", - "value_type": "var:1", - "key": "var:2", - "result": "var:3" - }, - - // If Node - { "constraint": "selection_check", - "id": "var:11", - "type": "type:0", - "then": [ ... ], // Nested list of constraints - "else": [ ... ], - }, - - // Generics - { "constraint": "enabled_check", - "id" : "var:12", - "then": [ ... ], - "else": [ ... ], - } - ] -} - - * @author mcarthur + *

// Variable values are set in the "variables": "var:ID": "type_value": key. + * + *

{ "version": "1", + * + *

"scoring": { "constraints": 1000, "variables": { "type:0" : 0, "type:1": 100 } }, + * + *

// Extra configurations on variables // Listing variables here is optional "variables": { + * "var:10" : { "type_value": "type:0", "keyfor_value" : [],' "score": { "type:0" : 0, "type:1": + * 1000 }, "possible_keyfor": ["mymap1", "mymap2"] } }, + * + *

"constraints": [ // Format 1 "var:10 <= type:0", + * + *

// Subtype { "constraint" : "subtype", // subtype, equality, inequality "lhs" : "var:1", + * "rhs": "var:2" "score": 100 }, + * + *

// Map.get { "constraint": "map.get", "name": "mymap1", "value_type": "var:1", "key": "var:2", + * "result": "var:3" }, * + *

// If Node { "constraint": "selection_check", "id": "var:11", "type": "type:0", "then": [ ... + * ], // Nested list of constraints "else": [ ... ], }, + * + *

// Generics { "constraint": "enabled_check", "id" : "var:12", "then": [ ... ], "else": [ ... + * ], } ] } + * + * @author mcarthur */ - public class JsonSerializer implements Serializer { // Version of this format @@ -164,15 +126,17 @@ public class JsonSerializer implements Serializer { @SuppressWarnings("unused") private final Collection slots; + private final Collection constraints; private final Map solutions; private AnnotationMirrorSerializer annotationSerializer; - public JsonSerializer(Collection slots, - Collection constraints, - Map solutions, - AnnotationMirrorSerializer annotationSerializer) { + public JsonSerializer( + Collection slots, + Collection constraints, + Map solutions, + AnnotationMirrorSerializer annotationSerializer) { this.slots = slots; this.constraints = constraints; @@ -183,7 +147,7 @@ public JsonSerializer(Collection slots, @SuppressWarnings("unchecked") public JSONObject generateConstraintFile() { JSONObject result = new JSONObject(); - result.put(VERSION_KEY, VERSION); + result.put(VERSION_KEY, VERSION); if (solutions != null && solutions.size() > 0) { result.put(VARIABLES_KEY, generateVariablesSection()); @@ -196,7 +160,7 @@ public JSONObject generateConstraintFile() { @SuppressWarnings("unchecked") protected JSONObject generateVariablesSection() { JSONObject variables = new JSONObject(); - for (Map.Entry entry: solutions.entrySet()) { + for (Map.Entry entry : solutions.entrySet()) { JSONObject variable = new JSONObject(); variable.put(VARIABLES_VALUE_KEY, getConstantString(entry.getValue())); variables.put(VAR_PREFIX + entry.getKey(), variable); @@ -236,10 +200,10 @@ public String serialize(RefinementVariableSlot slot) { @Override public String serialize(ExistentialVariableSlot slot) { - throw new UnsupportedOperationException("Existential slots should be normalized away before serialization."); + throw new UnsupportedOperationException( + "Existential slots should be normalized away before serialization."); } - @Override public String serialize(ConstantSlot slot) { return getConstantString(slot.getValue()); @@ -293,13 +257,12 @@ public JSONObject serialize(EqualityConstraint constraint) { return obj; } - @Override public JSONObject serialize(ExistentialConstraint constraint) { JSONObject obj = new JSONObject(); obj.put(CONSTRAINT_KEY, EXISTENTIAL_CONSTRAINT_KEY); - obj.put(EXISTENTIAL_ID, constraint.getPotentialVariable().serialize(this)); + obj.put(EXISTENTIAL_ID, constraint.getPotentialVariable().serialize(this)); obj.put(EXISTENTIAL_THEN, constraintsToJsonArray(constraint.potentialConstraints())); obj.put(EXISTENTIAL_ELSE, constraintsToJsonArray(constraint.getAlternateConstraints())); return obj; @@ -351,7 +314,9 @@ public JSONObject serialize(ComparisonConstraint constraint) { @SuppressWarnings("unchecked") @Override public JSONObject serialize(CombineConstraint constraint) { - if (constraint.getTarget() == null || constraint.getDeclared() == null || constraint.getResult() == null) { + if (constraint.getTarget() == null + || constraint.getDeclared() == null + || constraint.getResult() == null) { return null; } diff --git a/src/checkers/inference/model/serialization/JsonSerializerSolver.java b/src/checkers/inference/model/serialization/JsonSerializerSolver.java index cd54ca173..4fcd9543d 100644 --- a/src/checkers/inference/model/serialization/JsonSerializerSolver.java +++ b/src/checkers/inference/model/serialization/JsonSerializerSolver.java @@ -1,5 +1,8 @@ package checkers.inference.model.serialization; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + import org.checkerframework.framework.type.QualifierHierarchy; import java.io.FileNotFoundException; @@ -11,9 +14,6 @@ import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.AnnotationMirror; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; - import checkers.inference.InferenceResult; import checkers.inference.InferenceSolver; import checkers.inference.model.Constraint; @@ -23,9 +23,7 @@ * InferenceSolver that serializes constraints to a file in JSON format. * * @author mcarthur - * */ - public class JsonSerializerSolver implements InferenceSolver { private static final String FILE_KEY = "constraint-file"; @@ -43,8 +41,10 @@ public InferenceResult solve( this.configuration = configuration; AnnotationMirror top = qualHierarchy.getTopAnnotations().iterator().next(); AnnotationMirror bottom = qualHierarchy.getBottomAnnotations().iterator().next(); - SimpleAnnotationMirrorSerializer annotationSerializer = new SimpleAnnotationMirrorSerializer(top, bottom); - JsonSerializer serializer = new JsonSerializer(slots, constraints, null, annotationSerializer); + SimpleAnnotationMirrorSerializer annotationSerializer = + new SimpleAnnotationMirrorSerializer(top, bottom); + JsonSerializer serializer = + new JsonSerializer(slots, constraints, null, annotationSerializer); printJson(serializer); return null; @@ -54,9 +54,8 @@ protected void printJson(JsonSerializer serializer) { Gson gson = new GsonBuilder().setPrettyPrinting().create(); String json = gson.toJson(serializer.generateConstraintFile()); - String outFile = configuration.containsKey(FILE_KEY) ? - configuration.get(FILE_KEY) - : DEFAULT_FILE; + String outFile = + configuration.containsKey(FILE_KEY) ? configuration.get(FILE_KEY) : DEFAULT_FILE; try (PrintWriter writer = new PrintWriter(new FileOutputStream(outFile))) { writer.print(json); } catch (FileNotFoundException e) { diff --git a/src/checkers/inference/model/serialization/SimpleAnnotationMirrorSerializer.java b/src/checkers/inference/model/serialization/SimpleAnnotationMirrorSerializer.java index b21eaac81..f83f8102c 100644 --- a/src/checkers/inference/model/serialization/SimpleAnnotationMirrorSerializer.java +++ b/src/checkers/inference/model/serialization/SimpleAnnotationMirrorSerializer.java @@ -4,13 +4,13 @@ /** * A simple implementation of AnnotationMirrorSerializer. - * - * Only works on type systems with two types in a hierarchy (and one is strictly a subtype of the other). - * - * The serialized format is what the game expects: "type:0" and "type:1" - * - * @author mcarthur * + *

Only works on type systems with two types in a hierarchy (and one is strictly a subtype of the + * other). + * + *

The serialized format is what the game expects: "type:0" and "type:1" + * + * @author mcarthur */ public class SimpleAnnotationMirrorSerializer implements AnnotationMirrorSerializer { @@ -33,7 +33,8 @@ public AnnotationMirror deserialize(String amStr) { return bottom; } else { throw new IllegalArgumentException( - String.format("AnnotationMirror: %s could not be deserialzed by this class.", amStr)); + String.format( + "AnnotationMirror: %s could not be deserialzed by this class.", amStr)); } } @@ -45,8 +46,8 @@ public String serialize(AnnotationMirror am) { return BOTTOM_STR; } else { throw new IllegalArgumentException( - String.format("AnnotationMirror: %s could not be serialzed by this class.", am)); + String.format( + "AnnotationMirror: %s could not be serialzed by this class.", am)); } } - } diff --git a/src/checkers/inference/model/serialization/ToStringSerializer.java b/src/checkers/inference/model/serialization/ToStringSerializer.java index eddb8c6e2..0c629c953 100644 --- a/src/checkers/inference/model/serialization/ToStringSerializer.java +++ b/src/checkers/inference/model/serialization/ToStringSerializer.java @@ -1,15 +1,14 @@ package checkers.inference.model.serialization; +import org.checkerframework.framework.util.AnnotationFormatter; + import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.TreeMap; -import java.util.TreeSet; -import org.checkerframework.framework.util.AnnotationFormatter; -import org.checkerframework.javacutil.SystemUtil; + import checkers.inference.InferenceMain; import checkers.inference.model.ArithmeticConstraint; import checkers.inference.model.ArithmeticVariableSlot; @@ -34,9 +33,7 @@ import checkers.inference.model.SubtypeConstraint; import checkers.inference.model.VariableSlot; -/** - * This Serializer converts constraints and variables to human readable strings. - */ +/** This Serializer converts constraints and variables to human readable strings. */ public class ToStringSerializer implements Serializer { private final boolean showAstPaths; private boolean showVerboseVars; @@ -95,8 +92,7 @@ public String serializeSlots(Iterable slots, String delimiter) { for (Slot slot : slots) { // sort the slots by ID through insertion to TreeMap - serializedSlots.put(slot.getId(), - getCurrentIndentString() + slot.serialize(this)); + serializedSlots.put(slot.getId(), getCurrentIndentString() + slot.serialize(this)); } return String.join(delimiter, serializedSlots.values()); @@ -124,9 +120,9 @@ public String serialize(SubtypeConstraint constraint) { showVerboseVars = false; final StringBuilder sb = new StringBuilder(); sb.append(getCurrentIndentString()) - .append(constraint.getSubtype().serialize(this)) - .append(" <: ") - .append(constraint.getSupertype().serialize(this)); + .append(constraint.getSubtype().serialize(this)) + .append(" <: ") + .append(constraint.getSupertype().serialize(this)); showVerboseVars = prevShowVerboseVars; return sb.toString(); } @@ -137,9 +133,9 @@ public String serialize(EqualityConstraint constraint) { showVerboseVars = false; final StringBuilder sb = new StringBuilder(); sb.append(getCurrentIndentString()) - .append(constraint.getFirst().serialize(this)) - .append(" == ") - .append(constraint.getSecond().serialize(this)); + .append(constraint.getFirst().serialize(this)) + .append(" == ") + .append(constraint.getSecond().serialize(this)); showVerboseVars = prevShowVerboseVars; return sb.toString(); } @@ -150,23 +146,19 @@ public String serialize(ExistentialConstraint constraint) { showVerboseVars = false; final StringBuilder sb = new StringBuilder(); sb.append(getCurrentIndentString()) - .append("if ( ") - .append(constraint.getPotentialVariable().serialize(this)) - .append(" exists ) {\n"); + .append("if ( ") + .append(constraint.getPotentialVariable().serialize(this)) + .append(" exists ) {\n"); setIndentationLevel(indentationLevel + 1); sb.append(serializeConstraints(constraint.potentialConstraints(), "\n")); setIndentationLevel(indentationLevel - 1); - sb.append("\n") - .append(getCurrentIndentString()) - .append("} else {\n"); + sb.append("\n").append(getCurrentIndentString()).append("} else {\n"); setIndentationLevel(indentationLevel + 1); sb.append(serializeConstraints(constraint.getAlternateConstraints(), "\n")); setIndentationLevel(indentationLevel - 1); - sb.append("\n") - .append(getCurrentIndentString()) - .append("}"); + sb.append("\n").append(getCurrentIndentString()).append("}"); showVerboseVars = prevShowVerboseVars; return sb.toString(); } @@ -177,9 +169,9 @@ public String serialize(InequalityConstraint constraint) { showVerboseVars = false; final StringBuilder sb = new StringBuilder(); sb.append(getCurrentIndentString()) - .append(constraint.getFirst().serialize(this)) - .append(" != ") - .append(constraint.getSecond().serialize(this)); + .append(constraint.getFirst().serialize(this)) + .append(" != ") + .append(constraint.getSecond().serialize(this)); showVerboseVars = prevShowVerboseVars; return sb.toString(); } @@ -190,28 +182,28 @@ public String serialize(ComparableConstraint constraint) { showVerboseVars = false; final StringBuilder sb = new StringBuilder(); sb.append(getCurrentIndentString()) - .append(constraint.getFirst().serialize(this)) - .append(" <~> ") - .append(constraint.getSecond().serialize(this)); + .append(constraint.getFirst().serialize(this)) + .append(" <~> ") + .append(constraint.getSecond().serialize(this)); showVerboseVars = prevShowVerboseVars; return sb.toString(); } @Override public String serialize(ComparisonConstraint constraint) { - boolean prevShowVerboseVars = showVerboseVars; + boolean prevShowVerboseVars = showVerboseVars; showVerboseVars = false; // format: result <= ( left comp right ) final StringBuilder sb = new StringBuilder(); sb.append(getCurrentIndentString()) - .append(constraint.getResult().serialize(this)) - .append(" <= ( ") - .append(constraint.getLeft().serialize(this)) - .append(" ") - .append(constraint.getOperation().getSymbol()) - .append(" ") - .append(constraint.getRight().serialize(this)) - .append(" )"); + .append(constraint.getResult().serialize(this)) + .append(" <= ( ") + .append(constraint.getLeft().serialize(this)) + .append(" ") + .append(constraint.getOperation().getSymbol()) + .append(" ") + .append(constraint.getRight().serialize(this)) + .append(" )"); optionallyFormatAstPath(constraint, sb); showVerboseVars = prevShowVerboseVars; return sb.toString(); @@ -224,12 +216,12 @@ public String serialize(CombineConstraint constraint) { // "\u25B7" is unicode representation of viewpoint adaptation sign |> final StringBuilder sb = new StringBuilder(); sb.append(getCurrentIndentString()) - .append(constraint.getResult().serialize(this)) - .append(" = ( ") - .append(constraint.getTarget().serialize(this)) - .append(" \u25B7 ") - .append(constraint.getDeclared().serialize(this)) - .append(" )"); + .append(constraint.getResult().serialize(this)) + .append(" = ( ") + .append(constraint.getTarget().serialize(this)) + .append(" \u25B7 ") + .append(constraint.getDeclared().serialize(this)) + .append(" )"); showVerboseVars = prevShowVerboseVars; return sb.toString(); } @@ -240,11 +232,11 @@ public String serialize(PreferenceConstraint constraint) { showVerboseVars = false; final StringBuilder sb = new StringBuilder(); sb.append(getCurrentIndentString()) - .append(constraint.getVariable().serialize(this)) - .append(" == ") - .append(constraint.getGoal().serialize(this)) - .append(" weight = ") - .append(constraint.getWeight()); + .append(constraint.getVariable().serialize(this)) + .append(" == ") + .append(constraint.getGoal().serialize(this)) + .append(" weight = ") + .append(constraint.getWeight()); showVerboseVars = prevShowVerboseVars; return sb.toString(); } @@ -253,8 +245,8 @@ public String serialize(PreferenceConstraint constraint) { public String serialize(ConstantSlot slot) { final StringBuilder sb = new StringBuilder(); sb.append(slot.getId()) - .append(" ") - .append(formatter.formatAnnotationMirror(slot.getValue())); + .append(" ") + .append(formatter.formatAnnotationMirror(slot.getValue())); return sb.toString(); } @@ -265,14 +257,14 @@ public String serialize(ArithmeticConstraint arithmeticConstraint) { // format: result = ( leftOperand op rightOperand ) final StringBuilder sb = new StringBuilder(); sb.append(getCurrentIndentString()) - .append(arithmeticConstraint.getResult().serialize(this)) - .append(" = ( ") - .append(arithmeticConstraint.getLeftOperand().serialize(this)) - .append(" ") - .append(arithmeticConstraint.getOperation().getSymbol()) - .append(" ") - .append(arithmeticConstraint.getRightOperand().serialize(this)) - .append(" )"); + .append(arithmeticConstraint.getResult().serialize(this)) + .append(" = ( ") + .append(arithmeticConstraint.getLeftOperand().serialize(this)) + .append(" ") + .append(arithmeticConstraint.getOperation().getSymbol()) + .append(" ") + .append(arithmeticConstraint.getRightOperand().serialize(this)) + .append(" )"); optionallyFormatAstPath(arithmeticConstraint, sb); showVerboseVars = prevShowVerboseVars; return sb.toString(); @@ -287,7 +279,8 @@ public String serialize(ImplicationConstraint implicationConstraint) { final StringBuilder sb = new StringBuilder(); sb.append(getCurrentIndentString()); int oldIndentationLevel = indentationLevel; - // This is to avoid indentation for each sub constraint that comprises the implicationConstraint + // This is to avoid indentation for each sub constraint that comprises the + // implicationConstraint indentationLevel = 0; String assumptions = getAssumptionsString(implicationConstraint); String conclusion = implicationConstraint.getConclusion().serialize(this); @@ -324,7 +317,7 @@ public String serialize(RefinementVariableSlot slot) { final StringBuilder sb = new StringBuilder(); sb.append(slot.getId()); // \u21A7 is a downward arrow symbol - sb.append("[ \u21A7 "+ slot.getRefined().serialize(this) + " ]"); + sb.append("[ \u21A7 " + slot.getRefined().serialize(this) + " ]"); optionallyShowVerbose(slot, sb); return sb.toString(); } @@ -333,11 +326,11 @@ public String serialize(RefinementVariableSlot slot) { public String serialize(ExistentialVariableSlot slot) { final StringBuilder sb = new StringBuilder(); sb.append(slot.getId()) - .append(": ( ") - .append(slot.getPotentialSlot().getId()) - .append(" | ") - .append(slot.getAlternativeSlot().getId()) - .append(" ) "); + .append(": ( ") + .append(slot.getPotentialSlot().getId()) + .append(" | ") + .append(slot.getAlternativeSlot().getId()) + .append(" ) "); optionallyShowVerbose(slot, sb); return sb.toString(); } @@ -347,8 +340,7 @@ public String serialize(CombVariableSlot slot) { final StringBuilder sb = new StringBuilder(); sb.append(slot.getId()); if (showVerboseVars) { - sb.append(": combines ") - .append(Arrays.asList(slot.getFirst(), slot.getSecond())); + sb.append(": combines ").append(Arrays.asList(slot.getFirst(), slot.getSecond())); formatMerges(slot, sb); optionallyFormatAstPath(slot, sb); } @@ -389,8 +381,8 @@ public String serialize(ComparisonVariableSlot slot) { } /** - * @return the indent string for the current indentation level as stored in - * {@link #indentationLevel}. + * @return the indent string for the current indentation level as stored in {@link + * #indentationLevel}. */ public String getCurrentIndentString() { return indentStrings.get(indentationLevel); @@ -398,8 +390,7 @@ public String getCurrentIndentString() { private void formatMerges(final Slot slot, final StringBuilder sb) { if (!slot.getMergedToSlots().isEmpty()) { - sb.append(": merged to -> ") - .append(slot.getMergedToSlots()); + sb.append(": merged to -> ").append(slot.getMergedToSlots()); } } @@ -412,9 +403,7 @@ private void optionallyShowVerbose(final VariableSlot slot, final StringBuilder private void optionallyFormatAstPath(final VariableSlot varSlot, final StringBuilder sb) { if (showAstPaths && (varSlot.isInsertable() || (varSlot.getLocation() != null))) { - sb.append("\n") - .append(getCurrentIndentString()) - .append("AstPath: "); + sb.append("\n").append(getCurrentIndentString()).append("AstPath: "); if (varSlot.getLocation() == null) { sb.append(""); } else { @@ -425,9 +414,7 @@ private void optionallyFormatAstPath(final VariableSlot varSlot, final StringBui private void optionallyFormatAstPath(final Constraint constraint, final StringBuilder sb) { if (showAstPaths) { - sb.append("\n") - .append(getCurrentIndentString()) - .append("AstPath: "); + sb.append("\n").append(getCurrentIndentString()).append("AstPath: "); if (constraint.getLocation() == null) { sb.append(""); } else { diff --git a/src/checkers/inference/model/tree/ArtificialExtendsBoundTree.java b/src/checkers/inference/model/tree/ArtificialExtendsBoundTree.java index 93596a8f5..9365262d5 100644 --- a/src/checkers/inference/model/tree/ArtificialExtendsBoundTree.java +++ b/src/checkers/inference/model/tree/ArtificialExtendsBoundTree.java @@ -1,29 +1,25 @@ package checkers.inference.model.tree; -import java.util.Objects; - import com.sun.source.tree.WildcardTree; import com.sun.tools.javac.tree.JCTree.JCIdent; +import java.util.Objects; + /** * Artificial extend bound tree for representing extend bound of unbounded wildcard type. * - * This class is used to represent the extend bound of an - * unbounded wild card type. In order to let {@code VariableAnnotator} - * be able to insert two different VarAnnotations on the super bound and the - * extend bound of a unbounded wild card type. - * (A VarAnnotation will be inserted with the location of this artificial extend bound tree, - * and the VarAnnotation on wild card type would represent the "missing" bound --- super bound). - * - * Note: This class is specially created and should be only used by {@link VariableAnnotator} - * as key of {@link VariableAnnotator#treeToVarAnnoPair} cache. + *

This class is used to represent the extend bound of an unbounded wild card type. In order to + * let {@code VariableAnnotator} be able to insert two different VarAnnotations on the super bound + * and the extend bound of a unbounded wild card type. (A VarAnnotation will be inserted with the + * location of this artificial extend bound tree, and the VarAnnotation on wild card type would + * represent the "missing" bound --- super bound). * + *

Note: This class is specially created and should be only used by {@link VariableAnnotator} as + * key of {@link VariableAnnotator#treeToVarAnnoPair} cache. */ public class ArtificialExtendsBoundTree extends JCIdent { - /** - * The wild card tree bounded by this extend bound tree. - */ + /** The wild card tree bounded by this extend bound tree. */ private final WildcardTree boundedWildcard; public ArtificialExtendsBoundTree(WildcardTree wildcardTree) { @@ -35,13 +31,12 @@ public WildcardTree getBoundedWildcard() { return boundedWildcard; } - /** - * The bounded Wildcard tree determine the equality of artificial extend bound trees. - */ + /** The bounded Wildcard tree determine the equality of artificial extend bound trees. */ @Override public boolean equals(Object obj) { - return (obj instanceof ArtificialExtendsBoundTree) && - (this.boundedWildcard.equals(((ArtificialExtendsBoundTree) obj).getBoundedWildcard())); + return (obj instanceof ArtificialExtendsBoundTree) + && (this.boundedWildcard.equals( + ((ArtificialExtendsBoundTree) obj).getBoundedWildcard())); } @Override diff --git a/src/checkers/inference/qual/VarAnnot.java b/src/checkers/inference/qual/VarAnnot.java index 55c08070d..6cbd5fa5d 100644 --- a/src/checkers/inference/qual/VarAnnot.java +++ b/src/checkers/inference/qual/VarAnnot.java @@ -8,24 +8,22 @@ import java.lang.annotation.Target; /** - * The Checker Inference Framework's primary intent is to take a unannotated or partially annotated program and infer - * annotations for specific type system. VarAnnots represent locations in which an annotation can be written and does - * not already contain an annotation for the target type system. If a location which can have an annotation ALREADY - * has an annotation then it will remain (and be converted into a Constant for generating constraints). However, if - * a location DOES NOT have an annotation from the target type system then a VarAnnot is generated. Some locations - * which only implicitly exist in the source code will also have VarAnnots generated for their values. - * e.g. - * class MyClass - * becomes: - * class MyClass extends @VarAnnot(id) Object + * The Checker Inference Framework's primary intent is to take a unannotated or partially annotated + * program and infer annotations for specific type system. VarAnnots represent locations in which an + * annotation can be written and does not already contain an annotation for the target type system. + * If a location which can have an annotation ALREADY has an annotation then it will remain (and be + * converted into a Constant for generating constraints). However, if a location DOES NOT have an + * annotation from the target type system then a VarAnnot is generated. Some locations which only + * implicitly exist in the source code will also have VarAnnots generated for their values. e.g. + * class MyClass becomes: class MyClass extends @VarAnnot(id) Object * - * When annotations are inserted back into source code they usually are placed in the location an @VarAnnot annotation - * was generated for. If the VarAnnot was generated for an implicit location then source code should be generated to - * construct the appropriate location. + *

When annotations are inserted back into source code they usually are placed in the location + * an @VarAnnot annotation was generated for. If the VarAnnot was generated for an implicit location + * then source code should be generated to construct the appropriate location. */ @Retention(RetentionPolicy.RUNTIME) @SubtypeOf({}) @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) public @interface VarAnnot { int value(); -} \ No newline at end of file +} diff --git a/src/checkers/inference/solver/DebugSolver.java b/src/checkers/inference/solver/DebugSolver.java index a5cd4d5f2..c38ac401e 100644 --- a/src/checkers/inference/solver/DebugSolver.java +++ b/src/checkers/inference/solver/DebugSolver.java @@ -1,5 +1,7 @@ package checkers.inference.solver; +import org.checkerframework.framework.type.QualifierHierarchy; + import java.io.File; import java.io.FileWriter; import java.io.IOException; @@ -9,8 +11,9 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; + import javax.annotation.processing.ProcessingEnvironment; -import org.checkerframework.framework.type.QualifierHierarchy; + import checkers.inference.InferenceResult; import checkers.inference.InferenceSolver; import checkers.inference.model.Constraint; @@ -22,11 +25,11 @@ * Debug solver prints out variables and constraints. * * @author mcarthur - * */ public class DebugSolver implements InferenceSolver { - private static final boolean showAstPaths = true; // System.getProperty("showAstPaths", "false").equalsIgnoreCase("true"); + private static final boolean showAstPaths = + true; // System.getProperty("showAstPaths", "false").equalsIgnoreCase("true"); public static final String constraintFile = "constraint-file"; @Override @@ -71,8 +74,7 @@ public InferenceResult solve( if (configuration.containsKey(constraintFile)) { String filename = configuration.get(constraintFile); try (FileWriter file = new FileWriter(new File(filename))) { - for (String out : output) - file.write(out); + for (String out : output) file.write(out); file.flush(); } catch (IOException e) { e.printStackTrace(); diff --git a/src/checkers/inference/solver/MaxSat2TypeSolver.java b/src/checkers/inference/solver/MaxSat2TypeSolver.java index d1558afa8..f678fb87c 100644 --- a/src/checkers/inference/solver/MaxSat2TypeSolver.java +++ b/src/checkers/inference/solver/MaxSat2TypeSolver.java @@ -1,9 +1,11 @@ package checkers.inference.solver; -import checkers.inference.DefaultInferenceResult; -import checkers.inference.InferenceResult; import org.checkerframework.framework.type.QualifierHierarchy; import org.checkerframework.javacutil.AnnotationUtils; +import org.sat4j.core.VecInt; +import org.sat4j.maxsat.WeightedMaxSatDecorator; +import org.sat4j.specs.ContradictionException; +import org.sat4j.specs.TimeoutException; import java.util.Collection; import java.util.HashMap; @@ -15,23 +17,20 @@ import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.AnnotationMirror; -import org.sat4j.core.VecInt; -import org.sat4j.maxsat.WeightedMaxSatDecorator; - +import checkers.inference.DefaultInferenceResult; import checkers.inference.InferenceMain; +import checkers.inference.InferenceResult; import checkers.inference.InferenceSolver; import checkers.inference.SlotManager; import checkers.inference.model.ConstantSlot; import checkers.inference.model.Constraint; import checkers.inference.model.Slot; import checkers.inference.model.serialization.CnfVecIntSerializer; -import org.sat4j.specs.ContradictionException; -import org.sat4j.specs.TimeoutException; /** - * This solver is used to convert any constraint set using a type system with only 2 types (Top/Bottom), - * into a SAT problem. This SAT problem is then solved by SAT4J and the output is converted back - * into an InferenceResult. + * This solver is used to convert any constraint set using a type system with only 2 types + * (Top/Bottom), into a SAT problem. This SAT problem is then solved by SAT4J and the output is + * converted back into an InferenceResult. */ public class MaxSat2TypeSolver implements InferenceSolver { @@ -60,12 +59,13 @@ public InferenceResult solve( this.top = qualHierarchy.getTopAnnotations().iterator().next(); this.bottom = qualHierarchy.getBottomAnnotations().iterator().next(); this.slotManager = InferenceMain.getInstance().getSlotManager(); - this.serializer = new CnfVecIntSerializer(slotManager) { - @Override - protected boolean isTop(ConstantSlot constantSlot) { - return AnnotationUtils.areSame(constantSlot.getValue(), top); - } - }; + this.serializer = + new CnfVecIntSerializer(slotManager) { + @Override + protected boolean isTop(ConstantSlot constantSlot) { + return AnnotationUtils.areSame(constantSlot.getValue(), top); + } + }; // TODO: This needs to be parameterized based on the type system // this.defaultValue = top; @@ -82,16 +82,20 @@ public InferenceResult solve() { // if an exception occurs while creating a variable the id might be incremented // but the slot might not actually be recorded. Therefore, nextId is NOT // the number of slots but the maximum you might encounter. - // TODO: this is a workaround as currently when serialize existential constraint we lost the real existential + // TODO: this is a workaround as currently when serialize existential constraint we lost the + // real existential // TODO: variable id and create "fake" id stored in existentialToPotentialVar map. - // TODO: thus here the value of totalVars is the real slots number stored in slotManager, and plus the + // TODO: thus here the value of totalVars is the real slots number stored in slotManager, + // and plus the // TODO: "fake" slots number stored in existentialToPotentialVar - final int totalVars = slotManager.getNumberOfSlots() + serializer.getExistentialToPotentialVar().size(); + final int totalVars = + slotManager.getNumberOfSlots() + serializer.getExistentialToPotentialVar().size(); final int totalClauses = hardClauses.size() + softClauses.size(); - - // When .newBoth is called, SAT4J will run two solvers and return the result of the first to halt - final WeightedMaxSatDecorator solver = new WeightedMaxSatDecorator(org.sat4j.pb.SolverFactory.newBoth()); + // When .newBoth is called, SAT4J will run two solvers and return the result of the first to + // halt + final WeightedMaxSatDecorator solver = + new WeightedMaxSatDecorator(org.sat4j.pb.SolverFactory.newBoth()); solver.newVar(totalVars); solver.setExpectedNumberOfClauses(totalClauses); @@ -112,12 +116,17 @@ public InferenceResult solve() { } } catch (ContradictionException ce) { - // This happens when adding a clause causes trivial contradiction, such as adding -1 to {1} - System.out.println("Not solvable! Contradiction exception " + - "when adding clause: " + lastClause + "."); + // This happens when adding a clause causes trivial contradiction, such as adding -1 to + // {1} + System.out.println( + "Not solvable! Contradiction exception " + + "when adding clause: " + + lastClause + + "."); // pass empty set as the unsat explanation - // TODO: explain UNSAT possibly by reusing MaxSatSolver.MaxSATUnsatisfiableConstraintExplainer + // TODO: explain UNSAT possibly by reusing + // MaxSatSolver.MaxSATUnsatisfiableConstraintExplainer return new DefaultInferenceResult(new HashSet<>()); } @@ -126,32 +135,38 @@ public InferenceResult solve() { // isSatisfiable() launches the solvers and waits until one of them finishes isSatisfiable = solver.isSatisfiable(); - } catch(TimeoutException te) { + } catch (TimeoutException te) { throw new RuntimeException("MAX-SAT solving timeout! "); } if (!isSatisfiable) { System.out.println("Not solvable!"); // pass empty set as the unsat explanation - // TODO: explain UNSAT possibly by reusing MaxSatSolver.MaxSATUnsatisfiableConstraintExplainer + // TODO: explain UNSAT possibly by reusing + // MaxSatSolver.MaxSATUnsatisfiableConstraintExplainer return new DefaultInferenceResult(new HashSet<>()); } int[] solution = solver.model(); // The following code decodes VecInt solution to the slot-annotation mappings final Map decodedSolution = new HashMap<>(); - final Map existentialToPotentialIds = serializer.getExistentialToPotentialVar(); + final Map existentialToPotentialIds = + serializer.getExistentialToPotentialVar(); for (Integer var : solution) { Integer potential = existentialToPotentialIds.get(Math.abs(var)); if (potential != null) { - // Assume the 'solution' output by the solver is already sorted in the ascending order - // of their absolute values. So the existential variables come after the potential variables, - // which means the potential slot corresponding to the current existential variable is + // Assume the 'solution' output by the solver is already sorted in the ascending + // order + // of their absolute values. So the existential variables come after the potential + // variables, + // which means the potential slot corresponding to the current existential variable + // is // already inserted into 'solutions' assert decodedSolution.containsKey(potential); if (var < 0) { - // The existential variable is false, so the potential variable should not be inserted. + // The existential variable is false, so the potential variable should not be + // inserted. // Remove it from the solution. decodedSolution.remove(potential); } diff --git a/src/checkers/inference/solver/PropagationSolver.java b/src/checkers/inference/solver/PropagationSolver.java index 8fe69f30a..abc6c4735 100644 --- a/src/checkers/inference/solver/PropagationSolver.java +++ b/src/checkers/inference/solver/PropagationSolver.java @@ -1,8 +1,5 @@ package checkers.inference.solver; -import checkers.inference.DefaultInferenceResult; -import checkers.inference.InferenceResult; -import checkers.inference.model.VariableSlot; import org.checkerframework.framework.type.QualifierHierarchy; import org.checkerframework.javacutil.AnnotationUtils; @@ -17,7 +14,9 @@ import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.AnnotationMirror; +import checkers.inference.DefaultInferenceResult; import checkers.inference.InferenceMain; +import checkers.inference.InferenceResult; import checkers.inference.InferenceSolver; import checkers.inference.model.ConstantSlot; import checkers.inference.model.Constraint; @@ -25,14 +24,14 @@ import checkers.inference.model.ExistentialConstraint; import checkers.inference.model.Slot; import checkers.inference.model.SubtypeConstraint; +import checkers.inference.model.VariableSlot; /** * InferenceSolver FloodSolver implementation * - * TODO: Parameters to configure where to push conflicts? + *

TODO: Parameters to configure where to push conflicts? * * @author mcarthur - * */ public class PropagationSolver implements InferenceSolver { @@ -67,25 +66,23 @@ public InferenceResult solve( /** * Flood solve a list of constraints. * - * 1) Find all variables that must be top (@TOP <: Var or VAR == @TOP) + *

1) Find all variables that must be top (@TOP <: Var or VAR == @TOP) * - * 2) Find all variables that must be bot (Var <: @BOT or VAR == @BOT) + *

2) Find all variables that must be bot (Var <: @BOT or VAR == @BOT) * - * 3) From constraints, create propagation maps. - * These maps one variable to a list of other variables. - * If the key variable is a certain annotation the variables in the value list must also be that annotation. - * A map is create for subtype propagation and supertype propagation. + *

3) From constraints, create propagation maps. These maps one variable to a list of other + * variables. If the key variable is a certain annotation the variables in the value list must + * also be that annotation. A map is create for subtype propagation and supertype propagation. * - * As an example, given a subtype propagation map of: - * @1 -> [ @2, @3 ] + *

As an example, given a subtype propagation map of: @1 -> [ @2, @3 ] * - * If @1 was inferred to be @BOT, then @2 and @3 would also have to be bot. + *

If @1 was inferred to be @BOT, then @2 and @3 would also have to be bot. * - * 4) Propagate the supertype values first + *

4) Propagate the supertype values first * - * 5) Propagate the subtype values second + *

5) Propagate the subtype values second * - * 6) Merge the results to get just one AnnotationMirror for each variable. + *

6) Merge the results to get just one AnnotationMirror for each variable. * * @return Map of int variable id to its inferred AnnotationMirror value */ @@ -109,24 +106,27 @@ public InferenceResult solve() { /** * Perform steps 1-3 of flood solving. * - * The parameters are the results of processing. + *

The parameters are the results of processing. * - * fixedBottom and fixedTop contain relationships between variables and constants - * (the constant for bottom and the constant for top respectively) + *

fixedBottom and fixedTop contain relationships between variables and constants (the + * constant for bottom and the constant for top respectively) * - * superTypePropagation and subTypePropagation + *

superTypePropagation and subTypePropagation * * @param fixedBottom Variables that must be bottom * @param fixedTop Variables that must be top - * @param superTypePropagation Map, where if a key is a supertyp, all variables in the value must also be supertype - * @param subTypePropagation Map, where if a key is a subtype, all variables in the value must also be subtypes + * @param superTypePropagation Map, where if a key is a supertyp, all variables in the value + * must also be supertype + * @param subTypePropagation Map, where if a key is a subtype, all variables in the value must + * also be subtypes */ - private void preprocessConstraints(Set fixedBottom, + private void preprocessConstraints( + Set fixedBottom, Set fixedTop, Map> superTypePropagation, Map> subTypePropagation) { - for (Constraint constraint: constraints) { + for (Constraint constraint : constraints) { // Skip constraints that are just constants if (!checkContainsVariable(constraint)) { continue; @@ -153,11 +153,28 @@ private void preprocessConstraints(Set fixedBottom, fixedBottom.add(variable); } } else { - // Variable equality means values of one propagates to values of the other, for both subtype and supertype - addEntryToMap(superTypePropagation, equality.getFirst(), equality.getSecond(), constraint); - addEntryToMap(superTypePropagation, equality.getSecond(), equality.getFirst(), constraint); - addEntryToMap(subTypePropagation, equality.getFirst(), equality.getSecond(), constraint); - addEntryToMap(subTypePropagation, equality.getSecond(), equality.getFirst(), constraint); + // Variable equality means values of one propagates to values of the other, for + // both subtype and supertype + addEntryToMap( + superTypePropagation, + equality.getFirst(), + equality.getSecond(), + constraint); + addEntryToMap( + superTypePropagation, + equality.getSecond(), + equality.getFirst(), + constraint); + addEntryToMap( + subTypePropagation, + equality.getFirst(), + equality.getSecond(), + constraint); + addEntryToMap( + subTypePropagation, + equality.getSecond(), + equality.getFirst(), + constraint); } } else if (constraint instanceof SubtypeConstraint) { SubtypeConstraint subtype = (SubtypeConstraint) constraint; @@ -177,12 +194,23 @@ private void preprocessConstraints(Set fixedBottom, } } else { // If the RHS is top, the LHS must be top - addEntryToMap(superTypePropagation, subtype.getSubtype(), subtype.getSupertype(), constraint); + addEntryToMap( + superTypePropagation, + subtype.getSubtype(), + subtype.getSupertype(), + constraint); // If the LHS is bottom, the RHS must be bottom - addEntryToMap(subTypePropagation, subtype.getSupertype(), subtype.getSubtype(), constraint); + addEntryToMap( + subTypePropagation, + subtype.getSupertype(), + subtype.getSubtype(), + constraint); } } else if (constraint instanceof ExistentialConstraint) { - InferenceMain.getInstance().logger.warning("PropagationSolver: Existential constraint found. Inferred annotations may not type check "); + InferenceMain.getInstance() + .logger + .warning( + "PropagationSolver: Existential constraint found. Inferred annotations may not type check "); } } } @@ -190,15 +218,18 @@ private void preprocessConstraints(Set fixedBottom, /** * Given the inferred values, return a value for each slot. * - * Variables will have conflicting values if the constraints were not solvable. + *

Variables will have conflicting values if the constraints were not solvable. * - * This currently gives value precedence to fixedBottom, fixedTop, inferredBottom, inferredTop + *

This currently gives value precedence to fixedBottom, fixedTop, inferredBottom, + * inferredTop * * @return */ private InferenceResult mergeToResult( - Set fixedBottom, Set fixedTop, - Set inferredTop, Set inferredBottom) { + Set fixedBottom, + Set fixedTop, + Set inferredTop, + Set inferredBottom) { Map solutions = new HashMap(); for (Slot slot : slots) { @@ -225,16 +256,15 @@ private InferenceResult mergeToResult( } /** - * Given starting fixed values, iterate on the propagation map - * to propagate the resulting values. + * Given starting fixed values, iterate on the propagation map to propagate the resulting + * values. * * @param fixed The starting values that will trigger propagation - * @param typePropagation Maps of value to list of other values that will be propagated when the key is triggered. - * + * @param typePropagation Maps of value to list of other values that will be propagated when the + * key is triggered. * @return All values that were fixed flooded/propagated to. */ - private Set propagateValues(Set fixed, - Map> typePropagation) { + private Set propagateValues(Set fixed, Map> typePropagation) { Set results = new HashSet(); diff --git a/src/checkers/inference/solver/SolverEngine.java b/src/checkers/inference/solver/SolverEngine.java index e3e46e13d..10f39d6a6 100644 --- a/src/checkers/inference/solver/SolverEngine.java +++ b/src/checkers/inference/solver/SolverEngine.java @@ -1,13 +1,13 @@ package checkers.inference.solver; +import org.checkerframework.framework.type.QualifierHierarchy; +import org.checkerframework.javacutil.BugInCF; + import java.util.Collection; import java.util.Map; import javax.annotation.processing.ProcessingEnvironment; -import org.checkerframework.framework.type.QualifierHierarchy; -import org.checkerframework.javacutil.BugInCF; - import checkers.inference.InferenceResult; import checkers.inference.InferenceSolver; import checkers.inference.model.Constraint; @@ -25,18 +25,14 @@ import checkers.inference.solver.util.Statistics; /** - * SolverEngine is the entry point of general solver framework, and it is also - * the front end of whole solver system. SolverEngine configures command line - * arguments, creates corresponding solving strategy and solver factory, invokes - * strategy and returns the solution. + * SolverEngine is the entry point of general solver framework, and it is also the front end of + * whole solver system. SolverEngine configures command line arguments, creates corresponding + * solving strategy and solver factory, invokes strategy and returns the solution. * * @see SolverFactory * @see SolvingStrategy - * * @author jianchu - * */ - public class SolverEngine implements InferenceSolver { protected boolean collectStatistics; protected boolean writeSolutions; @@ -45,29 +41,19 @@ public class SolverEngine implements InferenceSolver { protected String solverName; public enum SolverEngineArg implements SolverArg { - /** - * solving strategy to use - */ + /** solving strategy to use */ solvingStrategy, - /** - * solver to use - */ + /** solver to use */ solver, - /** - * whether to collect and then print & write statistics - */ + /** whether to collect and then print & write statistics */ collectStatistics, - /** - * whether to write solutions (or unsolvable) to file output or not - */ + /** whether to write solutions (or unsolvable) to file output or not */ writeSolutions, - /** - * whether to write statistics & solutions in append mode or not - */ + /** whether to write statistics & solutions in append mode or not */ noAppend; } @@ -79,10 +65,12 @@ protected SolverFactory createSolverFactory() { final String solverFactoryClassName = solverName + "SolverFactory"; try { - Class SolverFactoryClass = Class.forName(solverPackageName + "." + solverFactoryClassName); + Class SolverFactoryClass = + Class.forName(solverPackageName + "." + solverFactoryClassName); return (SolverFactory) SolverFactoryClass.getConstructor().newInstance(); } catch (Exception e) { - throw new BugInCF("Exceptions happen when creating the solver factory for " + solverName, e); + throw new BugInCF( + "Exceptions happen when creating the solver factory for " + solverName, e); } } @@ -95,26 +83,40 @@ protected SolvingStrategy createSolvingStrategy(SolverFactory solverFactory) { final String strategyClassName = strategyName + "SolvingStrategy"; try { - Class solverStrategyClass = Class.forName(STRATEGY_PACKAGE_NAME + "." + strategyClassName); - return (SolvingStrategy) solverStrategyClass.getConstructor(SolverFactory.class).newInstance(solverFactory); + Class solverStrategyClass = + Class.forName(STRATEGY_PACKAGE_NAME + "." + strategyClassName); + return (SolvingStrategy) + solverStrategyClass + .getConstructor(SolverFactory.class) + .newInstance(solverFactory); } catch (Exception e) { - throw new BugInCF(e.getClass().getSimpleName() + " happens when creating [" + strategyName + "] solving strategy!", e); + throw new BugInCF( + e.getClass().getSimpleName() + + " happens when creating [" + + strategyName + + "] solving strategy!", + e); } } @Override - public final InferenceResult solve(Map configuration, Collection slots, - Collection constraints, QualifierHierarchy qualHierarchy, - ProcessingEnvironment processingEnvironment) { + public final InferenceResult solve( + Map configuration, + Collection slots, + Collection constraints, + QualifierHierarchy qualHierarchy, + ProcessingEnvironment processingEnvironment) { - SolverEnvironment solverEnvironment = new SolverEnvironment(configuration, processingEnvironment); + SolverEnvironment solverEnvironment = + new SolverEnvironment(configuration, processingEnvironment); configureSolverEngineArgs(solverEnvironment); - //TODO: Add solve timing statistic. + // TODO: Add solve timing statistic. Lattice lattice = new LatticeBuilder().buildLattice(qualHierarchy, slots); SolvingStrategy solvingStrategy = createSolvingStrategy(); - InferenceResult inferenceResult = solvingStrategy.solve(solverEnvironment, slots, constraints, lattice); + InferenceResult inferenceResult = + solvingStrategy.solve(solverEnvironment, slots, constraints, lattice); if (inferenceResult == null) { throw new BugInCF("InferenceResult should never be null, but null result detected!"); @@ -128,7 +130,8 @@ public final InferenceResult solve(Map configuration, Collection } else { PrintUtils.printUnsatConstraints(inferenceResult.getUnsatisfiableConstraints()); if (writeSolutions) { - PrintUtils.writeUnsatConstraints(inferenceResult.getUnsatisfiableConstraints(), noAppend); + PrintUtils.writeUnsatConstraints( + inferenceResult.getUnsatisfiableConstraints(), noAppend); } } @@ -150,14 +153,14 @@ public final InferenceResult solve(Map configuration, Collection */ private void configureSolverEngineArgs(SolverEnvironment solverEnvironment) { String strategyName = solverEnvironment.getArg(SolverEngineArg.solvingStrategy); - this.strategyName = strategyName == null ? - NameUtils.getStrategyName(PlainSolvingStrategy.class) - : strategyName; + this.strategyName = + strategyName == null + ? NameUtils.getStrategyName(PlainSolvingStrategy.class) + : strategyName; String solverName = solverEnvironment.getArg(SolverEngineArg.solver); - this.solverName = solverName == null ? - NameUtils.getSolverName(MaxSatSolver.class) - : solverName; + this.solverName = + solverName == null ? NameUtils.getSolverName(MaxSatSolver.class) : solverName; this.collectStatistics = solverEnvironment.getBoolArg(SolverEngineArg.collectStatistics); this.writeSolutions = solverEnvironment.getBoolArg(SolverEngineArg.writeSolutions); @@ -168,12 +171,11 @@ private void configureSolverEngineArgs(SolverEnvironment solverEnvironment) { } /** - * Sanitize and apply check of the configuration of solver based on a - * specific type system. Sub-class solver of a specific type system may - * override this method to sanitize the configuration of solver in the - * context of that type system. + * Sanitize and apply check of the configuration of solver based on a specific type system. + * Sub-class solver of a specific type system may override this method to sanitize the + * configuration of solver in the context of that type system. */ protected void sanitizeSolverEngineArgs() { - //Intentionally empty. + // Intentionally empty. } } diff --git a/src/checkers/inference/solver/backend/AbstractFormatTranslator.java b/src/checkers/inference/solver/backend/AbstractFormatTranslator.java index 483bc55e4..4fbd56e1e 100644 --- a/src/checkers/inference/solver/backend/AbstractFormatTranslator.java +++ b/src/checkers/inference/solver/backend/AbstractFormatTranslator.java @@ -16,8 +16,8 @@ import checkers.inference.model.LubVariableSlot; import checkers.inference.model.PreferenceConstraint; import checkers.inference.model.RefinementVariableSlot; -import checkers.inference.model.SubtypeConstraint; import checkers.inference.model.SourceVariableSlot; +import checkers.inference.model.SubtypeConstraint; import checkers.inference.solver.backend.encoder.ArithmeticConstraintEncoder; import checkers.inference.solver.backend.encoder.ComparisonConstraintEncoder; import checkers.inference.solver.backend.encoder.ConstraintEncoderCoordinator; @@ -35,39 +35,41 @@ /** * Abstract base class for all concrete {@link FormatTranslator}. * - * Class {@code AbstractFormatTranslator} provides default implementation for both serializing - * {@link checkers.inference.model.Slot slot} and {@link checkers.inference.model.Constraint constraint}: - *

- * {@link checkers.inference.model.Slot Slot} serialization methods does nothing but returns null. - * Subclasses of {@code AbstractFormatTranslator} should override corresponding {@code Slot} + *

Class {@code AbstractFormatTranslator} provides default implementation for both serializing + * {@link checkers.inference.model.Slot slot} and {@link checkers.inference.model.Constraint + * constraint}: + * + *

{@link checkers.inference.model.Slot Slot} serialization methods does nothing but returns + * null. Subclasses of {@code AbstractFormatTranslator} should override corresponding {@code Slot} * serialization methods if subclasses have concrete serialization logic. - *

- * {@link checkers.inference.model.Constraint Constraint} serialization methods first check + * + *

{@link checkers.inference.model.Constraint Constraint} serialization methods first check * whether corresponding encoder is null. If yes, returns null as the encoding. Otherwise, delegates * encoding job to that encoder. - *

- * Subclasses of {@code AbstractFormatTranslator} need to override method - * {@link #createConstraintEncoderFactory()} to create the concrete {@code - * ConstraintEncoderFactory}. Then at the last step of initializing subclasses of {@code AbstractFormatTranslator}, - * {@link #finishInitializingEncoders()} must be called in order to finish initializing encoders. - * The reason is: concrete {@link ConstraintEncoderFactory} may depend on some fields in subclasses - * of {@link AbstractFormatTranslator}. - *

- * For example, {@link checkers.inference.solver.backend.maxsat.encoder.MaxSATConstraintEncoderFactory} - * depends on {@link checkers.inference.solver.backend.maxsat.MaxSatFormatTranslator#typeToInt typeToInt} - * filed in {@link checkers.inference.solver.backend.maxsat.MaxSatFormatTranslator}. So only after those + * + *

Subclasses of {@code AbstractFormatTranslator} need to override method {@link + * #createConstraintEncoderFactory()} to create the concrete {@code ConstraintEncoderFactory}. Then + * at the last step of initializing subclasses of {@code AbstractFormatTranslator}, {@link + * #finishInitializingEncoders()} must be called in order to finish initializing encoders. The + * reason is: concrete {@link ConstraintEncoderFactory} may depend on some fields in subclasses of + * {@link AbstractFormatTranslator}. + * + *

For example, {@link + * checkers.inference.solver.backend.maxsat.encoder.MaxSATConstraintEncoderFactory} depends on + * {@link checkers.inference.solver.backend.maxsat.MaxSatFormatTranslator#typeToInt typeToInt} filed + * in {@link checkers.inference.solver.backend.maxsat.MaxSatFormatTranslator}. So only after those * dependent fields are initialized in subclasses constructors, encoders can be then initialized. - * Calling {@link #finishInitializingEncoders()} at the last step of initialization makes sure all the - * dependent fields are already initialized. - *

- * In terms of "last step of initialization", different {@code FormatTranslator}s have different definitions. - * For {@link checkers.inference.solver.backend.maxsat.MaxSatFormatTranslator} and + * Calling {@link #finishInitializingEncoders()} at the last step of initialization makes sure all + * the dependent fields are already initialized. + * + *

In terms of "last step of initialization", different {@code FormatTranslator}s have different + * definitions. For {@link checkers.inference.solver.backend.maxsat.MaxSatFormatTranslator} and * {@link checkers.inference.solver.backend.logiql.LogiQLFormatTranslator}, it's at the end of the - * subclass constructor; While for {@link checkers.inference.solver.backend.z3.Z3BitVectorFormatTranslator}, - * it's at the end of - * {@link checkers.inference.solver.backend.z3.Z3BitVectorFormatTranslator#initSolver(com.microsoft.z3.Optimize)}. - * The general guideline is that {@link #finishInitializingEncoders() finishInitializingEncoders()} call - * should always precede actual solving process. + * subclass constructor; While for {@link + * checkers.inference.solver.backend.z3.Z3BitVectorFormatTranslator}, it's at the end of {@link + * checkers.inference.solver.backend.z3.Z3BitVectorFormatTranslator#initSolver(com.microsoft.z3.Optimize)}. + * The general guideline is that {@link #finishInitializingEncoders() finishInitializingEncoders()} + * call should always precede actual solving process. * * @see ConstraintEncoderFactory * @see #finishInitializingEncoders() @@ -76,11 +78,9 @@ * @see checkers.inference.solver.backend.z3.Z3BitVectorFormatTranslator */ public abstract class AbstractFormatTranslator - implements FormatTranslator{ + implements FormatTranslator { - /** - * {@link Lattice} that is used by subclasses during format translation. - */ + /** {@link Lattice} that is used by subclasses during format translation. */ protected final Lattice lattice; /** @@ -89,27 +89,32 @@ public abstract class AbstractFormatTranslator subtypeConstraintEncoder; /** - * {@code EqualityConstraintEncoder} to which encoding of {@link EqualityConstraint} is delegated. + * {@code EqualityConstraintEncoder} to which encoding of {@link EqualityConstraint} is + * delegated. */ protected EqualityConstraintEncoder equalityConstraintEncoder; /** - * {@code InequalityConstraintEncoder} to which encoding of {@link InequalityConstraint} is delegated. + * {@code InequalityConstraintEncoder} to which encoding of {@link InequalityConstraint} is + * delegated. */ protected InequalityConstraintEncoder inequalityConstraintEncoder; /** - * {@code ComparableConstraintEncoder} to which encoding of {@link ComparableConstraint} is delegated. + * {@code ComparableConstraintEncoder} to which encoding of {@link ComparableConstraint} is + * delegated. */ protected ComparableConstraintEncoder comparableConstraintEncoder; /** - * {@code ComparisonConstraintEncoder} to which encoding of {@link ComparableConstraint} is delegated. + * {@code ComparisonConstraintEncoder} to which encoding of {@link ComparableConstraint} is + * delegated. */ protected ComparisonConstraintEncoder comparisonConstraintEncoder; /** - * {@code PreferenceConstraintEncoder} to which encoding of {@link PreferenceConstraint} is delegated. + * {@code PreferenceConstraintEncoder} to which encoding of {@link PreferenceConstraint} is + * delegated. */ protected PreferenceConstraintEncoder preferenceConstraintEncoder; @@ -119,14 +124,16 @@ public abstract class AbstractFormatTranslator combineConstraintEncoder; /** - * {@code ExistentialConstraintEncoder} to which encoding of {@link ExistentialConstraint} is delegated. + * {@code ExistentialConstraintEncoder} to which encoding of {@link ExistentialConstraint} is + * delegated. */ protected ExistentialConstraintEncoder existentialConstraintEncoder; protected ImplicationConstraintEncoder implicationConstraintEncoder; /** - * {@code ArithmeticConstraintEncoder} to which encoding of {@link ArithmeticConstraint} is delegated. + * {@code ArithmeticConstraintEncoder} to which encoding of {@link ArithmeticConstraint} is + * delegated. */ protected ArithmeticConstraintEncoder arithmeticConstraintEncoder; @@ -135,14 +142,15 @@ public AbstractFormatTranslator(Lattice lattice) { } /** - * Finishes initializing encoders for subclasses of {@code AbstractFormatTranslator}. Subclasses of - * {@code AbstractFormatTranslator} MUST call this method to finish initializing encoders at the end - * of initialization phase. See Javadoc on {@link AbstractFormatTranslator} to see what the last - * step of initialization phase means and why the encoder creation steps are separate out from constructor - * {@link AbstractFormatTranslator#AbstractFormatTranslator(Lattice)} + * Finishes initializing encoders for subclasses of {@code AbstractFormatTranslator}. Subclasses + * of {@code AbstractFormatTranslator} MUST call this method to finish initializing encoders at + * the end of initialization phase. See Javadoc on {@link AbstractFormatTranslator} to see what + * the last step of initialization phase means and why the encoder creation steps are separate + * out from constructor {@link AbstractFormatTranslator#AbstractFormatTranslator(Lattice)} */ protected void finishInitializingEncoders() { - final ConstraintEncoderFactory encoderFactory = createConstraintEncoderFactory(); + final ConstraintEncoderFactory encoderFactory = + createConstraintEncoderFactory(); subtypeConstraintEncoder = encoderFactory.createSubtypeConstraintEncoder(); equalityConstraintEncoder = encoderFactory.createEqualityConstraintEncoder(); inequalityConstraintEncoder = encoderFactory.createInequalityConstraintEncoder(); @@ -156,71 +164,84 @@ protected void finishInitializingEncoders() { } /** - * Creates concrete implementation of {@link ConstraintEncoderFactory}. Subclasses should implement this method - * to provide their concrete {@code ConstraintEncoderFactory}. + * Creates concrete implementation of {@link ConstraintEncoderFactory}. Subclasses should + * implement this method to provide their concrete {@code ConstraintEncoderFactory}. * - * @return Concrete implementation of {@link ConstraintEncoderFactory} for a particular solver backend + * @return Concrete implementation of {@link ConstraintEncoderFactory} for a particular solver + * backend */ - protected abstract ConstraintEncoderFactory createConstraintEncoderFactory(); + protected abstract ConstraintEncoderFactory + createConstraintEncoderFactory(); @Override public ConstraintEncodingT serialize(SubtypeConstraint constraint) { - return subtypeConstraintEncoder == null ? null : - ConstraintEncoderCoordinator.dispatch(constraint, subtypeConstraintEncoder); + return subtypeConstraintEncoder == null + ? null + : ConstraintEncoderCoordinator.dispatch(constraint, subtypeConstraintEncoder); } @Override public ConstraintEncodingT serialize(EqualityConstraint constraint) { - return equalityConstraintEncoder == null ? null : - ConstraintEncoderCoordinator.dispatch(constraint, equalityConstraintEncoder); + return equalityConstraintEncoder == null + ? null + : ConstraintEncoderCoordinator.dispatch(constraint, equalityConstraintEncoder); } @Override public ConstraintEncodingT serialize(InequalityConstraint constraint) { - return inequalityConstraintEncoder == null ? null : - ConstraintEncoderCoordinator.dispatch(constraint, inequalityConstraintEncoder); + return inequalityConstraintEncoder == null + ? null + : ConstraintEncoderCoordinator.dispatch(constraint, inequalityConstraintEncoder); } @Override public ConstraintEncodingT serialize(ComparableConstraint constraint) { - return comparableConstraintEncoder == null ? null : - ConstraintEncoderCoordinator.dispatch(constraint, comparableConstraintEncoder); + return comparableConstraintEncoder == null + ? null + : ConstraintEncoderCoordinator.dispatch(constraint, comparableConstraintEncoder); } @Override public ConstraintEncodingT serialize(ComparisonConstraint constraint) { - return comparisonConstraintEncoder == null ? null : - ConstraintEncoderCoordinator.dispatch(constraint, comparisonConstraintEncoder); + return comparisonConstraintEncoder == null + ? null + : ConstraintEncoderCoordinator.dispatch(constraint, comparisonConstraintEncoder); } @Override public ConstraintEncodingT serialize(PreferenceConstraint constraint) { - return constraint == null ? null : - ConstraintEncoderCoordinator.redirect(constraint, preferenceConstraintEncoder); + return constraint == null + ? null + : ConstraintEncoderCoordinator.redirect(constraint, preferenceConstraintEncoder); } @Override public ConstraintEncodingT serialize(CombineConstraint combineConstraint) { - return combineConstraintEncoder == null ? null : - ConstraintEncoderCoordinator.dispatch(combineConstraint, combineConstraintEncoder); + return combineConstraintEncoder == null + ? null + : ConstraintEncoderCoordinator.dispatch( + combineConstraint, combineConstraintEncoder); } @Override public ConstraintEncodingT serialize(ExistentialConstraint constraint) { - return existentialConstraintEncoder == null ? null : - ConstraintEncoderCoordinator.redirect(constraint, existentialConstraintEncoder); + return existentialConstraintEncoder == null + ? null + : ConstraintEncoderCoordinator.redirect(constraint, existentialConstraintEncoder); } @Override public ConstraintEncodingT serialize(ImplicationConstraint constraint) { - return implicationConstraintEncoder == null ? null : - ConstraintEncoderCoordinator.redirect(constraint, implicationConstraintEncoder); + return implicationConstraintEncoder == null + ? null + : ConstraintEncoderCoordinator.redirect(constraint, implicationConstraintEncoder); } - + @Override public ConstraintEncodingT serialize(ArithmeticConstraint constraint) { - return arithmeticConstraintEncoder == null ? null : - ConstraintEncoderCoordinator.dispatch(constraint, arithmeticConstraintEncoder); + return arithmeticConstraintEncoder == null + ? null + : ConstraintEncoderCoordinator.dispatch(constraint, arithmeticConstraintEncoder); } @Override diff --git a/src/checkers/inference/solver/backend/AbstractSolverFactory.java b/src/checkers/inference/solver/backend/AbstractSolverFactory.java index ba8edc5ec..086e43ad9 100644 --- a/src/checkers/inference/solver/backend/AbstractSolverFactory.java +++ b/src/checkers/inference/solver/backend/AbstractSolverFactory.java @@ -5,11 +5,13 @@ /** * Abstract base class for all concrete {@link SolverFactory}. * - * This class define an abstract method {@link #createFormatTranslator(Lattice)}, - * in order to let subclass be able to provide customized format translators. + *

This class define an abstract method {@link #createFormatTranslator(Lattice)}, in order to let + * subclass be able to provide customized format translators. + * * @param */ -public abstract class AbstractSolverFactory> implements SolverFactory { +public abstract class AbstractSolverFactory> + implements SolverFactory { /** * Create a format translator coordinate with the created solver by this factory. @@ -17,5 +19,5 @@ public abstract class AbstractSolverFactory> * @param lattice the target lattice * @return a format translator, responsible for decoding/encoding for the created solver. */ - abstract protected T createFormatTranslator(Lattice lattice); + protected abstract T createFormatTranslator(Lattice lattice); } diff --git a/src/checkers/inference/solver/backend/FormatTranslator.java b/src/checkers/inference/solver/backend/FormatTranslator.java index fea49700a..ff420103a 100644 --- a/src/checkers/inference/solver/backend/FormatTranslator.java +++ b/src/checkers/inference/solver/backend/FormatTranslator.java @@ -8,23 +8,25 @@ /** * Translator is responsible for encoding/decoding work for Backend. * - * It encode Slot and Constraint to specific types needed by underlying solver, - * and decode solver solution to AnnotationMirror. + *

It encode Slot and Constraint to specific types needed by underlying solver, and decode solver + * solution to AnnotationMirror. * * @author charleszhuochen - * * @param encoding type for slot. * @param encoding type for constraint. * @param type for underlying solver's solution of a Slot */ -public interface FormatTranslator extends Serializer { +public interface FormatTranslator + extends Serializer { /** * Decode solver's solution of a Slot to an AnnotationMirror represent this solution. * * @param solution solver's solution of a Slot - * @param processingEnvironment the process environment for creating the AnnotationMirror, if needed + * @param processingEnvironment the process environment for creating the AnnotationMirror, if + * needed * @return AnnotationMirror represent this solution */ - AnnotationMirror decodeSolution(SlotSolutionT solution, ProcessingEnvironment processingEnvironment); + AnnotationMirror decodeSolution( + SlotSolutionT solution, ProcessingEnvironment processingEnvironment); } diff --git a/src/checkers/inference/solver/backend/Solver.java b/src/checkers/inference/solver/backend/Solver.java index 2f24bcc9f..8374bfcd5 100644 --- a/src/checkers/inference/solver/backend/Solver.java +++ b/src/checkers/inference/solver/backend/Solver.java @@ -14,43 +14,33 @@ import checkers.inference.solver.util.SolverEnvironment; /** - * Solver adapts a concrete underlying solver, e.g. Sat4j, LogiQL, Z3, etc. - * This class is the super class for all concrete Solver sub-classes. - * For each concrete Solver, it adapts the type constraint solving process to - * the underlying solver implementation. + * Solver adapts a concrete underlying solver, e.g. Sat4j, LogiQL, Z3, etc. This class is the super + * class for all concrete Solver sub-classes. For each concrete Solver, it adapts the type + * constraint solving process to the underlying solver implementation. * - * A Solver takes type constraints from {@link checkers.inference.solver.SolverEngine}}, - * then delegates solving constraints responsibility to the underlying solver, and transform - * underlying solver solution as a map between an integer and an annotation mirror as - * the inferred result. + *

A Solver takes type constraints from {@link checkers.inference.solver.SolverEngine}}, then + * delegates solving constraints responsibility to the underlying solver, and transform underlying + * solver solution as a map between an integer and an annotation mirror as the inferred result. * - * Method {@link #solve()} is responsible for coordinating - * above steps. + *

Method {@link #solve()} is responsible for coordinating above steps. * - * {@link #solve()} method is the entry point of the solver adapter, and it is got - * called in class {@link checkers.inference.solver.SolverEngine}}. See - * {@link checkers.inference.solver.SolverEngine#solveInparall()} and - * {@link checkers.inference.solver.SolverEngine#solveInSequential()}. + *

{@link #solve()} method is the entry point of the solver adapter, and it is got called in + * class {@link checkers.inference.solver.SolverEngine}}. See {@link + * checkers.inference.solver.SolverEngine#solveInparall()} and {@link + * checkers.inference.solver.SolverEngine#solveInSequential()}. * * @author jianchu - * * @param type of FormatTranslator required by this Solver */ public abstract class Solver> { - /** - * SolverOptions, an argument manager for getting options from user. - */ + /** SolverOptions, an argument manager for getting options from user. */ protected final SolverEnvironment solverEnvironment; - /** - * Collection of all slots will be used by underlying solver - */ + /** Collection of all slots will be used by underlying solver */ protected final Collection slots; - /** - * Collection of all constraints will be solved by underlying solver - */ + /** Collection of all constraints will be solved by underlying solver */ protected final Collection constraints; /** @@ -59,18 +49,18 @@ public abstract class Solver> { */ protected final T formatTranslator; - /** - * Set of ids of all variable solts will be used by underlying solver - */ + /** Set of ids of all variable solts will be used by underlying solver */ protected final Set varSlotIds; - /** - * Target qualifier lattice - */ + /** Target qualifier lattice */ protected final Lattice lattice; - public Solver(SolverEnvironment solverEnvironment, Collection slots, - Collection constraints, T formatTranslator, Lattice lattice) { + public Solver( + SolverEnvironment solverEnvironment, + Collection slots, + Collection constraints, + T formatTranslator, + Lattice lattice) { this.solverEnvironment = solverEnvironment; this.slots = slots; this.constraints = constraints; @@ -81,28 +71,27 @@ public Solver(SolverEnvironment solverEnvironment, Collection slots, /** * A concrete solver adapter needs to override this method and implements its own - * constraint-solving strategy. In general, there will be three steps in this method: - * 1. Calls {@link #encodeAllConstraints()}, let {@link FormatTranslator} to convert constraints into - * the corresponding encoding form. Optionally, encode well-formedness restriction if the backend has it. - * 2. Calls the underlying solver to solve the encoding. - * 3. For UNSAT case, returns null. Otherwise let {@link FormatTranslator} decodes the solution from - * the underlying solver and create a map between an Integer(Slot Id) and an AnnotationMirror as it's - * inferred annotation. + * constraint-solving strategy. In general, there will be three steps in this method: 1. Calls + * {@link #encodeAllConstraints()}, let {@link FormatTranslator} to convert constraints into the + * corresponding encoding form. Optionally, encode well-formedness restriction if the backend + * has it. 2. Calls the underlying solver to solve the encoding. 3. For UNSAT case, returns + * null. Otherwise let {@link FormatTranslator} decodes the solution from the underlying solver + * and create a map between an Integer(Slot Id) and an AnnotationMirror as it's inferred + * annotation. * - * It is the concrete solver adapter's responsibility to implemented the logic of above instructions and - * statistic collection. - * See {@link checkers.inference.solver.backend.maxsat.MaxSatSolver#solve()}} for an example. + *

It is the concrete solver adapter's responsibility to implemented the logic of above + * instructions and statistic collection. See {@link + * checkers.inference.solver.backend.maxsat.MaxSatSolver#solve()}} for an example. */ public abstract Map solve(); - /** - * Returns a set of constraints that are not solvable together. - */ + /** Returns a set of constraints that are not solvable together. */ public abstract Collection explainUnsatisfiable(); /** - * Calls formatTranslator to convert constraints into the corresponding encoding - * form. See {@link checkers.inference.solver.backend.maxsat.MaxSatSolver#encodeAllConstraints()}} for an example. + * Calls formatTranslator to convert constraints into the corresponding encoding form. See + * {@link checkers.inference.solver.backend.maxsat.MaxSatSolver#encodeAllConstraints()}} for an + * example. */ protected abstract void encodeAllConstraints(); diff --git a/src/checkers/inference/solver/backend/SolverFactory.java b/src/checkers/inference/solver/backend/SolverFactory.java index d3a715649..441eb7724 100644 --- a/src/checkers/inference/solver/backend/SolverFactory.java +++ b/src/checkers/inference/solver/backend/SolverFactory.java @@ -11,24 +11,25 @@ /** * Factory class for creating an underlying {@link Solver}. * - * Note: subclass of this interface should have a zero parameter - * constructor, and should follow the naming convention to let {@code SolverEngine} - * reflectively load the subclass instance. + *

Note: subclass of this interface should have a zero parameter constructor, and should follow + * the naming convention to let {@code SolverEngine} reflectively load the subclass instance. * - * Naming convention of solver factory for underlying solvers: + *

Naming convention of solver factory for underlying solvers: * - * Package name should be: checkers.inference.solver.backend.[(all lower cases)underlying solver name] - * Under this package, create a subclass named: [underlying solver name]SolverFactory. + *

Package name should be: checkers.inference.solver.backend.[(all lower cases)underlying solver + * name] Under this package, create a subclass named: [underlying solver name]SolverFactory. * - * E.g. For MaxSat solver: + *

E.g. For MaxSat solver: * - * Package name: checkers.inference.solver.backend.maxsat - * Class name: MaxSatSolverFactory + *

Package name: checkers.inference.solver.backend.maxsat Class name: MaxSatSolverFactory * * @see SolverEngine#createSolverFactory() */ public interface SolverFactory { - Solver createSolver(SolverEnvironment solverOptions, - Collection slots, Collection constraints, Lattice lattice); + Solver createSolver( + SolverEnvironment solverOptions, + Collection slots, + Collection constraints, + Lattice lattice); } diff --git a/src/checkers/inference/solver/backend/encoder/AbstractConstraintEncoder.java b/src/checkers/inference/solver/backend/encoder/AbstractConstraintEncoder.java index 88b21d73e..890c98016 100644 --- a/src/checkers/inference/solver/backend/encoder/AbstractConstraintEncoder.java +++ b/src/checkers/inference/solver/backend/encoder/AbstractConstraintEncoder.java @@ -5,21 +5,25 @@ /** * Abstract base class for all concrete constraint encoders. * - * {@link checkers.inference.model.Constraint} and constraint encoder are one-to-one relation. + *

{@link checkers.inference.model.Constraint} and constraint encoder are one-to-one relation. * Each concrete constraint encoder only supports encoding one type of {@code Constraint}. */ public abstract class AbstractConstraintEncoder { - /**{@link Lattice} that is used to encode constraints.*/ + /** {@link Lattice} that is used to encode constraints. */ protected final Lattice lattice; - /** Empty value that doesn't add additional restrictions to solver solution. Always satisfiable. */ + /** + * Empty value that doesn't add additional restrictions to solver solution. Always satisfiable. + */ protected final ConstraintEncodingT emptyValue; - /** A contradictory or always-false value that triggers solver to give no solution.*/ + /** A contradictory or always-false value that triggers solver to give no solution. */ protected final ConstraintEncodingT contradictoryValue; - public AbstractConstraintEncoder(Lattice lattice, ConstraintEncodingT emptyValue, + public AbstractConstraintEncoder( + Lattice lattice, + ConstraintEncodingT emptyValue, ConstraintEncodingT contradictoryValue) { this.lattice = lattice; this.emptyValue = emptyValue; diff --git a/src/checkers/inference/solver/backend/encoder/AbstractConstraintEncoderFactory.java b/src/checkers/inference/solver/backend/encoder/AbstractConstraintEncoderFactory.java index d4a148768..4c4d59f28 100644 --- a/src/checkers/inference/solver/backend/encoder/AbstractConstraintEncoderFactory.java +++ b/src/checkers/inference/solver/backend/encoder/AbstractConstraintEncoderFactory.java @@ -4,25 +4,28 @@ import checkers.inference.solver.frontend.Lattice; /** - * Abstract base class for all concrete {@link ConstraintEncoderFactory}. Subclasses of {@code AbstractConstraintEncoderFactory} - * should override corresponding createXXXEncoder methods to return concrete implementations if the - * solver backend that the subclasses belong to support encoding such constraints. + * Abstract base class for all concrete {@link ConstraintEncoderFactory}. Subclasses of {@code + * AbstractConstraintEncoderFactory} should override corresponding createXXXEncoder methods to + * return concrete implementations if the solver backend that the subclasses belong to support + * encoding such constraints. * * @see ConstraintEncoderFactory */ -public abstract class AbstractConstraintEncoderFactory> - implements ConstraintEncoderFactory{ +public abstract class AbstractConstraintEncoderFactory< + ConstraintEncodingT, + FormatTranslatorT extends FormatTranslator> + implements ConstraintEncoderFactory { - /** - * {@link Lattice} instance that every constraint encoder needs - */ + /** {@link Lattice} instance that every constraint encoder needs */ protected final Lattice lattice; /** - * {@link FormatTranslator} instance that concrete subclass of {@link AbstractConstraintEncoder} might need. - * For example, {@link checkers.inference.solver.backend.z3.encoder.Z3BitVectorSubtypeConstraintEncoder} needs - * it to format translate {@SubtypeConstraint}. {@link checkers.inference.solver.backend.maxsat.encoder.MaxSATImplicationConstraintEncoder} - * needs it to delegate format translation task of non-{@code ImplicationConstraint}s. + * {@link FormatTranslator} instance that concrete subclass of {@link AbstractConstraintEncoder} + * might need. For example, {@link + * checkers.inference.solver.backend.z3.encoder.Z3BitVectorSubtypeConstraintEncoder} needs it to + * format translate {@SubtypeConstraint}. {@link + * checkers.inference.solver.backend.maxsat.encoder.MaxSATImplicationConstraintEncoder} needs it + * to delegate format translation task of non-{@code ImplicationConstraint}s. */ protected final FormatTranslatorT formatTranslator; diff --git a/src/checkers/inference/solver/backend/encoder/ArithmeticConstraintEncoder.java b/src/checkers/inference/solver/backend/encoder/ArithmeticConstraintEncoder.java index f4307d395..b9efe7516 100644 --- a/src/checkers/inference/solver/backend/encoder/ArithmeticConstraintEncoder.java +++ b/src/checkers/inference/solver/backend/encoder/ArithmeticConstraintEncoder.java @@ -6,23 +6,35 @@ import checkers.inference.model.VariableSlot; /** - * Interface that defines operations to encode a - * {@link checkers.inference.model.ArithmeticConstraint}. It has four methods depending on the - * {@link checkers.inference.solver.backend.encoder.SlotSlotCombo} of the {@code leftOperand} and - * {@code rightOperand} slots. + * Interface that defines operations to encode a {@link + * checkers.inference.model.ArithmeticConstraint}. It has four methods depending on the {@link + * checkers.inference.solver.backend.encoder.SlotSlotCombo} of the {@code leftOperand} and {@code + * rightOperand} slots. * * @see checkers.inference.model.ArithmeticConstraint */ public interface ArithmeticConstraintEncoder { - ConstraintEncodingT encodeVariable_Variable(ArithmeticOperationKind operation, - VariableSlot leftOperand, VariableSlot rightOperand, ArithmeticVariableSlot result); + ConstraintEncodingT encodeVariable_Variable( + ArithmeticOperationKind operation, + VariableSlot leftOperand, + VariableSlot rightOperand, + ArithmeticVariableSlot result); - ConstraintEncodingT encodeVariable_Constant(ArithmeticOperationKind operation, - VariableSlot leftOperand, ConstantSlot rightOperand, ArithmeticVariableSlot result); + ConstraintEncodingT encodeVariable_Constant( + ArithmeticOperationKind operation, + VariableSlot leftOperand, + ConstantSlot rightOperand, + ArithmeticVariableSlot result); - ConstraintEncodingT encodeConstant_Variable(ArithmeticOperationKind operation, - ConstantSlot leftOperand, VariableSlot rightOperand, ArithmeticVariableSlot result); + ConstraintEncodingT encodeConstant_Variable( + ArithmeticOperationKind operation, + ConstantSlot leftOperand, + VariableSlot rightOperand, + ArithmeticVariableSlot result); - ConstraintEncodingT encodeConstant_Constant(ArithmeticOperationKind operation, - ConstantSlot leftOperand, ConstantSlot rightOperand, ArithmeticVariableSlot result); + ConstraintEncodingT encodeConstant_Constant( + ArithmeticOperationKind operation, + ConstantSlot leftOperand, + ConstantSlot rightOperand, + ArithmeticVariableSlot result); } diff --git a/src/checkers/inference/solver/backend/encoder/ComparisonConstraintEncoder.java b/src/checkers/inference/solver/backend/encoder/ComparisonConstraintEncoder.java index 08cc9c704..773cf5e91 100644 --- a/src/checkers/inference/solver/backend/encoder/ComparisonConstraintEncoder.java +++ b/src/checkers/inference/solver/backend/encoder/ComparisonConstraintEncoder.java @@ -6,23 +6,36 @@ import checkers.inference.model.VariableSlot; /** - * A marker interface that all constraint encoders that support encoding {@link checkers.inference.model.ComparisonConstraint} - * should implement. Otherwise, the encoder will be considered not supporting encoding comparable - * constraint and rejected by the {@link AbstractConstraintEncoderFactory#createComparisonConstraintEncoder()} + * A marker interface that all constraint encoders that support encoding {@link + * checkers.inference.model.ComparisonConstraint} should implement. Otherwise, the encoder will be + * considered not supporting encoding comparable constraint and rejected by the {@link + * AbstractConstraintEncoderFactory#createComparisonConstraintEncoder()} * * @see checkers.inference.model.ComparisonConstraint * @see AbstractConstraintEncoderFactory#createComparisonConstraintEncoder() */ public interface ComparisonConstraintEncoder { - ConstraintEncodingT encodeVariable_Variable(ComparisonOperationKind operation, - VariableSlot left, VariableSlot right, ComparisonVariableSlot result); + ConstraintEncodingT encodeVariable_Variable( + ComparisonOperationKind operation, + VariableSlot left, + VariableSlot right, + ComparisonVariableSlot result); - ConstraintEncodingT encodeVariable_Constant(ComparisonOperationKind operation, - VariableSlot left, ConstantSlot right, ComparisonVariableSlot result); + ConstraintEncodingT encodeVariable_Constant( + ComparisonOperationKind operation, + VariableSlot left, + ConstantSlot right, + ComparisonVariableSlot result); - ConstraintEncodingT encodeConstant_Variable(ComparisonOperationKind operation, - ConstantSlot left, VariableSlot right, ComparisonVariableSlot result); + ConstraintEncodingT encodeConstant_Variable( + ComparisonOperationKind operation, + ConstantSlot left, + VariableSlot right, + ComparisonVariableSlot result); - ConstraintEncodingT encodeConstant_Constant(ComparisonOperationKind operation, - ConstantSlot left, ConstantSlot right, ComparisonVariableSlot result); + ConstraintEncodingT encodeConstant_Constant( + ComparisonOperationKind operation, + ConstantSlot left, + ConstantSlot right, + ComparisonVariableSlot result); } diff --git a/src/checkers/inference/solver/backend/encoder/ConstraintEncoderCoordinator.java b/src/checkers/inference/solver/backend/encoder/ConstraintEncoderCoordinator.java index 9be1d5448..b1acde512 100644 --- a/src/checkers/inference/solver/backend/encoder/ConstraintEncoderCoordinator.java +++ b/src/checkers/inference/solver/backend/encoder/ConstraintEncoderCoordinator.java @@ -1,12 +1,11 @@ package checkers.inference.solver.backend.encoder; import org.checkerframework.javacutil.BugInCF; + import checkers.inference.model.ArithmeticConstraint; import checkers.inference.model.BinaryConstraint; import checkers.inference.model.CombineConstraint; -import checkers.inference.model.ComparableConstraint; import checkers.inference.model.ComparisonConstraint; -import checkers.inference.model.ComparisonVariableSlot; import checkers.inference.model.ConstantSlot; import checkers.inference.model.ExistentialConstraint; import checkers.inference.model.ImplicationConstraint; @@ -22,12 +21,12 @@ /** * A coordinator class that has the coordinating logic how each encoder encodes its supported * constraint. - *

- * Dispatching example: this class dispatches the encoding of {@link BinaryConstraint} to the - * corresponding encodeXXX_YYY() method in {@link BinaryConstraintEncoder} depending on the - * {@link SlotSlotCombo} of {@link BinaryConstraint} that the encoder encodes. - *

- * Redirecting example: this class simply redirects encoding of {@link PreferenceConstraint} to + * + *

Dispatching example: this class dispatches the encoding of {@link BinaryConstraint} to the + * corresponding encodeXXX_YYY() method in {@link BinaryConstraintEncoder} depending on the {@link + * SlotSlotCombo} of {@link BinaryConstraint} that the encoder encodes. + * + *

Redirecting example: this class simply redirects encoding of {@link PreferenceConstraint} to * {@link PreferenceConstraintEncoder#encode(PreferenceConstraint)} method, as this kind of * constraint doesn't need the {@code SlotSlotCombo} information to encode it. * @@ -38,50 +37,44 @@ */ public class ConstraintEncoderCoordinator { - public static ConstraintEncodingT dispatch(BinaryConstraint constraint, - BinaryConstraintEncoder encoder) { + public static ConstraintEncodingT dispatch( + BinaryConstraint constraint, BinaryConstraintEncoder encoder) { Slot first = constraint.getFirst(); Slot second = constraint.getSecond(); switch (SlotSlotCombo.valueOf(first, second)) { case VARIABLE_VARIABLE: - return encoder.encodeVariable_Variable((VariableSlot) first, - (VariableSlot) second); + return encoder.encodeVariable_Variable((VariableSlot) first, (VariableSlot) second); case VARIABLE_CONSTANT: - return encoder.encodeVariable_Constant((VariableSlot) first, - (ConstantSlot) second); + return encoder.encodeVariable_Constant((VariableSlot) first, (ConstantSlot) second); case CONSTANT_VARIABLE: - return encoder.encodeConstant_Variable((ConstantSlot) first, - (VariableSlot) second); + return encoder.encodeConstant_Variable((ConstantSlot) first, (VariableSlot) second); case CONSTANT_CONSTANT: - throw new BugInCF("Attempting to encode a constant-constant combination " - + "for a binary constraint. This should be normalized to " - + "either AlwaysTrueConstraint or AlwaysFalseConstraint."); + throw new BugInCF( + "Attempting to encode a constant-constant combination " + + "for a binary constraint. This should be normalized to " + + "either AlwaysTrueConstraint or AlwaysFalseConstraint."); default: throw new BugInCF("Unsupported SlotSlotCombo enum."); } } - public static ConstraintEncodingT dispatch(CombineConstraint constraint, - CombineConstraintEncoder encoder) { + public static ConstraintEncodingT dispatch( + CombineConstraint constraint, CombineConstraintEncoder encoder) { Slot target = constraint.getTarget(); Slot declared = constraint.getDeclared(); switch (SlotSlotCombo.valueOf(target, declared)) { case VARIABLE_VARIABLE: - return encoder.encodeVariable_Variable((VariableSlot) target, - (VariableSlot) declared, - constraint.getResult()); + return encoder.encodeVariable_Variable( + (VariableSlot) target, (VariableSlot) declared, constraint.getResult()); case VARIABLE_CONSTANT: - return encoder.encodeVariable_Constant((VariableSlot) target, - (ConstantSlot) declared, - constraint.getResult()); + return encoder.encodeVariable_Constant( + (VariableSlot) target, (ConstantSlot) declared, constraint.getResult()); case CONSTANT_VARIABLE: - return encoder.encodeConstant_Variable((ConstantSlot) target, - (VariableSlot) declared, - constraint.getResult()); + return encoder.encodeConstant_Variable( + (ConstantSlot) target, (VariableSlot) declared, constraint.getResult()); case CONSTANT_CONSTANT: - return encoder.encodeConstant_Constant((ConstantSlot) target, - (ConstantSlot) declared, - constraint.getResult()); + return encoder.encodeConstant_Constant( + (ConstantSlot) target, (ConstantSlot) declared, constraint.getResult()); default: throw new BugInCF("Unsupported SlotSlotCombo enum."); } @@ -92,21 +85,29 @@ public static ConstraintEncodingT dispatch( ComparisonConstraintEncoder encoder) { switch (SlotSlotCombo.valueOf(constraint.getLeft(), constraint.getRight())) { case VARIABLE_VARIABLE: - return encoder.encodeVariable_Variable(constraint.getOperation(), + return encoder.encodeVariable_Variable( + constraint.getOperation(), (VariableSlot) constraint.getLeft(), - (VariableSlot) constraint.getRight(), constraint.getResult()); + (VariableSlot) constraint.getRight(), + constraint.getResult()); case VARIABLE_CONSTANT: - return encoder.encodeVariable_Constant(constraint.getOperation(), + return encoder.encodeVariable_Constant( + constraint.getOperation(), (VariableSlot) constraint.getLeft(), - (ConstantSlot) constraint.getRight(), constraint.getResult()); + (ConstantSlot) constraint.getRight(), + constraint.getResult()); case CONSTANT_VARIABLE: - return encoder.encodeConstant_Variable(constraint.getOperation(), + return encoder.encodeConstant_Variable( + constraint.getOperation(), (ConstantSlot) constraint.getLeft(), - (VariableSlot) constraint.getRight(), constraint.getResult()); + (VariableSlot) constraint.getRight(), + constraint.getResult()); case CONSTANT_CONSTANT: - return encoder.encodeConstant_Constant(constraint.getOperation(), + return encoder.encodeConstant_Constant( + constraint.getOperation(), (ConstantSlot) constraint.getLeft(), - (ConstantSlot) constraint.getRight(), constraint.getResult()); + (ConstantSlot) constraint.getRight(), + constraint.getResult()); } return null; } @@ -118,21 +119,29 @@ public static ConstraintEncodingT dispatch( Slot rightOperand = constraint.getRightOperand(); switch (SlotSlotCombo.valueOf(leftOperand, rightOperand)) { case VARIABLE_VARIABLE: - return encoder.encodeVariable_Variable(constraint.getOperation(), + return encoder.encodeVariable_Variable( + constraint.getOperation(), (VariableSlot) leftOperand, - (VariableSlot) rightOperand, constraint.getResult()); + (VariableSlot) rightOperand, + constraint.getResult()); case VARIABLE_CONSTANT: - return encoder.encodeVariable_Constant(constraint.getOperation(), + return encoder.encodeVariable_Constant( + constraint.getOperation(), (VariableSlot) leftOperand, - (ConstantSlot) rightOperand, constraint.getResult()); + (ConstantSlot) rightOperand, + constraint.getResult()); case CONSTANT_VARIABLE: - return encoder.encodeConstant_Variable(constraint.getOperation(), + return encoder.encodeConstant_Variable( + constraint.getOperation(), (ConstantSlot) leftOperand, - (VariableSlot) rightOperand, constraint.getResult()); + (VariableSlot) rightOperand, + constraint.getResult()); case CONSTANT_CONSTANT: - return encoder.encodeConstant_Constant(constraint.getOperation(), + return encoder.encodeConstant_Constant( + constraint.getOperation(), (ConstantSlot) leftOperand, - (ConstantSlot) rightOperand, constraint.getResult()); + (ConstantSlot) rightOperand, + constraint.getResult()); } return null; } @@ -149,7 +158,9 @@ public static ConstraintEncodingT redirect( return encoder.encode(constraint); } - public static ConstraintEncodingT redirect(ImplicationConstraint constraint, ImplicationConstraintEncoder encoder) { + public static ConstraintEncodingT redirect( + ImplicationConstraint constraint, + ImplicationConstraintEncoder encoder) { return encoder.encode(constraint); } } diff --git a/src/checkers/inference/solver/backend/encoder/ConstraintEncoderFactory.java b/src/checkers/inference/solver/backend/encoder/ConstraintEncoderFactory.java index 1331348d4..dcf31a5e9 100644 --- a/src/checkers/inference/solver/backend/encoder/ConstraintEncoderFactory.java +++ b/src/checkers/inference/solver/backend/encoder/ConstraintEncoderFactory.java @@ -12,22 +12,22 @@ /** * Factory that creates constraint encoders. * - *

- * Right now, {@link ConstraintEncoderFactory} interface supports creation of these encoders: + *

Right now, {@link ConstraintEncoderFactory} interface supports creation of these encoders: + * *

- *

- * User of this interface is {@link checkers.inference.solver.backend.AbstractFormatTranslator} + * + *

User of this interface is {@link checkers.inference.solver.backend.AbstractFormatTranslator} * and its subclasses. * * @see checkers.inference.solver.backend.AbstractFormatTranslator diff --git a/src/checkers/inference/solver/backend/encoder/SlotSlotCombo.java b/src/checkers/inference/solver/backend/encoder/SlotSlotCombo.java index a40d2b5c8..ad2fae4e1 100644 --- a/src/checkers/inference/solver/backend/encoder/SlotSlotCombo.java +++ b/src/checkers/inference/solver/backend/encoder/SlotSlotCombo.java @@ -5,38 +5,39 @@ import checkers.inference.model.Slot; import checkers.inference.model.VariableSlot; import checkers.inference.solver.backend.encoder.binary.BinaryConstraintEncoder; -import checkers.inference.solver.backend.encoder.combine.CombineConstraintEncoder; +import checkers.inference.solver.backend.encoder.combine.CombineConstraintEncoder; /** * Enum that models combination of slots in a {@link BinaryConstraint} and {@link CombineConstraint} - * (in this case, it's the combination of {@link CombineConstraint#target} and {@link CombineConstraint#decl}). - *

- * {@link BinaryConstraintEncoder} and {@link CombineConstraintEncoder} need to know the combination of - * {@link Slot.Kind} to determine which encodeXXX() method in {@link BinaryConstraintEncoder} and - * {@link CombineConstraintEncoder} should be called. - *

- * But the {@link Slot.Kind} that's needed here is coarser-grained than its original definition: - * Only knowing if a {@code Slot} is variable or constant is enough in solver encoding. Because solver - * treats every {@link checkers.inference.model.VariableSlot} and its subclasses essentially as having - * unknown value that is to be inferred and only the {@link checkers.inference.model.VariableSlot#id} is - * interesting; Solver treats {@link checkers.inference.model.ConstantSlot} as having a real qualifier - * that no inference is needed. + * (in this case, it's the combination of {@link CombineConstraint#target} and {@link + * CombineConstraint#decl}). + * + *

{@link BinaryConstraintEncoder} and {@link CombineConstraintEncoder} need to know the + * combination of {@link Slot.Kind} to determine which encodeXXX() method in {@link + * BinaryConstraintEncoder} and {@link CombineConstraintEncoder} should be called. + * + *

But the {@link Slot.Kind} that's needed here is coarser-grained than its original definition: + * Only knowing if a {@code Slot} is variable or constant is enough in solver encoding. Because + * solver treats every {@link checkers.inference.model.VariableSlot} and its subclasses essentially + * as having unknown value that is to be inferred and only the {@link + * checkers.inference.model.VariableSlot#id} is interesting; Solver treats {@link + * checkers.inference.model.ConstantSlot} as having a real qualifier that no inference is needed. * * @see ConstraintEncoderCoordinator#dispatch(BinaryConstraint, BinaryConstraintEncoder) * @see ConstraintEncoderCoordinator#dispatch(CombineConstraint, CombineConstraintEncoder) */ public enum SlotSlotCombo { - VARIABLE_VARIABLE(true, true), VARIABLE_CONSTANT(true, false), CONSTANT_VARIABLE(false, true), CONSTANT_CONSTANT(false, false); /** - * A {@link java.util.Map} that caches the mapping between two booleans(in implementation, converted - * to indecies according to the truth value) and {code SlotSlotCombo} that the two booleans represent. + * A {@link java.util.Map} that caches the mapping between two booleans(in implementation, + * converted to indecies according to the truth value) and {code SlotSlotCombo} that the two + * booleans represent. */ - static private final SlotSlotCombo[][] map = new SlotSlotCombo[2][2]; + private static final SlotSlotCombo[][] map = new SlotSlotCombo[2][2]; static { for (SlotSlotCombo combo : SlotSlotCombo.values()) { diff --git a/src/checkers/inference/solver/backend/encoder/binary/BinaryConstraintEncoder.java b/src/checkers/inference/solver/backend/encoder/binary/BinaryConstraintEncoder.java index e339893c7..1644baf2c 100644 --- a/src/checkers/inference/solver/backend/encoder/binary/BinaryConstraintEncoder.java +++ b/src/checkers/inference/solver/backend/encoder/binary/BinaryConstraintEncoder.java @@ -5,10 +5,10 @@ /** * Interface that defines operations to encode a {@link checkers.inference.model.BinaryConstraint}. - * It has three methods depending on the - * {@link checkers.inference.solver.backend.encoder.SlotSlotCombo} of the two slots that constitute - * this binary constraint. Note that the constant-constant slot combination is normalized to either - * True or False each BinaryConstraint's {@code create} method, thus will never need to be encoded. + * It has three methods depending on the {@link + * checkers.inference.solver.backend.encoder.SlotSlotCombo} of the two slots that constitute this + * binary constraint. Note that the constant-constant slot combination is normalized to either True + * or False each BinaryConstraint's {@code create} method, thus will never need to be encoded. * * @see checkers.inference.model.BinaryConstraint * @see checkers.inference.solver.backend.encoder.SlotSlotCombo diff --git a/src/checkers/inference/solver/backend/encoder/binary/ComparableConstraintEncoder.java b/src/checkers/inference/solver/backend/encoder/binary/ComparableConstraintEncoder.java index 4efb41b05..3a753cf66 100644 --- a/src/checkers/inference/solver/backend/encoder/binary/ComparableConstraintEncoder.java +++ b/src/checkers/inference/solver/backend/encoder/binary/ComparableConstraintEncoder.java @@ -3,12 +3,13 @@ import checkers.inference.solver.backend.encoder.AbstractConstraintEncoderFactory; /** - * A marker interface that all constraint encoders that support encoding {@link checkers.inference.model.ComparableConstraint} - * should implement. Otherwise, the encoder will be considered not supporting encoding comparable - * constraint and rejected by the {@link AbstractConstraintEncoderFactory#createComparableConstraintEncoder()} + * A marker interface that all constraint encoders that support encoding {@link + * checkers.inference.model.ComparableConstraint} should implement. Otherwise, the encoder will be + * considered not supporting encoding comparable constraint and rejected by the {@link + * AbstractConstraintEncoderFactory#createComparableConstraintEncoder()} * * @see checkers.inference.model.ComparableConstraint * @see AbstractConstraintEncoderFactory#createComparableConstraintEncoder() */ -public interface ComparableConstraintEncoder extends BinaryConstraintEncoder { -} +public interface ComparableConstraintEncoder + extends BinaryConstraintEncoder {} diff --git a/src/checkers/inference/solver/backend/encoder/binary/EqualityConstraintEncoder.java b/src/checkers/inference/solver/backend/encoder/binary/EqualityConstraintEncoder.java index c92a63343..5dc27aec8 100644 --- a/src/checkers/inference/solver/backend/encoder/binary/EqualityConstraintEncoder.java +++ b/src/checkers/inference/solver/backend/encoder/binary/EqualityConstraintEncoder.java @@ -3,12 +3,13 @@ import checkers.inference.solver.backend.encoder.AbstractConstraintEncoderFactory; /** - * A marker interface that all constraint encoders that support encoding {@link checkers.inference.model.EqualityConstraint} - * should implement. Otherwise, the encoder will be considered not supporting encoding equality constraint and rejected by - * the {@link AbstractConstraintEncoderFactory#createEqualityConstraintEncoder()} + * A marker interface that all constraint encoders that support encoding {@link + * checkers.inference.model.EqualityConstraint} should implement. Otherwise, the encoder will be + * considered not supporting encoding equality constraint and rejected by the {@link + * AbstractConstraintEncoderFactory#createEqualityConstraintEncoder()} * * @see checkers.inference.model.EqualityConstraint * @see AbstractConstraintEncoderFactory#createEqualityConstraintEncoder() */ -public interface EqualityConstraintEncoder extends BinaryConstraintEncoder { -} +public interface EqualityConstraintEncoder + extends BinaryConstraintEncoder {} diff --git a/src/checkers/inference/solver/backend/encoder/binary/InequalityConstraintEncoder.java b/src/checkers/inference/solver/backend/encoder/binary/InequalityConstraintEncoder.java index 76ba49311..15f4c5f99 100644 --- a/src/checkers/inference/solver/backend/encoder/binary/InequalityConstraintEncoder.java +++ b/src/checkers/inference/solver/backend/encoder/binary/InequalityConstraintEncoder.java @@ -3,12 +3,13 @@ import checkers.inference.solver.backend.encoder.AbstractConstraintEncoderFactory; /** - * A marker interface that all constraint encoders that support encoding {@link checkers.inference.model.InequalityConstraint} - * should implement. Otherwise, the encoder will be considered not supporting encoding inequality constraint and rejected by the - * {@link AbstractConstraintEncoderFactory#createInequalityConstraintEncoder()} + * A marker interface that all constraint encoders that support encoding {@link + * checkers.inference.model.InequalityConstraint} should implement. Otherwise, the encoder will be + * considered not supporting encoding inequality constraint and rejected by the {@link + * AbstractConstraintEncoderFactory#createInequalityConstraintEncoder()} * * @see checkers.inference.model.InequalityConstraint * @see AbstractConstraintEncoderFactory#createInequalityConstraintEncoder() */ -public interface InequalityConstraintEncoder extends BinaryConstraintEncoder { -} +public interface InequalityConstraintEncoder + extends BinaryConstraintEncoder {} diff --git a/src/checkers/inference/solver/backend/encoder/binary/SubtypeConstraintEncoder.java b/src/checkers/inference/solver/backend/encoder/binary/SubtypeConstraintEncoder.java index 873e5c6f3..330677934 100644 --- a/src/checkers/inference/solver/backend/encoder/binary/SubtypeConstraintEncoder.java +++ b/src/checkers/inference/solver/backend/encoder/binary/SubtypeConstraintEncoder.java @@ -3,12 +3,13 @@ import checkers.inference.solver.backend.encoder.AbstractConstraintEncoderFactory; /** - * A marker interface that all constraint encoders that support encoding {@link checkers.inference.model.SubtypeConstraint} - * should implement. Otherwise, the encoder will be considered not supporting encoding subtype constraint and rejected by the - * {@link AbstractConstraintEncoderFactory#createSubtypeConstraintEncoder()} + * A marker interface that all constraint encoders that support encoding {@link + * checkers.inference.model.SubtypeConstraint} should implement. Otherwise, the encoder will be + * considered not supporting encoding subtype constraint and rejected by the {@link + * AbstractConstraintEncoderFactory#createSubtypeConstraintEncoder()} * * @see checkers.inference.model.SubtypeConstraint * @see AbstractConstraintEncoderFactory#createSubtypeConstraintEncoder() */ -public interface SubtypeConstraintEncoder extends BinaryConstraintEncoder { -} +public interface SubtypeConstraintEncoder + extends BinaryConstraintEncoder {} diff --git a/src/checkers/inference/solver/backend/encoder/combine/CombineConstraintEncoder.java b/src/checkers/inference/solver/backend/encoder/combine/CombineConstraintEncoder.java index 0bcea3af5..637b0681a 100644 --- a/src/checkers/inference/solver/backend/encoder/combine/CombineConstraintEncoder.java +++ b/src/checkers/inference/solver/backend/encoder/combine/CombineConstraintEncoder.java @@ -6,25 +6,29 @@ import checkers.inference.model.VariableSlot; /** - * Interface that defines operations to encode a {@link checkers.inference.model.CombineConstraint}. It has four methods - * depending on the {@link checkers.inference.solver.backend.encoder.SlotSlotCombo} of {@code target} and {@code - * declared} slots. + * Interface that defines operations to encode a {@link checkers.inference.model.CombineConstraint}. + * It has four methods depending on the {@link + * checkers.inference.solver.backend.encoder.SlotSlotCombo} of {@code target} and {@code declared} + * slots. * - *

- * {@code result} is always {@link checkers.inference.model.CombVariableSlot}, which is essentially {@link Slot}, - * whose {@link Slot#id} is the only interesting knowledge in encoding phase. Therefore there don't exist - * methods in which {@code result} is {@link ConstantSlot}. + *

{@code result} is always {@link checkers.inference.model.CombVariableSlot}, which is + * essentially {@link Slot}, whose {@link Slot#id} is the only interesting knowledge in encoding + * phase. Therefore there don't exist methods in which {@code result} is {@link ConstantSlot}. * * @see checkers.inference.model.CombineConstraint * @see checkers.inference.solver.backend.encoder.SlotSlotCombo */ public interface CombineConstraintEncoder { - ConstraintEncodingT encodeVariable_Variable(VariableSlot target, VariableSlot declared, CombVariableSlot result); + ConstraintEncodingT encodeVariable_Variable( + VariableSlot target, VariableSlot declared, CombVariableSlot result); - ConstraintEncodingT encodeVariable_Constant(VariableSlot target, ConstantSlot declared, CombVariableSlot result); + ConstraintEncodingT encodeVariable_Constant( + VariableSlot target, ConstantSlot declared, CombVariableSlot result); - ConstraintEncodingT encodeConstant_Variable(ConstantSlot target, VariableSlot declared, CombVariableSlot result); + ConstraintEncodingT encodeConstant_Variable( + ConstantSlot target, VariableSlot declared, CombVariableSlot result); - ConstraintEncodingT encodeConstant_Constant(ConstantSlot target, ConstantSlot declared, CombVariableSlot result); + ConstraintEncodingT encodeConstant_Constant( + ConstantSlot target, ConstantSlot declared, CombVariableSlot result); } diff --git a/src/checkers/inference/solver/backend/encoder/existential/ExistentialConstraintEncoder.java b/src/checkers/inference/solver/backend/encoder/existential/ExistentialConstraintEncoder.java index 8d8f7c103..be32aca66 100644 --- a/src/checkers/inference/solver/backend/encoder/existential/ExistentialConstraintEncoder.java +++ b/src/checkers/inference/solver/backend/encoder/existential/ExistentialConstraintEncoder.java @@ -3,7 +3,8 @@ import checkers.inference.model.ExistentialConstraint; /** - * Interface that defines operations to encode a {@link checkers.inference.model.ExistentialConstraint}. + * Interface that defines operations to encode a {@link + * checkers.inference.model.ExistentialConstraint}. */ public interface ExistentialConstraintEncoder { diff --git a/src/checkers/inference/solver/backend/encoder/preference/PreferenceConstraintEncoder.java b/src/checkers/inference/solver/backend/encoder/preference/PreferenceConstraintEncoder.java index 104bc1216..4fb43f7c6 100644 --- a/src/checkers/inference/solver/backend/encoder/preference/PreferenceConstraintEncoder.java +++ b/src/checkers/inference/solver/backend/encoder/preference/PreferenceConstraintEncoder.java @@ -3,7 +3,8 @@ import checkers.inference.model.PreferenceConstraint; /** - * Interface that defines operations to encode a {@link checkers.inference.model.PreferenceConstraint}. + * Interface that defines operations to encode a {@link + * checkers.inference.model.PreferenceConstraint}. */ public interface PreferenceConstraintEncoder { diff --git a/src/checkers/inference/solver/backend/lingeling/LingelingSolver.java b/src/checkers/inference/solver/backend/lingeling/LingelingSolver.java index 3be9bc774..fa750e9b5 100644 --- a/src/checkers/inference/solver/backend/lingeling/LingelingSolver.java +++ b/src/checkers/inference/solver/backend/lingeling/LingelingSolver.java @@ -1,5 +1,7 @@ package checkers.inference.solver.backend.lingeling; +import org.sat4j.core.VecInt; + import java.io.BufferedReader; import java.io.IOException; import java.util.ArrayList; @@ -9,12 +11,9 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; -import java.nio.file.Paths; import javax.lang.model.element.AnnotationMirror; -import org.sat4j.core.VecInt; - import checkers.inference.model.Constraint; import checkers.inference.model.Slot; import checkers.inference.solver.backend.maxsat.MaxSatFormatTranslator; @@ -29,7 +28,6 @@ * doesn't support soft constraint. * * @author jianchu - * */ public class LingelingSolver extends MaxSatSolver { @@ -44,8 +42,11 @@ public class LingelingSolver extends MaxSatSolver { private long serializationStart; private long serializationEnd; - public LingelingSolver(SolverEnvironment solverEnvironment, Collection slots, - Collection constraints, MaxSatFormatTranslator formatTranslator, + public LingelingSolver( + SolverEnvironment solverEnvironment, + Collection slots, + Collection constraints, + MaxSatFormatTranslator formatTranslator, Lattice lattice) { super(solverEnvironment, slots, constraints, formatTranslator, lattice); } @@ -89,11 +90,12 @@ public Map solve() { * @return and int array, which stores truth assignment for CNF predicate. */ private int[] getSolverOutput(int localNth) { - String[] command = { lingeling, - CNFData.getAbsolutePath() + "/cnfdata" + localNth + ".txt" }; + String[] command = {lingeling, CNFData.getAbsolutePath() + "/cnfdata" + localNth + ".txt"}; final List resultList = new ArrayList(); - ExternalSolverUtils.runExternalSolver(command, stdOut -> parseStdOut(stdOut, resultList), + ExternalSolverUtils.runExternalSolver( + command, + stdOut -> parseStdOut(stdOut, resultList), stdErr -> ExternalSolverUtils.printStdStream(System.err, stdErr)); // Java 8 style of List to int[] conversion @@ -107,7 +109,9 @@ private void parseStdOut(BufferedReader stdOut, List resultList) { while ((line = stdOut.readLine()) != null) { if (line.charAt(0) == 'v') { for (String retval : line.split(" ")) { - if (!retval.equals("") && !retval.equals(" ") && !retval.equals("\n") + if (!retval.equals("") + && !retval.equals(" ") + && !retval.equals("\n") && !retval.equals("v")) { int val = Integer.parseInt(retval); if (variableSet.contains(Math.abs(val))) { diff --git a/src/checkers/inference/solver/backend/lingeling/LingelingSolverFactory.java b/src/checkers/inference/solver/backend/lingeling/LingelingSolverFactory.java index 5486e5d77..393ffea9b 100644 --- a/src/checkers/inference/solver/backend/lingeling/LingelingSolverFactory.java +++ b/src/checkers/inference/solver/backend/lingeling/LingelingSolverFactory.java @@ -13,15 +13,18 @@ public class LingelingSolverFactory extends AbstractSolverFactory { @Override - public Solver createSolver(SolverEnvironment solverEnvironment, Collection slots, - Collection constraints, Lattice lattice) { + public Solver createSolver( + SolverEnvironment solverEnvironment, + Collection slots, + Collection constraints, + Lattice lattice) { MaxSatFormatTranslator formatTranslator = createFormatTranslator(lattice); - return new LingelingSolver(solverEnvironment, slots, constraints, formatTranslator, lattice); + return new LingelingSolver( + solverEnvironment, slots, constraints, formatTranslator, lattice); } @Override protected MaxSatFormatTranslator createFormatTranslator(Lattice lattice) { - return new MaxSatFormatTranslator(lattice); + return new MaxSatFormatTranslator(lattice); } - } diff --git a/src/checkers/inference/solver/backend/logiql/DecodingTool.java b/src/checkers/inference/solver/backend/logiql/DecodingTool.java index a8191a429..baa115938 100644 --- a/src/checkers/inference/solver/backend/logiql/DecodingTool.java +++ b/src/checkers/inference/solver/backend/logiql/DecodingTool.java @@ -16,12 +16,10 @@ import checkers.inference.solver.util.NameUtils; /** - * DecodingTool decodes the result from LogicBlox, change the form to human - * readable form and put the result to HashMap result and return it to - * LogicSolver. + * DecodingTool decodes the result from LogicBlox, change the form to human readable form and put + * the result to HashMap result and return it to LogicSolver. * * @author Jianchu Li - * */ public class DecodingTool { @@ -49,8 +47,7 @@ public Map decodeResult() { } /** - * DecodeLogicBloxOutput decodes the LogicBloxOutput, and put it in HashMap - * result. + * DecodeLogicBloxOutput decodes the LogicBloxOutput, and put it in HashMap result. * * @throws FileNotFoundException */ diff --git a/src/checkers/inference/solver/backend/logiql/LogiQLFormatTranslator.java b/src/checkers/inference/solver/backend/logiql/LogiQLFormatTranslator.java index fb88c0f7e..41267b412 100644 --- a/src/checkers/inference/solver/backend/logiql/LogiQLFormatTranslator.java +++ b/src/checkers/inference/solver/backend/logiql/LogiQLFormatTranslator.java @@ -12,7 +12,6 @@ * LogiQLFormatTranslator converts constraint into string as logiQL data. * * @author jianchu - * */ public class LogiQLFormatTranslator extends AbstractFormatTranslator { @@ -27,10 +26,10 @@ protected ConstraintEncoderFactory createConstraintEncoderFactory() { } @Override - public AnnotationMirror decodeSolution(String solution, ProcessingEnvironment processingEnvironment) { + public AnnotationMirror decodeSolution( + String solution, ProcessingEnvironment processingEnvironment) { // TODO Refactor LogiQL backend to follow the design protocal. // https://github.com/opprop/checker-framework-inference/issues/108 return null; } - } diff --git a/src/checkers/inference/solver/backend/logiql/LogiQLPredicateGenerator.java b/src/checkers/inference/solver/backend/logiql/LogiQLPredicateGenerator.java index d94256d7a..305614d9b 100644 --- a/src/checkers/inference/solver/backend/logiql/LogiQLPredicateGenerator.java +++ b/src/checkers/inference/solver/backend/logiql/LogiQLPredicateGenerator.java @@ -11,12 +11,10 @@ import checkers.inference.solver.util.Statistics; /** - * LogiqlConstraintGenerator take QualifierHierarchy of current type system as - * input, and generate the logiql encoding of all constraint, and write the - * result in a .logic file. + * LogiqlConstraintGenerator take QualifierHierarchy of current type system as input, and generate + * the logiql encoding of all constraint, and write the result in a .logic file. * * @author Jianchu Li - * */ public class LogiQLPredicateGenerator { @@ -41,137 +39,206 @@ public void GenerateLogiqlEncoding() { // System.out.println(allEncodings.toString()); writeFile(allEncodings.toString()); - } - private String getEqualityConstraintEncoding() { StringBuilder equalityEncoding = new StringBuilder(); for (AnnotationMirror annoMirror : lattice.allTypes) { String simpleName = NameUtils.getSimpleName(annoMirror); - equalityEncoding.append("is" + simpleName + "[v2] = true <- equalityConstraint(v1, v2), is" - + simpleName + "[v1] = true.\n"); - equalityEncoding.append("is" + simpleName - + "[v2] = true <- equalityConstraintContainsConstant(v1, v2), hasconstantName(v1:\"" - + simpleName + "\").\n"); + equalityEncoding.append( + "is" + + simpleName + + "[v2] = true <- equalityConstraint(v1, v2), is" + + simpleName + + "[v1] = true.\n"); + equalityEncoding.append( + "is" + + simpleName + + "[v2] = true <- equalityConstraintContainsConstant(v1, v2), hasconstantName(v1:\"" + + simpleName + + "\").\n"); } return equalityEncoding.toString(); } - + private String getInequalityConstraintEncoding() { StringBuilder inequalityEncoding = new StringBuilder(); for (AnnotationMirror annoMirror : lattice.allTypes) { String simpleName = NameUtils.getSimpleName(annoMirror); - inequalityEncoding.append("is" + simpleName + "[v2] = false <- inequalityConstraint(v1, v2), is" - + simpleName + "[v1] = true.\n"); - inequalityEncoding.append("is" + simpleName - + "[v2] = false <- inequalityConstraintContainsConstant(v1, v2), hasconstantName(v1:\"" - + simpleName + "\").\n"); + inequalityEncoding.append( + "is" + + simpleName + + "[v2] = false <- inequalityConstraint(v1, v2), is" + + simpleName + + "[v1] = true.\n"); + inequalityEncoding.append( + "is" + + simpleName + + "[v2] = false <- inequalityConstraintContainsConstant(v1, v2), hasconstantName(v1:\"" + + simpleName + + "\").\n"); } return inequalityEncoding.toString(); } - + private String getSubTypeConstraintEncoding() { StringBuilder subtypeEncoding = new StringBuilder(); String topTypeStr = NameUtils.getSimpleName(lattice.top); String bottomTypeStr = NameUtils.getSimpleName(lattice.bottom); - subtypeEncoding.append("is" + topTypeStr + "[v2] = true <- subtypeConstraint(v1, v2), is" + topTypeStr + "[v1] = true.\n"); - subtypeEncoding.append("is" + topTypeStr+ "[v2] = true <- subtypeConstraintLeftConstant(v1, v2), hasconstantName(v1:\"" + topTypeStr + "\").\n"); - subtypeEncoding.append("is" + bottomTypeStr + "[v1] = true <- subtypeConstraint(v1, v2), is" + bottomTypeStr + "[v2] = true.\n"); - subtypeEncoding.append("is" + bottomTypeStr+ "[v1] = true <- subtypeConstraintRightConstant(v1, v2), hasconstantName(v2:\"" + bottomTypeStr + "\").\n\n"); - - for (Map.Entry> entry : lattice.subType.entrySet()) { + subtypeEncoding.append( + "is" + + topTypeStr + + "[v2] = true <- subtypeConstraint(v1, v2), is" + + topTypeStr + + "[v1] = true.\n"); + subtypeEncoding.append( + "is" + + topTypeStr + + "[v2] = true <- subtypeConstraintLeftConstant(v1, v2), hasconstantName(v1:\"" + + topTypeStr + + "\").\n"); + subtypeEncoding.append( + "is" + + bottomTypeStr + + "[v1] = true <- subtypeConstraint(v1, v2), is" + + bottomTypeStr + + "[v2] = true.\n"); + subtypeEncoding.append( + "is" + + bottomTypeStr + + "[v1] = true <- subtypeConstraintRightConstant(v1, v2), hasconstantName(v2:\"" + + bottomTypeStr + + "\").\n\n"); + + for (Map.Entry> entry : + lattice.subType.entrySet()) { String superTypeName = NameUtils.getSimpleName(entry.getKey()); for (AnnotationMirror subType : entry.getValue()) { String subTypeName = NameUtils.getSimpleName(subType); if (!superTypeName.equals(subTypeName)) { - subtypeEncoding.append("is" + subTypeName + "[v2] = false <- subtypeConstraint(v1, v2), is" + superTypeName + "[v1] = true.\n"); - subtypeEncoding.append("is" + subTypeName + "[v2] = false <- subtypeConstraintLeftConstant(v1, v2), hasconstantName(v1:\"" + superTypeName + "\").\n"); + subtypeEncoding.append( + "is" + + subTypeName + + "[v2] = false <- subtypeConstraint(v1, v2), is" + + superTypeName + + "[v1] = true.\n"); + subtypeEncoding.append( + "is" + + subTypeName + + "[v2] = false <- subtypeConstraintLeftConstant(v1, v2), hasconstantName(v1:\"" + + superTypeName + + "\").\n"); } } } subtypeEncoding.append("\n"); // duplicate code for easy understanding - for (Map.Entry> entry : lattice.superType.entrySet()) { + for (Map.Entry> entry : + lattice.superType.entrySet()) { String subTypeName = NameUtils.getSimpleName(entry.getKey()); for (AnnotationMirror superType : entry.getValue()) { String superTypeName = NameUtils.getSimpleName(superType); if (!superTypeName.equals(subTypeName)) { - subtypeEncoding.append("is" + superTypeName + "[v1] = false <- subtypeConstraintRightConstant(v1, v2), hasconstantName(v2:\"" + subTypeName + "\").\n"); + subtypeEncoding.append( + "is" + + superTypeName + + "[v1] = false <- subtypeConstraintRightConstant(v1, v2), hasconstantName(v2:\"" + + subTypeName + + "\").\n"); } } } subtypeEncoding.append("\n"); return subtypeEncoding.toString(); } - + private String getComparableConstraintEncoding() { StringBuilder ComparableEncoding = new StringBuilder(); // duplicate code for easy understanding - for (Map.Entry> entry : lattice.incomparableType.entrySet()) { + for (Map.Entry> entry : + lattice.incomparableType.entrySet()) { String incompType1Name = NameUtils.getSimpleName(entry.getKey()); for (AnnotationMirror incomparableType2 : entry.getValue()) { String incompType2Name = NameUtils.getSimpleName(incomparableType2); - ComparableEncoding.append("is" + incompType2Name + "[v1] = false <- subtypeConstraintRightConstant(v1, v2), hasconstantName(v2:\"" + incompType1Name + "\").\n"); + ComparableEncoding.append( + "is" + + incompType2Name + + "[v1] = false <- subtypeConstraintRightConstant(v1, v2), hasconstantName(v2:\"" + + incompType1Name + + "\").\n"); } } - + return ComparableEncoding.toString(); } - + private String getBasicEncoding() { StringBuilder basicEncoding = new StringBuilder(); basicEncoding.append("variable(v), hasvariableName(v:i) -> int(i).\n"); basicEncoding.append("constant(m), hasconstantName(m:i) -> string(i).\n"); basicEncoding.append("AnnotationOf[v] = a -> variable(v), string(a).\n"); - //predicates for making output in order. + // predicates for making output in order. basicEncoding.append("variableOrder(v) -> int(v).\n"); basicEncoding.append("variableOrder(i) <- variable(v), hasvariableName(v:i).\n"); basicEncoding.append("orderVariable[o] = v -> int(o), int(v).\n"); basicEncoding.append("orderVariable[o] = v <- seq<> variableOrder(v).\n"); basicEncoding.append("orderedAnnotationOf[v] = a -> int(v), string(a).\n"); - basicEncoding.append("orderedAnnotationOf[v] = a <- variable(q), hasvariableName(q:v), AnnotationOf[q]=a, orderVariable[_]=v.\n"); - //predicates for constraints. - //equality constraint + basicEncoding.append( + "orderedAnnotationOf[v] = a <- variable(q), hasvariableName(q:v), AnnotationOf[q]=a, orderVariable[_]=v.\n"); + // predicates for constraints. + // equality constraint basicEncoding.append("equalityConstraint(v1,v2) -> variable(v1), variable(v2).\n"); - basicEncoding.append("equalityConstraintContainsConstant(v1,v2) -> constant(v1), variable(v2).\n"); - //inequality constraint + basicEncoding.append( + "equalityConstraintContainsConstant(v1,v2) -> constant(v1), variable(v2).\n"); + // inequality constraint basicEncoding.append("inequalityConstraint(v1,v2) -> variable(v1), variable(v2).\n"); - basicEncoding.append("inequalityConstraintContainsConstant(v1,v2) -> constant(v1), variable(v2).\n"); - //subtype constraint + basicEncoding.append( + "inequalityConstraintContainsConstant(v1,v2) -> constant(v1), variable(v2).\n"); + // subtype constraint basicEncoding.append("subtypeConstraint(v1,v2) -> variable(v1), variable(v2).\n"); - basicEncoding.append("subtypeConstraintLeftConstant(v1,v2) -> constant(v1), variable(v2).\n"); - basicEncoding.append("subtypeConstraintRightConstant(v1,v2) -> variable(v1), constant(v2).\n"); - //comparable constraint + basicEncoding.append( + "subtypeConstraintLeftConstant(v1,v2) -> constant(v1), variable(v2).\n"); + basicEncoding.append( + "subtypeConstraintRightConstant(v1,v2) -> variable(v1), constant(v2).\n"); + // comparable constraint basicEncoding.append("comparableConstraint(v1,v2) -> variable(v1), variable(v2).\n"); - basicEncoding.append("comparableConstraintContainsConstant(v1,v2) -> constant(v1), variable(v2).\n"); + basicEncoding.append( + "comparableConstraintContainsConstant(v1,v2) -> constant(v1), variable(v2).\n"); // each type for (AnnotationMirror annoMirror : lattice.allTypes) { - basicEncoding.append("is" + NameUtils.getSimpleName(annoMirror) - + "[v] = i -> variable(v), boolean(i).\n"); + basicEncoding.append( + "is" + + NameUtils.getSimpleName(annoMirror) + + "[v] = i -> variable(v), boolean(i).\n"); } for (AnnotationMirror annoMirror : lattice.allTypes) { String simpleName = NameUtils.getSimpleName(annoMirror); - basicEncoding.append("AnnotationOf[v] = \"" + simpleName + "\" <- " + "is" + simpleName + "[v] = true.\n"); + basicEncoding.append( + "AnnotationOf[v] = \"" + + simpleName + + "\" <- " + + "is" + + simpleName + + "[v] = true.\n"); } for (AnnotationMirror rightAnnoMirror : lattice.allTypes) { for (AnnotationMirror leftAnnoMirror : lattice.allTypes) { String leftAnnoName = NameUtils.getSimpleName(leftAnnoMirror); String rightAnnoName = NameUtils.getSimpleName(rightAnnoMirror); if (!leftAnnoName.equals(rightAnnoName)) { - basicEncoding.append("is" + leftAnnoName + "[v] = false <- is" + rightAnnoName + "[v] = true.\n"); + basicEncoding.append( + "is" + + leftAnnoName + + "[v] = false <- is" + + rightAnnoName + + "[v] = true.\n"); } - } } return basicEncoding.toString(); } - - /** - * write all encoding generated by this class to file LogiqlEncoding.logic. - * - * - */ + + /** write all encoding generated by this class to file LogiqlEncoding.logic. */ private void writeFile(String output) { String[] lines = output.split("\r\n|\r|\n"); Statistics.addOrIncrementEntry("logiql_predicate_size", lines.length); diff --git a/src/checkers/inference/solver/backend/logiql/LogiQLSolver.java b/src/checkers/inference/solver/backend/logiql/LogiQLSolver.java index b66bb5214..275b1458e 100644 --- a/src/checkers/inference/solver/backend/logiql/LogiQLSolver.java +++ b/src/checkers/inference/solver/backend/logiql/LogiQLSolver.java @@ -19,13 +19,12 @@ import checkers.inference.solver.util.Statistics; /** - * LogiQLSolver first creates LogiQL predicates text, then calls format translator - * converts constraint into LogiQL data. With both predicate and data created, - * it calls LogicBloxRunner that runs logicblox to solve the LogiQL, and reads - * the output. Finally the output will be sent to DecodingTool and get decoded. + * LogiQLSolver first creates LogiQL predicates text, then calls format translator converts + * constraint into LogiQL data. With both predicate and data created, it calls LogicBloxRunner that + * runs logicblox to solve the LogiQL, and reads the output. Finally the output will be sent to + * DecodingTool and get decoded. * * @author jianchu - * */ public class LogiQLSolver extends Solver { @@ -36,10 +35,14 @@ public class LogiQLSolver extends Solver { private long serializationEnd; private long solvingStart; private long solvingEnd; - public LogiQLSolver(SolverEnvironment solverEnvironment, Collection slots, - Collection constraints, LogiQLFormatTranslator formatTranslator, Lattice lattice) { - super(solverEnvironment, slots, constraints, formatTranslator, - lattice); + + public LogiQLSolver( + SolverEnvironment solverEnvironment, + Collection slots, + Collection constraints, + LogiQLFormatTranslator formatTranslator, + Lattice lattice) { + super(solverEnvironment, slots, constraints, formatTranslator, lattice); logiqldata.mkdir(); } @@ -49,18 +52,17 @@ public Map solve() { String logiqldataPath = logiqldata.getAbsolutePath(); Map result = new HashMap<>(); /** - * creating a instance of LogiqlConstraintGenerator and running - * GenerateLogiqlEncoding method, in order to generate the logiql fixed - * encoding part of current type system. + * creating a instance of LogiqlConstraintGenerator and running GenerateLogiqlEncoding + * method, in order to generate the logiql fixed encoding part of current type system. */ - LogiQLPredicateGenerator constraintGenerator = new LogiQLPredicateGenerator(logiqldataPath, - lattice, localNth); + LogiQLPredicateGenerator constraintGenerator = + new LogiQLPredicateGenerator(logiqldataPath, lattice, localNth); constraintGenerator.GenerateLogiqlEncoding(); this.serializationStart = System.currentTimeMillis(); this.encodeAllConstraints(); this.serializationEnd = System.currentTimeMillis(); - Statistics.addOrIncrementEntry("logiql_serialization_time(ms)", - (serializationEnd - serializationStart)); + Statistics.addOrIncrementEntry( + "logiql_serialization_time(ms)", (serializationEnd - serializationStart)); addVariables(); addConstants(); writeLogiQLData(logiqldataPath, localNth); @@ -72,7 +74,7 @@ public Map solve() { Statistics.addOrIncrementEntry("logiql_solving_time(ms)", (solvingEnd - solvingStart)); - //TODO: Refactor this to let Translator take the responsiblity of decoding. + // TODO: Refactor this to let Translator take the responsiblity of decoding. DecodingTool DecodeTool = new DecodingTool(varSlotIds, logiqldataPath, lattice, localNth); result = DecodeTool.decodeResult(); return result; @@ -80,7 +82,7 @@ public Map solve() { @Override public Collection explainUnsatisfiable() { - return new HashSet<>();// Doesn't support right now + return new HashSet<>(); // Doesn't support right now } @Override diff --git a/src/checkers/inference/solver/backend/logiql/LogiQLSolverFactory.java b/src/checkers/inference/solver/backend/logiql/LogiQLSolverFactory.java index 48ce1eec0..bf8fa23af 100644 --- a/src/checkers/inference/solver/backend/logiql/LogiQLSolverFactory.java +++ b/src/checkers/inference/solver/backend/logiql/LogiQLSolverFactory.java @@ -12,8 +12,11 @@ public class LogiQLSolverFactory extends AbstractSolverFactory { @Override - public Solver createSolver(SolverEnvironment solverEnvironment, Collection slots, - Collection constraints, Lattice lattice) { + public Solver createSolver( + SolverEnvironment solverEnvironment, + Collection slots, + Collection constraints, + Lattice lattice) { LogiQLFormatTranslator formatTranslator = createFormatTranslator(lattice); return new LogiQLSolver(solverEnvironment, slots, constraints, formatTranslator, lattice); } @@ -22,5 +25,4 @@ public Solver createSolver(SolverEnvironment solverEnvironment, Collection { private static String EMPTY_STRING = ""; diff --git a/src/checkers/inference/solver/backend/logiql/encoder/LogiQLComparableConstraintEncoder.java b/src/checkers/inference/solver/backend/logiql/encoder/LogiQLComparableConstraintEncoder.java index 68a127f22..371be03cd 100644 --- a/src/checkers/inference/solver/backend/logiql/encoder/LogiQLComparableConstraintEncoder.java +++ b/src/checkers/inference/solver/backend/logiql/encoder/LogiQLComparableConstraintEncoder.java @@ -6,7 +6,8 @@ import checkers.inference.solver.frontend.Lattice; import checkers.inference.solver.util.NameUtils; -public class LogiQLComparableConstraintEncoder extends LogiQLAbstractConstraintEncoder implements ComparableConstraintEncoder { +public class LogiQLComparableConstraintEncoder extends LogiQLAbstractConstraintEncoder + implements ComparableConstraintEncoder { public LogiQLComparableConstraintEncoder(Lattice lattice) { super(lattice); @@ -14,8 +15,12 @@ public LogiQLComparableConstraintEncoder(Lattice lattice) { @Override public String encodeVariable_Variable(VariableSlot fst, VariableSlot snd) { - String logiQLData = "+comparableConstraint(v1, v2), +variable(v1), +hasvariableName[v1] = " - + fst.getId() + ", +variable(v2), +hasvariableName[v2] = " + snd.getId() + ".\n"; + String logiQLData = + "+comparableConstraint(v1, v2), +variable(v1), +hasvariableName[v1] = " + + fst.getId() + + ", +variable(v2), +hasvariableName[v2] = " + + snd.getId() + + ".\n"; return logiQLData; } @@ -28,8 +33,12 @@ public String encodeVariable_Constant(VariableSlot fst, ConstantSlot snd) { public String encodeConstant_Variable(ConstantSlot fst, VariableSlot snd) { String constantName = NameUtils.getSimpleName(fst.getValue()); int variableId = snd.getId(); - String logiQLData = "+equalityConstraintContainsConstant(c, v), +constant(c), +hasconstantName[c] = \"" - + constantName + "\", +variable(v), +hasvariableName[v] = " + variableId + ".\n"; + String logiQLData = + "+equalityConstraintContainsConstant(c, v), +constant(c), +hasconstantName[c] = \"" + + constantName + + "\", +variable(v), +hasvariableName[v] = " + + variableId + + ".\n"; return logiQLData; } } diff --git a/src/checkers/inference/solver/backend/logiql/encoder/LogiQLConstraintEncoderFactory.java b/src/checkers/inference/solver/backend/logiql/encoder/LogiQLConstraintEncoderFactory.java index 76990b819..6d23220fe 100644 --- a/src/checkers/inference/solver/backend/logiql/encoder/LogiQLConstraintEncoderFactory.java +++ b/src/checkers/inference/solver/backend/logiql/encoder/LogiQLConstraintEncoderFactory.java @@ -15,13 +15,16 @@ import checkers.inference.solver.frontend.Lattice; /** - * LogiQL implementation of {@link checkers.inference.solver.backend.encoder.ConstraintEncoderFactory}. + * LogiQL implementation of {@link + * checkers.inference.solver.backend.encoder.ConstraintEncoderFactory}. * * @see checkers.inference.solver.backend.encoder.ConstraintEncoderFactory */ -public class LogiQLConstraintEncoderFactory extends AbstractConstraintEncoderFactory { +public class LogiQLConstraintEncoderFactory + extends AbstractConstraintEncoderFactory { - public LogiQLConstraintEncoderFactory(Lattice lattice, LogiQLFormatTranslator formatTranslator) { + public LogiQLConstraintEncoderFactory( + Lattice lattice, LogiQLFormatTranslator formatTranslator) { super(lattice, formatTranslator); } diff --git a/src/checkers/inference/solver/backend/logiql/encoder/LogiQLEqualityConstraintEncoder.java b/src/checkers/inference/solver/backend/logiql/encoder/LogiQLEqualityConstraintEncoder.java index ba4a9653f..3c680974b 100644 --- a/src/checkers/inference/solver/backend/logiql/encoder/LogiQLEqualityConstraintEncoder.java +++ b/src/checkers/inference/solver/backend/logiql/encoder/LogiQLEqualityConstraintEncoder.java @@ -6,7 +6,8 @@ import checkers.inference.solver.frontend.Lattice; import checkers.inference.solver.util.NameUtils; -public class LogiQLEqualityConstraintEncoder extends LogiQLAbstractConstraintEncoder implements EqualityConstraintEncoder { +public class LogiQLEqualityConstraintEncoder extends LogiQLAbstractConstraintEncoder + implements EqualityConstraintEncoder { public LogiQLEqualityConstraintEncoder(Lattice lattice) { super(lattice); @@ -14,8 +15,12 @@ public LogiQLEqualityConstraintEncoder(Lattice lattice) { @Override public String encodeVariable_Variable(VariableSlot fst, VariableSlot snd) { - String logiQLData = "+equalityConstraint(v1, v2), +variable(v1), +hasvariableName[v1] = " - + fst.getId() + ", +variable(v2), +hasvariableName[v2] = " + snd.getId() + ".\n"; + String logiQLData = + "+equalityConstraint(v1, v2), +variable(v1), +hasvariableName[v1] = " + + fst.getId() + + ", +variable(v2), +hasvariableName[v2] = " + + snd.getId() + + ".\n"; return logiQLData; } @@ -28,8 +33,12 @@ public String encodeVariable_Constant(VariableSlot fst, ConstantSlot snd) { public String encodeConstant_Variable(ConstantSlot fst, VariableSlot snd) { String constantName = NameUtils.getSimpleName(fst.getValue()); int variableId = snd.getId(); - String logiQLData = "+equalityConstraintContainsConstant(c, v), +constant(c), +hasconstantName[c] = \"" - + constantName + "\", +variable(v), +hasvariableName[v] = " + variableId + ".\n"; + String logiQLData = + "+equalityConstraintContainsConstant(c, v), +constant(c), +hasconstantName[c] = \"" + + constantName + + "\", +variable(v), +hasvariableName[v] = " + + variableId + + ".\n"; return logiQLData; } } diff --git a/src/checkers/inference/solver/backend/logiql/encoder/LogiQLInequalityConstraintEncoder.java b/src/checkers/inference/solver/backend/logiql/encoder/LogiQLInequalityConstraintEncoder.java index 412539fa7..8137c8a91 100644 --- a/src/checkers/inference/solver/backend/logiql/encoder/LogiQLInequalityConstraintEncoder.java +++ b/src/checkers/inference/solver/backend/logiql/encoder/LogiQLInequalityConstraintEncoder.java @@ -6,7 +6,8 @@ import checkers.inference.solver.frontend.Lattice; import checkers.inference.solver.util.NameUtils; -public class LogiQLInequalityConstraintEncoder extends LogiQLAbstractConstraintEncoder implements InequalityConstraintEncoder { +public class LogiQLInequalityConstraintEncoder extends LogiQLAbstractConstraintEncoder + implements InequalityConstraintEncoder { public LogiQLInequalityConstraintEncoder(Lattice lattice) { super(lattice); @@ -14,8 +15,12 @@ public LogiQLInequalityConstraintEncoder(Lattice lattice) { @Override public String encodeVariable_Variable(VariableSlot fst, VariableSlot snd) { - String logiQLData = "+inequalityConstraint(v1, v2), +variable(v1), +hasvariableName[v1] = " - + fst.getId() + ", +variable(v2), +hasvariableName[v2] = " + snd.getId() + ".\n"; + String logiQLData = + "+inequalityConstraint(v1, v2), +variable(v1), +hasvariableName[v1] = " + + fst.getId() + + ", +variable(v2), +hasvariableName[v2] = " + + snd.getId() + + ".\n"; return logiQLData; } @@ -28,8 +33,12 @@ public String encodeVariable_Constant(VariableSlot fst, ConstantSlot snd) { public String encodeConstant_Variable(ConstantSlot fst, VariableSlot snd) { String constantName = NameUtils.getSimpleName(fst.getValue()); int variableId = snd.getId(); - String logiQLData = "+inequalityConstraintContainsConstant(c, v), +constant(c), +hasconstantName[c] = \"" - + constantName + "\", +variable(v), +hasvariableName[v] = " + variableId + ".\n"; + String logiQLData = + "+inequalityConstraintContainsConstant(c, v), +constant(c), +hasconstantName[c] = \"" + + constantName + + "\", +variable(v), +hasvariableName[v] = " + + variableId + + ".\n"; return logiQLData; } } diff --git a/src/checkers/inference/solver/backend/logiql/encoder/LogiQLSubtypeConstraintEncoder.java b/src/checkers/inference/solver/backend/logiql/encoder/LogiQLSubtypeConstraintEncoder.java index 5ebd3b4b2..4ea851b17 100644 --- a/src/checkers/inference/solver/backend/logiql/encoder/LogiQLSubtypeConstraintEncoder.java +++ b/src/checkers/inference/solver/backend/logiql/encoder/LogiQLSubtypeConstraintEncoder.java @@ -6,7 +6,8 @@ import checkers.inference.solver.frontend.Lattice; import checkers.inference.solver.util.NameUtils; -public class LogiQLSubtypeConstraintEncoder extends LogiQLAbstractConstraintEncoder implements SubtypeConstraintEncoder { +public class LogiQLSubtypeConstraintEncoder extends LogiQLAbstractConstraintEncoder + implements SubtypeConstraintEncoder { public LogiQLSubtypeConstraintEncoder(Lattice lattice) { super(lattice); @@ -14,9 +15,12 @@ public LogiQLSubtypeConstraintEncoder(Lattice lattice) { @Override public String encodeVariable_Variable(VariableSlot subtype, VariableSlot supertype) { - String logiQLData = "+subtypeConstraint(v1, v2), +variable(v1), +hasvariableName[v1] = " - + subtype.getId() + ", +variable(v2), +hasvariableName[v2] = " + supertype.getId() - + ".\n"; + String logiQLData = + "+subtypeConstraint(v1, v2), +variable(v1), +hasvariableName[v1] = " + + subtype.getId() + + ", +variable(v2), +hasvariableName[v2] = " + + supertype.getId() + + ".\n"; return logiQLData; } @@ -24,8 +28,12 @@ public String encodeVariable_Variable(VariableSlot subtype, VariableSlot superty public String encodeVariable_Constant(VariableSlot subtype, ConstantSlot supertype) { String supertypeName = NameUtils.getSimpleName(supertype.getValue()); int subtypeId = subtype.getId(); - String logiQLData = "+subtypeConstraintRightConstant(v, c), +variable(v), +hasvariableName[v] = " - + subtypeId + ", +constant(c), +hasconstantName[c] = \"" + supertypeName + "\" .\n"; + String logiQLData = + "+subtypeConstraintRightConstant(v, c), +variable(v), +hasvariableName[v] = " + + subtypeId + + ", +constant(c), +hasconstantName[c] = \"" + + supertypeName + + "\" .\n"; return logiQLData; } @@ -33,8 +41,12 @@ public String encodeVariable_Constant(VariableSlot subtype, ConstantSlot superty public String encodeConstant_Variable(ConstantSlot subtype, VariableSlot supertype) { String subtypeName = NameUtils.getSimpleName(subtype.getValue()); int supertypeId = supertype.getId(); - String logiQLData = "+subtypeConstraintLeftConstant(c, v), +constant(c), +hasconstantName[c] = \"" - + subtypeName + "\", +variable(v), +hasvariableName[v] = " + supertypeId + ".\n"; + String logiQLData = + "+subtypeConstraintLeftConstant(c, v), +constant(c), +hasconstantName[c] = \"" + + subtypeName + + "\", +variable(v), +hasvariableName[v] = " + + supertypeId + + ".\n"; return logiQLData; } } diff --git a/src/checkers/inference/solver/backend/maxsat/MathUtils.java b/src/checkers/inference/solver/backend/maxsat/MathUtils.java index 25a13891b..3aaf93581 100644 --- a/src/checkers/inference/solver/backend/maxsat/MathUtils.java +++ b/src/checkers/inference/solver/backend/maxsat/MathUtils.java @@ -4,20 +4,20 @@ /** * Methods convert between slot id and Max-SAT id. - * - * @author jianchu * + * @author jianchu */ public class MathUtils { /** - * Given a varSlot id, the integer representation of a type, and the lattice, map these to - * an int represents the boolean variable in SAT solver, that represents the case of - * this varSlot is the given type. (so the negative of the return value would be - * this varSlot is not the given type.) + * Given a varSlot id, the integer representation of a type, and the lattice, map these to an + * int represents the boolean variable in SAT solver, that represents the case of this varSlot + * is the given type. (so the negative of the return value would be this varSlot is not the + * given type.) + * * @param varId the slot id of the varSlot * @param typeInt the integer representation of a type - * @param lattice target lattice + * @param lattice target lattice * @return an integer represents a boolean variable in SAT solver */ public static int mapIdToMatrixEntry(int varId, int typeInt, Lattice lattice) { diff --git a/src/checkers/inference/solver/backend/maxsat/MaxSatFormatTranslator.java b/src/checkers/inference/solver/backend/maxsat/MaxSatFormatTranslator.java index ba00372c1..c4d6c4da0 100644 --- a/src/checkers/inference/solver/backend/maxsat/MaxSatFormatTranslator.java +++ b/src/checkers/inference/solver/backend/maxsat/MaxSatFormatTranslator.java @@ -1,5 +1,8 @@ package checkers.inference.solver.backend.maxsat; +import org.checkerframework.javacutil.AnnotationMirrorMap; +import org.sat4j.core.VecInt; + import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -12,44 +15,37 @@ import checkers.inference.solver.backend.AbstractFormatTranslator; import checkers.inference.solver.backend.encoder.ConstraintEncoderFactory; import checkers.inference.solver.backend.maxsat.encoder.MaxSATConstraintEncoderFactory; -import org.checkerframework.javacutil.AnnotationMirrorMap; -import org.checkerframework.javacutil.AnnotationUtils; -import org.sat4j.core.VecInt; - import checkers.inference.solver.frontend.Lattice; /** * MaxSatFormatTranslator converts constraint into array of VecInt as clauses. * * @author jianchu - * */ - public class MaxSatFormatTranslator extends AbstractFormatTranslator { /** - * typeToInt maps each type qualifier to an unique integer value starts from - * 0 on continuous basis. + * typeToInt maps each type qualifier to an unique integer value starts from 0 on continuous + * basis. */ protected final Map typeToInt; /** - * intToType maps an integer value to each type qualifier, which is a - * reversed map of typeToInt. + * intToType maps an integer value to each type qualifier, which is a reversed map of typeToInt. */ protected final Map intToType; public MaxSatFormatTranslator(Lattice lattice) { super(lattice); // Initialize mappings between type and int. - MaptypeToIntRes = new AnnotationMirrorMap<>(); + Map typeToIntRes = new AnnotationMirrorMap<>(); Map intToTypeRes = new HashMap(); int curInt = 0; for (AnnotationMirror type : lattice.allTypes) { typeToIntRes.put(type, curInt); intToTypeRes.put(curInt, type); - curInt ++; + curInt++; } typeToInt = Collections.unmodifiableMap(typeToIntRes); @@ -62,12 +58,9 @@ protected ConstraintEncoderFactory createConstraintEncoderFactory() { return new MaxSATConstraintEncoderFactory(lattice, typeToInt, this); } - /** - * generate well form clauses such that there is one and only one beta value - * can be true. - * - */ - public void generateWellFormednessClauses(List wellFormednessClauses, Integer varSlotId) { + /** generate well form clauses such that there is one and only one beta value can be true. */ + public void generateWellFormednessClauses( + List wellFormednessClauses, Integer varSlotId) { int[] leastOneIsTrue = new int[lattice.numTypes]; for (Integer i : intToType.keySet()) { leastOneIsTrue[i] = MathUtils.mapIdToMatrixEntry(varSlotId, i.intValue(), lattice); @@ -85,8 +78,8 @@ public void generateWellFormednessClauses(List wellFormednessClauses, In } @Override - public AnnotationMirror decodeSolution(Integer var, ProcessingEnvironment processingEnvironment) { + public AnnotationMirror decodeSolution( + Integer var, ProcessingEnvironment processingEnvironment) { return intToType.get(MathUtils.getIntRep(var, lattice)); } - } diff --git a/src/checkers/inference/solver/backend/maxsat/MaxSatSolver.java b/src/checkers/inference/solver/backend/maxsat/MaxSatSolver.java index 2986f7b23..7226aa59f 100644 --- a/src/checkers/inference/solver/backend/maxsat/MaxSatSolver.java +++ b/src/checkers/inference/solver/backend/maxsat/MaxSatSolver.java @@ -1,5 +1,16 @@ package checkers.inference.solver.backend.maxsat; +import org.checkerframework.javacutil.BugInCF; +import org.plumelib.util.IPair; +import org.sat4j.core.VecInt; +import org.sat4j.maxsat.SolverFactory; +import org.sat4j.maxsat.WeightedMaxSatDecorator; +import org.sat4j.pb.IPBSolver; +import org.sat4j.specs.ContradictionException; +import org.sat4j.specs.IConstr; +import org.sat4j.tools.xplain.DeletionStrategy; +import org.sat4j.tools.xplain.Xplain; + import java.io.File; import java.util.Collection; import java.util.HashMap; @@ -12,17 +23,6 @@ import javax.lang.model.element.AnnotationMirror; -import org.checkerframework.javacutil.BugInCF; -import org.plumelib.util.IPair; -import org.sat4j.core.VecInt; -import org.sat4j.maxsat.SolverFactory; -import org.sat4j.maxsat.WeightedMaxSatDecorator; -import org.sat4j.pb.IPBSolver; -import org.sat4j.specs.ContradictionException; -import org.sat4j.specs.IConstr; -import org.sat4j.tools.xplain.DeletionStrategy; -import org.sat4j.tools.xplain.Xplain; - import checkers.inference.InferenceMain; import checkers.inference.SlotManager; import checkers.inference.model.Constraint; @@ -36,18 +36,15 @@ import checkers.inference.solver.util.Statistics; /** - * MaxSatSolver calls MaxSatFormatTranslator that converts constraint into a list of - * VecInt, then invoke Sat4j lib to solve the clauses, and decode the result. + * MaxSatSolver calls MaxSatFormatTranslator that converts constraint into a list of VecInt, then + * invoke Sat4j lib to solve the clauses, and decode the result. * * @author jianchu - * */ public class MaxSatSolver extends Solver { protected enum MaxSatSolverArg implements SolverArg { - /** - * Whether should print the CNF formulas. - */ + /** Whether should print the CNF formulas. */ outputCNF; } @@ -64,10 +61,13 @@ protected enum MaxSatSolverArg implements SolverArg { protected long solvingStart; protected long solvingEnd; - public MaxSatSolver(SolverEnvironment solverEnvironment, Collection slots, - Collection constraints, MaxSatFormatTranslator formatTranslator, Lattice lattice) { - super(solverEnvironment, slots, constraints, formatTranslator, - lattice); + public MaxSatSolver( + SolverEnvironment solverEnvironment, + Collection slots, + Collection constraints, + MaxSatFormatTranslator formatTranslator, + Lattice lattice) { + super(solverEnvironment, slots, constraints, formatTranslator, lattice); this.slotManager = InferenceMain.getInstance().getSlotManager(); if (shouldOutputCNF()) { @@ -79,8 +79,8 @@ public MaxSatSolver(SolverEnvironment solverEnvironment, Collection slots, public Map solve() { Map solutions = null; - final WeightedMaxSatDecorator solver = new WeightedMaxSatDecorator( - org.sat4j.pb.SolverFactory.newBoth()); + final WeightedMaxSatDecorator solver = + new WeightedMaxSatDecorator(org.sat4j.pb.SolverFactory.newBoth()); this.serializationStart = System.currentTimeMillis(); // Serialization step: @@ -119,7 +119,8 @@ public Map solve() { } catch (ContradictionException e) { InferenceMain.getInstance().logger.warning("Contradiction exception: "); - // This case indicates that constraints are not solvable, too. This is normal so continue + // This case indicates that constraints are not solvable, too. This is normal so + // continue // execution and let solver strategy to explain why there is no solution unsatisfiableConstraintExplainer = new MaxSATUnsatisfiableConstraintExplainer(); } catch (Exception e) { @@ -128,24 +129,28 @@ public Map solve() { return solutions; } - /** - * Convert constraints to list of VecInt. - */ + /** Convert constraints to list of VecInt. */ @Override public void encodeAllConstraints() { for (Constraint constraint : constraints) { collectVarSlots(constraint); VecInt[] encoding = constraint.serialize(formatTranslator); if (encoding == null) { - InferenceMain.getInstance().logger.warning(getClass() - + " doesn't support encoding constraint: " + constraint - + "of class: " + constraint.getClass()); + InferenceMain.getInstance() + .logger + .warning( + getClass() + + " doesn't support encoding constraint: " + + constraint + + "of class: " + + constraint.getClass()); continue; } for (VecInt res : encoding) { if (res != null && res.size() != 0) { if (constraint instanceof PreferenceConstraint) { - softClauses.add(IPair.of(res, ((PreferenceConstraint) constraint).getWeight())); + softClauses.add( + IPair.of(res, ((PreferenceConstraint) constraint).getWeight())); } else { hardClauses.add(res); } @@ -168,7 +173,8 @@ protected void encodeWellFormednessRestriction() { private void configureSatSolver(WeightedMaxSatDecorator solver) { final int totalVars = (slotManager.getNumberOfSlots() * lattice.numTypes); - final int totalClauses = hardClauses.size() + wellFormednessClauses.size() + softClauses.size(); + final int totalClauses = + hardClauses.size() + wellFormednessClauses.size() + softClauses.size(); solver.newVar(totalVars); solver.setExpectedNumberOfClauses(totalClauses); @@ -182,7 +188,7 @@ private void addClausesToSolver(WeightedMaxSatDecorator solver) throws Contradic solver.addHardClause(hardClause); } - for (VecInt wellFormednessClause: wellFormednessClauses) { + for (VecInt wellFormednessClause : wellFormednessClauses) { solver.addHardClause(wellFormednessClause); } @@ -203,7 +209,9 @@ protected Map decode(int[] solution) { if (var > 0) { var = var - 1; int slotId = MathUtils.getSlotId(var, lattice); - AnnotationMirror type = formatTranslator.decodeSolution(var, solverEnvironment.processingEnvironment); + AnnotationMirror type = + formatTranslator.decodeSolution( + var, solverEnvironment.processingEnvironment); result.put(slotId, type); } } @@ -226,12 +234,10 @@ protected boolean shouldOutputCNF() { return solverEnvironment.getBoolArg(MaxSatSolverArg.outputCNF); } - /** - * Write CNF clauses into a string. - */ + /** Write CNF clauses into a string. */ protected void buildCNFInput() { - final int totalClauses = hardClauses.size()+ wellFormednessClauses.size(); + final int totalClauses = hardClauses.size() + wellFormednessClauses.size(); final int totalVars = slotManager.getNumberOfSlots() * lattice.numTypes; CNFInput.append("c This is the CNF input\n"); @@ -244,7 +250,7 @@ protected void buildCNFInput() { for (VecInt hardClause : hardClauses) { buildCNFInputHelper(hardClause); } - for (VecInt wellFormedNessClause: wellFormednessClauses) { + for (VecInt wellFormedNessClause : wellFormednessClauses) { buildCNFInputHelper(wellFormedNessClause); } } @@ -266,9 +272,7 @@ protected void writeCNFInput(String file) { FileUtils.writeFile(new File(CNFData.getAbsolutePath() + "/" + file), CNFInput.toString()); } - /** - * print all soft and hard clauses for testing. - */ + /** print all soft and hard clauses for testing. */ protected void printClauses() { System.out.println("Hard clauses: "); for (VecInt hardClause : hardClauses) { @@ -276,7 +280,7 @@ protected void printClauses() { } System.out.println(); System.out.println("WellFormedness clauses: "); - for (VecInt wellFormednessClause: wellFormednessClauses) { + for (VecInt wellFormednessClause : wellFormednessClauses) { System.out.println(wellFormednessClause); } System.out.println(); @@ -293,15 +297,10 @@ public Collection explainUnsatisfiable() { class MaxSATUnsatisfiableConstraintExplainer { - /** - * A mapping from VecInt to Constraint. - * */ + /** A mapping from VecInt to Constraint. */ private final Map vecIntConstraintMap; - /** - * A mapping from IConstr to VecInt. IConstr is the result of adding VecInt to solver. - */ - + /** A mapping from IConstr to VecInt. IConstr is the result of adding VecInt to solver. */ private final Map iConstrVecIntMap; private MaxSATUnsatisfiableConstraintExplainer() { @@ -315,7 +314,6 @@ private MaxSATUnsatisfiableConstraintExplainer() { // explanation solver fillHardClauses(); encodeWellFormednessRestriction(); - } // Compared to encodeAllConstrains(), this method doesn't format translate soft clauses, @@ -330,7 +328,9 @@ private void fillHardClauses() { continue; } for (VecInt e : encoding) { - if (e != null && e.size() != 0 && !(constraint instanceof PreferenceConstraint)) { + if (e != null + && e.size() != 0 + && !(constraint instanceof PreferenceConstraint)) { hardClauses.add(e); vecIntConstraintMap.put(e, constraint); } @@ -339,12 +339,14 @@ private void fillHardClauses() { } public Collection minimumUnsatisfiableConstraints() { - // It's ok to use HashSet for Constraint, because its hashCose() implementation differentiates different + // It's ok to use HashSet for Constraint, because its hashCose() implementation + // differentiates different // Constraints well. Set mus = new HashSet<>(); // Explainer solver that is used Xplain explanationSolver = new Xplain<>(SolverFactory.newDefault()); - configureExplanationSolver(hardClauses, wellFormednessClauses, slotManager, lattice, explanationSolver); + configureExplanationSolver( + hardClauses, wellFormednessClauses, slotManager, lattice, explanationSolver); try { addClausesToExplanationSolver(explanationSolver); assert !explanationSolver.isSatisfiable(); @@ -358,7 +360,8 @@ public Collection minimumUnsatisfiableConstraints() { mus.add(vecIntConstraintMap.get(vecInt)); } else { // This case indicates vecInt is well-formedness restriction - // TODO Instead of printing it, can we have a dedicated type, e.g. WellFormednessConstraint <: Constraint + // TODO Instead of printing it, can we have a dedicated type, e.g. + // WellFormednessConstraint <: Constraint // TODO so that we can also add it to the result set? System.out.println("Explanation hits well-formedness restriction: " + i); } @@ -369,8 +372,12 @@ public Collection minimumUnsatisfiableConstraints() { return mus; } - private void configureExplanationSolver(final List hardClauses, final List wellformedness, - final SlotManager slotManager, final Lattice lattice, final Xplain explainer) { + private void configureExplanationSolver( + final List hardClauses, + final List wellformedness, + final SlotManager slotManager, + final Lattice lattice, + final Xplain explainer) { int numberOfNewVars = slotManager.getNumberOfSlots() * lattice.numTypes; System.out.println("Number of variables: " + numberOfNewVars); int numberOfClauses = hardClauses.size() + wellformedness.size(); @@ -380,11 +387,11 @@ private void configureExplanationSolver(final List hardClauses, final Li explainer.setExpectedNumberOfClauses(numberOfClauses); } - private void addClausesToExplanationSolver(Xplain explanationSolver) throws ContradictionException { + private void addClausesToExplanationSolver(Xplain explanationSolver) + throws ContradictionException { for (VecInt clause : hardClauses) { IConstr iConstr = explanationSolver.addClause(clause); iConstrVecIntMap.put(iConstr, clause); - } for (VecInt clause : wellFormednessClauses) { IConstr iConstr = explanationSolver.addClause(clause); diff --git a/src/checkers/inference/solver/backend/maxsat/MaxSatSolverFactory.java b/src/checkers/inference/solver/backend/maxsat/MaxSatSolverFactory.java index 1b1fed932..2fbf96e67 100644 --- a/src/checkers/inference/solver/backend/maxsat/MaxSatSolverFactory.java +++ b/src/checkers/inference/solver/backend/maxsat/MaxSatSolverFactory.java @@ -12,8 +12,11 @@ public class MaxSatSolverFactory extends AbstractSolverFactory { @Override - public Solver createSolver(SolverEnvironment solverEnvironment, Collection slots, - Collection constraints, Lattice lattice) { + public Solver createSolver( + SolverEnvironment solverEnvironment, + Collection slots, + Collection constraints, + Lattice lattice) { MaxSatFormatTranslator formatTranslator = createFormatTranslator(lattice); return new MaxSatSolver(solverEnvironment, slots, constraints, formatTranslator, lattice); } @@ -22,5 +25,4 @@ public Solver createSolver(SolverEnvironment solverEnvironment, Collection { private static VecInt[] EMPTY_CLAUSE = new VecInt[0]; - // Any contradictory two clauses can be used to model contradiction. But here 1,-1 are chosen because it's simple and - // doesn't collides with real variable id 1 since 1 is almost always reserved for ConstantSlot(because every type system must - // have at least one real qualifier). The only exception to this assumption is when storeConstants is false when initializing + // Any contradictory two clauses can be used to model contradiction. But here 1,-1 are chosen + // because it's simple and + // doesn't collides with real variable id 1 since 1 is almost always reserved for + // ConstantSlot(because every type system must + // have at least one real qualifier). The only exception to this assumption is when + // storeConstants is false when initializing // DefaultSlotManager, but right now all the creation of DefaultSlotManager stores constants. - private static VecInt[] CONTRADICTORY_CLAUSES = new VecInt[]{VectorUtils.asVec(1), VectorUtils.asVec(-1)}; + private static VecInt[] CONTRADICTORY_CLAUSES = + new VecInt[] {VectorUtils.asVec(1), VectorUtils.asVec(-1)}; /** - * A map shared by every MaxSAT constraint encoder. - * See {@link checkers.inference.solver.backend.maxsat.MaxSatFormatTranslator#typeToInt} for what is stored. + * A map shared by every MaxSAT constraint encoder. See {@link + * checkers.inference.solver.backend.maxsat.MaxSatFormatTranslator#typeToInt} for what is + * stored. */ protected final Map typeToInt; - public MaxSATAbstractConstraintEncoder(Lattice lattice, Map typeToInt) { + public MaxSATAbstractConstraintEncoder( + Lattice lattice, Map typeToInt) { super(lattice, EMPTY_CLAUSE, CONTRADICTORY_CLAUSES); this.typeToInt = typeToInt; } diff --git a/src/checkers/inference/solver/backend/maxsat/encoder/MaxSATComparableConstraintEncoder.java b/src/checkers/inference/solver/backend/maxsat/encoder/MaxSATComparableConstraintEncoder.java index a9cb02d9a..83eac97cf 100644 --- a/src/checkers/inference/solver/backend/maxsat/encoder/MaxSATComparableConstraintEncoder.java +++ b/src/checkers/inference/solver/backend/maxsat/encoder/MaxSATComparableConstraintEncoder.java @@ -1,21 +1,25 @@ package checkers.inference.solver.backend.maxsat.encoder; +import org.sat4j.core.VecInt; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.lang.model.element.AnnotationMirror; + import checkers.inference.model.ConstantSlot; import checkers.inference.model.VariableSlot; import checkers.inference.solver.backend.encoder.binary.ComparableConstraintEncoder; import checkers.inference.solver.backend.maxsat.MathUtils; import checkers.inference.solver.backend.maxsat.VectorUtils; import checkers.inference.solver.frontend.Lattice; -import org.sat4j.core.VecInt; - -import javax.lang.model.element.AnnotationMirror; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -public class MaxSATComparableConstraintEncoder extends MaxSATAbstractConstraintEncoder implements ComparableConstraintEncoder { +public class MaxSATComparableConstraintEncoder extends MaxSATAbstractConstraintEncoder + implements ComparableConstraintEncoder { - public MaxSATComparableConstraintEncoder(Lattice lattice, Map typeToInt) { + public MaxSATComparableConstraintEncoder( + Lattice lattice, Map typeToInt) { super(lattice, typeToInt); } @@ -26,11 +30,16 @@ public VecInt[] encodeVariable_Variable(VariableSlot fst, VariableSlot snd) { for (AnnotationMirror type : lattice.allTypes) { if (lattice.incomparableType.keySet().contains(type)) { for (AnnotationMirror notComparable : lattice.incomparableType.get(type)) { - list.add(VectorUtils.asVec( - -MathUtils.mapIdToMatrixEntry(fst.getId(), typeToInt.get(type), lattice), - -MathUtils.mapIdToMatrixEntry(snd.getId(), typeToInt.get(notComparable), lattice), - MathUtils.mapIdToMatrixEntry(snd.getId(), typeToInt.get(notComparable), lattice), - MathUtils.mapIdToMatrixEntry(fst.getId(), typeToInt.get(type), lattice))); + list.add( + VectorUtils.asVec( + -MathUtils.mapIdToMatrixEntry( + fst.getId(), typeToInt.get(type), lattice), + -MathUtils.mapIdToMatrixEntry( + snd.getId(), typeToInt.get(notComparable), lattice), + MathUtils.mapIdToMatrixEntry( + snd.getId(), typeToInt.get(notComparable), lattice), + MathUtils.mapIdToMatrixEntry( + fst.getId(), typeToInt.get(type), lattice))); } } } @@ -45,8 +54,9 @@ public VecInt[] encodeVariable_Constant(VariableSlot fst, ConstantSlot snd) { for (AnnotationMirror incomparable : lattice.incomparableType.get(snd.getValue())) { // Should not be equal to incomparable resultList.add( - VectorUtils.asVec( - -MathUtils.mapIdToMatrixEntry(fst.getId(), typeToInt.get(incomparable), lattice))); + VectorUtils.asVec( + -MathUtils.mapIdToMatrixEntry( + fst.getId(), typeToInt.get(incomparable), lattice))); } VecInt[] resultArray = new VecInt[resultList.size()]; return resultList.toArray(resultArray); diff --git a/src/checkers/inference/solver/backend/maxsat/encoder/MaxSATConstraintEncoderFactory.java b/src/checkers/inference/solver/backend/maxsat/encoder/MaxSATConstraintEncoderFactory.java index 4564052cd..5068ce5ed 100644 --- a/src/checkers/inference/solver/backend/maxsat/encoder/MaxSATConstraintEncoderFactory.java +++ b/src/checkers/inference/solver/backend/maxsat/encoder/MaxSATConstraintEncoderFactory.java @@ -1,29 +1,34 @@ package checkers.inference.solver.backend.maxsat.encoder; +import org.sat4j.core.VecInt; + +import java.util.Map; + +import javax.lang.model.element.AnnotationMirror; + import checkers.inference.solver.backend.encoder.AbstractConstraintEncoderFactory; import checkers.inference.solver.backend.encoder.ArithmeticConstraintEncoder; import checkers.inference.solver.backend.encoder.ComparisonConstraintEncoder; import checkers.inference.solver.backend.encoder.combine.CombineConstraintEncoder; import checkers.inference.solver.backend.encoder.existential.ExistentialConstraintEncoder; -import checkers.inference.solver.backend.encoder.implication.ImplicationConstraintEncoder; import checkers.inference.solver.backend.maxsat.MaxSatFormatTranslator; import checkers.inference.solver.frontend.Lattice; -import org.sat4j.core.VecInt; - -import javax.lang.model.element.AnnotationMirror; -import java.util.Map; /** - * MaxSAT implementation of {@link checkers.inference.solver.backend.encoder.ConstraintEncoderFactory}. + * MaxSAT implementation of {@link + * checkers.inference.solver.backend.encoder.ConstraintEncoderFactory}. * * @see checkers.inference.solver.backend.encoder.ConstraintEncoderFactory */ -public class MaxSATConstraintEncoderFactory extends AbstractConstraintEncoderFactory { +public class MaxSATConstraintEncoderFactory + extends AbstractConstraintEncoderFactory { private final Map typeToInt; - public MaxSATConstraintEncoderFactory(Lattice lattice, Map typeToInt, - MaxSatFormatTranslator formatTranslator) { + public MaxSATConstraintEncoderFactory( + Lattice lattice, + Map typeToInt, + MaxSatFormatTranslator formatTranslator) { super(lattice, formatTranslator); this.typeToInt = typeToInt; } diff --git a/src/checkers/inference/solver/backend/maxsat/encoder/MaxSATEqualityConstraintEncoder.java b/src/checkers/inference/solver/backend/maxsat/encoder/MaxSATEqualityConstraintEncoder.java index d42c2a188..e2bc5f7f1 100644 --- a/src/checkers/inference/solver/backend/maxsat/encoder/MaxSATEqualityConstraintEncoder.java +++ b/src/checkers/inference/solver/backend/maxsat/encoder/MaxSATEqualityConstraintEncoder.java @@ -1,19 +1,23 @@ package checkers.inference.solver.backend.maxsat.encoder; +import org.sat4j.core.VecInt; + +import java.util.Map; + +import javax.lang.model.element.AnnotationMirror; + import checkers.inference.model.ConstantSlot; import checkers.inference.model.VariableSlot; import checkers.inference.solver.backend.encoder.binary.EqualityConstraintEncoder; import checkers.inference.solver.backend.maxsat.MathUtils; import checkers.inference.solver.backend.maxsat.VectorUtils; import checkers.inference.solver.frontend.Lattice; -import org.sat4j.core.VecInt; - -import javax.lang.model.element.AnnotationMirror; -import java.util.Map; -public class MaxSATEqualityConstraintEncoder extends MaxSATAbstractConstraintEncoder implements EqualityConstraintEncoder { +public class MaxSATEqualityConstraintEncoder extends MaxSATAbstractConstraintEncoder + implements EqualityConstraintEncoder { - public MaxSATEqualityConstraintEncoder(Lattice lattice, Map typeToInt) { + public MaxSATEqualityConstraintEncoder( + Lattice lattice, Map typeToInt) { super(lattice, typeToInt); } @@ -24,12 +28,18 @@ public VecInt[] encodeVariable_Variable(VariableSlot fst, VariableSlot snd) { int i = 0; for (AnnotationMirror type : lattice.allTypes) { if (lattice.allTypes.contains(type)) { - result[i++] = VectorUtils.asVec( - -MathUtils.mapIdToMatrixEntry(fst.getId(), typeToInt.get(type), lattice), - MathUtils.mapIdToMatrixEntry(snd.getId(), typeToInt.get(type), lattice)); - result[i++] = VectorUtils.asVec( - -MathUtils.mapIdToMatrixEntry(snd.getId(), typeToInt.get(type), lattice), - MathUtils.mapIdToMatrixEntry(fst.getId(), typeToInt.get(type), lattice)); + result[i++] = + VectorUtils.asVec( + -MathUtils.mapIdToMatrixEntry( + fst.getId(), typeToInt.get(type), lattice), + MathUtils.mapIdToMatrixEntry( + snd.getId(), typeToInt.get(type), lattice)); + result[i++] = + VectorUtils.asVec( + -MathUtils.mapIdToMatrixEntry( + snd.getId(), typeToInt.get(type), lattice), + MathUtils.mapIdToMatrixEntry( + fst.getId(), typeToInt.get(type), lattice)); } } return result; @@ -44,7 +54,8 @@ public VecInt[] encodeVariable_Constant(VariableSlot fst, ConstantSlot snd) { public VecInt[] encodeConstant_Variable(ConstantSlot fst, VariableSlot snd) { if (lattice.allTypes.contains(fst.getValue())) { return VectorUtils.asVecArray( - MathUtils.mapIdToMatrixEntry(snd.getId(), typeToInt.get(fst.getValue()), lattice)); + MathUtils.mapIdToMatrixEntry( + snd.getId(), typeToInt.get(fst.getValue()), lattice)); } else { return emptyValue; } diff --git a/src/checkers/inference/solver/backend/maxsat/encoder/MaxSATImplicationConstraintEncoder.java b/src/checkers/inference/solver/backend/maxsat/encoder/MaxSATImplicationConstraintEncoder.java index 1e7a7d4f8..67e4a388c 100644 --- a/src/checkers/inference/solver/backend/maxsat/encoder/MaxSATImplicationConstraintEncoder.java +++ b/src/checkers/inference/solver/backend/maxsat/encoder/MaxSATImplicationConstraintEncoder.java @@ -1,30 +1,31 @@ package checkers.inference.solver.backend.maxsat.encoder; -import checkers.inference.model.Constraint; -import checkers.inference.model.ImplicationConstraint; -import checkers.inference.solver.backend.encoder.implication.ImplicationConstraintEncoder; -import checkers.inference.solver.backend.maxsat.MaxSatFormatTranslator; -import checkers.inference.solver.frontend.Lattice; import org.sat4j.core.VecInt; -import javax.lang.model.element.AnnotationMirror; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; -public class MaxSATImplicationConstraintEncoder - extends MaxSATAbstractConstraintEncoder +import javax.lang.model.element.AnnotationMirror; + +import checkers.inference.model.Constraint; +import checkers.inference.model.ImplicationConstraint; +import checkers.inference.solver.backend.encoder.implication.ImplicationConstraintEncoder; +import checkers.inference.solver.backend.maxsat.MaxSatFormatTranslator; +import checkers.inference.solver.frontend.Lattice; + +public class MaxSATImplicationConstraintEncoder extends MaxSATAbstractConstraintEncoder implements ImplicationConstraintEncoder { /** - * {@link MaxSatFormatTranslator} instance to delegate format translating - * base {@link Constraint}s ({@code Constraint}s that are not - * {@link ImplicationConstraint}). + * {@link MaxSatFormatTranslator} instance to delegate format translating base {@link + * Constraint}s ({@code Constraint}s that are not {@link ImplicationConstraint}). */ private final MaxSatFormatTranslator formatTranslator; - public MaxSATImplicationConstraintEncoder(Lattice lattice, + public MaxSATImplicationConstraintEncoder( + Lattice lattice, Map typeToInt, MaxSatFormatTranslator formatTranslator) { super(lattice, typeToInt); @@ -87,8 +88,7 @@ public VecInt[] encode(ImplicationConstraint constraint) { List> cartesian = cartesianProduct(l); // Concatenate with every pair at the end - VecInt[] conclusionClauses = constraint.getConclusion() - .serialize(formatTranslator); + VecInt[] conclusionClauses = constraint.getConclusion().serialize(formatTranslator); int expectedSize = cartesian.size() * conclusionClauses.length; @@ -120,13 +120,11 @@ public VecInt[] encode(ImplicationConstraint constraint) { /** * Method to get cartesian set of input set. * - * For example, if the input is [[1,2], [3,4,5]], this method returns + *

For example, if the input is [[1,2], [3,4,5]], this method returns * [[1,3],[1,4],[1,5],[2,3],[2,4],[2,5]] * - * @param lists - * a set of set of elements - * @param - * type of element + * @param lists a set of set of elements + * @param type of element * @return cartesian set of elements */ protected List> cartesianProduct(List> lists) { @@ -136,8 +134,7 @@ protected List> cartesianProduct(List> lists) { return resultLists; } else { List firstList = lists.get(0); - List> remainingLists = cartesianProduct( - lists.subList(1, lists.size())); + List> remainingLists = cartesianProduct(lists.subList(1, lists.size())); for (T condition : firstList) { for (List remainingList : remainingLists) { ArrayList resultList = new ArrayList(); diff --git a/src/checkers/inference/solver/backend/maxsat/encoder/MaxSATInequalityConstraintEncoder.java b/src/checkers/inference/solver/backend/maxsat/encoder/MaxSATInequalityConstraintEncoder.java index fb850d54c..f6aa3ad4d 100644 --- a/src/checkers/inference/solver/backend/maxsat/encoder/MaxSATInequalityConstraintEncoder.java +++ b/src/checkers/inference/solver/backend/maxsat/encoder/MaxSATInequalityConstraintEncoder.java @@ -1,19 +1,23 @@ package checkers.inference.solver.backend.maxsat.encoder; +import org.sat4j.core.VecInt; + +import java.util.Map; + +import javax.lang.model.element.AnnotationMirror; + import checkers.inference.model.ConstantSlot; import checkers.inference.model.VariableSlot; import checkers.inference.solver.backend.encoder.binary.InequalityConstraintEncoder; import checkers.inference.solver.backend.maxsat.MathUtils; import checkers.inference.solver.backend.maxsat.VectorUtils; import checkers.inference.solver.frontend.Lattice; -import org.sat4j.core.VecInt; - -import javax.lang.model.element.AnnotationMirror; -import java.util.Map; -public class MaxSATInequalityConstraintEncoder extends MaxSATAbstractConstraintEncoder implements InequalityConstraintEncoder { +public class MaxSATInequalityConstraintEncoder extends MaxSATAbstractConstraintEncoder + implements InequalityConstraintEncoder { - public MaxSATInequalityConstraintEncoder(Lattice lattice, Map typeToInt) { + public MaxSATInequalityConstraintEncoder( + Lattice lattice, Map typeToInt) { super(lattice, typeToInt); } @@ -24,12 +28,18 @@ public VecInt[] encodeVariable_Variable(VariableSlot fst, VariableSlot snd) { int i = 0; for (AnnotationMirror type : lattice.allTypes) { if (lattice.allTypes.contains(type)) { - result[i++] = VectorUtils.asVec( - -MathUtils.mapIdToMatrixEntry(fst.getId(), typeToInt.get(type), lattice), - -MathUtils.mapIdToMatrixEntry(snd.getId(), typeToInt.get(type), lattice)); - result[i++] = VectorUtils.asVec( - MathUtils.mapIdToMatrixEntry(snd.getId(), typeToInt.get(type), lattice), - MathUtils.mapIdToMatrixEntry(fst.getId(), typeToInt.get(type), lattice)); + result[i++] = + VectorUtils.asVec( + -MathUtils.mapIdToMatrixEntry( + fst.getId(), typeToInt.get(type), lattice), + -MathUtils.mapIdToMatrixEntry( + snd.getId(), typeToInt.get(type), lattice)); + result[i++] = + VectorUtils.asVec( + MathUtils.mapIdToMatrixEntry( + snd.getId(), typeToInt.get(type), lattice), + MathUtils.mapIdToMatrixEntry( + fst.getId(), typeToInt.get(type), lattice)); } } return result; @@ -44,7 +54,8 @@ public VecInt[] encodeVariable_Constant(VariableSlot fst, ConstantSlot snd) { public VecInt[] encodeConstant_Variable(ConstantSlot fst, VariableSlot snd) { if (lattice.allTypes.contains(fst.getValue())) { return VectorUtils.asVecArray( - -MathUtils.mapIdToMatrixEntry(snd.getId(), typeToInt.get(fst.getValue()), lattice)); + -MathUtils.mapIdToMatrixEntry( + snd.getId(), typeToInt.get(fst.getValue()), lattice)); } else { return emptyValue; } diff --git a/src/checkers/inference/solver/backend/maxsat/encoder/MaxSATPreferenceConstraintEncoder.java b/src/checkers/inference/solver/backend/maxsat/encoder/MaxSATPreferenceConstraintEncoder.java index 7eb065957..95a2d88e1 100644 --- a/src/checkers/inference/solver/backend/maxsat/encoder/MaxSATPreferenceConstraintEncoder.java +++ b/src/checkers/inference/solver/backend/maxsat/encoder/MaxSATPreferenceConstraintEncoder.java @@ -1,5 +1,11 @@ package checkers.inference.solver.backend.maxsat.encoder; +import org.sat4j.core.VecInt; + +import java.util.Map; + +import javax.lang.model.element.AnnotationMirror; + import checkers.inference.model.ConstantSlot; import checkers.inference.model.PreferenceConstraint; import checkers.inference.model.VariableSlot; @@ -7,14 +13,12 @@ import checkers.inference.solver.backend.maxsat.MathUtils; import checkers.inference.solver.backend.maxsat.VectorUtils; import checkers.inference.solver.frontend.Lattice; -import org.sat4j.core.VecInt; - -import javax.lang.model.element.AnnotationMirror; -import java.util.Map; -public class MaxSATPreferenceConstraintEncoder extends MaxSATAbstractConstraintEncoder implements PreferenceConstraintEncoder { +public class MaxSATPreferenceConstraintEncoder extends MaxSATAbstractConstraintEncoder + implements PreferenceConstraintEncoder { - public MaxSATPreferenceConstraintEncoder(Lattice lattice, Map typeToInt) { + public MaxSATPreferenceConstraintEncoder( + Lattice lattice, Map typeToInt) { super(lattice, typeToInt); } @@ -25,8 +29,9 @@ public VecInt[] encode(PreferenceConstraint constraint) { VariableSlot vs = constraint.getVariable(); ConstantSlot cs = constraint.getGoal(); if (lattice.allTypes.contains(cs.getValue())) { - return VectorUtils.asVecArray(MathUtils.mapIdToMatrixEntry(vs.getId(), typeToInt.get(cs.getValue()), - lattice)); + return VectorUtils.asVecArray( + MathUtils.mapIdToMatrixEntry( + vs.getId(), typeToInt.get(cs.getValue()), lattice)); } else { return emptyValue; } diff --git a/src/checkers/inference/solver/backend/maxsat/encoder/MaxSATSubtypeConstraintEncoder.java b/src/checkers/inference/solver/backend/maxsat/encoder/MaxSATSubtypeConstraintEncoder.java index 1c641fb52..6c82dd688 100644 --- a/src/checkers/inference/solver/backend/maxsat/encoder/MaxSATSubtypeConstraintEncoder.java +++ b/src/checkers/inference/solver/backend/maxsat/encoder/MaxSATSubtypeConstraintEncoder.java @@ -1,16 +1,8 @@ package checkers.inference.solver.backend.maxsat.encoder; -import checkers.inference.model.ConstantSlot; -import checkers.inference.model.Slot; -import checkers.inference.model.VariableSlot; -import checkers.inference.solver.backend.encoder.binary.SubtypeConstraintEncoder; -import checkers.inference.solver.backend.maxsat.MathUtils; -import checkers.inference.solver.backend.maxsat.VectorUtils; -import checkers.inference.solver.frontend.Lattice; import org.checkerframework.javacutil.AnnotationUtils; import org.sat4j.core.VecInt; -import javax.lang.model.element.AnnotationMirror; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; @@ -19,23 +11,37 @@ import java.util.Map; import java.util.Set; -public class MaxSATSubtypeConstraintEncoder extends MaxSATAbstractConstraintEncoder implements SubtypeConstraintEncoder { +import javax.lang.model.element.AnnotationMirror; + +import checkers.inference.model.ConstantSlot; +import checkers.inference.model.Slot; +import checkers.inference.model.VariableSlot; +import checkers.inference.solver.backend.encoder.binary.SubtypeConstraintEncoder; +import checkers.inference.solver.backend.maxsat.MathUtils; +import checkers.inference.solver.backend.maxsat.VectorUtils; +import checkers.inference.solver.frontend.Lattice; + +public class MaxSATSubtypeConstraintEncoder extends MaxSATAbstractConstraintEncoder + implements SubtypeConstraintEncoder { - public MaxSATSubtypeConstraintEncoder(Lattice lattice, Map typeToInt) { + public MaxSATSubtypeConstraintEncoder( + Lattice lattice, Map typeToInt) { super(lattice, typeToInt); } /** - * For subtype constraint, if supertype is constant slot, then the subtype - * cannot be the super type of supertype, same for subtype + * For subtype constraint, if supertype is constant slot, then the subtype cannot be the super + * type of supertype, same for subtype */ - protected VecInt[] getMustNotBe(Set mustNotBe, Slot vSlot, ConstantSlot cSlot) { + protected VecInt[] getMustNotBe( + Set mustNotBe, Slot vSlot, ConstantSlot cSlot) { List resultList = new ArrayList(); for (AnnotationMirror sub : mustNotBe) { if (!AnnotationUtils.areSame(sub, cSlot.getValue())) { - resultList.add(-MathUtils.mapIdToMatrixEntry(vSlot.getId(), typeToInt.get(sub), lattice)); + resultList.add( + -MathUtils.mapIdToMatrixEntry(vSlot.getId(), typeToInt.get(sub), lattice)); } } @@ -50,13 +56,18 @@ protected VecInt[] getMustNotBe(Set mustNotBe, Slot vSlot, Con return emptyValue; } - protected int[] getMaybe(AnnotationMirror type, Slot knownType, Slot unknownType, - Collection maybeSet) { + protected int[] getMaybe( + AnnotationMirror type, + Slot knownType, + Slot unknownType, + Collection maybeSet) { int[] maybeArray = new int[maybeSet.size() + 1]; int i = 1; - maybeArray[0] = -MathUtils.mapIdToMatrixEntry(knownType.getId(), typeToInt.get(type), lattice); + maybeArray[0] = + -MathUtils.mapIdToMatrixEntry(knownType.getId(), typeToInt.get(type), lattice); for (AnnotationMirror sup : maybeSet) { - maybeArray[i] = MathUtils.mapIdToMatrixEntry(unknownType.getId(), typeToInt.get(sup), lattice); + maybeArray[i] = + MathUtils.mapIdToMatrixEntry(unknownType.getId(), typeToInt.get(sup), lattice); i++; } return maybeArray; @@ -66,25 +77,33 @@ protected int[] getMaybe(AnnotationMirror type, Slot knownType, Slot unknownType public VecInt[] encodeVariable_Variable(VariableSlot subtype, VariableSlot supertype) { // if subtype is top, then supertype is top. // if supertype is bottom, then subtype is bottom. - VecInt supertypeOfTop = VectorUtils.asVec( - -MathUtils.mapIdToMatrixEntry(subtype.getId(), typeToInt.get(lattice.top), lattice), - MathUtils.mapIdToMatrixEntry(supertype.getId(), typeToInt.get(lattice.top), lattice)); - VecInt subtypeOfBottom = VectorUtils.asVec( - -MathUtils.mapIdToMatrixEntry(supertype.getId(), typeToInt.get(lattice.bottom), lattice), - MathUtils.mapIdToMatrixEntry(subtype.getId(), typeToInt.get(lattice.bottom), lattice)); + VecInt supertypeOfTop = + VectorUtils.asVec( + -MathUtils.mapIdToMatrixEntry( + subtype.getId(), typeToInt.get(lattice.top), lattice), + MathUtils.mapIdToMatrixEntry( + supertype.getId(), typeToInt.get(lattice.top), lattice)); + VecInt subtypeOfBottom = + VectorUtils.asVec( + -MathUtils.mapIdToMatrixEntry( + supertype.getId(), typeToInt.get(lattice.bottom), lattice), + MathUtils.mapIdToMatrixEntry( + subtype.getId(), typeToInt.get(lattice.bottom), lattice)); List resultList = new ArrayList(); for (AnnotationMirror type : lattice.allTypes) { // if we know subtype if (!AnnotationUtils.areSame(type, lattice.top)) { - resultList.add(VectorUtils - .asVec(getMaybe(type, subtype, supertype, lattice.superType.get(type)))); + resultList.add( + VectorUtils.asVec( + getMaybe(type, subtype, supertype, lattice.superType.get(type)))); } // if we know supertype if (!AnnotationUtils.areSame(type, lattice.bottom)) { - resultList.add(VectorUtils - .asVec(getMaybe(type, supertype, subtype, lattice.subType.get(type)))); + resultList.add( + VectorUtils.asVec( + getMaybe(type, supertype, subtype, lattice.subType.get(type)))); } } resultList.add(supertypeOfTop); @@ -98,7 +117,8 @@ public VecInt[] encodeVariable_Constant(VariableSlot subtype, ConstantSlot super final Set mustNotBe = new HashSet<>(); if (AnnotationUtils.areSame(supertype.getValue(), lattice.bottom)) { return VectorUtils.asVecArray( - MathUtils.mapIdToMatrixEntry(subtype.getId(), typeToInt.get(lattice.bottom), lattice)); + MathUtils.mapIdToMatrixEntry( + subtype.getId(), typeToInt.get(lattice.bottom), lattice)); } if (lattice.superType.get(supertype.getValue()) != null) { @@ -115,7 +135,8 @@ public VecInt[] encodeConstant_Variable(ConstantSlot subtype, VariableSlot super final Set mustNotBe = new HashSet<>(); if (AnnotationUtils.areSame(subtype.getValue(), lattice.top)) { return VectorUtils.asVecArray( - MathUtils.mapIdToMatrixEntry(supertype.getId(), typeToInt.get(lattice.top), lattice)); + MathUtils.mapIdToMatrixEntry( + supertype.getId(), typeToInt.get(lattice.top), lattice)); } if (lattice.subType.get(subtype.getValue()) != null) { mustNotBe.addAll(lattice.subType.get(subtype.getValue())); diff --git a/src/checkers/inference/solver/backend/z3/Z3BitVectorCodec.java b/src/checkers/inference/solver/backend/z3/Z3BitVectorCodec.java index 1c4a0c455..cc382615d 100644 --- a/src/checkers/inference/solver/backend/z3/Z3BitVectorCodec.java +++ b/src/checkers/inference/solver/backend/z3/Z3BitVectorCodec.java @@ -8,17 +8,22 @@ public interface Z3BitVectorCodec { /** - * Get the fixed Bit Vector size. - * @return the fixed Bit Vector size - */ + * Get the fixed Bit Vector size. + * + * @return the fixed Bit Vector size + */ int getFixedBitVectorSize(); /** - * Encode a given AnnotationMirror to a numeric value whose binary representation is the encoded bit vector. + * Encode a given AnnotationMirror to a numeric value whose binary representation is the encoded + * bit vector. + * * @param am a given AnnotationMirror. - * @return numeral value of the encoded bit vector, -1 if the given {@code am} cannot be encoded. + * @return numeral value of the encoded bit vector, -1 if the given {@code am} cannot be + * encoded. */ BigInteger encodeConstantAM(AnnotationMirror am); - AnnotationMirror decodeNumeralValue(BigInteger numeralValue, ProcessingEnvironment processingEnvironment); + AnnotationMirror decodeNumeralValue( + BigInteger numeralValue, ProcessingEnvironment processingEnvironment); } diff --git a/src/checkers/inference/solver/backend/z3/Z3BitVectorFormatTranslator.java b/src/checkers/inference/solver/backend/z3/Z3BitVectorFormatTranslator.java index 93fce04c5..30236abaf 100644 --- a/src/checkers/inference/solver/backend/z3/Z3BitVectorFormatTranslator.java +++ b/src/checkers/inference/solver/backend/z3/Z3BitVectorFormatTranslator.java @@ -1,5 +1,11 @@ package checkers.inference.solver.backend.z3; +import com.microsoft.z3.BitVecExpr; +import com.microsoft.z3.BitVecNum; +import com.microsoft.z3.BoolExpr; +import com.microsoft.z3.Context; +import com.microsoft.z3.Optimize; + import java.math.BigInteger; import java.util.HashMap; import java.util.Map; @@ -7,29 +13,22 @@ import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.AnnotationMirror; -import checkers.inference.model.ComparisonVariableSlot; -import org.checkerframework.javacutil.BugInCF; - -import checkers.inference.solver.backend.AbstractFormatTranslator; -import checkers.inference.solver.backend.encoder.ConstraintEncoderFactory; -import checkers.inference.solver.backend.z3.encoder.Z3BitVectorConstraintEncoderFactory; -import com.microsoft.z3.BitVecExpr; -import com.microsoft.z3.BitVecNum; -import com.microsoft.z3.BoolExpr; -import com.microsoft.z3.Context; -import com.microsoft.z3.Optimize; - import checkers.inference.model.ArithmeticVariableSlot; import checkers.inference.model.CombVariableSlot; +import checkers.inference.model.ComparisonVariableSlot; import checkers.inference.model.ConstantSlot; import checkers.inference.model.ExistentialVariableSlot; import checkers.inference.model.LubVariableSlot; import checkers.inference.model.RefinementVariableSlot; import checkers.inference.model.SourceVariableSlot; import checkers.inference.model.VariableSlot; +import checkers.inference.solver.backend.AbstractFormatTranslator; +import checkers.inference.solver.backend.encoder.ConstraintEncoderFactory; +import checkers.inference.solver.backend.z3.encoder.Z3BitVectorConstraintEncoderFactory; import checkers.inference.solver.frontend.Lattice; -public abstract class Z3BitVectorFormatTranslator extends AbstractFormatTranslator { +public abstract class Z3BitVectorFormatTranslator + extends AbstractFormatTranslator { protected Context context; @@ -52,9 +51,8 @@ public final void initContext(Context context) { } /** - * Initialize fields that requires context. - * Sub-class override this method to initialize - * objects that require the context being initialized first. + * Initialize fields that requires context. Sub-class override this method to initialize objects + * that require the context being initialized first. */ protected void postInitWithContext() { // Intentional empty. @@ -65,8 +63,9 @@ public final void initSolver(Optimize solver) { } /** - * Create a Z3BitVectorCodec responsible for encoding/decoding a type qualifier. - * Each type system must provide a specific Z3BitVectorCodec. + * Create a Z3BitVectorCodec responsible for encoding/decoding a type qualifier. Each type + * system must provide a specific Z3BitVectorCodec. + * * @return a z3BitVectorCodec */ protected abstract Z3BitVectorCodec createZ3BitVectorCodec(); @@ -77,6 +76,7 @@ public Z3BitVectorCodec getZ3BitVectorCodec() { /** * Add a soft constraint to underlying solver. + * * @param constraint the soft constraint * @param weight the weight of this soft constraint * @param group the group of this soft constraint @@ -92,8 +92,9 @@ public BitVecExpr serializeVarSlot(VariableSlot slot) { return serializedSlots.get(slotId); } - BitVecExpr bitVector = context.mkBVConst(String.valueOf(slot.getId()), - z3BitVectorCodec.getFixedBitVectorSize()); + BitVecExpr bitVector = + context.mkBVConst( + String.valueOf(slot.getId()), z3BitVectorCodec.getFixedBitVectorSize()); serializedSlots.put(slotId, bitVector); return bitVector; @@ -108,7 +109,8 @@ public BitVecExpr serializeConstantSlot(ConstantSlot slot) { BigInteger numeralValue = z3BitVectorCodec.encodeConstantAM(slot.getValue()); - BitVecNum bitVecNum = context.mkBV(numeralValue.toString(), z3BitVectorCodec.getFixedBitVectorSize()); + BitVecNum bitVecNum = + context.mkBV(numeralValue.toString(), z3BitVectorCodec.getFixedBitVectorSize()); serializedSlots.put(slotId, bitVecNum); return bitVecNum; @@ -148,7 +150,7 @@ public BitVecExpr serialize(CombVariableSlot slot) { public BitVecExpr serialize(LubVariableSlot slot) { return serializeVarSlot(slot); } - + @Override public BitVecExpr serialize(ArithmeticVariableSlot slot) { return serializeVarSlot(slot); @@ -160,7 +162,8 @@ public BitVecExpr serialize(ComparisonVariableSlot slot) { } @Override - public AnnotationMirror decodeSolution(BitVecNum solution, ProcessingEnvironment processingEnvironment) { + public AnnotationMirror decodeSolution( + BitVecNum solution, ProcessingEnvironment processingEnvironment) { return z3BitVectorCodec.decodeNumeralValue(solution.getBigInteger(), processingEnvironment); } } diff --git a/src/checkers/inference/solver/backend/z3/Z3Solver.java b/src/checkers/inference/solver/backend/z3/Z3Solver.java index 25d7b78d2..b4e0236cb 100644 --- a/src/checkers/inference/solver/backend/z3/Z3Solver.java +++ b/src/checkers/inference/solver/backend/z3/Z3Solver.java @@ -1,13 +1,4 @@ - package checkers.inference.solver.backend.z3; - -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; - -import javax.lang.model.element.AnnotationMirror; - -import org.checkerframework.javacutil.BugInCF; +package checkers.inference.solver.backend.z3; import com.microsoft.z3.BitVecNum; import com.microsoft.z3.BoolExpr; @@ -17,6 +8,15 @@ import com.microsoft.z3.Model; import com.microsoft.z3.Optimize; +import org.checkerframework.javacutil.BugInCF; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + +import javax.lang.model.element.AnnotationMirror; + import checkers.inference.InferenceMain; import checkers.inference.model.Constraint; import checkers.inference.model.PreferenceConstraint; @@ -25,15 +25,18 @@ import checkers.inference.solver.frontend.Lattice; import checkers.inference.solver.util.SolverEnvironment; -public class Z3Solver extends Solver{ +public class Z3Solver extends Solver { protected final Context context; protected final Optimize solver; protected final Z3BitVectorCodec z3BitVectorCodec; - - public Z3Solver(SolverEnvironment solverEnvironment, Collection slots, - Collection constraints, Z3BitVectorFormatTranslator z3FormatTranslator, Lattice lattice) { + public Z3Solver( + SolverEnvironment solverEnvironment, + Collection slots, + Collection constraints, + Z3BitVectorFormatTranslator z3FormatTranslator, + Lattice lattice) { super(solverEnvironment, slots, constraints, z3FormatTranslator, lattice); context = new Context(); solver = context.mkOptimize(); @@ -49,28 +52,31 @@ public Map solve() { encodeAllConstraints(); switch (solver.Check()) { - case SATISFIABLE: { - result = decodeSolution(solver.getModel()); - break; - } - - case UNSATISFIABLE: { - System.out.println("Unsatisfiable!"); - break; - } + case SATISFIABLE: + { + result = decodeSolution(solver.getModel()); + break; + } + + case UNSATISFIABLE: + { + System.out.println("Unsatisfiable!"); + break; + } case UNKNOWN: - default: { - System.out.println("Solver failed to solve due to Unknown reason!"); - break; - } + default: + { + System.out.println("Solver failed to solve due to Unknown reason!"); + break; + } } return result; } @Override public Collection explainUnsatisfiable() { - return new HashSet<>();// Doesn't support right now + return new HashSet<>(); // Doesn't support right now } @Override @@ -80,9 +86,15 @@ protected void encodeAllConstraints() { if (serializedConstraint == null) { // TODO: Should error abort if unsupported constraint detected. - // Currently warning is a workaround for making ontology working, as in some cases existential constraints generated. - // Should investigate on this, and change this to ErrorAbort when eliminated unsupported constraints. - InferenceMain.getInstance().logger.warning("Unsupported constraint detected! Constraint type: " + constraint.getClass()); + // Currently warning is a workaround for making ontology working, as in some cases + // existential constraints generated. + // Should investigate on this, and change this to ErrorAbort when eliminated + // unsupported constraints. + InferenceMain.getInstance() + .logger + .warning( + "Unsupported constraint detected! Constraint type: " + + constraint.getClass()); continue; } else if (serializedConstraint.isTrue()) { // Skip tautology. @@ -90,27 +102,34 @@ protected void encodeAllConstraints() { } if (constraint instanceof PreferenceConstraint) { - solver.AssertSoft(serializedConstraint, ((PreferenceConstraint) constraint).getWeight(), "preferCons"); + solver.AssertSoft( + serializedConstraint, + ((PreferenceConstraint) constraint).getWeight(), + "preferCons"); } else { solver.Assert(serializedConstraint); } } } - protected Map decodeSolution(Model model) { Map result = new HashMap<>(); for (FuncDecl funcDecl : model.getDecls()) { int slotId = Integer.valueOf(funcDecl.getName().toString()); Expr constInterp = model.getConstInterp(funcDecl); - if (! (constInterp instanceof BitVecNum)) { - throw new BugInCF("Wrong solution type detected: All solution must be type of BitVecNum, but get: " + constInterp.getClass()); + if (!(constInterp instanceof BitVecNum)) { + throw new BugInCF( + "Wrong solution type detected: All solution must be type of BitVecNum, but get: " + + constInterp.getClass()); } - result.put(slotId, formatTranslator.decodeSolution((BitVecNum) constInterp, solverEnvironment.processingEnvironment)); + result.put( + slotId, + formatTranslator.decodeSolution( + (BitVecNum) constInterp, solverEnvironment.processingEnvironment)); } return result; } - } +} diff --git a/src/checkers/inference/solver/backend/z3/Z3SolverFactory.java b/src/checkers/inference/solver/backend/z3/Z3SolverFactory.java index 0ed262ad0..cb7a47048 100644 --- a/src/checkers/inference/solver/backend/z3/Z3SolverFactory.java +++ b/src/checkers/inference/solver/backend/z3/Z3SolverFactory.java @@ -1,6 +1,7 @@ package checkers.inference.solver.backend.z3; import java.util.Collection; + import checkers.inference.model.Constraint; import checkers.inference.model.Slot; import checkers.inference.solver.backend.AbstractSolverFactory; @@ -11,8 +12,11 @@ public abstract class Z3SolverFactory extends AbstractSolverFactory { @Override - public Solver createSolver(SolverEnvironment solverEnvironment, Collection slots, - Collection constraints, Lattice lattice) { + public Solver createSolver( + SolverEnvironment solverEnvironment, + Collection slots, + Collection constraints, + Lattice lattice) { Z3BitVectorFormatTranslator formatTranslator = createFormatTranslator(lattice); return new Z3Solver(solverEnvironment, slots, constraints, formatTranslator, lattice); } diff --git a/src/checkers/inference/solver/backend/z3/encoder/Z3BitVectorAbstractConstraintEncoder.java b/src/checkers/inference/solver/backend/z3/encoder/Z3BitVectorAbstractConstraintEncoder.java index 78ee292da..97e069d6a 100644 --- a/src/checkers/inference/solver/backend/z3/encoder/Z3BitVectorAbstractConstraintEncoder.java +++ b/src/checkers/inference/solver/backend/z3/encoder/Z3BitVectorAbstractConstraintEncoder.java @@ -1,20 +1,21 @@ package checkers.inference.solver.backend.z3.encoder; +import com.microsoft.z3.BoolExpr; +import com.microsoft.z3.Context; + import checkers.inference.solver.backend.encoder.AbstractConstraintEncoder; import checkers.inference.solver.backend.z3.Z3BitVectorFormatTranslator; import checkers.inference.solver.frontend.Lattice; -import com.microsoft.z3.BoolExpr; -import com.microsoft.z3.Context; -/** - * Abstract base class for every Z3BitVector constraint encoders. - */ +/** Abstract base class for every Z3BitVector constraint encoders. */ public class Z3BitVectorAbstractConstraintEncoder extends AbstractConstraintEncoder { protected final Context context; protected final Z3BitVectorFormatTranslator z3BitVectorFormatTranslator; - public Z3BitVectorAbstractConstraintEncoder(Lattice lattice, Context context, + public Z3BitVectorAbstractConstraintEncoder( + Lattice lattice, + Context context, Z3BitVectorFormatTranslator z3BitVectorFormatTranslator) { super(lattice, context.mkTrue(), context.mkFalse()); this.context = context; diff --git a/src/checkers/inference/solver/backend/z3/encoder/Z3BitVectorConstraintEncoderFactory.java b/src/checkers/inference/solver/backend/z3/encoder/Z3BitVectorConstraintEncoderFactory.java index 03a494602..768a2b87f 100644 --- a/src/checkers/inference/solver/backend/z3/encoder/Z3BitVectorConstraintEncoderFactory.java +++ b/src/checkers/inference/solver/backend/z3/encoder/Z3BitVectorConstraintEncoderFactory.java @@ -1,5 +1,8 @@ package checkers.inference.solver.backend.z3.encoder; +import com.microsoft.z3.BoolExpr; +import com.microsoft.z3.Context; + import checkers.inference.solver.backend.encoder.AbstractConstraintEncoderFactory; import checkers.inference.solver.backend.encoder.ArithmeticConstraintEncoder; import checkers.inference.solver.backend.encoder.ComparisonConstraintEncoder; @@ -12,20 +15,19 @@ import checkers.inference.solver.backend.encoder.preference.PreferenceConstraintEncoder; import checkers.inference.solver.backend.z3.Z3BitVectorFormatTranslator; import checkers.inference.solver.frontend.Lattice; -import com.microsoft.z3.BoolExpr; -import com.microsoft.z3.Context; /** * Z3 implementation of {@link checkers.inference.solver.backend.encoder.ConstraintEncoderFactory}. * * @see checkers.inference.solver.backend.encoder.ConstraintEncoderFactory */ -public class Z3BitVectorConstraintEncoderFactory extends AbstractConstraintEncoderFactory{ +public class Z3BitVectorConstraintEncoderFactory + extends AbstractConstraintEncoderFactory { protected final Context context; - public Z3BitVectorConstraintEncoderFactory(Lattice lattice, Context context, - Z3BitVectorFormatTranslator formatTranslator) { + public Z3BitVectorConstraintEncoderFactory( + Lattice lattice, Context context, Z3BitVectorFormatTranslator formatTranslator) { super(lattice, formatTranslator); this.context = context; } @@ -75,7 +77,7 @@ public ExistentialConstraintEncoder createExistentialConstraintEncoder public ImplicationConstraintEncoder createImplicationConstraintEncoder() { return null; } - + @Override public ArithmeticConstraintEncoder createArithmeticConstraintEncoder() { return null; diff --git a/src/checkers/inference/solver/backend/z3/encoder/Z3BitVectorEqualityConstraintEncoder.java b/src/checkers/inference/solver/backend/z3/encoder/Z3BitVectorEqualityConstraintEncoder.java index 6be615ccd..1a9b72c50 100644 --- a/src/checkers/inference/solver/backend/z3/encoder/Z3BitVectorEqualityConstraintEncoder.java +++ b/src/checkers/inference/solver/backend/z3/encoder/Z3BitVectorEqualityConstraintEncoder.java @@ -1,18 +1,22 @@ package checkers.inference.solver.backend.z3.encoder; +import com.microsoft.z3.BitVecExpr; +import com.microsoft.z3.BoolExpr; +import com.microsoft.z3.Context; + import checkers.inference.model.ConstantSlot; import checkers.inference.model.Slot; import checkers.inference.model.VariableSlot; import checkers.inference.solver.backend.encoder.binary.EqualityConstraintEncoder; import checkers.inference.solver.backend.z3.Z3BitVectorFormatTranslator; import checkers.inference.solver.frontend.Lattice; -import com.microsoft.z3.BitVecExpr; -import com.microsoft.z3.BoolExpr; -import com.microsoft.z3.Context; -public class Z3BitVectorEqualityConstraintEncoder extends Z3BitVectorAbstractConstraintEncoder implements EqualityConstraintEncoder { +public class Z3BitVectorEqualityConstraintEncoder extends Z3BitVectorAbstractConstraintEncoder + implements EqualityConstraintEncoder { - public Z3BitVectorEqualityConstraintEncoder(Lattice lattice, Context context, + public Z3BitVectorEqualityConstraintEncoder( + Lattice lattice, + Context context, Z3BitVectorFormatTranslator z3BitVectorFormatTranslator) { super(lattice, context, z3BitVectorFormatTranslator); } diff --git a/src/checkers/inference/solver/backend/z3/encoder/Z3BitVectorPreferenceConstraintEncoder.java b/src/checkers/inference/solver/backend/z3/encoder/Z3BitVectorPreferenceConstraintEncoder.java index b2ed3245c..53c0059bd 100644 --- a/src/checkers/inference/solver/backend/z3/encoder/Z3BitVectorPreferenceConstraintEncoder.java +++ b/src/checkers/inference/solver/backend/z3/encoder/Z3BitVectorPreferenceConstraintEncoder.java @@ -1,25 +1,29 @@ package checkers.inference.solver.backend.z3.encoder; +import com.microsoft.z3.BitVecExpr; +import com.microsoft.z3.BoolExpr; +import com.microsoft.z3.Context; + import checkers.inference.model.ConstantSlot; import checkers.inference.model.PreferenceConstraint; import checkers.inference.model.VariableSlot; import checkers.inference.solver.backend.encoder.preference.PreferenceConstraintEncoder; import checkers.inference.solver.backend.z3.Z3BitVectorFormatTranslator; import checkers.inference.solver.frontend.Lattice; -import com.microsoft.z3.BitVecExpr; -import com.microsoft.z3.BoolExpr; -import com.microsoft.z3.Context; -public class Z3BitVectorPreferenceConstraintEncoder extends Z3BitVectorAbstractConstraintEncoder implements PreferenceConstraintEncoder { +public class Z3BitVectorPreferenceConstraintEncoder extends Z3BitVectorAbstractConstraintEncoder + implements PreferenceConstraintEncoder { - public Z3BitVectorPreferenceConstraintEncoder(Lattice lattice, Context context, + public Z3BitVectorPreferenceConstraintEncoder( + Lattice lattice, + Context context, Z3BitVectorFormatTranslator z3BitVectorFormatTranslator) { super(lattice, context, z3BitVectorFormatTranslator); } /** - * Return an equality constraint between variable and constant goal. - * The caller should add the serialized constraint with soft option. + * Return an equality constraint between variable and constant goal. The caller should add the + * serialized constraint with soft option. */ @Override public BoolExpr encode(PreferenceConstraint constraint) { diff --git a/src/checkers/inference/solver/backend/z3/encoder/Z3BitVectorSubtypeConstraintEncoder.java b/src/checkers/inference/solver/backend/z3/encoder/Z3BitVectorSubtypeConstraintEncoder.java index 53e605a7d..ca26cd65e 100644 --- a/src/checkers/inference/solver/backend/z3/encoder/Z3BitVectorSubtypeConstraintEncoder.java +++ b/src/checkers/inference/solver/backend/z3/encoder/Z3BitVectorSubtypeConstraintEncoder.java @@ -1,18 +1,22 @@ package checkers.inference.solver.backend.z3.encoder; +import com.microsoft.z3.BitVecExpr; +import com.microsoft.z3.BoolExpr; +import com.microsoft.z3.Context; + import checkers.inference.model.ConstantSlot; import checkers.inference.model.Slot; import checkers.inference.model.VariableSlot; import checkers.inference.solver.backend.encoder.binary.SubtypeConstraintEncoder; import checkers.inference.solver.backend.z3.Z3BitVectorFormatTranslator; import checkers.inference.solver.frontend.Lattice; -import com.microsoft.z3.BitVecExpr; -import com.microsoft.z3.BoolExpr; -import com.microsoft.z3.Context; -public class Z3BitVectorSubtypeConstraintEncoder extends Z3BitVectorAbstractConstraintEncoder implements SubtypeConstraintEncoder { +public class Z3BitVectorSubtypeConstraintEncoder extends Z3BitVectorAbstractConstraintEncoder + implements SubtypeConstraintEncoder { - public Z3BitVectorSubtypeConstraintEncoder(Lattice lattice, Context context, + public Z3BitVectorSubtypeConstraintEncoder( + Lattice lattice, + Context context, Z3BitVectorFormatTranslator z3BitVectorFormatTranslator) { super(lattice, context, z3BitVectorFormatTranslator); } @@ -35,7 +39,8 @@ protected BoolExpr encode(Slot subtype, Slot supertype) { subSet = supertypeBv; } - BoolExpr sub_intersect_super = context.mkEq(context.mkBVAND(subtypeBv, supertypeBv), subSet); + BoolExpr sub_intersect_super = + context.mkEq(context.mkBVAND(subtypeBv, supertypeBv), subSet); BoolExpr sub_union_super = context.mkEq(context.mkBVOR(subtypeBv, supertypeBv), superSet); return context.mkAnd(sub_intersect_super, sub_union_super); @@ -43,7 +48,7 @@ protected BoolExpr encode(Slot subtype, Slot supertype) { @Override public BoolExpr encodeVariable_Variable(VariableSlot subtype, VariableSlot supertype) { - return encode(subtype, supertype); + return encode(subtype, supertype); } @Override diff --git a/src/checkers/inference/solver/backend/z3smt/Z3SmtFormatTranslator.java b/src/checkers/inference/solver/backend/z3smt/Z3SmtFormatTranslator.java index 53c29204a..91b46ec31 100644 --- a/src/checkers/inference/solver/backend/z3smt/Z3SmtFormatTranslator.java +++ b/src/checkers/inference/solver/backend/z3smt/Z3SmtFormatTranslator.java @@ -1,5 +1,16 @@ package checkers.inference.solver.backend.z3smt; +import com.microsoft.z3.BoolExpr; +import com.microsoft.z3.Context; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.AnnotationMirror; + import checkers.inference.model.ArithmeticVariableSlot; import checkers.inference.model.CombVariableSlot; import checkers.inference.model.ComparisonVariableSlot; @@ -13,18 +24,8 @@ import checkers.inference.solver.backend.AbstractFormatTranslator; import checkers.inference.solver.backend.z3smt.encoder.Z3SmtSoftConstraintEncoder; import checkers.inference.solver.frontend.Lattice; -import com.microsoft.z3.BoolExpr; -import com.microsoft.z3.Context; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.AnnotationMirror; -/** - * Abstract class for z3 format translator - */ +/** Abstract class for z3 format translator */ public abstract class Z3SmtFormatTranslator extends AbstractFormatTranslator { @@ -92,8 +93,9 @@ public SlotEncodingT serialize(ComparisonVariableSlot slot) { * optimization */ public void preAnalyzeSlots(Collection slots) {} - - protected abstract Z3SmtSoftConstraintEncoder createSoftConstraintEncoder(); + + protected abstract Z3SmtSoftConstraintEncoder + createSoftConstraintEncoder(); public abstract BoolExpr encodeSlotWellformednessConstraint(VariableSlot slot); diff --git a/src/checkers/inference/solver/backend/z3smt/Z3SmtSolver.java b/src/checkers/inference/solver/backend/z3smt/Z3SmtSolver.java index 9633fecb3..d4e1b3679 100644 --- a/src/checkers/inference/solver/backend/z3smt/Z3SmtSolver.java +++ b/src/checkers/inference/solver/backend/z3smt/Z3SmtSolver.java @@ -1,5 +1,23 @@ package checkers.inference.solver.backend.z3smt; +import com.microsoft.z3.BoolExpr; +import com.microsoft.z3.Context; +import com.microsoft.z3.Expr; + +import org.checkerframework.javacutil.BugInCF; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + +import javax.lang.model.element.AnnotationMirror; + import checkers.inference.InferenceMain; import checkers.inference.model.ArithmeticConstraint; import checkers.inference.model.ArithmeticConstraint.ArithmeticOperationKind; @@ -15,21 +33,6 @@ import checkers.inference.solver.util.SolverArg; import checkers.inference.solver.util.SolverEnvironment; import checkers.inference.solver.util.Statistics; -import com.microsoft.z3.BoolExpr; -import com.microsoft.z3.Context; -import com.microsoft.z3.Expr; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.logging.Logger; -import javax.lang.model.element.AnnotationMirror; -import org.checkerframework.javacutil.BugInCF; public class Z3SmtSolver extends Solver> { @@ -50,13 +53,13 @@ public enum Z3SolverEngineArg implements SolverArg { protected static final String z3Program = "z3"; protected boolean optimizingMode; - /** This field indicates that whether we are going to explain unsatisfiable.*/ + /** This field indicates that whether we are going to explain unsatisfiable. */ protected boolean explainUnsat; /** - * This fields store the mapping from the constraint string ID to the constraint. - * In non-optimizing mode, all ID-constraint mappings are cached during encoding, - * so that we can retrieve the unsat constraints later using the constraint name. + * This fields store the mapping from the constraint string ID to the constraint. In + * non-optimizing mode, all ID-constraint mappings are cached during encoding, so that we can + * retrieve the unsat constraints later using the constraint name. */ protected final Map serializedConstraints = new HashMap<>(); @@ -74,7 +77,6 @@ public enum Z3SolverEngineArg implements SolverArg { protected long solvingStart; protected long solvingEnd; - public Z3SmtSolver( SolverEnvironment solverEnvironment, Collection slots, @@ -124,9 +126,8 @@ public Map solve() { logger.fine("!!! The set of constraints is unsatisfiable! !!!"); return null; } - - return formatTranslator.decodeSolution( - results, solverEnvironment.processingEnvironment); + + return formatTranslator.decodeSolution(results, solverEnvironment.processingEnvironment); } @Override @@ -187,7 +188,7 @@ private void serializeSMTFileContents() { } else { smtFileContents.append("(get-model)\n"); } - + logger.fine("Writing constraints to file: " + constraintsFile); writeConstraintsToSMTFile(); @@ -210,11 +211,12 @@ private void writeConstraintsToSMTFile() { protected void encodeAllSlots() { // preprocess slots formatTranslator.preAnalyzeSlots(slots); - + // generate slot constraints for (Slot slot : slots) { if (slot instanceof VariableSlot) { - BoolExpr wfConstraint = formatTranslator.encodeSlotWellformednessConstraint((VariableSlot) slot); + BoolExpr wfConstraint = + formatTranslator.encodeSlotWellformednessConstraint((VariableSlot) slot); if (!wfConstraint.simplify().isTrue()) { solver.Assert(wfConstraint); @@ -302,21 +304,22 @@ protected void encodeAllConstraints() { } protected void encodeAllSoftConstraints() { - final Z3SmtSoftConstraintEncoder encoder = formatTranslator.createSoftConstraintEncoder(); + final Z3SmtSoftConstraintEncoder encoder = + formatTranslator.createSoftConstraintEncoder(); smtFileContents.append(encoder.encodeAndGetSoftConstraints(constraints)); } protected void encodeSlotPreferenceConstraint(VariableSlot varSlot) { // empty string means no optimization group // TODO: support variable weight for preference constraint - solver.AssertSoft( - formatTranslator.encodeSlotPreferenceConstraint(varSlot), 1, ""); + solver.AssertSoft(formatTranslator.encodeSlotPreferenceConstraint(varSlot), 1, ""); } /** * Runs z3 solver and returns the parsed results based on whether it's sat/unsat - * @param results an output parameter that stores (1) the parsed solution if it's sat - * (2) the unsatisfiable constraint identifier strings otherwise + * + * @param results an output parameter that stores (1) the parsed solution if it's sat (2) the + * unsatisfiable constraint identifier strings otherwise * @return true if sat and false otherwise */ private boolean runZ3Solver(List results) { @@ -342,9 +345,9 @@ private boolean runZ3Solver(List results) { /** * Parses the STD output from the z3 process and handles SAT and UNSAT outputs - * @param results For sat case, this stores the parsed solution - * For unsat case, this stores the unsatisfiable constraint identifiers - * parsed from the z3 output + * + * @param results For sat case, this stores the parsed solution For unsat case, this stores the + * unsatisfiable constraint identifiers parsed from the z3 output */ private void parseStdOut(BufferedReader stdOut, List results) { String line; @@ -424,9 +427,7 @@ private String readStdoutByLine(BufferedReader stdout) { } } - /** - * Prints arithmetic constraints for debugging - */ + /** Prints arithmetic constraints for debugging */ private void printArithmeticConstraints() { logger.fine("=== Arithmetic Constraints Printout ==="); Map arithmeticConstraintCounters = new HashMap<>(); diff --git a/src/checkers/inference/solver/backend/z3smt/Z3SmtSolverFactory.java b/src/checkers/inference/solver/backend/z3smt/Z3SmtSolverFactory.java index 9589f78eb..3f6027897 100644 --- a/src/checkers/inference/solver/backend/z3smt/Z3SmtSolverFactory.java +++ b/src/checkers/inference/solver/backend/z3smt/Z3SmtSolverFactory.java @@ -1,15 +1,13 @@ package checkers.inference.solver.backend.z3smt; +import java.util.Collection; + import checkers.inference.model.Constraint; import checkers.inference.model.Slot; import checkers.inference.solver.backend.AbstractSolverFactory; import checkers.inference.solver.backend.Solver; import checkers.inference.solver.frontend.Lattice; import checkers.inference.solver.util.SolverEnvironment; -import java.util.Collection; - -import checkers.inference.solver.backend.z3smt.Z3SmtFormatTranslator; -import checkers.inference.solver.backend.z3smt.Z3SmtSolver; public abstract class Z3SmtSolverFactory extends AbstractSolverFactory> { diff --git a/src/checkers/inference/solver/backend/z3smt/encoder/Z3SmtAbstractConstraintEncoder.java b/src/checkers/inference/solver/backend/z3smt/encoder/Z3SmtAbstractConstraintEncoder.java index 49f226334..4f3ac986a 100644 --- a/src/checkers/inference/solver/backend/z3smt/encoder/Z3SmtAbstractConstraintEncoder.java +++ b/src/checkers/inference/solver/backend/z3smt/encoder/Z3SmtAbstractConstraintEncoder.java @@ -1,19 +1,11 @@ package checkers.inference.solver.backend.z3smt.encoder; -import checkers.inference.model.ArithmeticConstraint; -import checkers.inference.model.CombineConstraint; -import checkers.inference.model.ComparableConstraint; -import checkers.inference.model.EqualityConstraint; -import checkers.inference.model.ExistentialConstraint; -import checkers.inference.model.ImplicationConstraint; -import checkers.inference.model.InequalityConstraint; -import checkers.inference.model.PreferenceConstraint; -import checkers.inference.model.SubtypeConstraint; +import com.microsoft.z3.BoolExpr; +import com.microsoft.z3.Context; + import checkers.inference.solver.backend.encoder.AbstractConstraintEncoder; import checkers.inference.solver.backend.z3smt.Z3SmtFormatTranslator; import checkers.inference.solver.frontend.Lattice; -import com.microsoft.z3.BoolExpr; -import com.microsoft.z3.Context; /** Abstract base class for every Z3Int constraint encoders. */ public abstract class Z3SmtAbstractConstraintEncoder @@ -22,10 +14,12 @@ public abstract class Z3SmtAbstractConstraintEncoder z3SmtFormatTranslator; @@ -38,5 +32,4 @@ public Z3SmtAbstractConstraintEncoder( this.ctx = ctx; this.z3SmtFormatTranslator = z3SmtFormatTranslator; } - } diff --git a/src/checkers/inference/solver/backend/z3smt/encoder/Z3SmtConstraintEncoderFactory.java b/src/checkers/inference/solver/backend/z3smt/encoder/Z3SmtConstraintEncoderFactory.java index 08ec710fa..b369b6499 100644 --- a/src/checkers/inference/solver/backend/z3smt/encoder/Z3SmtConstraintEncoderFactory.java +++ b/src/checkers/inference/solver/backend/z3smt/encoder/Z3SmtConstraintEncoderFactory.java @@ -1,27 +1,29 @@ package checkers.inference.solver.backend.z3smt.encoder; +import com.microsoft.z3.BoolExpr; +import com.microsoft.z3.Context; + import checkers.inference.solver.backend.encoder.AbstractConstraintEncoderFactory; import checkers.inference.solver.backend.z3smt.Z3SmtFormatTranslator; import checkers.inference.solver.frontend.Lattice; -import com.microsoft.z3.BoolExpr; -import com.microsoft.z3.Context; /** * Abstract Z3 implementation of {@link - * checkers.inference.solver.backend.encoder.ConstraintEncoderFactory}. - * Subclasses must specify the exact encoders used. + * checkers.inference.solver.backend.encoder.ConstraintEncoderFactory}. Subclasses must specify the + * exact encoders used. * * @see checkers.inference.solver.backend.encoder.ConstraintEncoderFactory */ public abstract class Z3SmtConstraintEncoderFactory - extends AbstractConstraintEncoderFactory> { - protected final Context ctx; + extends AbstractConstraintEncoderFactory< + BoolExpr, Z3SmtFormatTranslator> { + protected final Context ctx; - public Z3SmtConstraintEncoderFactory( - Lattice lattice, - Context ctx, - Z3SmtFormatTranslator z3SmtFormatTranslator) { - super(lattice, z3SmtFormatTranslator); - this.ctx = ctx; - } + public Z3SmtConstraintEncoderFactory( + Lattice lattice, + Context ctx, + Z3SmtFormatTranslator z3SmtFormatTranslator) { + super(lattice, z3SmtFormatTranslator); + this.ctx = ctx; + } } diff --git a/src/checkers/inference/solver/backend/z3smt/encoder/Z3SmtSoftConstraintEncoder.java b/src/checkers/inference/solver/backend/z3smt/encoder/Z3SmtSoftConstraintEncoder.java index 48efee7c5..559f2d4bb 100644 --- a/src/checkers/inference/solver/backend/z3smt/encoder/Z3SmtSoftConstraintEncoder.java +++ b/src/checkers/inference/solver/backend/z3smt/encoder/Z3SmtSoftConstraintEncoder.java @@ -1,23 +1,18 @@ package checkers.inference.solver.backend.z3smt.encoder; -import java.util.Collection; - import com.microsoft.z3.Context; import com.microsoft.z3.Expr; -import checkers.inference.model.ArithmeticConstraint; -import checkers.inference.model.CombineConstraint; -import checkers.inference.model.ComparableConstraint; +import org.checkerframework.javacutil.BugInCF; + +import java.util.Collection; + import checkers.inference.model.Constraint; import checkers.inference.model.EqualityConstraint; -import checkers.inference.model.ExistentialConstraint; -import checkers.inference.model.ImplicationConstraint; import checkers.inference.model.InequalityConstraint; -import checkers.inference.model.PreferenceConstraint; import checkers.inference.model.SubtypeConstraint; import checkers.inference.solver.backend.z3smt.Z3SmtFormatTranslator; import checkers.inference.solver.frontend.Lattice; -import org.checkerframework.javacutil.BugInCF; public abstract class Z3SmtSoftConstraintEncoder extends Z3SmtAbstractConstraintEncoder { @@ -33,7 +28,8 @@ public Z3SmtSoftConstraintEncoder( } protected void addSoftConstraint(Expr serializedConstraint, int weight) { - softConstraints.append("(assert-soft " + serializedConstraint + " :weight " + weight + ")\n"); + softConstraints.append( + "(assert-soft " + serializedConstraint + " :weight " + weight + ")\n"); } protected abstract void encodeSoftSubtypeConstraint(SubtypeConstraint constraint); @@ -60,7 +56,10 @@ public String encodeAndGetSoftConstraints(Collection constraints) { encodeSoftInequalityConstraint((InequalityConstraint) constraint); } else { - throw new BugInCF("Soft constraint for " + constraint.getClass().getName() + " is not supported"); + throw new BugInCF( + "Soft constraint for " + + constraint.getClass().getName() + + " is not supported"); } } String res = softConstraints.toString(); diff --git a/src/checkers/inference/solver/constraintgraph/ConstraintGraph.java b/src/checkers/inference/solver/constraintgraph/ConstraintGraph.java index f171f6011..34e3528b0 100644 --- a/src/checkers/inference/solver/constraintgraph/ConstraintGraph.java +++ b/src/checkers/inference/solver/constraintgraph/ConstraintGraph.java @@ -14,14 +14,12 @@ import checkers.inference.model.SubtypeConstraint; /** - * ConstraintGraph represents constraints in a graph form. Each constraint is an - * edge, and each slot is a vertex. ConstraintGraph is used for separating - * constraint into different components by running graph traversal algorithm on - * it. Normal edges in this graph are bi-directional edges, except SubtypeEdge - * is single-directed from subtype vertex to supertype vertex. - * - * @author jianchu + * ConstraintGraph represents constraints in a graph form. Each constraint is an edge, and each slot + * is a vertex. ConstraintGraph is used for separating constraint into different components by + * running graph traversal algorithm on it. Normal edges in this graph are bi-directional edges, + * except SubtypeEdge is single-directed from subtype vertex to supertype vertex. * + * @author jianchu */ public class ConstraintGraph { diff --git a/src/checkers/inference/solver/constraintgraph/Edge.java b/src/checkers/inference/solver/constraintgraph/Edge.java index 80a5a2dc1..50ccbd8ab 100644 --- a/src/checkers/inference/solver/constraintgraph/Edge.java +++ b/src/checkers/inference/solver/constraintgraph/Edge.java @@ -6,9 +6,8 @@ /** * Edge represents a constraint. Edge is undirected. - * - * @author jianchu * + * @author jianchu */ public class Edge { diff --git a/src/checkers/inference/solver/constraintgraph/GraphBuilder.java b/src/checkers/inference/solver/constraintgraph/GraphBuilder.java index 7fa29b4ef..a56fbd1d0 100644 --- a/src/checkers/inference/solver/constraintgraph/GraphBuilder.java +++ b/src/checkers/inference/solver/constraintgraph/GraphBuilder.java @@ -1,7 +1,7 @@ package checkers.inference.solver.constraintgraph; -import dataflow.DataflowAnnotatedTypeFactory; import org.checkerframework.javacutil.AnnotationUtils; +import org.checkerframework.javacutil.BugInCF; import java.util.ArrayList; import java.util.Collection; @@ -22,23 +22,22 @@ import checkers.inference.model.Slot; import checkers.inference.model.SubtypeConstraint; import checkers.inference.model.VariableSlot; +import dataflow.DataflowAnnotatedTypeFactory; import dataflow.DataflowVisitor; -import dataflow.util.DataflowUtils; -import org.checkerframework.javacutil.BugInCF; /** - * GraphBuilder builds the constraint graph and runs graph traversal algorithms - * to separate the graph in different components. - * - * @author jianchu + * GraphBuilder builds the constraint graph and runs graph traversal algorithms to separate the + * graph in different components. * + * @author jianchu */ public class GraphBuilder { private final Collection constraints; private final ConstraintGraph graph; private final AnnotationMirror top; - public GraphBuilder(Collection slots, Collection constraints, AnnotationMirror top) { + public GraphBuilder( + Collection slots, Collection constraints, AnnotationMirror top) { this.constraints = constraints; this.graph = new ConstraintGraph(); this.top = top; @@ -64,9 +63,7 @@ public ConstraintGraph buildGraph() { return getGraph(); } - /** - * Find all constant vertices. - */ + /** Find all constant vertices. */ private void addConstant() { for (Vertex vertex : graph.getVerticies()) { if (vertex.isConstant()) { @@ -75,10 +72,7 @@ private void addConstant() { } } - /** - * This method runs BFS based algorithm, and calculates all independent - * components. - */ + /** This method runs BFS based algorithm, and calculates all independent components. */ private void calculateIndependentPath() { Set visited = new HashSet(); for (Vertex vertex : this.graph.getVerticies()) { @@ -91,8 +85,10 @@ private void calculateIndependentPath() { visited.add(current); for (Edge edge : current.getEdges()) { independentPath.add(edge.getConstraint()); - Vertex next = edge.getFromVertex().equals(current) ? edge.getToVertex() : edge - .getFromVertex(); + Vertex next = + edge.getFromVertex().equals(current) + ? edge.getToVertex() + : edge.getFromVertex(); if (!visited.contains(next)) { queue.add(next); } @@ -104,8 +100,8 @@ private void calculateIndependentPath() { } /** - * For each constant vertex, this method run BFS based algorithm on it, and - * and put all edges that can be reached by the vertex into one set. + * For each constant vertex, this method run BFS based algorithm on it, and and put all edges + * that can be reached by the vertex into one set. */ private void calculateConstantPath() { for (Vertex vertex : this.graph.getConstantVerticies()) { @@ -126,29 +122,38 @@ private Set BFSSearch(Vertex vertex) { if ((edge instanceof SubtypeEdge) && current.equals(edge.to)) { continue; } - Vertex next = current.equals(edge.getToVertex()) ? edge.getFromVertex() : edge.getToVertex(); + Vertex next = + current.equals(edge.getToVertex()) + ? edge.getFromVertex() + : edge.getToVertex(); constantPathConstraints.add(edge.getConstraint()); if (!visited.contains(next)) { if (next.isConstant()) { if (AnnotationUtils.areSame(top, next.getValue())) { continue; - } else if (InferenceMain.getInstance().getVisitor() instanceof DataflowVisitor) { - // TODO: find a proper way to adapt this behavior in type-system specific subclasses. - DataflowAnnotatedTypeFactory typeFactory = (DataflowAnnotatedTypeFactory) - InferenceMain.getInstance().getRealTypeFactory(); - List typeNames = typeFactory.dataflowUtils.getTypeNames(next.getValue()); + } else if (InferenceMain.getInstance().getVisitor() + instanceof DataflowVisitor) { + // TODO: find a proper way to adapt this behavior in type-system + // specific subclasses. + DataflowAnnotatedTypeFactory typeFactory = + (DataflowAnnotatedTypeFactory) + InferenceMain.getInstance().getRealTypeFactory(); + List typeNames = + typeFactory.dataflowUtils.getTypeNames(next.getValue()); if (typeNames.size() == 1 && typeNames.get(0).isEmpty()) { continue; } } } else { VariableSlot slot = (VariableSlot) next.getSlot(); - if (slot.getLocation() != null && slot.getLocation().getKind().equals(Kind.MISSING)) { + if (slot.getLocation() != null + && slot.getLocation().getKind().equals(Kind.MISSING)) { if (InferenceMain.isHackMode()) { continue; } else { - throw new BugInCF("In GraphBuilder.BFSSearch: find a slot of which " + - "the location is either null or MISSING_LOCATION!"); + throw new BugInCF( + "In GraphBuilder.BFSSearch: find a slot of which " + + "the location is either null or MISSING_LOCATION!"); } } } @@ -172,9 +177,9 @@ private void addEdges(ArrayList slots, Constraint constraint) { } /** - * The order of subtype and supertype matters, first one has to be subtype, - * second one has to be supertype. - * + * The order of subtype and supertype matters, first one has to be subtype, second one has to be + * supertype. + * * @param subtypeConstraint */ private void addSubtypeEdge(SubtypeConstraint subtypeConstraint) { diff --git a/src/checkers/inference/solver/constraintgraph/SubtypeEdge.java b/src/checkers/inference/solver/constraintgraph/SubtypeEdge.java index 85ab8fe78..5344e0ca1 100644 --- a/src/checkers/inference/solver/constraintgraph/SubtypeEdge.java +++ b/src/checkers/inference/solver/constraintgraph/SubtypeEdge.java @@ -4,9 +4,8 @@ /** * SubtypeEdge is for subtype constraint. It can be treated as directed edge. - * - * @author jianchu * + * @author jianchu */ public class SubtypeEdge extends Edge { diff --git a/src/checkers/inference/solver/constraintgraph/Vertex.java b/src/checkers/inference/solver/constraintgraph/Vertex.java index fa933d142..8aa62d15a 100644 --- a/src/checkers/inference/solver/constraintgraph/Vertex.java +++ b/src/checkers/inference/solver/constraintgraph/Vertex.java @@ -10,9 +10,8 @@ /** * Vertex represents a slot. Two vertices are same if they have same slot id. - * - * @author jianchu * + * @author jianchu */ public class Vertex { diff --git a/src/checkers/inference/solver/frontend/Lattice.java b/src/checkers/inference/solver/frontend/Lattice.java index 89b2a0fb7..3faff73b9 100644 --- a/src/checkers/inference/solver/frontend/Lattice.java +++ b/src/checkers/inference/solver/frontend/Lattice.java @@ -1,5 +1,7 @@ package checkers.inference.solver.frontend; +import org.checkerframework.framework.type.QualifierHierarchy; + import java.util.Collection; import java.util.Collections; import java.util.Map; @@ -7,77 +9,62 @@ import javax.lang.model.element.AnnotationMirror; -import org.checkerframework.framework.type.QualifierHierarchy; - /** - * Lattice class pre-cache necessary qualifier information from qualifier hierarchy for - * constraint constraint solving. - * - * It is convenient to get all subtypes and supertypes of a specific type - * qualifier, all type qualifier, and bottom and top qualifiers from an instance - * of this class. + * Lattice class pre-cache necessary qualifier information from qualifier hierarchy for constraint + * constraint solving. * - * @author jianchu + *

It is convenient to get all subtypes and supertypes of a specific type qualifier, all type + * qualifier, and bottom and top qualifiers from an instance of this class. * + * @author jianchu */ public class Lattice { - /** - * subType maps each type qualifier to its sub types. - */ + /** subType maps each type qualifier to its sub types. */ public final Map> subType; - /** - * superType maps each type qualifier to its super types. - */ + /** superType maps each type qualifier to its super types. */ public final Map> superType; - /** - * incomparableType maps each type qualifier to its incomparable types. - */ + /** incomparableType maps each type qualifier to its incomparable types. */ public final Map> incomparableType; - /** - * All type qualifiers in underling type system. - */ + /** All type qualifiers in underling type system. */ public final Set allTypes; - /** - * Top qualifier of underling type system. - */ + /** Top qualifier of underling type system. */ public final AnnotationMirror top; - /** - * Bottom type qualifier of underling type system. - */ + /** Bottom type qualifier of underling type system. */ public final AnnotationMirror bottom; - /** - * Number of type qualifier in underling type system. - */ + /** Number of type qualifier in underling type system. */ public final int numTypes; /** - * All concrete qualifiers information that collected from the program - * CF Inference running on. - * This field is useful for type systems that has a dynamic number - * of type qualifiers. + * All concrete qualifiers information that collected from the program CF Inference running on. + * This field is useful for type systems that has a dynamic number of type qualifiers. */ public final Collection allAnnotations; /** - * Underlying qualifier hierarchy that this lattice built based on. - * This field is nullable, it will be null if this lattice doesn't built based on - * a real qualifier hierarchy. (E.g. TwoQualifierLattice). + * Underlying qualifier hierarchy that this lattice built based on. This field is nullable, it + * will be null if this lattice doesn't built based on a real qualifier hierarchy. (E.g. + * TwoQualifierLattice). */ /* @Nullable */ private final QualifierHierarchy underlyingQualifierHierarchy; - public Lattice(Map> subType, + public Lattice( + Map> subType, Map> superType, Map> incomparableType, - Set allTypes, AnnotationMirror top, AnnotationMirror bottom, - int numTypes, Collection runtimeAMs, /* @Nullable */ QualifierHierarchy qualifierHierarchy) { + Set allTypes, + AnnotationMirror top, + AnnotationMirror bottom, + int numTypes, + Collection runtimeAMs, /* @Nullable */ + QualifierHierarchy qualifierHierarchy) { this.subType = Collections.unmodifiableMap(subType); this.superType = Collections.unmodifiableMap(superType); this.incomparableType = Collections.unmodifiableMap(incomparableType); @@ -91,6 +78,5 @@ public Lattice(Map> subType, public boolean isSubtype(AnnotationMirror a1, AnnotationMirror a2) { return underlyingQualifierHierarchy.isSubtypeQualifiersOnly(a1, a2); - } } diff --git a/src/checkers/inference/solver/frontend/LatticeBuilder.java b/src/checkers/inference/solver/frontend/LatticeBuilder.java index e0b85bd25..acc0610c4 100644 --- a/src/checkers/inference/solver/frontend/LatticeBuilder.java +++ b/src/checkers/inference/solver/frontend/LatticeBuilder.java @@ -1,5 +1,11 @@ package checkers.inference.solver.frontend; +import org.checkerframework.framework.type.QualifierHierarchy; +import org.checkerframework.javacutil.AnnotationBuilder; +import org.checkerframework.javacutil.AnnotationMirrorMap; +import org.checkerframework.javacutil.AnnotationMirrorSet; +import org.checkerframework.javacutil.AnnotationUtils; + import java.lang.annotation.Annotation; import java.util.Collection; import java.util.Collections; @@ -10,60 +16,40 @@ import javax.lang.model.element.AnnotationMirror; import checkers.inference.InferenceMain; -import org.checkerframework.framework.type.QualifierHierarchy; -import org.checkerframework.javacutil.AnnotationBuilder; -import org.checkerframework.javacutil.AnnotationMirrorMap; -import org.checkerframework.javacutil.AnnotationMirrorSet; -import org.checkerframework.javacutil.AnnotationUtils; - import checkers.inference.model.ConstantSlot; import checkers.inference.model.Slot; public class LatticeBuilder { - /** - * subType maps each type qualifier to its sub types. - */ + /** subType maps each type qualifier to its sub types. */ private final Map> subType; - /** - * superType maps each type qualifier to its super types. - */ + /** superType maps each type qualifier to its super types. */ private final Map> superType; - /** - * incomparableType maps each type qualifier to its incomparable types. - */ + /** incomparableType maps each type qualifier to its incomparable types. */ private final Map> incomparableType; /** - * All type qualifiers in underling type system. - * Requires annotation ordering, so must created with {@code AnnotationUtils.createAnnotationSet()} when constructing from empty set, - * even if being converted to {@code UnmodifiableSet} later on - * TODO remove the dependency to TreeSet + * All type qualifiers in underling type system. Requires annotation ordering, so must created + * with {@code AnnotationUtils.createAnnotationSet()} when constructing from empty set, even if + * being converted to {@code UnmodifiableSet} later on TODO remove the dependency to TreeSet */ private Set allTypes; - /** - * Top qualifier of underling type system. - */ + /** Top qualifier of underling type system. */ private AnnotationMirror top; - /** - * Bottom type qualifier of underling type system. - */ + /** Bottom type qualifier of underling type system. */ private AnnotationMirror bottom; - /** - * Number of type qualifier in underling type system. - */ + /** Number of type qualifier in underling type system. */ private int numTypes; /** - * All concrete qualifiers extracted from slots collected from the program - * that CF Inference running on. - * This field is useful for type systems that has a dynamic number - * of type qualifiers. + * All concrete qualifiers extracted from slots collected from the program that CF Inference + * running on. This field is useful for type systems that has a dynamic number of type + * qualifiers. */ public final Collection allAnnotations; @@ -72,7 +58,6 @@ public LatticeBuilder() { superType = new AnnotationMirrorMap<>(); incomparableType = new AnnotationMirrorMap<>(); allAnnotations = new AnnotationMirrorSet(); - } /** @@ -87,9 +72,14 @@ public Lattice buildLattice(QualifierHierarchy qualHierarchy, Collection s Set supportedAnnos = new AnnotationMirrorSet(); Set> annoClasses = InferenceMain.getInstance().getRealTypeFactory().getSupportedTypeQualifiers(); - for (Class ac: annoClasses) { - supportedAnnos.add(new AnnotationBuilder( - InferenceMain.getInstance().getRealTypeFactory().getProcessingEnv(), ac).build()); + for (Class ac : annoClasses) { + supportedAnnos.add( + new AnnotationBuilder( + InferenceMain.getInstance() + .getRealTypeFactory() + .getProcessingEnv(), + ac) + .build()); } top = qualHierarchy.getTopAnnotations().iterator().next(); @@ -134,13 +124,21 @@ public Lattice buildLattice(QualifierHierarchy qualHierarchy, Collection s collectConstantAnnotationMirrors(slots); - return new Lattice(subType, superType, incomparableType, allTypes, top, - bottom, numTypes, allAnnotations, qualHierarchy); + return new Lattice( + subType, + superType, + incomparableType, + allTypes, + top, + bottom, + numTypes, + allAnnotations, + qualHierarchy); } /** * Build a two-qualifier lattice with all fields configured. - * + * * @param top type qualifier of underling type system. * @param bottom type qualifier of underling type system. * @return a new TwoQualifiersLattice instance. @@ -168,16 +166,16 @@ public TwoQualifiersLattice buildTwoTypeLattice(AnnotationMirror top, Annotation // Incomparable map should be empty in two qualifiers lattice. incomparableType.clear(); - //TODO: RuntimeAMs information seems only useful for dynamic lattices. + // TODO: RuntimeAMs information seems only useful for dynamic lattices. // Is there a need to extract runtime annotation mirrors for two qualifiers lattice? - return new TwoQualifiersLattice(subType, superType, incomparableType, - allTypes, top, bottom, numTypes); + return new TwoQualifiersLattice( + subType, superType, incomparableType, allTypes, top, bottom, numTypes); } /** - * Clear all fields. Will be called when build a new lattice to make sure - * the old values are gone. + * Clear all fields. Will be called when build a new lattice to make sure the old values are + * gone. */ private void clear() { allAnnotations.clear(); @@ -192,13 +190,14 @@ private void clear() { /** * Extract annotation mirrors in constant slots of a given collection of slots. + * * @param slots a collection of slots. */ private void collectConstantAnnotationMirrors(Collection slots) { - for(Slot slot : slots) { - if (slot instanceof ConstantSlot) { - allAnnotations.add(((ConstantSlot) slot).getValue()); - } - } - } + for (Slot slot : slots) { + if (slot instanceof ConstantSlot) { + allAnnotations.add(((ConstantSlot) slot).getValue()); + } + } + } } diff --git a/src/checkers/inference/solver/frontend/TwoQualifiersLattice.java b/src/checkers/inference/solver/frontend/TwoQualifiersLattice.java index 7f3d822c9..a92ab069c 100644 --- a/src/checkers/inference/solver/frontend/TwoQualifiersLattice.java +++ b/src/checkers/inference/solver/frontend/TwoQualifiersLattice.java @@ -1,36 +1,44 @@ package checkers.inference.solver.frontend; +import org.checkerframework.javacutil.AnnotationUtils; +import org.checkerframework.javacutil.BugInCF; + import java.util.Collection; import java.util.Map; import java.util.Set; import javax.lang.model.element.AnnotationMirror; -import org.checkerframework.javacutil.AnnotationUtils; -import org.checkerframework.javacutil.BugInCF; - /** * Special Lattice class for two qualifier type system. - * - * @author jianchu * + * @author jianchu */ public class TwoQualifiersLattice extends Lattice { - public TwoQualifiersLattice(Map> subType, + public TwoQualifiersLattice( + Map> subType, Map> superType, Map> incomparableType, - Set allTypes, AnnotationMirror top, AnnotationMirror bottom, + Set allTypes, + AnnotationMirror top, + AnnotationMirror bottom, int numTypes) { super(subType, superType, incomparableType, allTypes, top, bottom, numTypes, null, null); } @Override public boolean isSubtype(AnnotationMirror a1, AnnotationMirror a2) { - if (!AnnotationUtils.containsSame(allTypes, a1) || !AnnotationUtils.containsSame(allTypes, a2)) { - throw new BugInCF("Enconture invalid type when perform isSubtype judgement: " + - " all type qualifiers in this lattice are: " + allTypes + - " but a1 is : + " + a1 + " and a2 is: " + a2); + if (!AnnotationUtils.containsSame(allTypes, a1) + || !AnnotationUtils.containsSame(allTypes, a2)) { + throw new BugInCF( + "Enconture invalid type when perform isSubtype judgement: " + + " all type qualifiers in this lattice are: " + + allTypes + + " but a1 is : + " + + a1 + + " and a2 is: " + + a2); } return AnnotationUtils.areSame(bottom, a1) || AnnotationUtils.areSame(top, a2); diff --git a/src/checkers/inference/solver/strategy/AbstractSolvingStrategy.java b/src/checkers/inference/solver/strategy/AbstractSolvingStrategy.java index c0049f24d..cf84d813a 100644 --- a/src/checkers/inference/solver/strategy/AbstractSolvingStrategy.java +++ b/src/checkers/inference/solver/strategy/AbstractSolvingStrategy.java @@ -2,19 +2,16 @@ import checkers.inference.solver.backend.SolverFactory; -/** - * Abstract base class for all concrete {@link SolvingStrategy} implementation. * - */ +/** Abstract base class for all concrete {@link SolvingStrategy} implementation. * */ public abstract class AbstractSolvingStrategy implements SolvingStrategy { /** - * The solver factory used to create underlying solver that responsible for - * solving constraints in this solving strategy. + * The solver factory used to create underlying solver that responsible for solving constraints + * in this solving strategy. */ protected final SolverFactory solverFactory; public AbstractSolvingStrategy(SolverFactory solverFactory) { this.solverFactory = solverFactory; } - } diff --git a/src/checkers/inference/solver/strategy/GraphSolvingStrategy.java b/src/checkers/inference/solver/strategy/GraphSolvingStrategy.java index 72b22e1cc..aa28b905d 100644 --- a/src/checkers/inference/solver/strategy/GraphSolvingStrategy.java +++ b/src/checkers/inference/solver/strategy/GraphSolvingStrategy.java @@ -1,5 +1,9 @@ package checkers.inference.solver.strategy; +import com.sun.tools.javac.util.Pair; + +import org.checkerframework.framework.type.QualifierHierarchy; + import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -31,19 +35,17 @@ import checkers.inference.solver.util.SolverArg; import checkers.inference.solver.util.SolverEnvironment; import checkers.inference.solver.util.Statistics; -import com.sun.tools.javac.util.Pair; -import org.checkerframework.framework.type.QualifierHierarchy; /** * GraphSolvingStrategy solves a given set of constraints by a divide-and-conquer way: * - * 1. Build a {@link ConstraintGraph} based on the given set of constraints. - * 2. Divide the constraint graph to multiple sub-graphs. - * 3. For each sub-graphs, assign an underlying solver to solve it. - * 4. Merge solutions of sub-graphs to get the final solution. + *

1. Build a {@link ConstraintGraph} based on the given set of constraints. 2. Divide the + * constraint graph to multiple sub-graphs. 3. For each sub-graphs, assign an underlying solver to + * solve it. 4. Merge solutions of sub-graphs to get the final solution. * - * This solving strategy is useful when solving constraints for a type system with a huge number of qualifers. - * Normal plain solving strategy meet exponentially increased solving time in this case. + *

This solving strategy is useful when solving constraints for a type system with a huge number + * of qualifers. Normal plain solving strategy meet exponentially increased solving time in this + * case. */ public class GraphSolvingStrategy extends AbstractSolvingStrategy { @@ -56,24 +58,31 @@ public GraphSolvingStrategy(SolverFactory solverFactory) { } @Override - public InferenceResult solve(SolverEnvironment solverEnvironment, Collection slots, - Collection constraints, Lattice lattice) { + public InferenceResult solve( + SolverEnvironment solverEnvironment, + Collection slots, + Collection constraints, + Lattice lattice) { - //TODO: Remove the coupling of using SolverEngineArg. - final boolean solveInParallel = !"lingeling".equals(solverEnvironment.getArg(SolverEngineArg.solver)) - && solverEnvironment.getBoolArg(GraphSolveStrategyArg.solveInParallel); + // TODO: Remove the coupling of using SolverEngineArg. + final boolean solveInParallel = + !"lingeling".equals(solverEnvironment.getArg(SolverEngineArg.solver)) + && solverEnvironment.getBoolArg(GraphSolveStrategyArg.solveInParallel); // Build graph final long graphBuildingStart = System.currentTimeMillis(); - ConstraintGraph constraintGraph = generateGraph(slots, constraints, solverEnvironment.processingEnvironment); + ConstraintGraph constraintGraph = + generateGraph(slots, constraints, solverEnvironment.processingEnvironment); final long graphBuildingEnd = System.currentTimeMillis(); - // Separate constraint graph, and assign each separated sub-graph to a underlying solver to solve. - List> separatedGraphSolvers = separateGraph(solverEnvironment, constraintGraph, - slots, constraints, lattice); + // Separate constraint graph, and assign each separated sub-graph to a underlying solver to + // solve. + List> separatedGraphSolvers = + separateGraph(solverEnvironment, constraintGraph, slots, constraints, lattice); // Solving. - List, Collection>> inferenceResults = new LinkedList<>(); + List, Collection>> inferenceResults = + new LinkedList<>(); if (separatedGraphSolvers.size() > 0) { if (solveInParallel) { @@ -90,7 +99,8 @@ public InferenceResult solve(SolverEnvironment solverEnvironment, CollectionThis method should be overridden in special cases, e.g, type systems with multiple - * type hierarchies. + *

This method should be overridden in special cases, e.g, type systems with multiple type + * hierarchies. + * * @return the top annotation of the constraint graph */ protected AnnotationMirror getGraphTopAnnotation() { - QualifierHierarchy qualHierarchy = InferenceMain.getInstance().getRealTypeFactory().getQualifierHierarchy(); + QualifierHierarchy qualHierarchy = + InferenceMain.getInstance().getRealTypeFactory().getQualifierHierarchy(); return qualHierarchy.getTopAnnotations().iterator().next(); } - protected ConstraintGraph generateGraph(Collection slots, Collection constraints, + protected ConstraintGraph generateGraph( + Collection slots, + Collection constraints, ProcessingEnvironment processingEnvironment) { GraphBuilder graphBuilder = new GraphBuilder(slots, constraints, getGraphTopAnnotation()); ConstraintGraph constraintGraph = graphBuilder.buildGraph(); @@ -120,17 +134,24 @@ protected ConstraintGraph generateGraph(Collection slots, CollectionSub-class may customize their own way of separating the constraint graph by overriding + * this method. * * @return a list of underlying solvers, each of them responsible for solving a separated - * sub-graph from the given constraint graph. + * sub-graph from the given constraint graph. */ - protected List> separateGraph(SolverEnvironment solverEnvironment, ConstraintGraph constraintGraph, - Collection slots, Collection constraints, Lattice lattice) { + protected List> separateGraph( + SolverEnvironment solverEnvironment, + ConstraintGraph constraintGraph, + Collection slots, + Collection constraints, + Lattice lattice) { List> separatedGraphSovlers = new ArrayList<>(); for (Set independentConstraints : constraintGraph.getIndependentPath()) { - separatedGraphSovlers.add(solverFactory.createSolver(solverEnvironment, slots, independentConstraints, lattice)); + separatedGraphSovlers.add( + solverFactory.createSolver( + solverEnvironment, slots, independentConstraints, lattice)); } return separatedGraphSovlers; @@ -144,34 +165,39 @@ protected List> separateGraph(SolverEnvironment solverEnvironment, Con * @throws InterruptedException * @throws ExecutionException */ - protected List, Collection>> solveInparallel(List> underlyingSolvers) - throws InterruptedException, ExecutionException { + protected List, Collection>> solveInparallel( + List> underlyingSolvers) throws InterruptedException, ExecutionException { ExecutorService service = Executors.newFixedThreadPool(30); - List, Collection>>> futures = new ArrayList<>(); + List, Collection>>> futures = + new ArrayList<>(); long solvingStart = System.currentTimeMillis(); for (final Solver underlyingSolver : underlyingSolvers) { - Callable, Collection>> callable = () -> { - Map solution = underlyingSolver.solve(); - if (solution != null) { - return new Pair<>(solution, new HashSet<>()); - } else { - return new Pair<>(solution, underlyingSolver.explainUnsatisfiable()); - } - }; + Callable, Collection>> callable = + () -> { + Map solution = underlyingSolver.solve(); + if (solution != null) { + return new Pair<>(solution, new HashSet<>()); + } else { + return new Pair<>(solution, underlyingSolver.explainUnsatisfiable()); + } + }; futures.add(service.submit(callable)); } service.shutdown(); - List, Collection>> results = new ArrayList<>(); + List, Collection>> results = + new ArrayList<>(); - for (Future, Collection>> future : futures) { + for (Future, Collection>> future : + futures) { results.add(future.get()); } long solvingEnd = System.currentTimeMillis(); - Statistics.addOrIncrementEntry("overall_parallel_solving_time(ms)", (solvingEnd - solvingStart)); + Statistics.addOrIncrementEntry( + "overall_parallel_solving_time(ms)", (solvingEnd - solvingStart)); return results; } @@ -181,9 +207,11 @@ protected List, Collection>> sol * @param underlyingSolvers * @return A list of Map that contains solutions from all underlying solvers. */ - protected List, Collection>> solveInSequential(List> underlyingSolvers) { + protected List, Collection>> solveInSequential( + List> underlyingSolvers) { - List, Collection>> results = new ArrayList<>(); + List, Collection>> results = + new ArrayList<>(); long solvingStart = System.currentTimeMillis(); for (final Solver underlyingSolver : underlyingSolvers) { @@ -196,7 +224,8 @@ protected List, Collection>> sol } long solvingEnd = System.currentTimeMillis(); - Statistics.addOrIncrementEntry("overall_sequential_solving_time(ms)", (solvingEnd - solvingStart)); + Statistics.addOrIncrementEntry( + "overall_sequential_solving_time(ms)", (solvingEnd - solvingStart)); return results; } @@ -206,11 +235,13 @@ protected List, Collection>> sol * @param inferenceResults * @return an InferenceResult for the given slots/constraints */ - protected InferenceResult mergeInferenceResults(List, Collection>> inferenceResults) { + protected InferenceResult mergeInferenceResults( + List, Collection>> inferenceResults) { Map solutions = new HashMap<>(); - for (Pair, Collection> inferenceResult : inferenceResults) { + for (Pair, Collection> inferenceResult : + inferenceResults) { if (inferenceResult.fst != null) { solutions.putAll(inferenceResult.fst); } else { diff --git a/src/checkers/inference/solver/strategy/PlainSolvingStrategy.java b/src/checkers/inference/solver/strategy/PlainSolvingStrategy.java index 0b5ab442f..fe52068a9 100644 --- a/src/checkers/inference/solver/strategy/PlainSolvingStrategy.java +++ b/src/checkers/inference/solver/strategy/PlainSolvingStrategy.java @@ -14,17 +14,21 @@ import checkers.inference.solver.frontend.Lattice; import checkers.inference.solver.util.SolverEnvironment; -public class PlainSolvingStrategy extends AbstractSolvingStrategy{ +public class PlainSolvingStrategy extends AbstractSolvingStrategy { public PlainSolvingStrategy(SolverFactory solverFactory) { super(solverFactory); } @Override - public InferenceResult solve(SolverEnvironment solverEnvironment, Collection slots, - Collection constraints, Lattice lattice) { - - Solver underlyingSolver = solverFactory.createSolver(solverEnvironment, slots, constraints, lattice); + public InferenceResult solve( + SolverEnvironment solverEnvironment, + Collection slots, + Collection constraints, + Lattice lattice) { + + Solver underlyingSolver = + solverFactory.createSolver(solverEnvironment, slots, constraints, lattice); Map solutions = underlyingSolver.solve(); diff --git a/src/checkers/inference/solver/strategy/SolvingStrategy.java b/src/checkers/inference/solver/strategy/SolvingStrategy.java index 55709db49..a1e0f0d90 100644 --- a/src/checkers/inference/solver/strategy/SolvingStrategy.java +++ b/src/checkers/inference/solver/strategy/SolvingStrategy.java @@ -12,23 +12,22 @@ /** * Define a strategy on solving constriants. * - * Note: subclasses within the Solver Framework should follow naming conventions, - * in order to let {@code SolverEngine} be able to reflectively load subclass instance. + *

Note: subclasses within the Solver Framework should follow naming conventions, in order to let + * {@code SolverEngine} be able to reflectively load subclass instance. * - * Naming convention is: - * Package: subclasses should be created within current package checkers.inference.solver.strategy. - * Class name: [StrategyName]SolvingStrategy. + *

Naming convention is: Package: subclasses should be created within current package + * checkers.inference.solver.strategy. Class name: [StrategyName]SolvingStrategy. * - * E.g. For graph solving strategy, the class name should be: GraphSolvingStrategy. + *

E.g. For graph solving strategy, the class name should be: GraphSolvingStrategy. * * @see SolverEngine#createSolvingStrategy() */ public interface SolvingStrategy { - /** - * Solve the constraints by the solving strategy defined in this method. - * - */ - InferenceResult solve(SolverEnvironment solverEnvironment, Collection slots, - Collection constraints, Lattice lattice); + /** Solve the constraints by the solving strategy defined in this method. */ + InferenceResult solve( + SolverEnvironment solverEnvironment, + Collection slots, + Collection constraints, + Lattice lattice); } diff --git a/src/checkers/inference/solver/util/ExternalSolverUtils.java b/src/checkers/inference/solver/util/ExternalSolverUtils.java index 9465734b1..14ad94a8c 100644 --- a/src/checkers/inference/solver/util/ExternalSolverUtils.java +++ b/src/checkers/inference/solver/util/ExternalSolverUtils.java @@ -1,5 +1,8 @@ package checkers.inference.solver.util; +import org.checkerframework.javacutil.BugInCF; +import org.checkerframework.javacutil.UserError; + import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -8,12 +11,9 @@ import java.util.function.Consumer; import java.util.logging.Logger; -import org.checkerframework.javacutil.BugInCF; -import org.checkerframework.javacutil.UserError; - /** * Utility class with methods to run an external solver program. - * + * * @see FileUtils */ public class ExternalSolverUtils { @@ -21,21 +21,20 @@ public class ExternalSolverUtils { public static final Logger logger = Logger.getLogger(ExternalSolverUtils.class.getName()); /** - * Runs the external solver as given by command and uses the given - * stdOutHandler and stdErrHandler lambdas to process stdOut and stdErr. + * Runs the external solver as given by command and uses the given stdOutHandler and + * stdErrHandler lambdas to process stdOut and stdErr. * - * @param command - * an external solver command to be executed, each string in the - * array is space-concatenated to form the final command. - * @param stdOutHandler - * a lambda which takes a {@link BufferedReader} providing the - * stdOut of the external solver and handles the stdOut. - * @param stdErrHandler - * a lambda which takes a {@link BufferedReader} providing the - * stdErr of the external solver and handles the stdErr. + * @param command an external solver command to be executed, each string in the array is + * space-concatenated to form the final command. + * @param stdOutHandler a lambda which takes a {@link BufferedReader} providing the stdOut of + * the external solver and handles the stdOut. + * @param stdErrHandler a lambda which takes a {@link BufferedReader} providing the stdErr of + * the external solver and handles the stdErr. * @return the exit status code of the external command. */ - public static int runExternalSolver(String[] command, Consumer stdOutHandler, + public static int runExternalSolver( + String[] command, + Consumer stdOutHandler, Consumer stdErrHandler) { logger.info("Running external solver command \"" + String.join(" ", command) + "\"."); @@ -49,10 +48,10 @@ public static int runExternalSolver(String[] command, Consumer s } // Create threads to handle stdOut and stdErr - StdHandlerThread stdOutHandlerThread = new StdHandlerThread(process.getInputStream(), - stdOutHandler); - StdHandlerThread stdErrHandlerThread = new StdHandlerThread(process.getErrorStream(), - stdErrHandler); + StdHandlerThread stdOutHandlerThread = + new StdHandlerThread(process.getInputStream(), stdOutHandler); + StdHandlerThread stdErrHandlerThread = + new StdHandlerThread(process.getErrorStream(), stdErrHandler); stdOutHandlerThread.start(); stdErrHandlerThread.start(); @@ -84,8 +83,8 @@ public static int runExternalSolver(String[] command, Consumer s } /** - * A thread which wraps an InputStream in a BufferedReader and tasks the - * lambda function to handle the outputs. + * A thread which wraps an InputStream in a BufferedReader and tasks the lambda function to + * handle the outputs. */ private static class StdHandlerThread extends Thread { private InputStream stream; @@ -103,14 +102,12 @@ public void run() { } /** - * A default implementation of a handler which prints any content from the - * given {@link BufferedReader} to the given stream. + * A default implementation of a handler which prints any content from the given {@link + * BufferedReader} to the given stream. * - * @param stream - * an output stream to print the contents of the reader to. - * @param stdReader - * a BufferedReader containing the contents of an external - * process's std output stream. + * @param stream an output stream to print the contents of the reader to. + * @param stdReader a BufferedReader containing the contents of an external process's std output + * stream. */ public static void printStdStream(PrintStream stream, BufferedReader stdReader) { String line; diff --git a/src/checkers/inference/solver/util/FileUtils.java b/src/checkers/inference/solver/util/FileUtils.java index ad63ea855..33aa532e1 100644 --- a/src/checkers/inference/solver/util/FileUtils.java +++ b/src/checkers/inference/solver/util/FileUtils.java @@ -1,23 +1,20 @@ package checkers.inference.solver.util; +import org.checkerframework.javacutil.BugInCF; + import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintStream; -import org.checkerframework.javacutil.BugInCF; - public class FileUtils { /** - * Helper method which opens the given file and returns a PrintStream to the - * file. + * Helper method which opens the given file and returns a PrintStream to the file. * - * @param file - * a file to be written to. - * @param append - * if set to true the file will be appended, and if set to false - * the file will be written over. + * @param file a file to be written to. + * @param append if set to true the file will be appended, and if set to false the file will be + * written over. * @return a PrintStream to the file. */ public static PrintStream getFilePrintStream(File file, boolean append) { @@ -29,26 +26,22 @@ public static PrintStream getFilePrintStream(File file, boolean append) { } /** - * Writes the given content to the given file. This method overwrites the - * given file if it already exists. + * Writes the given content to the given file. This method overwrites the given file if it + * already exists. * - * @param file - * a file to be written to. - * @param content - * the content to be written to the file. + * @param file a file to be written to. + * @param content the content to be written to the file. */ public static void writeFile(File file, String content) { writeToFile(file, content, false); } /** - * Writes the given content to the given file. This method appends to the - * given file if it already exists. + * Writes the given content to the given file. This method appends to the given file if it + * already exists. * - * @param file - * a file to be written to. - * @param content - * the content to be written to the file. + * @param file a file to be written to. + * @param content the content to be written to the file. */ public static void appendFile(File file, String content) { writeToFile(file, content, true); diff --git a/src/checkers/inference/solver/util/NameUtils.java b/src/checkers/inference/solver/util/NameUtils.java index b1832770d..18c32689f 100644 --- a/src/checkers/inference/solver/util/NameUtils.java +++ b/src/checkers/inference/solver/util/NameUtils.java @@ -16,9 +16,8 @@ public static String getSimpleName(AnnotationMirror annoMirror) { } /** - * Given a strategy class, return the strategy name by removing the common naming suffix. - * E.g. Given PlainSolvingStrategy, this method return "Plain". - * + * Given a strategy class, return the strategy name by removing the common naming suffix. E.g. + * Given PlainSolvingStrategy, this method return "Plain". */ public static String getStrategyName(Class strategyClass) { final String strategyClassName = strategyClass.getSimpleName(); @@ -27,9 +26,8 @@ public static String getStrategyName(Class strategyCl } /** - * Given a solver class, return the solver name by removing the common naming suffix. - * E.g. Given MaxSatSolver, this method return "MaxSat". - * + * Given a solver class, return the solver name by removing the common naming suffix. E.g. Given + * MaxSatSolver, this method return "MaxSat". */ public static String getSolverName(Class> solverClass) { final String solverClassName = solverClass.getSimpleName(); diff --git a/src/checkers/inference/solver/util/PrintUtils.java b/src/checkers/inference/solver/util/PrintUtils.java index 3c0aa7961..a185a0f79 100644 --- a/src/checkers/inference/solver/util/PrintUtils.java +++ b/src/checkers/inference/solver/util/PrintUtils.java @@ -1,5 +1,7 @@ package checkers.inference.solver.util; +import org.checkerframework.framework.type.AnnotatedTypeFactory; + import java.io.File; import java.io.PrintStream; import java.util.Collection; @@ -9,8 +11,6 @@ import javax.lang.model.element.AnnotationMirror; -import org.checkerframework.framework.type.AnnotatedTypeFactory; - import checkers.inference.InferenceMain; import checkers.inference.model.ArithmeticConstraint; import checkers.inference.model.ArithmeticVariableSlot; @@ -36,25 +36,24 @@ import checkers.inference.model.VariableSlot; import checkers.inference.model.serialization.ToStringSerializer; -/** - * PrintUtils contains methods for printing and writing the solved results. - */ +/** PrintUtils contains methods for printing and writing the solved results. */ public class PrintUtils { /** - * Outputs the inference solutions to the given stream, where each row shows - * the id and the annotation of a slot. + * Outputs the inference solutions to the given stream, where each row shows the id and the + * annotation of a slot. * * @param stream an output stream - * @param solutions - * inference solutions: a map between slot IDs and annotation - * mirrors + * @param solutions inference solutions: a map between slot IDs and annotation mirrors */ - private static void outputSolutions(PrintStream stream, Map solutions) { + private static void outputSolutions( + PrintStream stream, Map solutions) { final AnnotatedTypeFactory atf = InferenceMain.getInstance().getRealTypeFactory(); // string length of the highest slot ID, used to pad spaces for pretty formatting - final int maxLength = String.valueOf(InferenceMain.getInstance().getSlotManager().getNumberOfSlots()).length(); + final int maxLength = + String.valueOf(InferenceMain.getInstance().getSlotManager().getNumberOfSlots()) + .length(); stream.println("======================= Solutions ======================="); @@ -63,16 +62,16 @@ private static void outputSolutions(PrintStream stream, Map solutions) { outputSolutions(System.out, solutions); } @@ -80,14 +79,11 @@ public static void printSolutions(Map solutions) { /** * Write the solved solutions to a file called solutions.txt. * - * @param solutions - * a map between slot IDs to its solution annotation. - * @param noAppend - * if set to true the file will be written over, and if set to - * false the file will be appended. + * @param solutions a map between slot IDs to its solution annotation. + * @param noAppend if set to true the file will be written over, and if set to false the file + * will be appended. */ - public static void writeSolutions(Map solutions, - boolean noAppend) { + public static void writeSolutions(Map solutions, boolean noAppend) { File outFile = new File("solutions.txt"); try (PrintStream out = FileUtils.getFilePrintStream(outFile, !noAppend)) { outputSolutions(out, solutions); @@ -97,6 +93,7 @@ public static void writeSolutions(Map solutions, /** * Outputs the statistics to the given stream. + * * @param stream * @param statistics */ @@ -108,9 +105,7 @@ private static void outputStatistics(PrintStream stream, Map stati stream.println("========================================================="); } - /** - * Print the statistics to screen. - */ + /** Print the statistics to screen. */ public static void printStatistics(Map statistics) { outputStatistics(System.out, statistics); } @@ -118,11 +113,9 @@ public static void printStatistics(Map statistics) { /** * Write the statistics to a file called statistics.txt. * - * @param statistics - * a map between stats keys and their long values. - * @param noAppend - * if set to true the file will be written over, and if set to - * false the file will be appended. + * @param statistics a map between stats keys and their long values. + * @param noAppend if set to true the file will be written over, and if set to false the file + * will be appended. */ public static void writeStatistics(Map statistics, boolean noAppend) { File outFile = new File("statistics.txt"); @@ -132,13 +125,14 @@ public static void writeStatistics(Map statistics, boolean noAppen System.out.println("Statistics have been written to: " + outFile.getAbsolutePath() + "\n"); } - /** * Outputs unsat constraints to the given stream. + * * @param stream * @param unsatConstraints */ - private static void outputUnsatConstraints(PrintStream stream, Collection unsatConstraints) { + private static void outputUnsatConstraints( + PrintStream stream, Collection unsatConstraints) { stream.println("=================== Unsat Constraints ==================="); ToStringSerializer toStringSerializer = new ToStringSerializer(false); @@ -160,9 +154,11 @@ private static void outputUnsatConstraints(PrintStream stream, Collection unsatConstraints) { if (unsatConstraints == null || unsatConstraints.isEmpty()) { System.out.println("The backend you used doesn't support explanation feature!"); @@ -186,24 +180,23 @@ public static void printUnsatConstraints(Collection unsatConstraints /** * Write the unsat constraints to a file called unsatConstraints.txt. * - * @param unsatConstraints - * a collection of unsat constraints. - * @param noAppend - * if set to true the file will be written over, and if set to - * false the file will be appended. + * @param unsatConstraints a collection of unsat constraints. + * @param noAppend if set to true the file will be written over, and if set to false the file + * will be appended. */ - public static void writeUnsatConstraints(Collection unsatConstraints, boolean noAppend) { + public static void writeUnsatConstraints( + Collection unsatConstraints, boolean noAppend) { File outFile = new File("unsatConstraints.txt"); try (PrintStream out = FileUtils.getFilePrintStream(outFile, !noAppend)) { outputUnsatConstraints(out, unsatConstraints); } - System.out.println("Unsat constraints have been written to: " + outFile.getAbsolutePath() + "\n"); + System.out.println( + "Unsat constraints have been written to: " + outFile.getAbsolutePath() + "\n"); } /** - * This class visits a collection of constraints and collects from the - * constraints a list of unique non-constant slots present in the - * constraints. + * This class visits a collection of constraints and collects from the constraints a list of + * unique non-constant slots present in the constraints. */ public static final class UniqueSlotCollector implements Serializer { @@ -338,7 +331,7 @@ public Void serialize(LubVariableSlot slot) { addSlotIfNotAdded(slot); return null; } - + @Override public Void serialize(ArithmeticVariableSlot slot) { addSlotIfNotAdded(slot); diff --git a/src/checkers/inference/solver/util/SolverArg.java b/src/checkers/inference/solver/util/SolverArg.java index ddb203386..d7bd73f4d 100644 --- a/src/checkers/inference/solver/util/SolverArg.java +++ b/src/checkers/inference/solver/util/SolverArg.java @@ -3,19 +3,18 @@ /** * Command line solver argument definition. * - * Subclass of this interface should be an enum class that - * grouping a set of related solver arguments. + *

Subclass of this interface should be an enum class that grouping a set of related solver + * arguments. * - * {@link SolverEnvironment} provides methods of taking SolverArg - * and parsing them to String value or boolean values. + *

{@link SolverEnvironment} provides methods of taking SolverArg and parsing them to String + * value or boolean values. */ public interface SolverArg { /** - * The string value of the argument name. - * This method is intentionally named as same as the {@link Enum#name()} - * method, so that concrete enum class only take car of defining - * arguments, and could use the default {@link Enum#name()} as the - * implementation of this method. + * The string value of the argument name. This method is intentionally named as same as the + * {@link Enum#name()} method, so that concrete enum class only take car of defining arguments, + * and could use the default {@link Enum#name()} as the implementation of this method. + * * @return */ String name(); diff --git a/src/checkers/inference/solver/util/SolverEnvironment.java b/src/checkers/inference/solver/util/SolverEnvironment.java index 02f110ebd..6249f1d0e 100644 --- a/src/checkers/inference/solver/util/SolverEnvironment.java +++ b/src/checkers/inference/solver/util/SolverEnvironment.java @@ -6,32 +6,28 @@ import javax.annotation.processing.ProcessingEnvironment; /** - * SolverEnvironment encapsulates general context that used - * for all phases during solving. - * - * All components in Solver Framework should ask this class to - * get the general context information, includes command line - * arguments for solver, and the processing environment. + * SolverEnvironment encapsulates general context that used for all phases during solving. + * + *

All components in Solver Framework should ask this class to get the general context + * information, includes command line arguments for solver, and the processing environment. */ public class SolverEnvironment { - /** - * Map of configuration. Key is argument name, value is argument value. - */ + /** Map of configuration. Key is argument name, value is argument value. */ private final Map options; - /** - * Processing environment providing by the tool framework. - */ + /** Processing environment providing by the tool framework. */ public final ProcessingEnvironment processingEnvironment; - public SolverEnvironment(final Map configuration, ProcessingEnvironment processingEnvironment) { + public SolverEnvironment( + final Map configuration, ProcessingEnvironment processingEnvironment) { this.options = Collections.unmodifiableMap(configuration); this.processingEnvironment = processingEnvironment; } /** * Get the value for a given argument name. + * * @param argName the name of the given argument. * @return the string value for a given argument name. */ @@ -44,7 +40,7 @@ public String getArg(SolverArg arg) { * * @param argName the name of the given argument. * @return true if the lower case of the string value of this argument equals to "true", - * otherwise return false. + * otherwise return false. */ public boolean getBoolArg(SolverArg arg) { String argValue = options.get(arg.name()); diff --git a/src/checkers/inference/solver/util/Statistics.java b/src/checkers/inference/solver/util/Statistics.java index 1ad63c56e..88b5b1545 100644 --- a/src/checkers/inference/solver/util/Statistics.java +++ b/src/checkers/inference/solver/util/Statistics.java @@ -10,21 +10,17 @@ import checkers.inference.model.Slot; import checkers.inference.model.VariableSlot; -/** - * Recorder for statistics. - */ +/** Recorder for statistics. */ public class Statistics { // statistics are sorted by insertion order - private final static Map statistics = new LinkedHashMap<>(); + private static final Map statistics = new LinkedHashMap<>(); /** * Adds or increments the given value to the statistics for the given key. * - * @param key - * a statistic key. The key is treated case-insensitive: it will always be considered - * in terms of its lower-case equivalent. - * @param value - * a value + * @param key a statistic key. The key is treated case-insensitive: it will always be considered + * in terms of its lower-case equivalent. + * @param value a value */ public static void addOrIncrementEntry(String key, long value) { synchronized (statistics) { @@ -110,9 +106,7 @@ public static Map getStatistics() { return Collections.unmodifiableMap(statistics); } - /** - * Erases all collected statistics. - */ + /** Erases all collected statistics. */ public static void clearStatistics() { statistics.clear(); } diff --git a/src/checkers/inference/typearginference/InferenceTypeArgumentInference.java b/src/checkers/inference/typearginference/InferenceTypeArgumentInference.java index d2dce2faa..aa501923f 100644 --- a/src/checkers/inference/typearginference/InferenceTypeArgumentInference.java +++ b/src/checkers/inference/typearginference/InferenceTypeArgumentInference.java @@ -1,5 +1,9 @@ package checkers.inference.typearginference; +import com.sun.source.tree.ExpressionTree; +import com.sun.source.tree.MethodInvocationTree; +import com.sun.source.tree.NewClassTree; + import org.checkerframework.framework.type.AnnotatedTypeFactory; import org.checkerframework.framework.type.AnnotatedTypeFactory.ParameterizedExecutableType; import org.checkerframework.framework.type.AnnotatedTypeMirror; @@ -30,10 +34,6 @@ import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeVariable; -import com.sun.source.tree.ExpressionTree; -import com.sun.source.tree.MethodInvocationTree; -import com.sun.source.tree.NewClassTree; - import checkers.inference.InferenceAnnotatedTypeFactory; import checkers.inference.InferenceTypeHierarchy; import checkers.inference.SlotManager; @@ -46,27 +46,25 @@ import checkers.inference.util.InferenceUtil; /** + * The basic algorithm for type argument inference for Checker Framework Inference is as follows: 1) + * Infer the unqualified Java types for each type argument * - * The basic algorithm for type argument inference for Checker Framework Inference is as follows: - * 1) Infer the unqualified Java types for each type argument - * - * 2) Apply annotations to each Java type inferred in step 1 - * If an inferred Java type is a type variable then it should be annotated with ExistentialVariables - * just like any other type variable. + *

2) Apply annotations to each Java type inferred in step 1 If an inferred Java type is a type + * variable then it should be annotated with ExistentialVariables just like any other type variable. * - * 3) Extract the primary variables that were applied in step 2 for use in steps 4+ + *

3) Extract the primary variables that were applied in step 2 for use in steps 4+ * - * 4) For each use of a target type variable (i.e. one that we are inferring) in the - * formal parameter list, replace any ExistentialVariables that involve the bounds of the type variable - * to use the annotations from step 3 instead. + *

4) For each use of a target type variable (i.e. one that we are inferring) in the formal + * parameter list, replace any ExistentialVariables that involve the bounds of the type variable to + * use the annotations from step 3 instead. * - * 5) Compute TUConstraints using the standard type argument inference algorithm found in - * DefaultTypeArgumentInference. + *

5) Compute TUConstraints using the standard type argument inference algorithm found in + * DefaultTypeArgumentInference. * - * 6) Add the constraints between the types inferred in step 1 and the corresponding type parameter's - * bounds. + *

6) Add the constraints between the types inferred in step 1 and the corresponding type + * parameter's bounds. * - * 7) Convert the TUConstraints from step 5 into Checker Framework Inference Constraints + *

7) Convert the TUConstraints from step 5 into Checker Framework Inference Constraints */ public class InferenceTypeArgumentInference extends DefaultTypeArgumentInference { @@ -77,12 +75,13 @@ public class InferenceTypeArgumentInference extends DefaultTypeArgumentInference private final AnnotationMirror varAnnot; private final SlotManager slotManager; - public InferenceTypeArgumentInference(SlotManager slotManager, - ConstraintManager constraintManager, - VariableAnnotator variableAnnotator, - InferenceAnnotatedTypeFactory inferenceTypeFactory, - AnnotatedTypeFactory realTypeFactory, - AnnotationMirror varAnnot) { + public InferenceTypeArgumentInference( + SlotManager slotManager, + ConstraintManager constraintManager, + VariableAnnotator variableAnnotator, + InferenceAnnotatedTypeFactory inferenceTypeFactory, + AnnotatedTypeFactory realTypeFactory, + AnnotationMirror varAnnot) { super(realTypeFactory); this.slotManager = slotManager; this.constraintManager = constraintManager; @@ -93,10 +92,11 @@ public InferenceTypeArgumentInference(SlotManager slotManager, } @Override - public Map inferTypeArgs(AnnotatedTypeFactory typeFactory, - ExpressionTree expressionTree, - ExecutableElement methodElem, - AnnotatedExecutableType methodType) { + public Map inferTypeArgs( + AnnotatedTypeFactory typeFactory, + ExpressionTree expressionTree, + ExecutableElement methodElem, + AnnotatedExecutableType methodType) { // we don't want any lubs etc. used in inferreing types to generate constraints constraintManager.startIgnoringConstraints(); @@ -108,7 +108,8 @@ public Map inferTypeArgs(AnnotatedTypeFactory final Set targets = TypeArgInferenceUtil.methodTypeToTargets(methodType); - Map targetToType = InferenceUtil.makeOrderedMap(targets, targetTypes); + Map targetToType = + InferenceUtil.makeOrderedMap(targets, targetTypes); Map targetToPrimary = findTargetVariableSlots(targetToType); final List argTypes = @@ -118,7 +119,8 @@ public Map inferTypeArgs(AnnotatedTypeFactory final AnnotatedExecutableType updatedMethod = methodType.deepCopy(); replaceExistentialVariables(updatedMethod, typeFactory, targetToPrimary); - Set tuConstraints = createTUConstraints(argTypes, assignedTo, updatedMethod, targetToType, typeFactory); + Set tuConstraints = + createTUConstraints(argTypes, assignedTo, updatedMethod, targetToType, typeFactory); constraintManager.stopIgnoringConstraints(); @@ -126,15 +128,18 @@ public Map inferTypeArgs(AnnotatedTypeFactory return targetToType; } - private Set createTUConstraints(List argTypes, AnnotatedTypeMirror assignedTo, - AnnotatedExecutableType methodType, - Map targetToTypes, - AnnotatedTypeFactory typeFactory) { + private Set createTUConstraints( + List argTypes, + AnnotatedTypeMirror assignedTo, + AnnotatedExecutableType methodType, + Map targetToTypes, + AnnotatedTypeFactory typeFactory) { Set targets = targetToTypes.keySet(); - Set reducedConstraints = createArgumentAFConstraints(typeFactory, argTypes, - methodType, targets, true); - reducedConstraints.addAll(createBoundAndAssignmentAFs(assignedTo, methodType, targetToTypes, typeFactory)); + Set reducedConstraints = + createArgumentAFConstraints(typeFactory, argTypes, methodType, targets, true); + reducedConstraints.addAll( + createBoundAndAssignmentAFs(assignedTo, methodType, targetToTypes, typeFactory)); Set tuConstraints = afToTuConstraints(reducedConstraints, targets); addConstraintsBetweenTargets(tuConstraints, targets, false, typeFactory); @@ -142,16 +147,18 @@ private Set createTUConstraints(List argTypes return tuConstraints; } - private Set createBoundAndAssignmentAFs(AnnotatedTypeMirror assignedTo, - AnnotatedExecutableType methodType, - Map targetToTypes, - AnnotatedTypeFactory typeFactory) { + private Set createBoundAndAssignmentAFs( + AnnotatedTypeMirror assignedTo, + AnnotatedExecutableType methodType, + Map targetToTypes, + AnnotatedTypeFactory typeFactory) { final LinkedList boundAndAssignmentAfs = new LinkedList<>(); for (AnnotatedTypeVariable typeParam : methodType.getTypeVariables()) { final TypeVariable target = typeParam.getUnderlyingType(); final AnnotatedTypeMirror inferredType = targetToTypes.get(target); - // for all inferred types Ti: Ti >> Bi where Bi is upper bound and Ti << Li where Li is the lower bound + // for all inferred types Ti: Ti >> Bi where Bi is upper bound and Ti << Li where Li is + // the lower bound // for all uninferred types Tu: Tu >> Bi and Lu >> Tu if (inferredType != null) { boundAndAssignmentAfs.add(new A2F(inferredType, typeParam.getUpperBound())); @@ -166,7 +173,8 @@ private Set createBoundAndAssignmentAFs(AnnotatedTypeMirror assign if (declaredReturnType.getKind() != TypeKind.VOID) { final AnnotatedTypeMirror boxedReturnType; if (declaredReturnType.getKind().isPrimitive()) { - boxedReturnType = typeFactory.getBoxedType((AnnotatedPrimitiveType) declaredReturnType); + boxedReturnType = + typeFactory.getBoxedType((AnnotatedPrimitiveType) declaredReturnType); } else { boxedReturnType = declaredReturnType; } @@ -175,31 +183,37 @@ private Set createBoundAndAssignmentAFs(AnnotatedTypeMirror assign } Set reducedConstraints = new LinkedHashSet<>(); - reduceAfConstraints(typeFactory, reducedConstraints, boundAndAssignmentAfs, targetToTypes.keySet()); + reduceAfConstraints( + typeFactory, reducedConstraints, boundAndAssignmentAfs, targetToTypes.keySet()); return reducedConstraints; } - // TODO: Figure out if we need to make copies of the types - private void replaceExistentialVariables(AnnotatedExecutableType methodType, AnnotatedTypeFactory typeFactory, - Map targetToPrimary) { - VariableSlotReplacer variableSlotReplacer = new VariableSlotReplacer(slotManager, variableAnnotator, - varAnnot, true); + private void replaceExistentialVariables( + AnnotatedExecutableType methodType, + AnnotatedTypeFactory typeFactory, + Map targetToPrimary) { + VariableSlotReplacer variableSlotReplacer = + new VariableSlotReplacer(slotManager, variableAnnotator, varAnnot, true); for (TypeVariable target : targetToPrimary.keySet()) { - AnnotatedTypeVariable typeVariable = (AnnotatedTypeVariable) typeFactory.getAnnotatedType(target.asElement()); + AnnotatedTypeVariable typeVariable = + (AnnotatedTypeVariable) typeFactory.getAnnotatedType(target.asElement()); AnnotatedTypeMirror upperBound = typeVariable.getUpperBound(); AnnotatedTypeMirror lowerBound = typeVariable.getLowerBound(); AnnotationMirror upperBoundAnno = - AnnotatedTypes.findEffectiveAnnotationInHierarchy(inferenceTypeFactory.getQualifierHierarchy(), upperBound, varAnnot); + AnnotatedTypes.findEffectiveAnnotationInHierarchy( + inferenceTypeFactory.getQualifierHierarchy(), upperBound, varAnnot); Slot upperBoundVariable = slotManager.getSlot(upperBoundAnno); - // handles the cases like , the upper bound anno on E will appear as a potential + // handles the cases like , the upper bound anno on E will appear as a + // potential // annotation on T if (upperBoundVariable instanceof ExistentialVariableSlot) { - upperBoundVariable = ((ExistentialVariableSlot) upperBoundVariable).getPotentialSlot(); + upperBoundVariable = + ((ExistentialVariableSlot) upperBoundVariable).getPotentialSlot(); } Slot lowerBoundVariable = slotManager.getSlot(lowerBound); @@ -217,10 +231,10 @@ private void replaceExistentialVariables(AnnotatedExecutableType methodType, Ann if (returnType.getKind() != TypeKind.VOID) { variableSlotReplacer.replaceSlots(returnType); } - } - private Map findTargetVariableSlots(Map targetToType) { + private Map findTargetVariableSlots( + Map targetToType) { Map targetToVar = new LinkedHashMap<>(); @@ -231,8 +245,9 @@ private Map findTargetVariableSlots(Map findTargetVariableSlots(Map findTargetVariableSlots(Map getUnannotatedTypeArgs(ExpressionTree expressi switch (expressionTree.getKind()) { case METHOD_INVOCATION: - fromUseResult = realTypeFactory.methodFromUse((MethodInvocationTree) expressionTree); + fromUseResult = + realTypeFactory.methodFromUse((MethodInvocationTree) expressionTree); break; case NEW_CLASS: @@ -274,32 +289,38 @@ private List getUnannotatedTypeArgs(ExpressionTree expressi break; default: - throw new IllegalArgumentException("expressionTree should be a MethodInvocation or NewClass tree\n" - + "expressionTree=" + expressionTree); + throw new IllegalArgumentException( + "expressionTree should be a MethodInvocation or NewClass tree\n" + + "expressionTree=" + + expressionTree); } - List emptyAnnotatedTypeMirrors = new ArrayList<>(fromUseResult.typeArgs.size()); + List emptyAnnotatedTypeMirrors = + new ArrayList<>(fromUseResult.typeArgs.size()); for (AnnotatedTypeMirror realAnnotatedType : fromUseResult.typeArgs) { - AnnotatedTypeMirror inferenceType = CrossFactoryAtmCopier.copy(realAnnotatedType, inferenceTypeFactory, false); + AnnotatedTypeMirror inferenceType = + CrossFactoryAtmCopier.copy(realAnnotatedType, inferenceTypeFactory, false); emptyAnnotatedTypeMirrors.add(inferenceType); } return emptyAnnotatedTypeMirrors; } - private void recordConstraints(Set tuConstraints) { - InferenceTypeHierarchy inferenceTypeHierarchy = (InferenceTypeHierarchy) inferenceTypeFactory.getTypeHierarchy(); + InferenceTypeHierarchy inferenceTypeHierarchy = + (InferenceTypeHierarchy) inferenceTypeFactory.getTypeHierarchy(); for (TUConstraint tuConstraint : tuConstraints) { if (tuConstraint instanceof TSubU) { - inferenceTypeHierarchy.isSubtype(tuConstraint.typeVariable, tuConstraint.relatedType); + inferenceTypeHierarchy.isSubtype( + tuConstraint.typeVariable, tuConstraint.relatedType); } else if (tuConstraint instanceof TSuperU) { - inferenceTypeHierarchy.isSubtype(tuConstraint.relatedType, tuConstraint.typeVariable); + inferenceTypeHierarchy.isSubtype( + tuConstraint.relatedType, tuConstraint.typeVariable); } else if (tuConstraint instanceof TIsU) { - inferenceTypeHierarchy.areEqual(tuConstraint.relatedType, tuConstraint.typeVariable); - + inferenceTypeHierarchy.areEqual( + tuConstraint.relatedType, tuConstraint.typeVariable); } } } diff --git a/src/checkers/inference/util/ASTPathUtil.java b/src/checkers/inference/util/ASTPathUtil.java index 1f4c7f038..c8a8da4df 100644 --- a/src/checkers/inference/util/ASTPathUtil.java +++ b/src/checkers/inference/util/ASTPathUtil.java @@ -1,5 +1,12 @@ package checkers.inference.util; +import com.sun.source.tree.Tree; +import com.sun.source.tree.Tree.Kind; +import com.sun.source.util.TreePath; + +import org.checkerframework.afu.scenelib.io.ASTIndex; +import org.checkerframework.afu.scenelib.io.ASTPath; +import org.checkerframework.afu.scenelib.io.ASTRecord; import org.checkerframework.framework.type.AnnotatedTypeFactory; import org.checkerframework.framework.type.AnnotatedTypeMirror; import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType; @@ -15,41 +22,33 @@ import org.checkerframework.framework.type.visitor.AnnotatedTypeScanner; import org.checkerframework.framework.util.AnnotatedTypes; import org.checkerframework.javacutil.BugInCF; +import org.plumelib.util.IPair; import java.util.IdentityHashMap; import java.util.logging.Logger; -import com.sun.source.tree.Tree; -import com.sun.source.tree.Tree.Kind; -import com.sun.source.util.TreePath; - -import org.checkerframework.afu.scenelib.io.ASTIndex; -import org.checkerframework.afu.scenelib.io.ASTPath; -import org.checkerframework.afu.scenelib.io.ASTRecord; -import org.plumelib.util.IPair; - /** - * ASTPathUtil is a collection of utilities to create ASTRecord for existing trees, as well - * as trees that are implied to exist but are not required by the compiler (e.g. extends Object). + * ASTPathUtil is a collection of utilities to create ASTRecord for existing trees, as well as trees + * that are implied to exist but are not required by the compiler (e.g. extends Object). */ public class ASTPathUtil { protected static final Logger logger = Logger.getLogger(ASTPathUtil.class.getName()); - public static final String AFU_CONSTRUCTOR_ID = "()V"; public static ASTRecord getASTRecordForNode(final AnnotatedTypeFactory typeFactory, Tree node) { return getASTRecordForPath(typeFactory, typeFactory.getPath(node)); } - /** * Look up an ASTRecord for a node. + * * @param typeFactory Type factory to look up tree path (and CompilationUnit) * @return The ASTRecord for node */ - public static ASTRecord getASTRecordForPath(final AnnotatedTypeFactory typeFactory, TreePath pathToNode) { + public static ASTRecord getASTRecordForPath( + final AnnotatedTypeFactory typeFactory, TreePath pathToNode) { if (pathToNode == null) { return null; } @@ -74,23 +73,27 @@ public static ASTRecord getASTRecordForPath(final AnnotatedTypeFactory typeFacto * this class. */ public static ASTRecord getConstructorRecord(ASTRecord classRecord) { - return new ASTRecord(classRecord.ast, classRecord.className, AFU_CONSTRUCTOR_ID, null, ASTPath.empty()); + return new ASTRecord( + classRecord.ast, classRecord.className, AFU_CONSTRUCTOR_ID, null, ASTPath.empty()); } /** - * Some times there are trees that are implied by the source code but not explicitly written. (e.g. extends Object) - * The AFU will create these trees if we try to insert an annotation on them. Therefore, we need to create - * an AFU record that corresponds to the location on the "implied" (non-existant) tree. + * Some times there are trees that are implied by the source code but not explicitly written. + * (e.g. extends Object) The AFU will create these trees if we try to insert an annotation on + * them. Therefore, we need to create an AFU record that corresponds to the location on the + * "implied" (non-existant) tree. * - * This method creates a mapping of AnnotatedTypeMirrors that are children of type and an ASTRecord that - * corresponds to annotating the primary annotation of that type. + *

This method creates a mapping of AnnotatedTypeMirrors that are children of type and an + * ASTRecord that corresponds to annotating the primary annotation of that type. * * @param parent The parent of the implied tree * @param type The type on which we are storing annotations. - * @return A mapping of annotated type mirror to the ASTRecord that locates the primary annotation of the - * annotated type mirror in source code. i.e. (ATM -> locatation of primary annotation on ATM in source code) + * @return A mapping of annotated type mirror to the ASTRecord that locates the primary + * annotation of the annotated type mirror in source code. i.e. (ATM -> locatation of + * primary annotation on ATM in source code) */ - public static IdentityHashMap getImpliedRecordForUse(final ASTRecord parent, final AnnotatedTypeMirror type) { + public static IdentityHashMap getImpliedRecordForUse( + final ASTRecord parent, final AnnotatedTypeMirror type) { AFUPathMapper pathMapper = new AFUPathMapper(); pathMapper.visit(type, parent); @@ -98,19 +101,21 @@ public static IdentityHashMap getImpliedRecordFo } /** - * A scanner that builds a mapping of - * ATM -> (AstRecord representing the location of the primary annotation of ATM) + * A scanner that builds a mapping of ATM -> (AstRecord representing the location of the primary + * annotation of ATM) */ protected static class AFUPathMapper extends AnnotatedTypeScanner { final IdentityHashMap mapping = new IdentityHashMap<>(); - public ASTRecord extendParent(final ASTRecord parent, Tree.Kind treeKind, String type, int arg) { + public ASTRecord extendParent( + final ASTRecord parent, Tree.Kind treeKind, String type, int arg) { return parent.extend(treeKind, type, arg); } /** - * @return true if this is the first time we have encountered type and therefore we stored type -> path + * @return true if this is the first time we have encountered type and therefore we stored + * type -> path */ public boolean storeCurrent(final AnnotatedTypeMirror type, ASTRecord currentPath) { if (mapping.containsKey(type)) { @@ -127,7 +132,12 @@ public Void visitDeclared(AnnotatedDeclaredType type, ASTRecord current) { int typeArgIndex = 0; for (AnnotatedTypeMirror typeArg : type.getTypeArguments()) { - ASTRecord next = extendParent(current, Kind.PARAMETERIZED_TYPE, ASTPath.TYPE_ARGUMENT, typeArgIndex); + ASTRecord next = + extendParent( + current, + Kind.PARAMETERIZED_TYPE, + ASTPath.TYPE_ARGUMENT, + typeArgIndex); visit(typeArg, next); typeArgIndex++; } @@ -141,7 +151,8 @@ public Void visitIntersection(AnnotatedIntersectionType type, ASTRecord current) int boundIndex = 0; for (AnnotatedTypeMirror bound : type.directSupertypes()) { - ASTRecord toBound = extendParent(current, Kind.INTERSECTION_TYPE, ASTPath.BOUND, boundIndex); + ASTRecord toBound = + extendParent(current, Kind.INTERSECTION_TYPE, ASTPath.BOUND, boundIndex); visit(bound, toBound); boundIndex++; } @@ -154,7 +165,12 @@ public Void visitUnion(AnnotatedUnionType type, ASTRecord current) { int alternativeIndex = 0; for (AnnotatedDeclaredType bound : type.getAlternatives()) { - ASTRecord toBound = extendParent(current, Kind.UNION_TYPE, ASTPath.TYPE_ALTERNATIVE, alternativeIndex); + ASTRecord toBound = + extendParent( + current, + Kind.UNION_TYPE, + ASTPath.TYPE_ALTERNATIVE, + alternativeIndex); visit(bound, toBound); alternativeIndex++; } @@ -174,7 +190,8 @@ public Void visitArray(AnnotatedArrayType type, ASTRecord current) { @Override public Void visitExecutable(AnnotatedExecutableType type, ASTRecord parent) { - throw new UnsupportedOperationException("This class was not intended to create paths for methods."); + throw new UnsupportedOperationException( + "This class was not intended to create paths for methods."); } @Override @@ -211,15 +228,18 @@ public Void visitWildcard(AnnotatedWildcardType type, ASTRecord current) { mapping.put(type.getSuperBound(), current); if (AnnotatedTypes.hasExplicitExtendsBound(type)) { - final ASTRecord toBound = extendParent(current, Kind.EXTENDS_WILDCARD, ASTPath.BOUND, 0); + final ASTRecord toBound = + extendParent(current, Kind.EXTENDS_WILDCARD, ASTPath.BOUND, 0); visit(type.getExtendsBound(), toBound); } else { - final ASTRecord toBound = extendParent(current, Kind.UNBOUNDED_WILDCARD, ASTPath.BOUND, 0); + final ASTRecord toBound = + extendParent(current, Kind.UNBOUNDED_WILDCARD, ASTPath.BOUND, 0); visit(type.getExtendsBound(), toBound); } } else { mapping.put(type.getExtendsBound(), current); - final ASTRecord toBound = extendParent(current, Kind.SUPER_WILDCARD, ASTPath.BOUND, 0); + final ASTRecord toBound = + extendParent(current, Kind.SUPER_WILDCARD, ASTPath.BOUND, 0); visit(type.getSuperBound(), toBound); } @@ -227,9 +247,7 @@ public Void visitWildcard(AnnotatedWildcardType type, ASTRecord current) { } } - /** - * Converts fully qualified class name into a pair of Strings (packageName -> className) - */ + /** Converts fully qualified class name into a pair of Strings (packageName -> className) */ public static IPair splitFullyQualifiedClass(String fullClassname) { String pkgName; String className; diff --git a/src/checkers/inference/util/ConstantToVariableAnnotator.java b/src/checkers/inference/util/ConstantToVariableAnnotator.java index 23ebb982c..ea3c52e32 100644 --- a/src/checkers/inference/util/ConstantToVariableAnnotator.java +++ b/src/checkers/inference/util/ConstantToVariableAnnotator.java @@ -1,18 +1,16 @@ package checkers.inference.util; -import javax.lang.model.element.AnnotationMirror; - import org.checkerframework.framework.type.AnnotatedTypeMirror; import org.checkerframework.framework.type.visitor.AnnotatedTypeScanner; +import javax.lang.model.element.AnnotationMirror; + import checkers.inference.InferenceMain; import checkers.inference.SlotManager; - /** - * Adds VarAnnot to all locations in type that already have an annotation - * in the "real" qualifier hierarchy. Adds equality annotations between the - * VarAnnot and the real qualifier. + * Adds VarAnnot to all locations in type that already have an annotation in the "real" qualifier + * hierarchy. Adds equality annotations between the VarAnnot and the real qualifier. */ public class ConstantToVariableAnnotator extends AnnotatedTypeScanner { @@ -36,9 +34,9 @@ protected Void scan(AnnotatedTypeMirror type, Void aVoid) { } /** - * if type is not annotated in the VarAnnot qualifier hierarchy: - * Find the "Constant" varAnnot that corresponds to the "real qualifier on VarAnnot" - * add the VarAnnot to the definite type use location + * if type is not annotated in the VarAnnot qualifier hierarchy: Find the "Constant" varAnnot + * that corresponds to the "real qualifier on VarAnnot" add the VarAnnot to the definite type + * use location * * @param type A type annotated in the "real qualifier hierarch" */ @@ -51,15 +49,18 @@ protected void addVariablePrimaryAnnotation(final AnnotatedTypeMirror type) { AnnotationMirror equivalentVarAnno = slotManager.createEquivalentVarAnno(realQualifier); type.addAnnotation(equivalentVarAnno); type.removeAnnotation(realQualifier); -// -// for (Entry, VariableSlot> qualToVarAnnot : constantToVarAnnot.entrySet()) { -// -// if (AnnotationUtils.areSameByClass(realQualifier, qualToVarAnnot.getKey())) { -// type.replaceAnnotation(slotManager.getAnnotation(qualToVarAnnot.getValue())); -// return; -// } -// } -// -// throw new BugInCF("Could not find VarAnnot for real qualifier: " + realQualifier + " type =" + type); + // + // for (Entry, VariableSlot> qualToVarAnnot : + // constantToVarAnnot.entrySet()) { + // + // if (AnnotationUtils.areSameByClass(realQualifier, qualToVarAnnot.getKey())) { + // + // type.replaceAnnotation(slotManager.getAnnotation(qualToVarAnnot.getValue())); + // return; + // } + // } + // + // throw new BugInCF("Could not find VarAnnot for real qualifier: " + realQualifier + + // " type =" + type); } } diff --git a/src/checkers/inference/util/CopyUtil.java b/src/checkers/inference/util/CopyUtil.java index 511b84a53..d4df18602 100644 --- a/src/checkers/inference/util/CopyUtil.java +++ b/src/checkers/inference/util/CopyUtil.java @@ -3,14 +3,14 @@ import static javax.lang.model.type.TypeKind.ARRAY; import static javax.lang.model.type.TypeKind.DECLARED; import static javax.lang.model.type.TypeKind.EXECUTABLE; +import static javax.lang.model.type.TypeKind.INTERSECTION; import static javax.lang.model.type.TypeKind.NONE; import static javax.lang.model.type.TypeKind.NULL; import static javax.lang.model.type.TypeKind.PACKAGE; import static javax.lang.model.type.TypeKind.TYPEVAR; +import static javax.lang.model.type.TypeKind.UNION; import static javax.lang.model.type.TypeKind.VOID; import static javax.lang.model.type.TypeKind.WILDCARD; -import static javax.lang.model.type.TypeKind.INTERSECTION; -import static javax.lang.model.type.TypeKind.UNION; import org.checkerframework.framework.type.AnnotatedTypeMirror; import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType; @@ -31,9 +31,7 @@ import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; -/** - * Contains utility methods and classes for copying annotaitons from one type to another. - */ +/** Contains utility methods and classes for copying annotaitons from one type to another. */ public class CopyUtil { public static interface CopyMethod { @@ -42,9 +40,11 @@ public static interface CopyMethod { public static class ClearAndCopy implements CopyMethod { - /** Clear to of any annotations and copy those from 'from' to 'to' - * Does not descend into nested types if any - * @param from AnnotatedTypeMirror to copy + /** + * Clear to of any annotations and copy those from 'from' to 'to' Does not descend into + * nested types if any + * + * @param from AnnotatedTypeMirror to copy * @param to AnnotatedTypeMirror to clear then add to * @return The original set of annotations on Mod */ @@ -56,22 +56,30 @@ public void copy(AnnotatedTypeMirror from, AnnotatedTypeMirror to) { } /** - * Copy annotations from in to mod, descending into any nested types in - * the two AnnotatedTypeMirrors. Any existing annotations will be cleared first + * Copy annotations from in to mod, descending into any nested types in the two + * AnnotatedTypeMirrors. Any existing annotations will be cleared first + * * @param from The AnnotatedTypeMirror that should be copied * @param to The AnnotatedTypeMirror to which annotations will be copied */ - public static void copyAnnotations(final AnnotatedTypeMirror from, final AnnotatedTypeMirror to) { - copyAnnotationsImpl(from, to, new ClearAndCopy(), new IdentityHashMap()); + public static void copyAnnotations( + final AnnotatedTypeMirror from, final AnnotatedTypeMirror to) { + copyAnnotationsImpl( + from, + to, + new ClearAndCopy(), + new IdentityHashMap()); } /** - * Use copyAnnotations to deep copy the return type and parameter type annotations - * from one AnnotatedExecutableType to another + * Use copyAnnotations to deep copy the return type and parameter type annotations from one + * AnnotatedExecutableType to another + * * @param from The executable type with annotations to copy - * @param to The executable type to which annotations will be copied + * @param to The executable type to which annotations will be copied */ - public static void copyParameterReceiverAndReturnTypes(final AnnotatedExecutableType from, AnnotatedExecutableType to) { + public static void copyParameterReceiverAndReturnTypes( + final AnnotatedExecutableType from, AnnotatedExecutableType to) { if (from.getReturnType().getKind() != TypeKind.NONE) { copyAnnotations(from.getReturnType(), to.getReturnType()); @@ -84,18 +92,21 @@ public static void copyParameterReceiverAndReturnTypes(final AnnotatedExecutable to.getReceiverType().addAnnotations(from.getReceiverType().getAnnotations()); } - final List fromParams = from.getParameterTypes(); - final List toParams = to.getParameterTypes(); + final List fromParams = from.getParameterTypes(); + final List toParams = to.getParameterTypes(); - assert(fromParams.size() == toParams.size()); + assert (fromParams.size() == toParams.size()); for (int i = 0; i < toParams.size(); i++) { copyAnnotations(fromParams.get(i), toParams.get(i)); } } - private static void copyAnnotationsImpl(final AnnotatedTypeMirror from, final AnnotatedTypeMirror to, - final CopyMethod copyMethod, final IdentityHashMap visited) { + private static void copyAnnotationsImpl( + final AnnotatedTypeMirror from, + final AnnotatedTypeMirror to, + final CopyMethod copyMethod, + final IdentityHashMap visited) { if (visited.keySet().contains(from)) { return; @@ -114,7 +125,8 @@ private static void copyAnnotationsImpl(final AnnotatedTypeMirror from, final An return; } else if (fromKind == DECLARED && toKind == DECLARED) { // Copy annotations on enclosing types recursively - AnnotatedDeclaredType enclosingOfFrom = ((AnnotatedDeclaredType) from).getEnclosingType(); + AnnotatedDeclaredType enclosingOfFrom = + ((AnnotatedDeclaredType) from).getEnclosingType(); AnnotatedDeclaredType enclosingOfTo = ((AnnotatedDeclaredType) to).getEnclosingType(); while (enclosingOfFrom != null && enclosingOfTo != null) { copyAnnotationsImpl(enclosingOfFrom, enclosingOfTo, copyMethod, visited); @@ -122,33 +134,52 @@ private static void copyAnnotationsImpl(final AnnotatedTypeMirror from, final An enclosingOfTo = enclosingOfTo.getEnclosingType(); } - copyAnnotationsTogether(((AnnotatedDeclaredType) from).getTypeArguments(), - ((AnnotatedDeclaredType) to).getTypeArguments(), - copyMethod, visited); + copyAnnotationsTogether( + ((AnnotatedDeclaredType) from).getTypeArguments(), + ((AnnotatedDeclaredType) to).getTypeArguments(), + copyMethod, + visited); } else if (fromKind == EXECUTABLE && toKind == EXECUTABLE) { final AnnotatedExecutableType fromExeType = (AnnotatedExecutableType) from; - final AnnotatedExecutableType toExeType = (AnnotatedExecutableType) to; + final AnnotatedExecutableType toExeType = (AnnotatedExecutableType) to; - copyAnnotationsImpl(fromExeType.getReturnType(), toExeType.getReturnType(), copyMethod, visited); + copyAnnotationsImpl( + fromExeType.getReturnType(), toExeType.getReturnType(), copyMethod, visited); // Static methods don't have a receiver. if (fromExeType.getReceiverType() != null) { - copyAnnotationsImpl(fromExeType.getReceiverType(), toExeType.getReceiverType(), copyMethod, visited); + copyAnnotationsImpl( + fromExeType.getReceiverType(), + toExeType.getReceiverType(), + copyMethod, + visited); } - copyAnnotationsTogether(fromExeType.getParameterTypes(), toExeType.getParameterTypes(), copyMethod, visited); - copyAnnotationsTogether(fromExeType.getTypeVariables(), toExeType.getTypeVariables(), copyMethod, visited); + copyAnnotationsTogether( + fromExeType.getParameterTypes(), + toExeType.getParameterTypes(), + copyMethod, + visited); + copyAnnotationsTogether( + fromExeType.getTypeVariables(), + toExeType.getTypeVariables(), + copyMethod, + visited); } else if (fromKind == ARRAY && toKind == ARRAY) { - copyAnnotationsImpl(((AnnotatedArrayType) from).getComponentType(), - ((AnnotatedArrayType) to).getComponentType(), - copyMethod, visited); + copyAnnotationsImpl( + ((AnnotatedArrayType) from).getComponentType(), + ((AnnotatedArrayType) to).getComponentType(), + copyMethod, + visited); } else if (fromKind == TYPEVAR && toKind == TYPEVAR) { final AnnotatedTypeVariable fromAtv = (AnnotatedTypeVariable) from; - final AnnotatedTypeVariable toAtv = (AnnotatedTypeVariable) to; + final AnnotatedTypeVariable toAtv = (AnnotatedTypeVariable) to; - copyAnnotationsImpl(fromAtv.getUpperBound(), toAtv.getUpperBound(), copyMethod, visited); - copyAnnotationsImpl(fromAtv.getLowerBound(), toAtv.getLowerBound(), copyMethod, visited); + copyAnnotationsImpl( + fromAtv.getUpperBound(), toAtv.getUpperBound(), copyMethod, visited); + copyAnnotationsImpl( + fromAtv.getLowerBound(), toAtv.getLowerBound(), copyMethod, visited); } else if (toKind == TYPEVAR) { // Why is sometimes the mod a type variable, but in is Declared or Wildcard? @@ -157,17 +188,23 @@ private static void copyAnnotationsImpl(final AnnotatedTypeMirror from, final An } else if (fromKind == WILDCARD && toKind == WILDCARD) { final AnnotatedWildcardType fromWct = (AnnotatedWildcardType) from; - final AnnotatedWildcardType tpWct = (AnnotatedWildcardType) to; + final AnnotatedWildcardType tpWct = (AnnotatedWildcardType) to; - copyAnnotationsImpl(fromWct.getExtendsBound(), tpWct.getExtendsBound(), copyMethod, visited); - copyAnnotationsImpl(fromWct.getSuperBound(), tpWct.getSuperBound(), copyMethod, visited); + copyAnnotationsImpl( + fromWct.getExtendsBound(), tpWct.getExtendsBound(), copyMethod, visited); + copyAnnotationsImpl( + fromWct.getSuperBound(), tpWct.getSuperBound(), copyMethod, visited); } else if (fromKind.isPrimitive() && toKind.isPrimitive()) { - // Primitives only take one annotation, which was already copied - - } else if (fromKind == NONE || fromKind == NULL || fromKind == VOID || - toKind == NONE || toKind == NULL || toKind == VOID) { - // No annotations + // Primitives only take one annotation, which was already copied + + } else if (fromKind == NONE + || fromKind == NULL + || fromKind == VOID + || toKind == NONE + || toKind == NULL + || toKind == VOID) { + // No annotations } else if (fromKind == INTERSECTION && toKind == INTERSECTION) { AnnotatedIntersectionType fromIntersec = (AnnotatedIntersectionType) from; AnnotatedIntersectionType toIntersec = (AnnotatedIntersectionType) to; @@ -183,18 +220,28 @@ private static void copyAnnotationsImpl(final AnnotatedTypeMirror from, final An List fromAlternatives = fromUnion.getAlternatives(); List toAlternatives = toUnion.getAlternatives(); - copyAnnotationsOnDeclaredTypeList(fromAlternatives, toAlternatives, copyMethod, visited); + copyAnnotationsOnDeclaredTypeList( + fromAlternatives, toAlternatives, copyMethod, visited); } else { - throw new BugInCF("CopyUtils.copyAnnotationsImpl: unhandled getKind results: " + from + - " and " + to + "\n of kinds: " + fromKind + " and " + toKind); + throw new BugInCF( + "CopyUtils.copyAnnotationsImpl: unhandled getKind results: " + + from + + " and " + + to + + "\n of kinds: " + + fromKind + + " and " + + toKind); } } /** - * Helper method for copying annotations from a given declared type list to another declared type list. + * Helper method for copying annotations from a given declared type list to another declared + * type list. */ - private static void copyAnnotationsOnDeclaredTypeList(final List from, + private static void copyAnnotationsOnDeclaredTypeList( + final List from, final List to, final CopyMethod copyMethod, final IdentityHashMap visited) { @@ -217,21 +264,28 @@ private static void copyAnnotationsOnDeclaredTypeList(final List entry : fromMap.entrySet()) { copyAnnotationsImpl(entry.getValue(), toMap.get(entry.getKey()), copyMethod, visited); } } - private static void copyAnnotationsTogether(final List from, - final List to, - final CopyMethod copyMethod, - final IdentityHashMap visited) { + private static void copyAnnotationsTogether( + final List from, + final List to, + final CopyMethod copyMethod, + final IdentityHashMap visited) { for (int i = 0; i < from.size(); i++) { // TODO: HackMode if (i >= to.size()) { diff --git a/src/checkers/inference/util/CrossFactoryAtmCopier.java b/src/checkers/inference/util/CrossFactoryAtmCopier.java index fbb1f2e89..ea935b909 100644 --- a/src/checkers/inference/util/CrossFactoryAtmCopier.java +++ b/src/checkers/inference/util/CrossFactoryAtmCopier.java @@ -5,27 +5,33 @@ import org.checkerframework.framework.type.AnnotatedTypeMirror; /** - * Copies annotated type mirrors as per AnnotatedTypeCopier but, in the new type, it replaces - * the original underlying type factory with a new type factory (passed via constructor) + * Copies annotated type mirrors as per AnnotatedTypeCopier but, in the new type, it replaces the + * original underlying type factory with a new type factory (passed via constructor) */ public class CrossFactoryAtmCopier extends AnnotatedTypeCopier { - public static ATM copy(ATM annotatedType, AnnotatedTypeFactory newTypeFactory, - boolean copyAnnotations) { - return (ATM) new CrossFactoryAtmCopier(newTypeFactory, copyAnnotations).visit(annotatedType); + public static ATM copy( + ATM annotatedType, AnnotatedTypeFactory newTypeFactory, boolean copyAnnotations) { + return (ATM) + new CrossFactoryAtmCopier(newTypeFactory, copyAnnotations).visit(annotatedType); } private final AnnotatedTypeFactory newTypeFactory; - public CrossFactoryAtmCopier(final AnnotatedTypeFactory newTypeFactory, final boolean copyAnnotations) { + public CrossFactoryAtmCopier( + final AnnotatedTypeFactory newTypeFactory, final boolean copyAnnotations) { super(copyAnnotations); this.newTypeFactory = newTypeFactory; } @Override protected T makeCopy(T original) { - final T copy = (T) AnnotatedTypeMirror.createType( - original.getUnderlyingType(), newTypeFactory, original.isDeclaration()); + final T copy = + (T) + AnnotatedTypeMirror.createType( + original.getUnderlyingType(), + newTypeFactory, + original.isDeclaration()); maybeCopyPrimaryAnnotations(original, copy); return copy; diff --git a/src/checkers/inference/util/InferenceUtil.java b/src/checkers/inference/util/InferenceUtil.java index a947ff23a..2c076fe95 100644 --- a/src/checkers/inference/util/InferenceUtil.java +++ b/src/checkers/inference/util/InferenceUtil.java @@ -1,11 +1,15 @@ package checkers.inference.util; +import com.sun.source.tree.ClassTree; +import com.sun.source.tree.IdentifierTree; +import com.sun.source.tree.NewClassTree; +import com.sun.source.tree.Tree; +import com.sun.source.tree.VariableTree; + import org.checkerframework.framework.type.AnnotatedTypeMirror; -import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedIntersectionType; import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable; import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedWildcardType; import org.checkerframework.javacutil.AnnotationMirrorSet; -import org.checkerframework.javacutil.AnnotationUtils; import org.checkerframework.javacutil.BugInCF; import java.util.Arrays; @@ -24,16 +28,11 @@ import javax.lang.model.element.AnnotationMirror; -import com.sun.source.tree.ClassTree; -import com.sun.source.tree.IdentifierTree; -import com.sun.source.tree.NewClassTree; -import com.sun.source.tree.Tree; -import com.sun.source.tree.VariableTree; - public class InferenceUtil { /** * Clear all primary annotations on atm + * * @return the set of cleared annotations */ public static Set clearAnnos(final AnnotatedTypeMirror atm) { @@ -48,10 +47,11 @@ public static Set clearAnnos(final AnnotatedTypeMirror atm) { /** * TODO: This method is similar to the code in https://github.com/eisop/checker-framework * /blob/6f12277290642f8fb89a5c614b31fe419eb0a7b1/framework/src/main/java/ - * org/checkerframework/framework/type/DefaultInferredTypesApplier.java#L134, - * it should be cleaned up when the code of this link is improved. + * org/checkerframework/framework/type/DefaultInferredTypesApplier.java#L134, it should be + * cleaned up when the code of this link is improved. */ - public static void removePrimaryTypeVariableAnnotation(AnnotatedTypeVariable atv, AnnotationMirror potentialVarAnno) { + public static void removePrimaryTypeVariableAnnotation( + AnnotatedTypeVariable atv, AnnotationMirror potentialVarAnno) { AnnotationMirror ub = atv.getUpperBound().getAnnotationInHierarchy(potentialVarAnno); AnnotationMirror lb = atv.getLowerBound().getAnnotationInHierarchy(potentialVarAnno); atv.removeAnnotation(potentialVarAnno); @@ -72,16 +72,13 @@ public static void testArgument(boolean condition, final String message) { } } - /** - * Is the given classTree a declaration of an anonymous class - */ + /** Is the given classTree a declaration of an anonymous class */ public static boolean isAnonymousClass(ClassTree classTree) { - return (classTree.getSimpleName() == null) || (classTree.getSimpleName().toString().equals("")); + return (classTree.getSimpleName() == null) + || (classTree.getSimpleName().toString().equals("")); } - /** - * Is this newClassTree a declaration of an anonymous class - */ + /** Is this newClassTree a declaration of an anonymous class */ public static boolean isAnonymousClass(NewClassTree newClassTree) { if (newClassTree.getClassBody() == null) { return false; @@ -91,8 +88,9 @@ public static boolean isAnonymousClass(NewClassTree newClassTree) { } /** - * Converts the collection to a string using its natural ordering. - * Objects are converted using their toString method and then delimited by a comma (,) + * Converts the collection to a string using its natural ordering. Objects are converted using + * their toString method and then delimited by a comma (,) + * * @param toPrint The collection to joined together as a string. * @return toPrint in string form */ @@ -101,8 +99,9 @@ public static String join(Collection toPrint) { } /** - * Converts the collection to a string using its natural ordering. - * Objects are converted using their toString method and then delimited by separator + * Converts the collection to a string using its natural ordering. Objects are converted using + * their toString method and then delimited by separator + * * @param toPrint The collection to joined together as a string. * @return all elements of toPrint converted to strings and separated by separator */ @@ -130,40 +129,41 @@ public static String join(Collection toPrint, final String separator) { /** * For the given map, create a string from all entries in the map's natural order, separated by * ", " + * * @see checkers.inference.util.InferenceUtil#join(java.util.Map, String) * @param toPrint The Map we wish to create a string from * @return A string containing the entries of toPrint separated by separator */ - public static String join(Map toPrint) { + public static String join(Map toPrint) { return join(toPrint, ", "); } - /** - * For the given map, create a string from all entries in the map's natural order arranged as follows: - * Key1 -> Value1Key2 -> Value2...KeyN -> ValueN - * e.g for a Map( 1 -> "One", 2 -> "Two", 3 -> "Three" ) and a separator of "_sep_" - * the output would be "1 -> One_sep_2 -> Two_sep_3 -> Three + * For the given map, create a string from all entries in the map's natural order arranged as + * follows: Key1 -> Value1Key2 -> Value2...KeyN -> ValueN e.g for a Map( 1 + * -> "One", 2 -> "Two", 3 -> "Three" ) and a separator of "_sep_" the output would be "1 -> + * One_sep_2 -> Two_sep_3 -> Three + * * @param toPrint The Map we wish to create a string from * @return A string containing the entries of toPrint separated by separator */ - public static String join(Map toPrint, final String separator) { + public static String join(Map toPrint, final String separator) { if (toPrint == null) { return null; } if (toPrint.isEmpty()) { - return ""; + return ""; } - final Iterator> iterator = toPrint.entrySet().iterator(); + final Iterator> iterator = toPrint.entrySet().iterator(); final StringBuilder sb = new StringBuilder(); - final Map.Entry first = iterator.next(); + final Map.Entry first = iterator.next(); sb.append(first.getKey() + " -> " + first.getValue()); - for (Map.Entry entry : toPrint.entrySet()) { + for (Map.Entry entry : toPrint.entrySet()) { sb.append(separator); sb.append(entry.getKey() + " -> " + entry.getValue()); } @@ -171,7 +171,8 @@ public static String join(Map toPrint, final String separator) { return sb.toString(); } - private static List detachedVarSymbols = Arrays.asList("index#num", "iter#num", "assertionsEnabled#num", "array#num"); + private static List detachedVarSymbols = + Arrays.asList("index#num", "iter#num", "assertionsEnabled#num", "array#num"); public static boolean isDetachedVariable(Tree targetTree) { String name; @@ -191,7 +192,6 @@ public static boolean isDetachedVariable(Tree targetTree) { return false; } - public static AnnotatedTypeMirror findUpperBoundType(final AnnotatedTypeVariable typeVariable) { return findUpperBoundType(typeVariable, false); } @@ -201,42 +201,47 @@ public static AnnotatedTypeMirror findUpperBoundType( AnnotatedTypeMirror upperBoundType = typeVariable.getUpperBound(); while (upperBoundType.getAnnotations().isEmpty()) { switch (upperBoundType.getKind()) { - case TYPEVAR: - upperBoundType = ((AnnotatedTypeVariable) upperBoundType).getUpperBound(); - break; + case TYPEVAR: + upperBoundType = ((AnnotatedTypeVariable) upperBoundType).getUpperBound(); + break; - case WILDCARD: - upperBoundType = ((AnnotatedWildcardType) upperBoundType).getExtendsBound(); - break; + case WILDCARD: + upperBoundType = ((AnnotatedWildcardType) upperBoundType).getExtendsBound(); + break; - case INTERSECTION: - // TODO: We need clear semantics for INTERSECTIONS, using first - // alternative for now - upperBoundType = upperBoundType.directSupertypes().get(0); - break; + case INTERSECTION: + // TODO: We need clear semantics for INTERSECTIONS, using first + // alternative for now + upperBoundType = upperBoundType.directSupertypes().get(0); + break; - default: - if (!allowUnannotatedTypes) { - throw new BugInCF("Couldn't find upperBoundType, annotations are empty!:\n" + "typeVariable=" - + typeVariable + "\n" + "currentUpperBoundType=" + upperBoundType); - } else { - return upperBoundType; - } + default: + if (!allowUnannotatedTypes) { + throw new BugInCF( + "Couldn't find upperBoundType, annotations are empty!:\n" + + "typeVariable=" + + typeVariable + + "\n" + + "currentUpperBoundType=" + + upperBoundType); + } else { + return upperBoundType; + } } } return upperBoundType; } - public static AnnotatedTypeMirror findLowerBoundType( - final AnnotatedTypeVariable typeVariable) { + public static AnnotatedTypeMirror findLowerBoundType(final AnnotatedTypeVariable typeVariable) { return findLowerBoundType(typeVariable, false); } + public static AnnotatedTypeMirror findLowerBoundType( final AnnotatedTypeVariable typeVariable, final boolean allowUnannotatedTypes) { AnnotatedTypeMirror lowerBoundType = typeVariable.getLowerBound(); while (lowerBoundType.getAnnotations().isEmpty()) { - switch(lowerBoundType.getKind()) { + switch (lowerBoundType.getKind()) { case TYPEVAR: lowerBoundType = ((AnnotatedTypeVariable) lowerBoundType).getLowerBound(); break; @@ -246,16 +251,20 @@ public static AnnotatedTypeMirror findLowerBoundType( break; case INTERSECTION: - // TODO: We need clear semantics for INTERSECTIONS, using first alternative for now + // TODO: We need clear semantics for INTERSECTIONS, using first alternative for + // now lowerBoundType = lowerBoundType.directSupertypes().get(0); break; - default: if (!allowUnannotatedTypes) { - throw new BugInCF("Couldn't find lowerBoundType, annotations are empty!:\n" - + "typeVariable=" + typeVariable + "\n" - + "currentLowerBoundType=" + lowerBoundType); + throw new BugInCF( + "Couldn't find lowerBoundType, annotations are empty!:\n" + + "typeVariable=" + + typeVariable + + "\n" + + "currentLowerBoundType=" + + lowerBoundType); } else { return lowerBoundType; } @@ -265,10 +274,7 @@ public static AnnotatedTypeMirror findLowerBoundType( return lowerBoundType; } - - /** - * Set the root logging level and handler level. - */ + /** Set the root logging level and handler level. */ public static void setLoggingLevel(Level level) { Logger root = Logger.getLogger(""); root.setLevel(level); @@ -307,7 +313,8 @@ public static void flushAllLoggers(boolean flushSystemOut) { } } - public static LinkedHashMap makeOrderedMap(Set keys, Collection values) { + public static LinkedHashMap makeOrderedMap( + Set keys, Collection values) { if (keys.size() != values.size()) { throw new RuntimeException("Keys.size != values.size" + keys + "\n -> \n" + values); } diff --git a/src/checkers/inference/util/InferenceViewpointAdapter.java b/src/checkers/inference/util/InferenceViewpointAdapter.java index fb754e4c8..d66cd4ac0 100644 --- a/src/checkers/inference/util/InferenceViewpointAdapter.java +++ b/src/checkers/inference/util/InferenceViewpointAdapter.java @@ -1,21 +1,23 @@ package checkers.inference.util; -import checkers.inference.InferenceMain; -import checkers.inference.SlotManager; -import checkers.inference.model.CombVariableSlot; -import checkers.inference.model.ConstraintManager; -import checkers.inference.model.Slot; +import org.checkerframework.framework.type.AbstractViewpointAdapter; import org.checkerframework.framework.type.AnnotatedTypeFactory; import org.checkerframework.framework.type.AnnotatedTypeMirror; -import org.checkerframework.framework.type.AbstractViewpointAdapter; import org.checkerframework.javacutil.BugInCF; import javax.lang.model.element.AnnotationMirror; +import checkers.inference.InferenceMain; +import checkers.inference.SlotManager; +import checkers.inference.model.CombVariableSlot; +import checkers.inference.model.ConstraintManager; +import checkers.inference.model.Slot; + public class InferenceViewpointAdapter extends AbstractViewpointAdapter { private final SlotManager slotManager = InferenceMain.getInstance().getSlotManager(); - private final ConstraintManager constraintManager = InferenceMain.getInstance().getConstraintManager(); + private final ConstraintManager constraintManager = + InferenceMain.getInstance().getConstraintManager(); public InferenceViewpointAdapter(AnnotatedTypeFactory atypeFactory) { super(atypeFactory); @@ -37,7 +39,8 @@ protected AnnotationMirror combineAnnotationWithAnnotation( assert receiverAnnotation != null && declaredAnnotation != null; final Slot recvSlot = slotManager.getSlot(receiverAnnotation); final Slot declSlot = slotManager.getSlot(declaredAnnotation); - final CombVariableSlot combVariableSlot = slotManager.createCombVariableSlot(recvSlot, declSlot); + final CombVariableSlot combVariableSlot = + slotManager.createCombVariableSlot(recvSlot, declSlot); constraintManager.addCombineConstraint(recvSlot, declSlot, combVariableSlot); return slotManager.getAnnotation(combVariableSlot); } diff --git a/src/checkers/inference/util/JaifBuilder.java b/src/checkers/inference/util/JaifBuilder.java index aa0174f53..a5322bd86 100644 --- a/src/checkers/inference/util/JaifBuilder.java +++ b/src/checkers/inference/util/JaifBuilder.java @@ -1,8 +1,11 @@ package checkers.inference.util; -import org.checkerframework.afu.scenelib.io.ASTRecord; +import com.sun.source.tree.Tree; + import org.checkerframework.afu.scenelib.io.ASTPath; import org.checkerframework.afu.scenelib.io.ASTPath.ASTEntry; +import org.checkerframework.afu.scenelib.io.ASTRecord; +import org.plumelib.util.IPair; import java.lang.annotation.Annotation; import java.lang.reflect.Method; @@ -20,54 +23,51 @@ import checkers.inference.model.AnnotationLocation.AstPathLocation; import checkers.inference.model.AnnotationLocation.ClassDeclLocation; -import com.sun.source.tree.Tree; - -import org.plumelib.util.IPair; - /** * JaifBuilder creates Jaifs from a Map of ASTRecords to AnnotationMirrors. * - * JaifBuilder first organizes ASTRecords by class and top level member, and then - * builds a Jaif string. + *

JaifBuilder first organizes ASTRecords by class and top level member, and then builds a Jaif + * string. * * @author mcarthur - * */ public class JaifBuilder { /** - * Data structure that maps a class to its members (fields, variables, initializer) - * The nested Map maps a member to the List of VariableSlots for that member. + * Data structure that maps a class to its members (fields, variables, initializer) The nested + * Map maps a member to the List of VariableSlots for that member. */ private Map classesMap; /** - * Represents a map of AnnotationLocation to the serialized form of the annotation - * that should be inserted at that location + * Represents a map of AnnotationLocation to the serialized form of the annotation that should + * be inserted at that location */ private final Map locationToAnno; /** - * Used to build the import section of the Jaif and import all annotations that - * are referenced in locationToAnnos + * Used to build the import section of the Jaif and import all annotations that are referenced + * in locationToAnnos */ private final Set> supportedAnnotations; - /** - * Caches annotation definitions that have been written - */ + /** Caches annotation definitions that have been written */ private final Set> writeAnnotationHeaderCache = new HashSet<>(); private final boolean insertMainModOfLocalVar; private StringBuilder builder; - public JaifBuilder(Map locationToAnno, - Set> annotationMirrors) { + public JaifBuilder( + Map locationToAnno, + Set> annotationMirrors) { this(locationToAnno, annotationMirrors, false); } - public JaifBuilder(Map locationToAnno, - Set> annotationMirrors, boolean insertMethodBodies) { + + public JaifBuilder( + Map locationToAnno, + Set> annotationMirrors, + boolean insertMethodBodies) { this.locationToAnno = locationToAnno; this.supportedAnnotations = annotationMirrors; this.insertMainModOfLocalVar = insertMethodBodies; @@ -91,7 +91,7 @@ public String createJaif() { } // Write out each class - for (Map.Entry entry: classesMap.entrySet()) { + for (Map.Entry entry : classesMap.entrySet()) { writeClassJaif(entry.getValue()); } @@ -134,8 +134,7 @@ private void writeAnnotationHeader(Class annotation) { } // write the header for the given annotation - builder.append(buildAnnotationHeader(annotation)) - .append("\n"); + builder.append(buildAnnotationHeader(annotation)).append("\n"); } /** @@ -148,20 +147,20 @@ private String buildAnnotationHeader(Class annotation) { StringBuilder sb = new StringBuilder(); // insert package name sb.append(annotation.getPackage()) - .append(":\n annotation @") - // insert class name - .append(annotation.getSimpleName()) - .append(":\n"); + .append(":\n annotation @") + // insert class name + .append(annotation.getSimpleName()) + .append(":\n"); for (Method method : annotation.getDeclaredMethods()) { // insert 4 space indentation for each return type sb.append(" ") - // insert the return type - .append(getAnnotationHeaderReturnType(method.getReturnType())) - .append(" ") - // insert method name - .append(method.getName()) - .append("\n"); + // insert the return type + .append(getAnnotationHeaderReturnType(method.getReturnType())) + .append(" ") + // insert method name + .append(method.getName()) + .append("\n"); } return sb.toString(); @@ -170,20 +169,20 @@ private String buildAnnotationHeader(Class annotation) { /** * Java allows the method return types in an annotation to be: * - * 1) Enums + *

1) Enums * - * 2) Annotations + *

2) Annotations * - * 3) String types + *

3) String types * - * 4) Class types + *

4) Class types * - * 5) primitive types + *

5) primitive types * - * 6) 1D arrays with a component type of one of the above + *

6) 1D arrays with a component type of one of the above * - * This method returns the appropriate return type name according to the JAIF specification for - * each of these scenarios for the given returnType argument. + *

This method returns the appropriate return type name according to the JAIF specification + * for each of these scenarios for the given returnType argument. */ private String getAnnotationHeaderReturnType(final Class returnType) { // de-sugar array return types @@ -212,8 +211,9 @@ private String getAnnotationHeaderReturnType(final Class returnType) { /** * Add the jaif for the given classname and members. - * @param classEntry A unique entry for all members of a class that will be converted to - * a jaif entry for that class + * + * @param classEntry A unique entry for all members of a class that will be converted to a jaif + * entry for that class */ private void writeClassJaif(ClassEntry classEntry) { builder.append("package " + classEntry.packageName + ":\n"); @@ -253,6 +253,7 @@ private void writeClassJaif(ClassEntry classEntry) { /** * Add the Jaif entries for all records under memberName + * * @param memberName the member * @param memberRecords the records for the member */ @@ -265,7 +266,7 @@ private void writeMemberJaif(String memberName, MemberRecords memberRecords) { builder.append(memberName); } - for (RecordValue value: memberRecords.entries) { + for (RecordValue value : memberRecords.entries) { builder.append("insert-annotation "); builder.append(value.astPath.toString()); builder.append(": "); @@ -275,9 +276,7 @@ private void writeMemberJaif(String memberName, MemberRecords memberRecords) { builder.append("\n"); } - /** - * Change the Enum name to a String in the format required by AFU - */ + /** Change the Enum name to a String in the format required by AFU */ private String treeKindToTitleCase(Tree.Kind kind) { String[] parts = kind.toString().toUpperCase().split("_"); String result = ""; @@ -288,11 +287,9 @@ private String treeKindToTitleCase(Tree.Kind kind) { return result; } - /** - * Iterate through each variable and add it to the appropriate Class and Member list. - */ + /** Iterate through each variable and add it to the appropriate Class and Member list. */ private void buildClassEntries() { - for (Entry entry: locationToAnno.entrySet()) { + for (Entry entry : locationToAnno.entrySet()) { AnnotationLocation location = entry.getKey(); String annotation = entry.getValue(); switch (location.getKind()) { @@ -301,9 +298,10 @@ private void buildClassEntries() { ClassEntry classEntry = getClassEntry(astLocation); ASTRecord astRecord = astLocation.getAstRecord(); - MemberRecords memberRecords = classEntry.getMemberRecords(astRecord.methodName, astRecord.varName); + MemberRecords memberRecords = + classEntry.getMemberRecords(astRecord.methodName, astRecord.varName); if (!insertMainModOfLocalVar && isMainModOfLocalVar(astRecord.astPath)) { - continue; + continue; } // Don't insert annotation for empty ASTPath @@ -313,7 +311,7 @@ private void buildClassEntries() { continue; } - memberRecords.entries.add(new RecordValue(astRecord.astPath,annotation)); + memberRecords.entries.add(new RecordValue(astRecord.astPath, annotation)); break; case CLASS_DECL: @@ -326,21 +324,22 @@ private void buildClassEntries() { break; default: - throw new RuntimeException("Unhandled AnnotationLocation " + location + - " with value " + annotation); - + throw new RuntimeException( + "Unhandled AnnotationLocation " + + location + + " with value " + + annotation); } } } /** * @param astRecord - * @return true if the given AST path represents a main modifier of a local variable - * An AST Path represents a main modifier of a local variable should have pattern like - * 1) ..., Block.statement #, ..., Variable.type - * 2) ..., Block.statement #, ..., Variable.type, ParameterizedType.type - * reference: Local Variable Declaration Statements in JLS8 - * https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.4 + * @return true if the given AST path represents a main modifier of a local variable An AST Path + * represents a main modifier of a local variable should have pattern like 1) ..., + * Block.statement #, ..., Variable.type 2) ..., Block.statement #, ..., Variable.type, + * ParameterizedType.type reference: Local Variable Declaration Statements in JLS8 + * https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.4 */ protected boolean isMainModOfLocalVar(ASTPath astPath) { Iterator iterator = astPath.iterator(); @@ -372,8 +371,9 @@ protected boolean isMainModOfLocalVar(ASTPath astPath) { if (isEntry(Tree.Kind.VARIABLE, ASTPath.TYPE, leafEntry)) { // the first kind of AST path of main modifier of local variable return true; - } else if (prevEntry != null && isEntry(Tree.Kind.VARIABLE, ASTPath.TYPE, prevEntry) && - isEntry(Tree.Kind.PARAMETERIZED_TYPE, ASTPath.TYPE, leafEntry)) { + } else if (prevEntry != null + && isEntry(Tree.Kind.VARIABLE, ASTPath.TYPE, prevEntry) + && isEntry(Tree.Kind.PARAMETERIZED_TYPE, ASTPath.TYPE, leafEntry)) { // the second kind return true; } @@ -382,14 +382,16 @@ protected boolean isMainModOfLocalVar(ASTPath astPath) { } /** - * determine whether a given {@code ASTEntry} represents - * {@code (Tree.Kind).childSelector }, e.g. given an ASTEntry entry: - *

-     * {@code
+     * determine whether a given {@code ASTEntry} represents {@code (Tree.Kind).childSelector },
+     * e.g. given an ASTEntry entry:
+     *
+     * 
{@code
      * Block.statement #
      * }
- * the tree kind is "Block", the childSelector is "statement" - * thus, {@code isEntry(Tree.BLOCK, ASTPATH.STATEMENT, entry) } will return true + * + * the tree kind is "Block", the childSelector is "statement" thus, {@code isEntry(Tree.BLOCK, + * ASTPATH.STATEMENT, entry) } will return true + * * @param kind * @param childSelector * @param entry @@ -408,15 +410,16 @@ private ClassEntry getClassEntry(ClassDeclLocation location) { } /** - * Lookup or create, for a given class, a map of Members of that class - * to a list of VariableSlots for those members. + * Lookup or create, for a given class, a map of Members of that class to a list of + * VariableSlots for those members. * * @param fullyQualified The class to look up. */ private ClassEntry getClassEntry(String fullyQualified) { ClassEntry classEntry = this.classesMap.get(fullyQualified); if (classEntry == null) { - IPair packageToClass = ASTPathUtil.splitFullyQualifiedClass(fullyQualified); + IPair packageToClass = + ASTPathUtil.splitFullyQualifiedClass(fullyQualified); classEntry = new ClassEntry(packageToClass.first, packageToClass.second); this.classesMap.put(fullyQualified, classEntry); } @@ -424,8 +427,8 @@ private ClassEntry getClassEntry(String fullyQualified) { } /** - * Lookup or create, for a given class, a map of Members of that class - * to a list of VariableSlots for those members. + * Lookup or create, for a given class, a map of Members of that class to a list of + * VariableSlots for those members. * * @param record a record identifying a unique class */ @@ -466,17 +469,17 @@ public ClassEntry(String packageName, String className) { declAnnos = new LinkedHashSet<>(); } - /** - * Add an annotation that should go on the declaration of the class - */ + /** Add an annotation that should go on the declaration of the class */ public void addDeclarationAnnotation(String annotation) { declAnnos.add(annotation); } /** * Lookup or create the List of VariableSLots for a Class and Member + * * @param memberName The top-level member name to look up - * @param variableName If the record occurs in relation to a variable, this specifies the variable name + * @param variableName If the record occurs in relation to a variable, this specifies the + * variable name * @return */ public MemberRecords getMemberRecords(String memberName, String variableName) { @@ -491,19 +494,16 @@ public MemberRecords getMemberRecords(String memberName, String variableName) { Map members = new HashMap<>(); } - /** - * The records for a member. - */ + /** The records for a member. */ private static class MemberRecords { List entries = new ArrayList<>(); } - /** - * The value for a record. - */ + /** The value for a record. */ private static class RecordValue { ASTPath astPath; String value; + RecordValue(ASTPath record, String value) { this.astPath = record; this.value = value; diff --git a/src/checkers/inference/util/JaifFileReader.java b/src/checkers/inference/util/JaifFileReader.java index 9670390b4..d4efd5492 100644 --- a/src/checkers/inference/util/JaifFileReader.java +++ b/src/checkers/inference/util/JaifFileReader.java @@ -1,7 +1,5 @@ package checkers.inference.util; -import checkers.inference.util.JaifFileReader.JaifPackage; - import java.io.BufferedReader; import java.io.File; import java.io.FileReader; @@ -12,18 +10,18 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import checkers.inference.util.JaifFileReader.JaifPackage; + /** - * A JaifFileIterator will open a jaif and provide an iterator that reads - * Jaif information package by package. Note, if a package occurs multiple times - * then there will be multiple Package objects for this package; they will NOT - * be aggregated into 1 + * A JaifFileIterator will open a jaif and provide an iterator that reads Jaif information package + * by package. Note, if a package occurs multiple times then there will be multiple Package objects + * for this package; they will NOT be aggregated into 1 * - * To use JaifIterator + *

To use JaifIterator * - * 1. Create a new iterator: new JaifFileIterator(jaifFile) - * 2. Open the iterator (this opens the file, creates a file handle) - * 3. Iterate over the iterator - * 4. Close the iterator (this will close the file handle) + *

1. Create a new iterator: new JaifFileIterator(jaifFile) 2. Open the iterator (this opens the + * file, creates a file handle) 3. Iterate over the iterator 4. Close the iterator (this will close + * the file handle) */ public class JaifFileReader implements Iterable { private final File jaifFile; @@ -38,7 +36,7 @@ public JaifFileIterator iterator() { } } - public class Block{ + public class Block { public final List lines; Block(List lines) { @@ -78,10 +76,10 @@ public JaifFileReader(File jaifFile) { } /* - * Breaks a file into Packages. Each package consists of a list of Blocks, - * a block is a sequential set of lines in the original JAIF file ending in a newline, - * which is excluded. - */ + * Breaks a file into Packages. Each package consists of a list of Blocks, + * a block is a sequential set of lines in the original JAIF file ending in a newline, + * which is excluded. + */ public class JaifFileIterator implements Iterator { private final BufferedReader bufferedReader; private boolean endOfStream = false; @@ -153,7 +151,6 @@ protected JaifPackage readNext() throws IOException { } else { lineBuffer.add(line); } - } addBlocks(lineBuffer, blockBuffer); @@ -166,14 +163,14 @@ protected JaifPackage readNext() throws IOException { return next; } - /** - * Creates a Block object using the lines in lineBuffer and clears the lineBuffer. The resulting - * Block object is added to blockBuffer. If lineBuffer is empty, then no object is created or added + * Creates a Block object using the lines in lineBuffer and clears the lineBuffer. The + * resulting Block object is added to blockBuffer. If lineBuffer is empty, then no object is + * created or added */ private void addBlocks(List lineBuffer, List blockBuffer) { if (!lineBuffer.isEmpty()) { - blockBuffer.add( new Block(new ArrayList<>(lineBuffer))); + blockBuffer.add(new Block(new ArrayList<>(lineBuffer))); lineBuffer.clear(); } } diff --git a/src/checkers/inference/util/JaifSplitter.java b/src/checkers/inference/util/JaifSplitter.java index 5ab61a2a4..1b423a464 100644 --- a/src/checkers/inference/util/JaifSplitter.java +++ b/src/checkers/inference/util/JaifSplitter.java @@ -15,53 +15,56 @@ import checkers.inference.util.JaifFileReader.JaifPackage; /** - * Splits a JAIF file by package into many JAIFs and writes them to the outputDir. - * Creates a shell script that will insert all of them one-by-one. + * Splits a JAIF file by package into many JAIFs and writes them to the outputDir. Creates a shell + * script that will insert all of them one-by-one. * - * When running insert-annotation-to-source you must pass a list of Java files as arguments. Sometimes this - * list is longer than the permissiable number of arguments on the command line (this occurs for Hadoop). - * In these cases you can use the JaifSplitter to split the jaif into many files that can be inserted individually. - * In order to make it easy to insert all of them, JaifSplitter will also write a shell script that will - * insert all of the jaifs one-by-one. + *

When running insert-annotation-to-source you must pass a list of Java files as arguments. + * Sometimes this list is longer than the permissiable number of arguments on the command line (this + * occurs for Hadoop). In these cases you can use the JaifSplitter to split the jaif into many files + * that can be inserted individually. In order to make it easy to insert all of them, JaifSplitter + * will also write a shell script that will insert all of the jaifs one-by-one. * - * Splitting jaifs also has the following effects: - * a) The AFU doesn't have to search as many Java files when searching for the correct file to insert into. - * b) If the AFU crashes on a malformed JAIF for one package, annotations are still inserted into the other - * packages - * c) The shell script can and will report when it has completed a package and how many total packages - * there are. Therefore, you can get some sense of progress when inserting the annotations for a large project + *

Splitting jaifs also has the following effects: a) The AFU doesn't have to search as many Java + * files when searching for the correct file to insert into. b) If the AFU crashes on a malformed + * JAIF for one package, annotations are still inserted into the other packages c) The shell script + * can and will report when it has completed a package and how many total packages there are. + * Therefore, you can get some sense of progress when inserting the annotations for a large project * - * To use JaifSplitter from source code, create a new JaifSplitter and call jaifSplitter.split() - * To use JaifSplitter from the command-line, run scripts/splitJaif or scripts/debugSplitJaif + *

To use JaifSplitter from source code, create a new JaifSplitter and call jaifSplitter.split() + * To use JaifSplitter from the command-line, run scripts/splitJaif or scripts/debugSplitJaif */ public class JaifSplitter { - /** - * The input JAIF file - */ + /** The input JAIF file */ private final File jaifFile; - /** - */ + /** */ private final File outputDir; + private final File commandFile; private final List annos; private final String srcPattern; /** - * @param jaifFile the input JAIF file - * @param outputDir the directory in which the new jaifs, created by splitting jaifFile, will be placed - * @param commandFile the shell file in which to place the shell script for inserting all jaifs in outputDir - * @param srcPattern in order to limit the directories searched for java file, srcPattern should be a path - * from the projects root to an ancestor directory of all java files - * e.g. for Maven project, src/main/java - * @param annos the annotations to place in every jaif files header, these annotations should be strings of - * the following format: - * fully.qualified.AnnotationClassName[type arg, type arg] - * Where "type arg" specifies a property of AnnotationClassName, e.g. "int value" - * VarAnnot would be represented as checkers.inference.qual.VarAnnot[int value] + * @param jaifFile the input JAIF file + * @param outputDir the directory in which the new jaifs, created by splitting jaifFile, will be + * placed + * @param commandFile the shell file in which to place the shell script for inserting all jaifs + * in outputDir + * @param srcPattern in order to limit the directories searched for java file, srcPattern should + * be a path from the projects root to an ancestor directory of all java files e.g. for + * Maven project, src/main/java + * @param annos the annotations to place in every jaif files header, these annotations should be + * strings of the following format: fully.qualified.AnnotationClassName[type arg, type arg] + * Where "type arg" specifies a property of AnnotationClassName, e.g. "int value" VarAnnot + * would be represented as checkers.inference.qual.VarAnnot[int value] */ - public JaifSplitter(File jaifFile, File outputDir, File commandFile, String srcPattern, List annos) { + public JaifSplitter( + File jaifFile, + File outputDir, + File commandFile, + String srcPattern, + List annos) { this.jaifFile = jaifFile; this.outputDir = outputDir; this.commandFile = commandFile; @@ -69,7 +72,7 @@ public JaifSplitter(File jaifFile, File outputDir, File commandFile, String srcP this.annos = annos; } - public static void main(String [] args) { + public static void main(String[] args) { if (args.length < 5) { printError("Too few arguments"); } // else @@ -79,21 +82,27 @@ public static void main(String [] args) { annos.add(args[i]); } - new JaifSplitter(new File(args[0]), new File(args[1]), new File(args[2]), args[3], annos).split(); + new JaifSplitter(new File(args[0]), new File(args[1]), new File(args[2]), args[3], annos) + .split(); } public static void printUsage() { - System.out.println("This class splits a large jaif into a number of smaller jaifs and generates a shell script " - + "that will insert the jaif into source code starting at $PWD/**/srcPattern\n"); - System.out.println("Usage: JaifSplitter jaifFile outputDir commandFile srcPattern anno [anno ...]"); + System.out.println( + "This class splits a large jaif into a number of smaller jaifs and generates a shell script " + + "that will insert the jaif into source code starting at $PWD/**/srcPattern\n"); + System.out.println( + "Usage: JaifSplitter jaifFile outputDir commandFile srcPattern anno [anno ...]"); System.out.println(" jaifFile -- the file to split"); System.out.println(" outputDir -- the directory in which to put the new jaifs"); - System.out.println(" commandFile -- the sh file in which to place sh commands to insert the new jaifs"); - System.out.println(" srcPattern -- a path from the root of your project directory to the start of " + - "the source files, e.g. for hadoop src/main/java"); - System.out.println(" anno -- annotations used in the jaif, there must be at least 1. Use the format " - + "my.path.to.Qual[String arg1, int arg2] or my.path.to.no.arg.Qual[] e.g., " - + "checkers.inference.qual.VarAnnot[int value]"); + System.out.println( + " commandFile -- the sh file in which to place sh commands to insert the new jaifs"); + System.out.println( + " srcPattern -- a path from the root of your project directory to the start of " + + "the source files, e.g. for hadoop src/main/java"); + System.out.println( + " anno -- annotations used in the jaif, there must be at least 1. Use the format " + + "my.path.to.Qual[String arg1, int arg2] or my.path.to.no.arg.Qual[] e.g., " + + "checkers.inference.qual.VarAnnot[int value]"); } public static void printError(String message) { @@ -111,15 +120,17 @@ public void split() { public static Pattern ANNOTATION_PATTERN = Pattern.compile("^((?:\\w+\\.)*)(\\w+)\\[(.*)\\]$"); /** - * Split a large jaif into smaller jaifs by package name. The smaller jaifs are placed - * in output dir. This method also generates a shell script full of insert-annotations-to-source - * commands that will insert all of the jaifs. + * Split a large jaif into smaller jaifs by package name. The smaller jaifs are placed in output + * dir. This method also generates a shell script full of insert-annotations-to-source commands + * that will insert all of the jaifs. + * * @param jaifFile The file to be split * @param outputDir The directory to place the output jaifs * @param commandFile The shell script in which to place the insert commands * @param header A header placed at the top of every jaif */ - protected static void splitAndWrite(File jaifFile, File outputDir, File commandFile, String srcPattern, String header) { + protected static void splitAndWrite( + File jaifFile, File outputDir, File commandFile, String srcPattern, String header) { Set insertionCommands = new LinkedHashSet<>(); Set visitedFiles = new LinkedHashSet<>(); @@ -129,7 +140,8 @@ protected static void splitAndWrite(File jaifFile, File outputDir, File commandF if (!visitedFiles.contains(outputJaif)) { overwriteLines(outputJaif, Arrays.asList(header, "\n")); - insertionCommands.add(makeInsertionCommand(outputJaif, jaifPackage.name, srcPattern)); + insertionCommands.add( + makeInsertionCommand(outputJaif, jaifPackage.name, srcPattern)); visitedFiles.add(outputJaif); } @@ -142,18 +154,23 @@ protected static void splitAndWrite(File jaifFile, File outputDir, File commandF System.out.flush(); } - System.out.println("Writing " + insertionCommands.size() + " insertions commands to file:\n" - + commandFile.getAbsolutePath()); + System.out.println( + "Writing " + + insertionCommands.size() + + " insertions commands to file:\n" + + commandFile.getAbsolutePath()); writeInsertShellScript(commandFile, insertionCommands, visitedFiles); } - public static void writeInsertShellScript(File commandFile, Set insertionCommands, Set jaifs) { + public static void writeInsertShellScript( + File commandFile, Set insertionCommands, Set jaifs) { List shFileCommands = new ArrayList<>(insertionCommands.size() + 6); shFileCommands.add("if [ -z \"$1\" ]"); shFileCommands.add("then"); - shFileCommands.add("echo \"You must specify 1 argument, the root of the source directory that contains " + - "all source files to which annotations should be added.\""); + shFileCommands.add( + "echo \"You must specify 1 argument, the root of the source directory that contains " + + "all source files to which annotations should be added.\""); shFileCommands.add("exit 1"); shFileCommands.add("fi"); shFileCommands.add(""); @@ -169,7 +186,14 @@ public static void writeInsertShellScript(File commandFile, Set insertio File jaif = jaifIter.next(); shFileCommands.add("echo \"-----------------\""); - shFileCommands.add("echo \"running insertion (" + current + " / " + total + ") on file " + jaif.getAbsolutePath() + "\"" ); + shFileCommands.add( + "echo \"running insertion (" + + current + + " / " + + total + + ") on file " + + jaif.getAbsolutePath() + + "\""); shFileCommands.add(insertionCommand); shFileCommands.add("echo \"-----------------\""); shFileCommands.add("echo \"\""); @@ -177,7 +201,6 @@ public static void writeInsertShellScript(File commandFile, Set insertio ++current; } - overwriteLines(commandFile, shFileCommands); } @@ -187,9 +210,9 @@ public static void makeDirectoryOrFail(final File dir) { } } - /** * Writes the input set of lines to the given file + * * @param file destination file for lines * @param append whether or not to append the lines to the file * @param lines the lines to write @@ -218,7 +241,6 @@ private static void overwriteLines(File file, Iterable lines) writeLines(file, false, lines); } - private static class AnnotationDescription { public final String packageName; public final String className; @@ -230,9 +252,11 @@ private static class AnnotationDescription { this.argsList = argsList; } } + /** - * Takes a list of fully qualified annotations and turns them into Jaif headers that - * allow them to be used within insertions + * Takes a list of fully qualified annotations and turns them into Jaif headers that allow them + * to be used within insertions + * * @param fullyQualifiedAnnotations * @return */ @@ -257,7 +281,6 @@ public static String makeHeader(List fullyQualifiedAnnotations) { return header.toString(); } - /** * This method does not handle nested annotations at the moment * @@ -268,7 +291,7 @@ private static AnnotationDescription parseAnnotation(String fullyQualifiedAnnota Matcher matcher = ANNOTATION_PATTERN.matcher(fullyQualifiedAnnotation); if (matcher.matches()) { String packageName = matcher.group(1); - packageName = packageName.substring(0, packageName.length() - 1); // drop trailing (.) + packageName = packageName.substring(0, packageName.length() - 1); // drop trailing (.) String annotationName = "@" + matcher.group(2); List argsList = arrayToArgsList(matcher.group(3).split(",")); @@ -276,11 +299,12 @@ private static AnnotationDescription parseAnnotation(String fullyQualifiedAnnota } throw new IllegalArgumentException( - "Annotations must be in the form: package.path.ClassName[arg1,arg2,...,argN]\n" + - "found: " + fullyQualifiedAnnotation); + "Annotations must be in the form: package.path.ClassName[arg1,arg2,...,argN]\n" + + "found: " + + fullyQualifiedAnnotation); } - private static List arrayToArgsList(String [] args) { + private static List arrayToArgsList(String[] args) { List argList = new ArrayList<>(args.length); for (String arg : args) { arg = arg.trim(); @@ -293,18 +317,21 @@ private static List arrayToArgsList(String [] args) { } /** - * Given a jaif file and the corresponding package name for that jaif file, return an insert-annotations-to-source - * command that will find the correct files and insert the jaif + * Given a jaif file and the corresponding package name for that jaif file, return an + * insert-annotations-to-source command that will find the correct files and insert the jaif */ - private static String makeInsertionCommand(File jaifFile, String packageName, String srcPattern) { + private static String makeInsertionCommand( + File jaifFile, String packageName, String srcPattern) { String packagePath = packageName.replace(".", File.separator); // right now this is tailored for hadoop - String srcPath = "**/" + srcPattern + File.separator + packagePath + File.separator + "*.java"; + String srcPath = + "**/" + srcPattern + File.separator + packagePath + File.separator + "*.java"; String findPackageSourcesCmd = " `find $1 -path " + srcPath + "`"; - return "insert-annotations-to-source -i \"" + jaifFile.getAbsolutePath() + "\" " + findPackageSourcesCmd; + return "insert-annotations-to-source -i \"" + + jaifFile.getAbsolutePath() + + "\" " + + findPackageSourcesCmd; } - } - diff --git a/src/checkers/inference/util/SlotDefaultTypeResolver.java b/src/checkers/inference/util/SlotDefaultTypeResolver.java index 2f081931f..d24a59879 100644 --- a/src/checkers/inference/util/SlotDefaultTypeResolver.java +++ b/src/checkers/inference/util/SlotDefaultTypeResolver.java @@ -9,6 +9,7 @@ import com.sun.source.tree.TypeParameterTree; import com.sun.source.tree.WildcardTree; import com.sun.source.util.TreeScanner; + import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; import org.checkerframework.framework.type.AnnotatedTypeMirror; import org.checkerframework.javacutil.TreeUtils; @@ -18,28 +19,22 @@ import java.util.Map; /** - * A utility class to help SlotManager to find the real default type of - * each slot. + * A utility class to help SlotManager to find the real default type of each slot. * - * Slot manager tries to create a slot for each type declaration or type - * use in the class, so the associated tree is usually a type tree. - * Currently, AnnotatedTypeFactory cannot properly determine the annotated - * type of the type tree because it's unaware of the tree's location. + *

Slot manager tries to create a slot for each type declaration or type use in the class, so the + * associated tree is usually a type tree. Currently, AnnotatedTypeFactory cannot properly determine + * the annotated type of the type tree because it's unaware of the tree's location. * - * For example, AnnotatedTypeFactory returns the same annotated type for - * "Object" in the following two cases: - * 1. Object s = "123"; - * 2. List l = new ArrayList<>(); - * But it's possible to have a different default type for the upperbound. + *

For example, AnnotatedTypeFactory returns the same annotated type for "Object" in the + * following two cases: 1. Object s = "123"; 2. List l = new ArrayList<>(); But + * it's possible to have a different default type for the upperbound. * - * This class aims to properly find the real default type for type trees. + *

This class aims to properly find the real default type for type trees. */ public class SlotDefaultTypeResolver { public static Map resolve( - ClassTree classTree, - BaseAnnotatedTypeFactory realTypeFactory - ) { + ClassTree classTree, BaseAnnotatedTypeFactory realTypeFactory) { DefaultTypeFinder finder = new DefaultTypeFinder(realTypeFactory); finder.scan(classTree, null); @@ -47,13 +42,12 @@ public static Map resolve( } /** - * A tree visitor that focuses on collecting the real default types for - * type trees under this tree. + * A tree visitor that focuses on collecting the real default types for type trees under this + * tree. * - * The results may contain information for trees that are not a type - * tree. For example, the implements clause of a class can either be - * an IdentifierTree or a ParameterizedTypeTree, but we always store - * its type for simplicity. + *

The results may contain information for trees that are not a type tree. For example, the + * implements clause of a class can either be an IdentifierTree or a ParameterizedTypeTree, but + * we always store its type for simplicity. */ private static class DefaultTypeFinder extends TreeScanner { @@ -136,12 +130,14 @@ public Void visitParameterizedType(ParameterizedTypeTree tree, Void unused) { In the tree of `ArrayList<>`, we have no type arguments, but its type does have "String" as its type argument. */ - assert typeArgumentTrees.size() == 0 || typeArgumentTrees.size() == typeArgumentTypes.size(); + assert typeArgumentTrees.size() == 0 + || typeArgumentTrees.size() == typeArgumentTypes.size(); for (int i = 0; i < typeArgumentTrees.size(); ++i) { defaultTypes.put(typeArgumentTrees.get(i), typeArgumentTypes.get(i)); } - // Sometimes, the slot manager annotates the underlying type tree instead of this ParameterizedTypeTree + // Sometimes, the slot manager annotates the underlying type tree instead of this + // ParameterizedTypeTree defaultTypes.put(tree.getType(), defaultType.getErased()); return super.visitParameterizedType(tree, unused); diff --git a/src/checkers/inference/util/defaults/InferenceQualifierDefaults.java b/src/checkers/inference/util/defaults/InferenceQualifierDefaults.java index 3d805c251..36c36067b 100644 --- a/src/checkers/inference/util/defaults/InferenceQualifierDefaults.java +++ b/src/checkers/inference/util/defaults/InferenceQualifierDefaults.java @@ -1,60 +1,61 @@ package checkers.inference.util.defaults; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.Element; -import javax.lang.model.util.Elements; - import org.checkerframework.framework.type.AnnotatedTypeFactory; import org.checkerframework.framework.type.AnnotatedTypeMirror; import org.checkerframework.framework.util.defaults.Default; import org.checkerframework.framework.util.defaults.QualifierDefaults; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.util.Elements; + import checkers.inference.InferenceMain; import checkers.inference.SlotManager; -import checkers.inference.model.Slot; import checkers.inference.qual.VarAnnot; -import checkers.inference.util.ConstantToVariableAnnotator; /** * Apply default qualifiers in inference mode. * - * In inference mode, unchecked bytecode needs default qualifiers. - * To build constraints, these default qualifiers should be VarAnnots. - * The super class {@code QualifierDefaults} would determine real - * qualifiers for each type use location, and this class would replace - * those real qualifiers by equivalent VarAnnots, and apply these - * VarAnnots as defaults to a given type only if this type has not been - * annotated with a VarAnnot. + *

In inference mode, unchecked bytecode needs default qualifiers. To build constraints, these + * default qualifiers should be VarAnnots. The super class {@code QualifierDefaults} would determine + * real qualifiers for each type use location, and this class would replace those real qualifiers by + * equivalent VarAnnots, and apply these VarAnnots as defaults to a given type only if this type has + * not been annotated with a VarAnnot. * * @see org.checkerframework.framework.util.defaults.QualifierDefaults - * */ public class InferenceQualifierDefaults extends QualifierDefaults { private final SlotManager slotManager; + public InferenceQualifierDefaults(Elements elements, AnnotatedTypeFactory atypeFactory) { super(elements, atypeFactory); slotManager = InferenceMain.getInstance().getSlotManager(); } @Override - protected DefaultApplierElement createDefaultApplierElement(AnnotatedTypeFactory atypeFactory, - Element annotationScope, AnnotatedTypeMirror type, boolean applyToTypeVar) { - return new InferenceDefaultApplierElement(atypeFactory, annotationScope, type, applyToTypeVar); + protected DefaultApplierElement createDefaultApplierElement( + AnnotatedTypeFactory atypeFactory, + Element annotationScope, + AnnotatedTypeMirror type, + boolean applyToTypeVar) { + return new InferenceDefaultApplierElement( + atypeFactory, annotationScope, type, applyToTypeVar); } public class InferenceDefaultApplierElement extends DefaultApplierElement { - public InferenceDefaultApplierElement(AnnotatedTypeFactory atypeFactory, Element scope, - AnnotatedTypeMirror type, boolean applyToTypeVar) { + public InferenceDefaultApplierElement( + AnnotatedTypeFactory atypeFactory, + Element scope, + AnnotatedTypeMirror type, + boolean applyToTypeVar) { super(atypeFactory, scope, type, applyToTypeVar); } /** - * Instead of applying the real qualifier stored - * in the given {@code def}, replacing it with the - * equivalent VarAnnot and apply the VarAnnot on - * the applied type. + * Instead of applying the real qualifier stored in the given {@code def}, replacing it with + * the equivalent VarAnnot and apply the VarAnnot on the applied type. */ @Override public void applyDefault(Default def) { @@ -74,8 +75,8 @@ public void applyDefault(Default def) { @Override protected boolean shouldBeAnnotated(AnnotatedTypeMirror type, boolean applyToTypeVar) { - return super.shouldBeAnnotated(type, applyToTypeVar) && !type.hasAnnotation(VarAnnot.class); + return super.shouldBeAnnotated(type, applyToTypeVar) + && !type.hasAnnotation(VarAnnot.class); } } - } diff --git a/src/dataflow/DataflowAnnotatedTypeFactory.java b/src/dataflow/DataflowAnnotatedTypeFactory.java index 56bda64a1..3272a97c0 100644 --- a/src/dataflow/DataflowAnnotatedTypeFactory.java +++ b/src/dataflow/DataflowAnnotatedTypeFactory.java @@ -1,8 +1,29 @@ package dataflow; +import com.sun.source.tree.LiteralTree; +import com.sun.source.tree.MethodInvocationTree; +import com.sun.source.tree.NewArrayTree; +import com.sun.source.tree.NewClassTree; +import com.sun.source.tree.Tree.Kind; + +import org.checkerframework.common.basetype.BaseTypeChecker; +import org.checkerframework.framework.type.AnnotatedTypeMirror; +import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType; +import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType; +import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedPrimitiveType; +import org.checkerframework.framework.type.MostlyNoElementQualifierHierarchy; +import org.checkerframework.framework.type.QualifierHierarchy; +import org.checkerframework.framework.type.treeannotator.ListTreeAnnotator; +import org.checkerframework.framework.type.treeannotator.TreeAnnotator; +import org.checkerframework.framework.util.QualifierKind; +import org.checkerframework.javacutil.AnnotationBuilder; +import org.checkerframework.javacutil.AnnotationUtils; +import org.checkerframework.javacutil.ElementUtils; +import org.checkerframework.javacutil.TreeUtils; +import org.checkerframework.javacutil.TypeSystemError; + import java.lang.annotation.Annotation; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -20,47 +41,24 @@ import javax.lang.model.util.Elements; import checkers.inference.BaseInferenceRealTypeFactory; -import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; -import org.checkerframework.common.basetype.BaseTypeChecker; -import org.checkerframework.framework.type.AnnotatedTypeMirror; -import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType; -import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType; -import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedPrimitiveType; -import org.checkerframework.framework.type.MostlyNoElementQualifierHierarchy; -import org.checkerframework.framework.type.QualifierHierarchy; -import org.checkerframework.framework.type.treeannotator.ListTreeAnnotator; -import org.checkerframework.framework.type.treeannotator.TreeAnnotator; -import org.checkerframework.framework.util.QualifierKind; -import org.checkerframework.javacutil.AnnotationBuilder; -import org.checkerframework.javacutil.AnnotationUtils; -import org.checkerframework.javacutil.ElementUtils; -import org.checkerframework.javacutil.TreeUtils; -import org.checkerframework.javacutil.TypeSystemError; - -import com.sun.source.tree.LiteralTree; -import com.sun.source.tree.MethodInvocationTree; -import com.sun.source.tree.NewArrayTree; -import com.sun.source.tree.NewClassTree; -import com.sun.source.tree.Tree.Kind; - import dataflow.qual.DataFlow; import dataflow.qual.DataFlowTop; import dataflow.util.DataflowUtils; /** - * DataflowAnnotatedTypeFactory is the type factory for Dataflow type system. It - * defines the subtype relationship of Dataflow type system, annotate the base - * cases, and implements simplification algorithm. - * - * @author jianchu + * DataflowAnnotatedTypeFactory is the type factory for Dataflow type system. It defines the subtype + * relationship of Dataflow type system, annotate the base cases, and implements simplification + * algorithm. * + * @author jianchu */ public class DataflowAnnotatedTypeFactory extends BaseInferenceRealTypeFactory { protected final AnnotationMirror DATAFLOW, DATAFLOWBOTTOM, DATAFLOWTOP; + /** - * For each Java type is present in the target program, typeNamesMap maps - * String of the type to the TypeMirror. + * For each Java type is present in the target program, typeNamesMap maps String of the type to + * the TypeMirror. */ private final Map typeNamesMap = new HashMap(); @@ -69,7 +67,8 @@ public class DataflowAnnotatedTypeFactory extends BaseInferenceRealTypeFactory { public DataflowAnnotatedTypeFactory(BaseTypeChecker checker, boolean isInfer) { super(checker, isInfer); DATAFLOW = AnnotationBuilder.fromClass(elements, DataFlow.class); - DATAFLOWBOTTOM = DataflowUtils.createDataflowAnnotation(DataflowUtils.convert(""), processingEnv); + DATAFLOWBOTTOM = + DataflowUtils.createDataflowAnnotation(DataflowUtils.convert(""), processingEnv); DATAFLOWTOP = AnnotationBuilder.fromClass(elements, DataFlowTop.class); dataflowUtils = new DataflowUtils(processingEnv); postInit(); @@ -86,33 +85,33 @@ public QualifierHierarchy createQualifierHierarchy() { } /** - * This method handles autoboxing for primitive type. - * For statements, Integer i = 3; - * The annotation for i should be @DataFlow(typeNames = {"Integer"}). + * This method handles autoboxing for primitive type. For statements, Integer i = 3; The + * annotation for i should be @DataFlow(typeNames = {"Integer"}). */ @Override public AnnotatedDeclaredType getBoxedType(AnnotatedPrimitiveType type) { TypeElement typeElt = types.boxedClass(type.getUnderlyingType()); - AnnotationMirror am = DataflowUtils.createDataflowAnnotation(typeElt.asType().toString(), - this.processingEnv); + AnnotationMirror am = + DataflowUtils.createDataflowAnnotation( + typeElt.asType().toString(), this.processingEnv); AnnotatedDeclaredType dt = fromElement(typeElt); dt.addAnnotation(am); return dt; } /** - * This method handles unboxing for reference type. - * For statements, int i = new Integer(3); - * The annotation for i should be @DataFlow(typeNames = {"int"}). + * This method handles unboxing for reference type. For statements, int i = new Integer(3); The + * annotation for i should be @DataFlow(typeNames = {"int"}). */ @Override public AnnotatedPrimitiveType getUnboxedType(AnnotatedDeclaredType type) throws IllegalArgumentException { PrimitiveType primitiveType = types.unboxedType(type.getUnderlyingType()); - AnnotationMirror am = DataflowUtils.createDataflowAnnotation(primitiveType.toString(), - this.processingEnv); - AnnotatedPrimitiveType pt = (AnnotatedPrimitiveType) AnnotatedTypeMirror.createType( - primitiveType, this, false); + AnnotationMirror am = + DataflowUtils.createDataflowAnnotation( + primitiveType.toString(), this.processingEnv); + AnnotatedPrimitiveType pt = + (AnnotatedPrimitiveType) AnnotatedTypeMirror.createType(primitiveType, this, false); pt.addAnnotation(am); return pt; } @@ -123,17 +122,15 @@ private final class DataFlowQualifierHierarchy extends MostlyNoElementQualifierH private final QualifierKind DATAFLOW_KIND; public DataFlowQualifierHierarchy( - Collection> qualifierClasses, - Elements elements - ) { + Collection> qualifierClasses, Elements elements) { super(qualifierClasses, elements, DataflowAnnotatedTypeFactory.this); DATAFLOW_KIND = getQualifierKind(DATAFLOW); } /** - * This method checks whether rhs is subtype of lhs. rhs and lhs are - * both Dataflow types with typeNameRoots argument. - * + * This method checks whether rhs is subtype of lhs. rhs and lhs are both Dataflow types + * with typeNameRoots argument. + * * @param rhs * @param lhs * @return true is rhs is subtype of lhs, otherwise return false. @@ -151,8 +148,9 @@ private boolean isSubtypeWithRoots(AnnotationMirror rhs, AnnotationMirror lhs) { combinedRoots.addAll(rRootsSet); combinedRoots.addAll(lRootsSet); - AnnotationMirror combinedAnno = DataflowUtils.createDataflowAnnotationWithRoots( - combinedTypeNames, combinedRoots, processingEnv); + AnnotationMirror combinedAnno = + DataflowUtils.createDataflowAnnotationWithRoots( + combinedTypeNames, combinedRoots, processingEnv); AnnotationMirror refinedCombinedAnno = refineDataflow(combinedAnno); AnnotationMirror refinedLhs = refineDataflow(lhs); @@ -164,11 +162,10 @@ private boolean isSubtypeWithRoots(AnnotationMirror rhs, AnnotationMirror lhs) { } /** - * This method checks whether rhs is subtype of lhs. rhs and lhs are - * both Dataflow types without typeNameRoots argument. Currently this - * method is not used, but we can use it for a lightweight dataflow type - * system. (One without typeNameRoots argument). - * + * This method checks whether rhs is subtype of lhs. rhs and lhs are both Dataflow types + * without typeNameRoots argument. Currently this method is not used, but we can use it for + * a lightweight dataflow type system. (One without typeNameRoots argument). + * * @param rhs * @param lhs * @return true is rhs is subtype of lhs, otherwise return false. @@ -184,8 +181,7 @@ protected boolean isSubtypeWithElements( AnnotationMirror subAnno, QualifierKind subKind, AnnotationMirror superAnno, - QualifierKind superKind - ) { + QualifierKind superKind) { if (subKind == DATAFLOW_KIND && superKind == DATAFLOW_KIND) { return isSubtypeWithRoots(subAnno, superAnno); } @@ -199,8 +195,7 @@ protected AnnotationMirror leastUpperBoundWithElements( QualifierKind qualifierKind1, AnnotationMirror a2, QualifierKind qualifierKind2, - QualifierKind lubKind - ) { + QualifierKind lubKind) { if (qualifierKind1.isBottom()) { return a2; } else if (qualifierKind2.isBottom()) { @@ -225,8 +220,7 @@ protected AnnotationMirror greatestLowerBoundWithElements( QualifierKind qualifierKind1, AnnotationMirror a2, QualifierKind qualifierKind2, - QualifierKind glbKind - ) { + QualifierKind glbKind) { if (qualifierKind1.isTop()) { return a2; } else if (qualifierKind2.isTop()) { @@ -253,8 +247,8 @@ public DataflowTreeAnnotator() { @Override public Void visitNewArray(final NewArrayTree node, final AnnotatedTypeMirror type) { - AnnotationMirror dataFlowType = DataflowUtils.genereateDataflowAnnoFromNewClass(type, - processingEnv); + AnnotationMirror dataFlowType = + DataflowUtils.genereateDataflowAnnoFromNewClass(type, processingEnv); TypeMirror tm = type.getUnderlyingType(); typeNamesMap.put(tm.toString(), tm); type.replaceAnnotation(dataFlowType); @@ -263,8 +257,8 @@ public Void visitNewArray(final NewArrayTree node, final AnnotatedTypeMirror typ @Override public Void visitNewClass(NewClassTree node, AnnotatedTypeMirror type) { - AnnotationMirror dataFlowType = DataflowUtils.genereateDataflowAnnoFromNewClass(type, - processingEnv); + AnnotationMirror dataFlowType = + DataflowUtils.genereateDataflowAnnoFromNewClass(type, processingEnv); TypeMirror tm = type.getUnderlyingType(); typeNamesMap.put(tm.toString(), tm); type.replaceAnnotation(dataFlowType); @@ -275,8 +269,8 @@ public Void visitNewClass(NewClassTree node, AnnotatedTypeMirror type) { public Void visitLiteral(LiteralTree node, AnnotatedTypeMirror type) { if (!node.getKind().equals(Kind.NULL_LITERAL)) { AnnotatedTypeMirror annoType = type; - AnnotationMirror dataFlowType = DataflowUtils.generateDataflowAnnoFromLiteral(annoType, - processingEnv); + AnnotationMirror dataFlowType = + DataflowUtils.generateDataflowAnnoFromLiteral(annoType, processingEnv); type.replaceAnnotation(dataFlowType); } return super.visitLiteral(node, type); @@ -287,8 +281,8 @@ public Void visitMethodInvocation(MethodInvocationTree node, AnnotatedTypeMirror ExecutableElement methodElement = TreeUtils.elementFromUse(node); boolean isBytecode = ElementUtils.isElementFromByteCode(methodElement); if (isBytecode) { - AnnotationMirror dataFlowType = DataflowUtils.genereateDataflowAnnoFromByteCode(type, - processingEnv); + AnnotationMirror dataFlowType = + DataflowUtils.genereateDataflowAnnoFromByteCode(type, processingEnv); TypeMirror tm = type.getUnderlyingType(); if (tm.getKind() == TypeKind.ARRAY) { replaceArrayComponentATM((AnnotatedArrayType) type); @@ -299,10 +293,10 @@ public Void visitMethodInvocation(MethodInvocationTree node, AnnotatedTypeMirror return super.visitMethodInvocation(node, type); } } - + /** * Simplification algorithm. - * + * * @param type * @return A simplified annotation. */ @@ -342,21 +336,24 @@ public AnnotationMirror refineDataflow(AnnotationMirror type) { } } - return DataflowUtils.createDataflowAnnotationWithRoots(refinedtypeNames, refinedRoots, - processingEnv); + return DataflowUtils.createDataflowAnnotationWithRoots( + refinedtypeNames, refinedRoots, processingEnv); } /** - * Add the bytecode default Dataflow annotation for component type of the given {@link AnnotatedArrayType}. + * Add the bytecode default Dataflow annotation for component type of the given {@link + * AnnotatedArrayType}. * - *

For multi-dimensional array, this method will recursively add bytecode default Dataflow annotation to array's component type. + *

For multi-dimensional array, this method will recursively add bytecode default Dataflow + * annotation to array's component type. * - * @param arrayAtm the given {@link AnnotatedArrayType}, whose component type will be added the bytecode default. + * @param arrayAtm the given {@link AnnotatedArrayType}, whose component type will be added the + * bytecode default. */ private void replaceArrayComponentATM(AnnotatedArrayType arrayAtm) { AnnotatedTypeMirror componentAtm = arrayAtm.getComponentType(); - AnnotationMirror componentAnno = DataflowUtils.genereateDataflowAnnoFromByteCode(componentAtm, - processingEnv); + AnnotationMirror componentAnno = + DataflowUtils.genereateDataflowAnnoFromByteCode(componentAtm, processingEnv); componentAtm.replaceAnnotation(componentAnno); if (componentAtm.getKind() == TypeKind.ARRAY) { replaceArrayComponentATM((AnnotatedArrayType) componentAtm); @@ -406,24 +403,24 @@ private TypeMirror getTypeMirror(String typeName) { private String convertToReferenceType(String typeName) { switch (typeName) { - case "int": - return Integer.class.getName(); - case "short": - return Short.class.getName(); - case "byte": - return Byte.class.getName(); - case "long": - return Long.class.getName(); - case "char": - return Character.class.getName(); - case "float": - return Float.class.getName(); - case "double": - return Double.class.getName(); - case "boolean": - return Boolean.class.getName(); - default: - return typeName; + case "int": + return Integer.class.getName(); + case "short": + return Short.class.getName(); + case "byte": + return Byte.class.getName(); + case "long": + return Long.class.getName(); + case "char": + return Character.class.getName(); + case "float": + return Float.class.getName(); + case "double": + return Double.class.getName(); + case "boolean": + return Boolean.class.getName(); + default: + return typeName; } } diff --git a/src/dataflow/DataflowChecker.java b/src/dataflow/DataflowChecker.java index c98424101..9652e776c 100644 --- a/src/dataflow/DataflowChecker.java +++ b/src/dataflow/DataflowChecker.java @@ -1,11 +1,11 @@ package dataflow; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.util.Elements; - import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; import org.checkerframework.javacutil.AnnotationBuilder; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.util.Elements; + import checkers.inference.BaseInferrableChecker; import checkers.inference.InferenceChecker; import checkers.inference.InferrableChecker; @@ -16,9 +16,8 @@ /** * Checker for Dataflow type system. - * - * @author jianchu * + * @author jianchu */ public class DataflowChecker extends BaseInferrableChecker { public AnnotationMirror DATAFLOW, DATAFLOWTOP; @@ -36,8 +35,8 @@ protected void setAnnotations() { } @Override - public DataflowVisitor createVisitor(InferenceChecker ichecker, BaseAnnotatedTypeFactory factory, - boolean infer) { + public DataflowVisitor createVisitor( + InferenceChecker ichecker, BaseAnnotatedTypeFactory factory, boolean infer) { return new DataflowVisitor(this, ichecker, factory, infer); } @@ -47,12 +46,20 @@ public DataflowAnnotatedTypeFactory createRealTypeFactory(boolean infer) { } @Override - public DataflowInferenceAnnotatedTypeFactory createInferenceATF(InferenceChecker inferenceChecker, - InferrableChecker realChecker, BaseAnnotatedTypeFactory realTypeFactory, - SlotManager slotManager, ConstraintManager constraintManager) { - DataflowInferenceAnnotatedTypeFactory dataflowInferenceTypeFactory = new DataflowInferenceAnnotatedTypeFactory( - inferenceChecker, realChecker.withCombineConstraints(), realTypeFactory, realChecker, - slotManager, constraintManager); + public DataflowInferenceAnnotatedTypeFactory createInferenceATF( + InferenceChecker inferenceChecker, + InferrableChecker realChecker, + BaseAnnotatedTypeFactory realTypeFactory, + SlotManager slotManager, + ConstraintManager constraintManager) { + DataflowInferenceAnnotatedTypeFactory dataflowInferenceTypeFactory = + new DataflowInferenceAnnotatedTypeFactory( + inferenceChecker, + realChecker.withCombineConstraints(), + realTypeFactory, + realChecker, + slotManager, + constraintManager); return dataflowInferenceTypeFactory; } -} \ No newline at end of file +} diff --git a/src/dataflow/DataflowInferenceAnnotatedTypeFactory.java b/src/dataflow/DataflowInferenceAnnotatedTypeFactory.java index 4cf755f6e..c69a915d6 100644 --- a/src/dataflow/DataflowInferenceAnnotatedTypeFactory.java +++ b/src/dataflow/DataflowInferenceAnnotatedTypeFactory.java @@ -22,35 +22,44 @@ import dataflow.util.DataflowUtils; /** - * DataflowInferenceAnnotatedTypeFactory handles boxing and unboxing for - * primitive types. The Dataflow type should always same as declared type for - * both cases. - * - * @author jianchu + * DataflowInferenceAnnotatedTypeFactory handles boxing and unboxing for primitive types. The + * Dataflow type should always same as declared type for both cases. * + * @author jianchu */ public class DataflowInferenceAnnotatedTypeFactory extends InferenceAnnotatedTypeFactory { - public DataflowInferenceAnnotatedTypeFactory(InferenceChecker inferenceChecker, - boolean withCombineConstraints, BaseAnnotatedTypeFactory realTypeFactory, - InferrableChecker realChecker, SlotManager slotManager, ConstraintManager constraintManager) { - super(inferenceChecker, withCombineConstraints, realTypeFactory, realChecker, slotManager, + public DataflowInferenceAnnotatedTypeFactory( + InferenceChecker inferenceChecker, + boolean withCombineConstraints, + BaseAnnotatedTypeFactory realTypeFactory, + InferrableChecker realChecker, + SlotManager slotManager, + ConstraintManager constraintManager) { + super( + inferenceChecker, + withCombineConstraints, + realTypeFactory, + realChecker, + slotManager, constraintManager); postInit(); } @Override public TreeAnnotator createTreeAnnotator() { - return new ListTreeAnnotator(new LiteralTreeAnnotator(this), - new DataflowInferenceTreeAnnotator(this, realChecker, realTypeFactory, - variableAnnotator, slotManager)); + return new ListTreeAnnotator( + new LiteralTreeAnnotator(this), + new DataflowInferenceTreeAnnotator( + this, realChecker, realTypeFactory, variableAnnotator, slotManager)); } @Override public AnnotatedDeclaredType getBoxedType(AnnotatedPrimitiveType type) { TypeElement typeElt = types.boxedClass(type.getUnderlyingType()); - AnnotationMirror am = DataflowUtils.createDataflowAnnotation(typeElt.asType().toString(), - this.processingEnv); + AnnotationMirror am = + DataflowUtils.createDataflowAnnotation( + typeElt.asType().toString(), this.processingEnv); AnnotatedDeclaredType dt = fromElement(typeElt); ConstantSlot cs = InferenceMain.getInstance().getSlotManager().createConstantSlot(am); dt.addAnnotation(InferenceMain.getInstance().getSlotManager().getAnnotation(cs)); @@ -62,10 +71,11 @@ public AnnotatedDeclaredType getBoxedType(AnnotatedPrimitiveType type) { public AnnotatedPrimitiveType getUnboxedType(AnnotatedDeclaredType type) throws IllegalArgumentException { PrimitiveType primitiveType = types.unboxedType(type.getUnderlyingType()); - AnnotationMirror am = DataflowUtils.createDataflowAnnotation(primitiveType.toString(), - this.processingEnv); - AnnotatedPrimitiveType pt = (AnnotatedPrimitiveType) AnnotatedTypeMirror.createType( - primitiveType, this, false); + AnnotationMirror am = + DataflowUtils.createDataflowAnnotation( + primitiveType.toString(), this.processingEnv); + AnnotatedPrimitiveType pt = + (AnnotatedPrimitiveType) AnnotatedTypeMirror.createType(primitiveType, this, false); ConstantSlot cs = InferenceMain.getInstance().getSlotManager().createConstantSlot(am); pt.addAnnotation(InferenceMain.getInstance().getSlotManager().getAnnotation(cs)); pt.addAnnotation(cs.getValue()); diff --git a/src/dataflow/DataflowInferenceTreeAnnotator.java b/src/dataflow/DataflowInferenceTreeAnnotator.java index 407b15f83..c2300b697 100644 --- a/src/dataflow/DataflowInferenceTreeAnnotator.java +++ b/src/dataflow/DataflowInferenceTreeAnnotator.java @@ -1,5 +1,14 @@ package dataflow; +import com.sun.source.tree.LiteralTree; +import com.sun.source.tree.MethodInvocationTree; +import com.sun.source.tree.NewArrayTree; +import com.sun.source.tree.NewClassTree; +import com.sun.source.tree.ParameterizedTypeTree; +import com.sun.source.tree.Tree; +import com.sun.source.tree.Tree.Kind; +import com.sun.source.util.TreePath; + import org.checkerframework.framework.type.AnnotatedTypeFactory; import org.checkerframework.framework.type.AnnotatedTypeMirror; import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType; @@ -20,23 +29,12 @@ import checkers.inference.VariableAnnotator; import checkers.inference.model.ConstantSlot; import checkers.inference.qual.VarAnnot; - -import com.sun.source.tree.LiteralTree; -import com.sun.source.tree.MethodInvocationTree; -import com.sun.source.tree.NewArrayTree; -import com.sun.source.tree.NewClassTree; -import com.sun.source.tree.ParameterizedTypeTree; -import com.sun.source.tree.Tree; -import com.sun.source.tree.Tree.Kind; -import com.sun.source.util.TreePath; - import dataflow.util.DataflowUtils; /** * DataflowInferenceTreeAnnotator creates constant slot for base cases. - * - * @author jianchu * + * @author jianchu */ public class DataflowInferenceTreeAnnotator extends InferenceTreeAnnotator { @@ -44,9 +42,12 @@ public class DataflowInferenceTreeAnnotator extends InferenceTreeAnnotator { private final AnnotatedTypeFactory realTypeFactory; private final SlotManager slotManager; - public DataflowInferenceTreeAnnotator(InferenceAnnotatedTypeFactory atypeFactory, - InferrableChecker realChecker, AnnotatedTypeFactory realAnnotatedTypeFactory, - VariableAnnotator variableAnnotator, SlotManager slotManager) { + public DataflowInferenceTreeAnnotator( + InferenceAnnotatedTypeFactory atypeFactory, + InferrableChecker realChecker, + AnnotatedTypeFactory realAnnotatedTypeFactory, + VariableAnnotator variableAnnotator, + SlotManager slotManager) { super(atypeFactory, realChecker, realAnnotatedTypeFactory, variableAnnotator, slotManager); this.variableAnnotator = variableAnnotator; @@ -57,8 +58,9 @@ public DataflowInferenceTreeAnnotator(InferenceAnnotatedTypeFactory atypeFactory @Override public Void visitLiteral(final LiteralTree literalTree, final AnnotatedTypeMirror atm) { if (!literalTree.getKind().equals(Kind.NULL_LITERAL)) { - AnnotationMirror anno = DataflowUtils.generateDataflowAnnoFromLiteral(literalTree, - this.realTypeFactory.getProcessingEnv()); + AnnotationMirror anno = + DataflowUtils.generateDataflowAnnoFromLiteral( + literalTree, this.realTypeFactory.getProcessingEnv()); replaceATM(atm, anno); } else { super.visitLiteral(literalTree, atm); @@ -69,16 +71,20 @@ public Void visitLiteral(final LiteralTree literalTree, final AnnotatedTypeMirro @Override public Void visitNewClass(final NewClassTree newClassTree, final AnnotatedTypeMirror atm) { TypeMirror tm = atm.getUnderlyingType(); - ((DataflowAnnotatedTypeFactory) this.realTypeFactory).getTypeNameMap().put(tm.toString(), tm); - AnnotationMirror anno = DataflowUtils.genereateDataflowAnnoFromNewClass(atm, - this.realTypeFactory.getProcessingEnv()); + ((DataflowAnnotatedTypeFactory) this.realTypeFactory) + .getTypeNameMap() + .put(tm.toString(), tm); + AnnotationMirror anno = + DataflowUtils.genereateDataflowAnnoFromNewClass( + atm, this.realTypeFactory.getProcessingEnv()); replaceATM(atm, anno); variableAnnotator.visit(atm, newClassTree.getIdentifier()); return null; } @Override - public Void visitParameterizedType(final ParameterizedTypeTree param, final AnnotatedTypeMirror atm) { + public Void visitParameterizedType( + final ParameterizedTypeTree param, final AnnotatedTypeMirror atm) { TreePath path = atypeFactory.getPath(param); if (path != null) { final TreePath parentPath = path.getParentPath(); @@ -93,24 +99,29 @@ public Void visitParameterizedType(final ParameterizedTypeTree param, final Anno @Override public Void visitNewArray(final NewArrayTree newArrayTree, final AnnotatedTypeMirror atm) { TypeMirror tm = atm.getUnderlyingType(); - ((DataflowAnnotatedTypeFactory) this.realTypeFactory).getTypeNameMap().put(tm.toString(), tm); - AnnotationMirror anno = DataflowUtils.genereateDataflowAnnoFromNewClass(atm, - this.realTypeFactory.getProcessingEnv()); + ((DataflowAnnotatedTypeFactory) this.realTypeFactory) + .getTypeNameMap() + .put(tm.toString(), tm); + AnnotationMirror anno = + DataflowUtils.genereateDataflowAnnoFromNewClass( + atm, this.realTypeFactory.getProcessingEnv()); replaceATM(atm, anno); return null; } @Override - public Void visitMethodInvocation(MethodInvocationTree methodInvocationTree, - final AnnotatedTypeMirror atm) { + public Void visitMethodInvocation( + MethodInvocationTree methodInvocationTree, final AnnotatedTypeMirror atm) { ExecutableElement methodElement = TreeUtils.elementFromUse(methodInvocationTree); boolean isBytecode = ElementUtils.isElementFromByteCode(methodElement); if (isBytecode) { TypeMirror tm = atm.getUnderlyingType(); - ((DataflowAnnotatedTypeFactory) this.realTypeFactory).getTypeNameMap() + ((DataflowAnnotatedTypeFactory) this.realTypeFactory) + .getTypeNameMap() .put(tm.toString(), tm); - AnnotationMirror anno = DataflowUtils.genereateDataflowAnnoFromByteCode(atm, - this.realTypeFactory.getProcessingEnv()); + AnnotationMirror anno = + DataflowUtils.genereateDataflowAnnoFromByteCode( + atm, this.realTypeFactory.getProcessingEnv()); if (atm.getKind() == TypeKind.ARRAY) { // If the return type of a byte code method is Array type, @@ -128,29 +139,33 @@ public Void visitMethodInvocation(MethodInvocationTree methodInvocationTree, private void replaceATM(AnnotatedTypeMirror atm, AnnotationMirror dataflowAM) { final ConstantSlot cs = slotManager.createConstantSlot(dataflowAM); slotManager.createConstantSlot(dataflowAM); - AnnotationBuilder ab = new AnnotationBuilder(realTypeFactory.getProcessingEnv(), VarAnnot.class); + AnnotationBuilder ab = + new AnnotationBuilder(realTypeFactory.getProcessingEnv(), VarAnnot.class); ab.setValue("value", cs.getId()); AnnotationMirror varAnno = ab.build(); atm.replaceAnnotation(varAnno); } /** - * Add the bytecode default Dataflow annotation for component type of the given {@link AnnotatedArrayType}. + * Add the bytecode default Dataflow annotation for component type of the given {@link + * AnnotatedArrayType}. * - *

For multi-dimensional array, this method will recursively add bytecode default Dataflow annotation to array's component type. + *

For multi-dimensional array, this method will recursively add bytecode default Dataflow + * annotation to array's component type. * - * @param arrayAtm the given {@link AnnotatedArrayType}, whose component type will be added the bytecode default. + * @param arrayAtm the given {@link AnnotatedArrayType}, whose component type will be added the + * bytecode default. */ private void replaceArrayComponentATM(AnnotatedArrayType arrayAtm) { AnnotatedTypeMirror componentAtm = arrayAtm.getComponentType(); - AnnotationMirror componentAnno = DataflowUtils.genereateDataflowAnnoFromByteCode(componentAtm, - this.realTypeFactory.getProcessingEnv()); + AnnotationMirror componentAnno = + DataflowUtils.genereateDataflowAnnoFromByteCode( + componentAtm, this.realTypeFactory.getProcessingEnv()); replaceATM(componentAtm, componentAnno); if (componentAtm.getKind() == TypeKind.ARRAY) { - //if component is also an array type, then recursively annotate its component also. + // if component is also an array type, then recursively annotate its component also. replaceArrayComponentATM((AnnotatedArrayType) componentAtm); } } - } diff --git a/src/dataflow/DataflowVisitor.java b/src/dataflow/DataflowVisitor.java index 71f74f595..b486ff6b0 100644 --- a/src/dataflow/DataflowVisitor.java +++ b/src/dataflow/DataflowVisitor.java @@ -3,30 +3,31 @@ import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType; +import javax.lang.model.element.ExecutableElement; + import checkers.inference.InferenceChecker; import checkers.inference.InferenceVisitor; -import javax.lang.model.element.ExecutableElement; - /** * Don't generate any special constraint for Dataflow type system. - * - * @author jianchu * + * @author jianchu */ public class DataflowVisitor extends InferenceVisitor { - public DataflowVisitor(DataflowChecker checker, InferenceChecker ichecker, - BaseAnnotatedTypeFactory factory, boolean infer) { + public DataflowVisitor( + DataflowChecker checker, + InferenceChecker ichecker, + BaseAnnotatedTypeFactory factory, + boolean infer) { super(checker, ichecker, factory, infer); } /** - * Skip this test because a constructor always produces objects of that underlying type. - * TODO: validate constructor result appropriately. + * Skip this test because a constructor always produces objects of that underlying type. TODO: + * validate constructor result appropriately. */ @Override protected void checkConstructorResult( - AnnotatedExecutableType constructorType, ExecutableElement constructorElement) { - } + AnnotatedExecutableType constructorType, ExecutableElement constructorElement) {} } diff --git a/src/dataflow/qual/DataFlow.java b/src/dataflow/qual/DataFlow.java index 44f4b5e86..f307b76c5 100644 --- a/src/dataflow/qual/DataFlow.java +++ b/src/dataflow/qual/DataFlow.java @@ -7,10 +7,10 @@ import java.lang.annotation.Target; @Documented -@Target({ ElementType.TYPE_USE, ElementType.TYPE_PARAMETER }) -@SubtypeOf({ DataFlowTop.class }) +@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) +@SubtypeOf({DataFlowTop.class}) public @interface DataFlow { String[] typeNames() default {}; String[] typeNameRoots() default {}; -} \ No newline at end of file +} diff --git a/src/dataflow/qual/DataFlowInferenceBottom.java b/src/dataflow/qual/DataFlowInferenceBottom.java index 44a68f37f..a1aa56fad 100644 --- a/src/dataflow/qual/DataFlowInferenceBottom.java +++ b/src/dataflow/qual/DataFlowInferenceBottom.java @@ -10,13 +10,11 @@ /** * Annotation for inferring dataflow type system. - * @author jianchu * + * @author jianchu */ @InvisibleQualifier -@SubtypeOf({ DataFlow.class }) -@Target({ ElementType.TYPE_USE }) -@TargetLocations({ TypeUseLocation.ALL }) -public @interface DataFlowInferenceBottom { - -} +@SubtypeOf({DataFlow.class}) +@Target({ElementType.TYPE_USE}) +@TargetLocations({TypeUseLocation.ALL}) +public @interface DataFlowInferenceBottom {} diff --git a/src/dataflow/qual/DataFlowTop.java b/src/dataflow/qual/DataFlowTop.java index 20dc906f6..52908ef65 100644 --- a/src/dataflow/qual/DataFlowTop.java +++ b/src/dataflow/qual/DataFlowTop.java @@ -12,8 +12,6 @@ @DefaultQualifierInHierarchy @InvisibleQualifier @SubtypeOf({}) -@Target({ ElementType.TYPE_USE }) -@TargetLocations({ TypeUseLocation.ALL }) -public @interface DataFlowTop { - -} +@Target({ElementType.TYPE_USE}) +@TargetLocations({TypeUseLocation.ALL}) +public @interface DataFlowTop {} diff --git a/src/dataflow/solvers/classic/DataflowResult.java b/src/dataflow/solvers/classic/DataflowResult.java index 796a127d6..9d10eba43 100644 --- a/src/dataflow/solvers/classic/DataflowResult.java +++ b/src/dataflow/solvers/classic/DataflowResult.java @@ -22,13 +22,15 @@ public class DataflowResult extends DefaultInferenceResult { private final Map idToExistance; private final DataflowAnnotatedTypeFactory realTypeFactory; - public DataflowResult(Collection solutions, ProcessingEnvironment processingEnv) { + public DataflowResult( + Collection solutions, ProcessingEnvironment processingEnv) { // Legacy solver doesn't support explanation super(); this.typeNameResults = new HashMap<>(); this.typeRootResults = new HashMap<>(); this.idToExistance = new HashMap<>(); - this.realTypeFactory = (DataflowAnnotatedTypeFactory)InferenceMain.getInstance().getRealTypeFactory(); + this.realTypeFactory = + (DataflowAnnotatedTypeFactory) InferenceMain.getInstance().getRealTypeFactory(); mergeSolutions(solutions); createAnnotations(processingEnv); simplifyAnnotation(); @@ -79,7 +81,9 @@ private void createAnnotations(ProcessingEnvironment processingEnv) { Set roots = typeRootResults.get(slotId); AnnotationMirror anno; if (roots != null) { - anno = DataflowUtils.createDataflowAnnotationWithRoots(datatypes, typeRootResults.get(slotId), processingEnv); + anno = + DataflowUtils.createDataflowAnnotationWithRoots( + datatypes, typeRootResults.get(slotId), processingEnv); } else { anno = DataflowUtils.createDataflowAnnotation(datatypes, processingEnv); } @@ -91,16 +95,17 @@ private void createAnnotations(ProcessingEnvironment processingEnv) { Set roots = entry.getValue(); Set typeNames = typeNameResults.get(slotId); if (typeNames == null) { - AnnotationMirror anno = DataflowUtils.createDataflowAnnotationWithoutName(roots, processingEnv); + AnnotationMirror anno = + DataflowUtils.createDataflowAnnotationWithoutName(roots, processingEnv); varIdToAnnotation.put(slotId, anno); } } - } private void simplifyAnnotation() { for (Map.Entry entry : varIdToAnnotation.entrySet()) { - AnnotationMirror refinedDataflow = this.realTypeFactory.refineDataflow(entry.getValue()); + AnnotationMirror refinedDataflow = + this.realTypeFactory.refineDataflow(entry.getValue()); entry.setValue(refinedDataflow); } } @@ -112,7 +117,9 @@ private void mergeIdToExistance(DatatypeSolution solution) { if (idToExistance.containsKey(id)) { boolean alreadyExists = idToExistance.get(id); if (alreadyExists ^ existsDatatype) { - InferenceMain.getInstance().logger.log(Level.INFO, "Mismatch between existance of annotation"); + InferenceMain.getInstance() + .logger + .log(Level.INFO, "Mismatch between existance of annotation"); } } else { idToExistance.put(id, existsDatatype); @@ -127,5 +134,4 @@ private void mergeIdToExistance(DatatypeSolution solution) { public boolean containsSolutionForVariable(int varId) { return idToExistance.containsKey(varId); } - } diff --git a/src/dataflow/solvers/classic/DataflowSerializer.java b/src/dataflow/solvers/classic/DataflowSerializer.java index 3fa4603b9..7d8e1e8c5 100644 --- a/src/dataflow/solvers/classic/DataflowSerializer.java +++ b/src/dataflow/solvers/classic/DataflowSerializer.java @@ -1,16 +1,14 @@ package dataflow.solvers.classic; import org.checkerframework.javacutil.AnnotationUtils; +import org.sat4j.core.VecInt; -import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.lang.model.element.AnnotationMirror; -import org.sat4j.core.VecInt; - import checkers.inference.InferenceMain; import checkers.inference.model.ConstantSlot; import checkers.inference.model.Constraint; @@ -56,8 +54,7 @@ private boolean annoIsPresented(AnnotationMirror anno) { } @Override - public List convertAll(Iterable constraints, - List results) { + public List convertAll(Iterable constraints, List results) { for (Constraint constraint : constraints) { for (VecInt res : constraint.serialize(this)) { if (res.size() != 0) { diff --git a/src/dataflow/solvers/classic/DataflowSolver.java b/src/dataflow/solvers/classic/DataflowSolver.java index 85755a9a6..fdd0a8917 100644 --- a/src/dataflow/solvers/classic/DataflowSolver.java +++ b/src/dataflow/solvers/classic/DataflowSolver.java @@ -1,5 +1,9 @@ package dataflow.solvers.classic; +import org.checkerframework.framework.type.QualifierHierarchy; +import org.checkerframework.javacutil.AnnotationBuilder; +import org.checkerframework.javacutil.AnnotationUtils; + import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -15,11 +19,6 @@ import javax.lang.model.element.AnnotationMirror; import javax.lang.model.util.Elements; -import dataflow.qual.DataFlowTop; -import org.checkerframework.framework.type.QualifierHierarchy; -import org.checkerframework.javacutil.AnnotationUtils; -import org.checkerframework.javacutil.AnnotationBuilder; - import checkers.inference.InferenceResult; import checkers.inference.InferenceSolver; import checkers.inference.model.Constraint; @@ -28,13 +27,13 @@ import checkers.inference.solver.constraintgraph.GraphBuilder; import checkers.inference.solver.constraintgraph.Vertex; import dataflow.qual.DataFlow; +import dataflow.qual.DataFlowTop; import dataflow.util.DataflowUtils; /** * A solver for dataflow type system that is independent from GeneralSolver. * * @author jianchu - * */ public class DataflowSolver implements InferenceSolver { @@ -43,10 +42,12 @@ public class DataflowSolver implements InferenceSolver { protected DataflowUtils dataflowUtils; @Override - public InferenceResult solve(Map configuration, - Collection slots, Collection constraints, - QualifierHierarchy qualHierarchy, - ProcessingEnvironment processingEnvironment) { + public InferenceResult solve( + Map configuration, + Collection slots, + Collection constraints, + QualifierHierarchy qualHierarchy, + ProcessingEnvironment processingEnvironment) { Elements elements = processingEnvironment.getElementUtils(); DATAFLOW = AnnotationBuilder.fromClass(elements, DataFlow.class); @@ -58,24 +59,23 @@ public InferenceResult solve(Map configuration, List dataflowSolvers = new ArrayList<>(); // Configure datatype solvers - for (Map.Entry> entry : constraintGraph.getConstantPath().entrySet()) { + for (Map.Entry> entry : + constraintGraph.getConstantPath().entrySet()) { AnnotationMirror anno = entry.getKey().getValue(); if (AnnotationUtils.areSameByName(anno, DATAFLOW)) { List dataflowValues = dataflowUtils.getTypeNames(anno); List dataflowRoots = dataflowUtils.getTypeNameRoots(anno); if (dataflowValues.size() == 1) { String datatype = dataflowValues.get(0); - DatatypeSolver solver = new DatatypeSolver( - datatype, - entry.getValue(), - getSerializer(datatype, false)); + DatatypeSolver solver = + new DatatypeSolver( + datatype, entry.getValue(), getSerializer(datatype, false)); dataflowSolvers.add(solver); } else if (dataflowRoots.size() == 1) { String datatype = dataflowRoots.get(0); - DatatypeSolver solver = new DatatypeSolver( - datatype, - entry.getValue(), - getSerializer(datatype, true)); + DatatypeSolver solver = + new DatatypeSolver( + datatype, entry.getValue(), getSerializer(datatype, true)); dataflowSolvers.add(solver); } } @@ -100,12 +100,13 @@ private List solveInparallel(List dataflowSolv List> futures = new ArrayList>(); for (final DatatypeSolver solver : dataflowSolvers) { - Callable callable = new Callable() { - @Override - public DatatypeSolution call() throws Exception { - return solver.solve(); - } - }; + Callable callable = + new Callable() { + @Override + public DatatypeSolution call() throws Exception { + return solver.solve(); + } + }; futures.add(service.submit(callable)); } service.shutdown(); @@ -121,8 +122,8 @@ protected DataflowSerializer getSerializer(String datatype, boolean isRoot) { return new DataflowSerializer(datatype, isRoot, dataflowUtils); } - protected InferenceResult getMergedResultFromSolutions(ProcessingEnvironment processingEnvironment, - List solutions) { + protected InferenceResult getMergedResultFromSolutions( + ProcessingEnvironment processingEnvironment, List solutions) { return new DataflowResult(solutions, processingEnvironment); } } diff --git a/src/dataflow/solvers/classic/DatatypeSolution.java b/src/dataflow/solvers/classic/DatatypeSolution.java index 35922a0a7..707e2efa4 100644 --- a/src/dataflow/solvers/classic/DatatypeSolution.java +++ b/src/dataflow/solvers/classic/DatatypeSolution.java @@ -33,5 +33,4 @@ public static DatatypeSolution noSolution(String datatype) { public boolean isRoot() { return this.isRoot; } - } diff --git a/src/dataflow/solvers/classic/DatatypeSolver.java b/src/dataflow/solvers/classic/DatatypeSolver.java index 154843795..5bb32d088 100644 --- a/src/dataflow/solvers/classic/DatatypeSolver.java +++ b/src/dataflow/solvers/classic/DatatypeSolver.java @@ -1,5 +1,8 @@ package dataflow.solvers.classic; +import org.sat4j.core.VecInt; +import org.sat4j.maxsat.WeightedMaxSatDecorator; + import java.io.File; import java.io.PrintWriter; import java.util.Collection; @@ -7,9 +10,6 @@ import java.util.List; import java.util.Map; -import org.sat4j.core.VecInt; -import org.sat4j.maxsat.WeightedMaxSatDecorator; - import checkers.inference.InferenceMain; import checkers.inference.SlotManager; import checkers.inference.model.Constraint; @@ -20,7 +20,8 @@ public class DatatypeSolver { private final DataflowSerializer serializer; private final List clauses; - public DatatypeSolver(String datatype, Collection constraints, DataflowSerializer serializer) { + public DatatypeSolver( + String datatype, Collection constraints, DataflowSerializer serializer) { this.datatype = datatype; this.serializer = serializer; this.slotManager = InferenceMain.getInstance().getSlotManager(); @@ -66,31 +67,34 @@ public DatatypeSolution solve() { final int totalClauses = clauses.size(); try { - //**** Prep Solver **** - //org.sat4j.pb.SolverFactory.newBoth() Runs both of sat4j solves and uses the result of the first to finish + // **** Prep Solver **** + // org.sat4j.pb.SolverFactory.newBoth() Runs both of sat4j solves and uses the result of + // the first to finish // JLTODO: why is this a weighted max-sat solver? Isn't this only // creating sat constraints? - final WeightedMaxSatDecorator solver = new WeightedMaxSatDecorator(org.sat4j.pb.SolverFactory.newBoth()); + final WeightedMaxSatDecorator solver = + new WeightedMaxSatDecorator(org.sat4j.pb.SolverFactory.newBoth()); solver.newVar(totalVars); solver.setExpectedNumberOfClauses(totalClauses); - //Arbitrary timeout + // Arbitrary timeout solver.setTimeoutMs(1000000); for (VecInt clause : clauses) { solver.addSoftClause(clause); } - //**** Solve **** + // **** Solve **** boolean hasSolution = solver.isSatisfiable(); if (hasSolution) { // **** Remove exatential vars from solution - final Map existentialToPotentialIds = serializer.getExistentialToPotentialVar(); + final Map existentialToPotentialIds = + serializer.getExistentialToPotentialVar(); int[] solution = solver.model(); for (Integer var : solution) { boolean varIsTrue = var > 0; - //Need postive var + // Need postive var var = Math.abs(var); Integer potential = existentialToPotentialIds.get(var); if (potential == null) { diff --git a/src/dataflow/solvers/general/DataflowGraphSolvingStrategy.java b/src/dataflow/solvers/general/DataflowGraphSolvingStrategy.java index eb826e9e8..a51bd0fe9 100644 --- a/src/dataflow/solvers/general/DataflowGraphSolvingStrategy.java +++ b/src/dataflow/solvers/general/DataflowGraphSolvingStrategy.java @@ -1,5 +1,11 @@ package dataflow.solvers.general; +import com.sun.tools.javac.util.Pair; + +import org.checkerframework.javacutil.AnnotationBuilder; +import org.checkerframework.javacutil.AnnotationMirrorSet; +import org.checkerframework.javacutil.AnnotationUtils; + import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -12,11 +18,6 @@ import javax.lang.model.element.AnnotationMirror; import checkers.inference.DefaultInferenceResult; -import com.sun.tools.javac.util.Pair; -import org.checkerframework.javacutil.AnnotationBuilder; -import org.checkerframework.javacutil.AnnotationMirrorSet; -import org.checkerframework.javacutil.AnnotationUtils; - import checkers.inference.InferenceMain; import checkers.inference.InferenceResult; import checkers.inference.model.Constraint; @@ -24,19 +25,16 @@ import checkers.inference.solver.backend.Solver; import checkers.inference.solver.backend.SolverFactory; import checkers.inference.solver.constraintgraph.ConstraintGraph; -import checkers.inference.solver.constraintgraph.GraphBuilder; import checkers.inference.solver.constraintgraph.Vertex; import checkers.inference.solver.frontend.Lattice; import checkers.inference.solver.frontend.LatticeBuilder; import checkers.inference.solver.frontend.TwoQualifiersLattice; import checkers.inference.solver.strategy.GraphSolvingStrategy; -import checkers.inference.solver.util.PrintUtils; import checkers.inference.solver.util.SolverEnvironment; import checkers.inference.solver.util.Statistics; import dataflow.DataflowAnnotatedTypeFactory; import dataflow.qual.DataFlow; import dataflow.qual.DataFlowInferenceBottom; -import dataflow.qual.DataFlowTop; import dataflow.util.DataflowUtils; public class DataflowGraphSolvingStrategy extends GraphSolvingStrategy { @@ -52,38 +50,57 @@ public DataflowGraphSolvingStrategy(SolverFactory solverFactory) { } @Override - public InferenceResult solve(SolverEnvironment solverEnvironment, Collection slots, - Collection constraints, Lattice lattice) { + public InferenceResult solve( + SolverEnvironment solverEnvironment, + Collection slots, + Collection constraints, + Lattice lattice) { this.processingEnvironment = solverEnvironment.processingEnvironment; this.dataflowUtils = new DataflowUtils(this.processingEnvironment); return super.solve(solverEnvironment, slots, constraints, lattice); } @Override - protected List> separateGraph(SolverEnvironment solverEnvironment, ConstraintGraph constraintGraph, - Collection slots, Collection constraints, Lattice lattice) { - AnnotationMirror DATAFLOW = AnnotationBuilder.fromClass(processingEnvironment.getElementUtils(), DataFlow.class); - AnnotationMirror DATAFLOWBOTTOM = AnnotationBuilder.fromClass(processingEnvironment.getElementUtils(), - DataFlowInferenceBottom.class); + protected List> separateGraph( + SolverEnvironment solverEnvironment, + ConstraintGraph constraintGraph, + Collection slots, + Collection constraints, + Lattice lattice) { + AnnotationMirror DATAFLOW = + AnnotationBuilder.fromClass( + processingEnvironment.getElementUtils(), DataFlow.class); + AnnotationMirror DATAFLOWBOTTOM = + AnnotationBuilder.fromClass( + processingEnvironment.getElementUtils(), DataFlowInferenceBottom.class); List> solvers = new ArrayList<>(); Statistics.addOrIncrementEntry("graph_size", constraintGraph.getConstantPath().size()); - for (Map.Entry> entry : constraintGraph.getConstantPath().entrySet()) { + for (Map.Entry> entry : + constraintGraph.getConstantPath().entrySet()) { AnnotationMirror anno = entry.getKey().getValue(); if (AnnotationUtils.areSameByName(anno, DATAFLOW)) { List dataflowValues = dataflowUtils.getTypeNames(anno); List dataflowRoots = dataflowUtils.getTypeNameRoots(anno); if (dataflowValues.size() == 1) { - AnnotationMirror DATAFLOWTOP = DataflowUtils.createDataflowAnnotation( - dataflowValues.toArray(new String[0]), processingEnvironment); - TwoQualifiersLattice latticeFor2 = new LatticeBuilder().buildTwoTypeLattice(DATAFLOWTOP, DATAFLOWBOTTOM); - solvers.add(solverFactory.createSolver(solverEnvironment, slots, entry.getValue(), latticeFor2)); + AnnotationMirror DATAFLOWTOP = + DataflowUtils.createDataflowAnnotation( + dataflowValues.toArray(new String[0]), processingEnvironment); + TwoQualifiersLattice latticeFor2 = + new LatticeBuilder().buildTwoTypeLattice(DATAFLOWTOP, DATAFLOWBOTTOM); + solvers.add( + solverFactory.createSolver( + solverEnvironment, slots, entry.getValue(), latticeFor2)); } else if (dataflowRoots.size() == 1) { - AnnotationMirror DATAFLOWTOP = DataflowUtils.createDataflowAnnotationForByte( - dataflowRoots.toArray(new String[0]), processingEnvironment); - TwoQualifiersLattice latticeFor2 = new LatticeBuilder().buildTwoTypeLattice(DATAFLOWTOP, DATAFLOWBOTTOM); - solvers.add(solverFactory.createSolver(solverEnvironment, slots, entry.getValue(), latticeFor2)); + AnnotationMirror DATAFLOWTOP = + DataflowUtils.createDataflowAnnotationForByte( + dataflowRoots.toArray(new String[0]), processingEnvironment); + TwoQualifiersLattice latticeFor2 = + new LatticeBuilder().buildTwoTypeLattice(DATAFLOWTOP, DATAFLOWBOTTOM); + solvers.add( + solverFactory.createSolver( + solverEnvironment, slots, entry.getValue(), latticeFor2)); } } } @@ -92,11 +109,13 @@ protected List> separateGraph(SolverEnvironment solverEnvironment, Con } @Override - protected InferenceResult mergeInferenceResults(List, Collection>> inferenceResults) { + protected InferenceResult mergeInferenceResults( + List, Collection>> inferenceResults) { Map solutions = new HashMap<>(); Map> dataflowResults = new HashMap<>(); - for (Pair, Collection> inferenceResult : inferenceResults) { + for (Pair, Collection> inferenceResult : + inferenceResults) { Map inferenceSolutionMap = inferenceResult.fst; if (inferenceResult.fst != null) { for (Map.Entry entry : inferenceSolutionMap.entrySet()) { @@ -130,13 +149,16 @@ protected InferenceResult mergeInferenceResults(List entry : solutions.entrySet()) { - AnnotationMirror refinedDataflow = ((DataflowAnnotatedTypeFactory) InferenceMain - .getInstance().getRealTypeFactory()).refineDataflow(entry.getValue()); + AnnotationMirror refinedDataflow = + ((DataflowAnnotatedTypeFactory) + InferenceMain.getInstance().getRealTypeFactory()) + .refineDataflow(entry.getValue()); entry.setValue(refinedDataflow); } diff --git a/src/dataflow/solvers/general/DataflowSolverEngine.java b/src/dataflow/solvers/general/DataflowSolverEngine.java index 89fd99dd0..2adaa948e 100644 --- a/src/dataflow/solvers/general/DataflowSolverEngine.java +++ b/src/dataflow/solvers/general/DataflowSolverEngine.java @@ -8,11 +8,10 @@ import checkers.inference.solver.util.NameUtils; /** - * DataflowGeneralSolver is the solver for dataflow type system. It encode - * dataflow type hierarchy as two qualifiers type system. - * - * @author jianchu + * DataflowGeneralSolver is the solver for dataflow type system. It encode dataflow type hierarchy + * as two qualifiers type system. * + * @author jianchu */ public class DataflowSolverEngine extends SolverEngine { @@ -24,8 +23,13 @@ protected SolvingStrategy createSolvingStrategy(SolverFactory solverFactory) { @Override protected void sanitizeSolverEngineArgs() { if (!NameUtils.getStrategyName(GraphSolvingStrategy.class).equals(strategyName)) { - InferenceMain.getInstance().logger.warning("Dataflow type system must use graph solve strategy." - + "Change strategy from " + strategyName + " to graph."); + InferenceMain.getInstance() + .logger + .warning( + "Dataflow type system must use graph solve strategy." + + "Change strategy from " + + strategyName + + " to graph."); strategyName = NameUtils.getStrategyName(GraphSolvingStrategy.class); } } diff --git a/src/dataflow/util/DataflowUtils.java b/src/dataflow/util/DataflowUtils.java index 20b73b147..a887a4662 100644 --- a/src/dataflow/util/DataflowUtils.java +++ b/src/dataflow/util/DataflowUtils.java @@ -1,5 +1,13 @@ package dataflow.util; +import com.sun.source.tree.LiteralTree; + +import org.checkerframework.framework.type.AnnotatedTypeMirror; +import org.checkerframework.javacutil.AnnotationBuilder; +import org.checkerframework.javacutil.AnnotationUtils; +import org.checkerframework.javacutil.BugInCF; +import org.checkerframework.javacutil.TreeUtils; + import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -10,21 +18,12 @@ import javax.lang.model.element.ExecutableElement; import javax.lang.model.type.TypeMirror; -import org.checkerframework.framework.type.AnnotatedTypeMirror; -import org.checkerframework.javacutil.AnnotationBuilder; -import org.checkerframework.javacutil.AnnotationUtils; -import org.checkerframework.javacutil.BugInCF; -import org.checkerframework.javacutil.TreeUtils; - -import com.sun.source.tree.LiteralTree; - import dataflow.qual.DataFlow; /** * Utility class for Dataflow type system. - * - * @author jianchu * + * @author jianchu */ public class DataflowUtils { @@ -36,7 +35,8 @@ public class DataflowUtils { public DataflowUtils(ProcessingEnvironment processingEnv) { dataflowTypeNamesElement = TreeUtils.getMethod(DataFlow.class, "typeNames", processingEnv); - dataflowTypeNameRootsElement = TreeUtils.getMethod(DataFlow.class, "typeNameRoots", processingEnv); + dataflowTypeNameRootsElement = + TreeUtils.getMethod(DataFlow.class, "typeNameRoots", processingEnv); } public List getTypeNames(AnnotationMirror type) { @@ -49,15 +49,15 @@ public List getTypeNameRoots(AnnotationMirror type) { type, dataflowTypeNameRootsElement, String.class, Collections.emptyList()); } - public static AnnotationMirror createDataflowAnnotationForByte(String[] dataType, - ProcessingEnvironment processingEnv) { + public static AnnotationMirror createDataflowAnnotationForByte( + String[] dataType, ProcessingEnvironment processingEnv) { AnnotationBuilder builder = new AnnotationBuilder(processingEnv, DataFlow.class); builder.setValue("typeNameRoots", dataType); return builder.build(); } - private static AnnotationMirror createDataflowAnnotation(final Set datatypes, - final AnnotationBuilder builder) { + private static AnnotationMirror createDataflowAnnotation( + final Set datatypes, final AnnotationBuilder builder) { String[] datatypesInArray = new String[datatypes.size()]; int i = 0; for (String datatype : datatypes) { @@ -68,8 +68,8 @@ private static AnnotationMirror createDataflowAnnotation(final Set datat return builder.build(); } - private static AnnotationMirror createDataflowAnnotationWithoutName(final Set roots, - final AnnotationBuilder builder) { + private static AnnotationMirror createDataflowAnnotationWithoutName( + final Set roots, final AnnotationBuilder builder) { String[] datatypesInArray = new String[roots.size()]; int i = 0; for (String datatype : roots) { @@ -80,35 +80,38 @@ private static AnnotationMirror createDataflowAnnotationWithoutName(final Set datatypes, - ProcessingEnvironment processingEnv) { + public static AnnotationMirror createDataflowAnnotation( + Set datatypes, ProcessingEnvironment processingEnv) { AnnotationBuilder builder = new AnnotationBuilder(processingEnv, DataFlow.class); return createDataflowAnnotation(datatypes, builder); } - public static AnnotationMirror createDataflowAnnotationWithoutName(Set roots, - ProcessingEnvironment processingEnv) { + public static AnnotationMirror createDataflowAnnotationWithoutName( + Set roots, ProcessingEnvironment processingEnv) { AnnotationBuilder builder = new AnnotationBuilder(processingEnv, DataFlow.class); return createDataflowAnnotationWithoutName(roots, builder); - } - public static AnnotationMirror createDataflowAnnotation(String[] dataType, - ProcessingEnvironment processingEnv) { + public static AnnotationMirror createDataflowAnnotation( + String[] dataType, ProcessingEnvironment processingEnv) { AnnotationBuilder builder = new AnnotationBuilder(processingEnv, DataFlow.class); builder.setValue("typeNames", dataType); return builder.build(); } - public static AnnotationMirror createDataflowAnnotationWithRoots(Set datatypes, - Set datatypesRoots, ProcessingEnvironment processingEnv) { + public static AnnotationMirror createDataflowAnnotationWithRoots( + Set datatypes, + Set datatypesRoots, + ProcessingEnvironment processingEnv) { AnnotationBuilder builder = new AnnotationBuilder(processingEnv, DataFlow.class); return createDataflowAnnotationWithRoots(datatypes, datatypesRoots, builder); } - private static AnnotationMirror createDataflowAnnotationWithRoots(final Set datatypes, - final Set datatypesRoots, final AnnotationBuilder builder) { + private static AnnotationMirror createDataflowAnnotationWithRoots( + final Set datatypes, + final Set datatypesRoots, + final AnnotationBuilder builder) { String[] datatypesInArray = new String[datatypes.size()]; int i = 0; for (String datatype : datatypes) { @@ -132,60 +135,60 @@ private static AnnotationMirror createDataflowAnnotationWithRoots(final Set typeNames = new HashSet(); typeNames.add(typeName); AnnotationMirror am = DataflowUtils.createDataflowAnnotation(typeNames, processingEnv); diff --git a/src/hardcoded/HardcodedChecker.java b/src/hardcoded/HardcodedChecker.java index a446f99ef..37c6f6171 100644 --- a/src/hardcoded/HardcodedChecker.java +++ b/src/hardcoded/HardcodedChecker.java @@ -1,16 +1,15 @@ package hardcoded; +import com.sun.source.tree.LiteralTree; +import com.sun.source.tree.Tree; + import org.checkerframework.javacutil.AnnotationBuilder; import javax.lang.model.util.Elements; -import trusted.TrustedChecker; - -import com.sun.source.tree.LiteralTree; -import com.sun.source.tree.Tree; - import hardcoded.qual.MaybeHardcoded; import hardcoded.qual.NotHardcoded; +import trusted.TrustedChecker; public class HardcodedChecker extends TrustedChecker { @@ -21,9 +20,10 @@ public boolean isConstant(Tree node) { @Override protected void setAnnotations() { - final Elements elements = processingEnv.getElementUtils(); // TODO: Makes you think a utils is being returned + final Elements elements = + processingEnv.getElementUtils(); // TODO: Makes you think a utils is being returned UNTRUSTED = AnnotationBuilder.fromClass(elements, MaybeHardcoded.class); - TRUSTED = AnnotationBuilder.fromClass(elements, NotHardcoded.class); + TRUSTED = AnnotationBuilder.fromClass(elements, NotHardcoded.class); } -} \ No newline at end of file +} diff --git a/src/hardcoded/qual/MaybeHardcoded.java b/src/hardcoded/qual/MaybeHardcoded.java index 13cbf8e36..58e127cc2 100644 --- a/src/hardcoded/qual/MaybeHardcoded.java +++ b/src/hardcoded/qual/MaybeHardcoded.java @@ -1,7 +1,7 @@ package hardcoded.qual; -import org.checkerframework.framework.qual.DefaultQualifierInHierarchy; import org.checkerframework.framework.qual.DefaultFor; +import org.checkerframework.framework.qual.DefaultQualifierInHierarchy; import org.checkerframework.framework.qual.LiteralKind; import org.checkerframework.framework.qual.QualifierForLiterals; import org.checkerframework.framework.qual.SubtypeOf; @@ -13,30 +13,28 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -/** - * Represents data that may have been hardcoded. - */ +/** Represents data that may have been hardcoded. */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @SubtypeOf({}) @DefaultQualifierInHierarchy @QualifierForLiterals({ - LiteralKind.BOOLEAN, - LiteralKind.CHAR, - LiteralKind.DOUBLE, - LiteralKind.FLOAT, - LiteralKind.INT, - LiteralKind.LONG, - LiteralKind.STRING, - }) + LiteralKind.BOOLEAN, + LiteralKind.CHAR, + LiteralKind.DOUBLE, + LiteralKind.FLOAT, + LiteralKind.INT, + LiteralKind.LONG, + LiteralKind.STRING, +}) @DefaultFor( - typeKinds={ - TypeKind.BOOLEAN, - TypeKind.CHAR, - TypeKind.DOUBLE, - TypeKind.FLOAT, - TypeKind.INT, - TypeKind.LONG, + typeKinds = { + TypeKind.BOOLEAN, + TypeKind.CHAR, + TypeKind.DOUBLE, + TypeKind.FLOAT, + TypeKind.INT, + TypeKind.LONG, }) public @interface MaybeHardcoded {} diff --git a/src/hardcoded/qual/NotHardcoded.java b/src/hardcoded/qual/NotHardcoded.java index 84f49a1a2..2f8fa0cdc 100644 --- a/src/hardcoded/qual/NotHardcoded.java +++ b/src/hardcoded/qual/NotHardcoded.java @@ -24,5 +24,5 @@ @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @SubtypeOf({MaybeHardcoded.class}) @QualifierForLiterals(LiteralKind.NULL) -@DefaultFor(typeKinds={ TypeKind.NULL }) +@DefaultFor(typeKinds = {TypeKind.NULL}) public @interface NotHardcoded {} diff --git a/src/hardcoded/qual/PolyHardcoded.java b/src/hardcoded/qual/PolyHardcoded.java index 86ecf23d8..d91c89c96 100644 --- a/src/hardcoded/qual/PolyHardcoded.java +++ b/src/hardcoded/qual/PolyHardcoded.java @@ -9,12 +9,13 @@ import java.lang.annotation.Target; /** - * A Polymorphic qualifier for {@code Hardcoded}.

+ * A Polymorphic qualifier for {@code Hardcoded}. * - * See {@link + *

See {@link * http://types.cs.washington.edu/checker-framework/current/checkers-manual.html#qualifier-polymorphism} - * for information on the semantics of polymorphic qualifiers in the checker - * framework.

+ * for information on the semantics of polymorphic qualifiers in the checker framework. + * + *

* * @see NotHardcoded * @see MaybeHardcoded diff --git a/src/interning/InterningAnnotatedTypeFactory.java b/src/interning/InterningAnnotatedTypeFactory.java index 37dbff13f..cce30671b 100644 --- a/src/interning/InterningAnnotatedTypeFactory.java +++ b/src/interning/InterningAnnotatedTypeFactory.java @@ -1,10 +1,12 @@ package interning; -import checkers.inference.BaseInferenceRealTypeFactory; +import com.sun.source.tree.BinaryTree; +import com.sun.source.tree.CompoundAssignmentTree; +import com.sun.source.tree.Tree; + import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; import org.checkerframework.common.basetype.BaseTypeChecker; import org.checkerframework.framework.qual.DefaultQualifier; -import org.checkerframework.framework.qual.DefaultFor; import org.checkerframework.framework.type.AnnotatedTypeFactory; import org.checkerframework.framework.type.AnnotatedTypeMirror; import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType; @@ -17,38 +19,32 @@ import org.checkerframework.javacutil.ElementUtils; import org.checkerframework.javacutil.TreeUtils; -import interning.qual.Interned; -import interning.qual.PolyInterned; -import interning.qual.UnknownInterned; - import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.CompoundAssignmentTree; -import com.sun.source.tree.Tree; +import checkers.inference.BaseInferenceRealTypeFactory; +import interning.qual.Interned; +import interning.qual.PolyInterned; +import interning.qual.UnknownInterned; /** - * An {@link AnnotatedTypeFactory} that accounts for the properties of the - * Interned type system. This type factory will add the {@link Interned} - * annotation to a type if the input: + * An {@link AnnotatedTypeFactory} that accounts for the properties of the Interned type system. + * This type factory will add the {@link Interned} annotation to a type if the input: * *

    - *
  1. is a String literal - *
  2. is a class literal - *
  3. has an enum type - *
  4. has a primitive type - *
  5. has the type java.lang.Class - *
  6. is a use of a class declared to be @Interned
  7. + *
  8. is a String literal + *
  9. is a class literal + *
  10. has an enum type + *
  11. has a primitive type + *
  12. has the type java.lang.Class + *
  13. is a use of a class declared to be @Interned *
* - * This factory extends {@link BaseAnnotatedTypeFactory} and inherits its - * functionality, including: flow-sensitive qualifier inference, qualifier - * polymorphism (of {@link PolyInterned}), implicit annotations via - * {@link ImplicitFor} on {@link Interned} (to handle cases 1, 2, 4), and - * user-specified defaults via {@link DefaultQualifier}. - * Case 5 is handled by the stub library. + * This factory extends {@link BaseAnnotatedTypeFactory} and inherits its functionality, including: + * flow-sensitive qualifier inference, qualifier polymorphism (of {@link PolyInterned}), implicit + * annotations via {@link ImplicitFor} on {@link Interned} (to handle cases 1, 2, 4), and + * user-specified defaults via {@link DefaultQualifier}. Case 5 is handled by the stub library. */ public class InterningAnnotatedTypeFactory extends BaseInferenceRealTypeFactory { @@ -56,8 +52,7 @@ public class InterningAnnotatedTypeFactory extends BaseInferenceRealTypeFactory final AnnotationMirror INTERNED, TOP; /** - * Creates a new {@link InterningAnnotatedTypeFactory} that operates on a - * particular AST. + * Creates a new {@link InterningAnnotatedTypeFactory} that operates on a particular AST. * * @param checker the checker to use */ @@ -74,18 +69,12 @@ public InterningAnnotatedTypeFactory(BaseTypeChecker checker, boolean isInfer) { @Override protected TreeAnnotator createTreeAnnotator() { - return new ListTreeAnnotator( - super.createTreeAnnotator(), - new InterningTreeAnnotator(this) - ); + return new ListTreeAnnotator(super.createTreeAnnotator(), new InterningTreeAnnotator(this)); } @Override protected TypeAnnotator createTypeAnnotator() { - return new ListTypeAnnotator( - new InterningTypeAnnotator(this), - super.createTypeAnnotator() - ); + return new ListTypeAnnotator(new InterningTypeAnnotator(this), super.createTypeAnnotator()); } @Override @@ -95,10 +84,8 @@ public void addComputedTypeAnnotations(Element element, AnnotatedTypeMirror type super.addComputedTypeAnnotations(element, type); } - /** - * A class for adding annotations based on tree - */ - private class InterningTreeAnnotator extends TreeAnnotator { + /** A class for adding annotations based on tree */ + private class InterningTreeAnnotator extends TreeAnnotator { InterningTreeAnnotator(InterningAnnotatedTypeFactory atypeFactory) { super(atypeFactory); @@ -110,9 +97,9 @@ public Void visitBinary(BinaryTree node, AnnotatedTypeMirror type) { type.replaceAnnotation(INTERNED); } else if (TreeUtils.isStringConcatenation(node)) { type.replaceAnnotation(TOP); - } else if ((type.getKind().isPrimitive()) || - node.getKind() == Tree.Kind.EQUAL_TO || - node.getKind() == Tree.Kind.NOT_EQUAL_TO) { + } else if ((type.getKind().isPrimitive()) + || node.getKind() == Tree.Kind.EQUAL_TO + || node.getKind() == Tree.Kind.NOT_EQUAL_TO) { type.replaceAnnotation(INTERNED); } else { type.replaceAnnotation(TOP); @@ -124,14 +111,12 @@ public Void visitBinary(BinaryTree node, AnnotatedTypeMirror type) { */ @Override public Void visitCompoundAssignment(CompoundAssignmentTree node, AnnotatedTypeMirror type) { - type.replaceAnnotation(TOP); - return super.visitCompoundAssignment(node, type); + type.replaceAnnotation(TOP); + return super.visitCompoundAssignment(node, type); } } - /** - * Adds @Interned to enum types and any use of a class that is declared to be @Interned - */ + /** Adds @Interned to enum types and any use of a class that is declared to be @Interned */ private class InterningTypeAnnotator extends TypeAnnotator { InterningTypeAnnotator(InterningAnnotatedTypeFactory atypeFactory) { @@ -147,12 +132,14 @@ public Void visitDeclared(AnnotatedDeclaredType t, Void p) { if (elt.getKind() == ElementKind.ENUM) { t.replaceAnnotation(INTERNED); - // TODO: CODE REVIEW: - // TODO: I am not sure this makes sense. An element for a declared type doesn't always have - // TODO: to be a class declaration. AND I would assume if the class declaration has - // TODO: @Interned then the type would already receive an @Interned from the framework without - // TODO: this case (I think from InheritFromClass) - // TODO: IF this is true, perhaps remove item 6 I added to the class comment + // TODO: CODE REVIEW: + // TODO: I am not sure this makes sense. An element for a declared type doesn't + // always have + // TODO: to be a class declaration. AND I would assume if the class declaration has + // TODO: @Interned then the type would already receive an @Interned from the + // framework without + // TODO: this case (I think from InheritFromClass) + // TODO: IF this is true, perhaps remove item 6 I added to the class comment } else if (atypeFactory.fromElement(elt).hasAnnotation(INTERNED)) { // If the class/interface has an @Interned annotation, use it. t.replaceAnnotation(INTERNED); @@ -163,8 +150,8 @@ public Void visitDeclared(AnnotatedDeclaredType t, Void p) { } /** - * Unbox type and replace any interning type annotatiosn with @Interned since all - * all primitives can safely use ==. See case 4 in the class comments. + * Unbox type and replace any interning type annotatiosn with @Interned since all all primitives + * can safely use ==. See case 4 in the class comments. */ @Override public AnnotatedPrimitiveType getUnboxedType(AnnotatedDeclaredType type) { diff --git a/src/interning/InterningChecker.java b/src/interning/InterningChecker.java index 435121186..592a366ac 100644 --- a/src/interning/InterningChecker.java +++ b/src/interning/InterningChecker.java @@ -14,17 +14,13 @@ import interning.qual.Interned; /** - * A type-checker plug-in for the {@link Interned} qualifier that - * finds (and verifies the absence of) equality-testing and interning errors. + * A type-checker plug-in for the {@link Interned} qualifier that finds (and verifies the absence + * of) equality-testing and interning errors. * - *

- * - * The {@link Interned} annotation indicates that a variable - * refers to the canonical instance of an object, meaning that it is safe to - * compare that object using the "==" operator. This plugin warns whenever - * "==" is used in cases where one or both operands are not - * {@link Interned}. Optionally, it suggests using "==" - * instead of ".equals" where possible. + *

The {@link Interned} annotation indicates that a variable refers to the canonical instance of + * an object, meaning that it is safe to compare that object using the "==" operator. This plugin + * warns whenever "==" is used in cases where one or both operands are not {@link Interned}. + * Optionally, it suggests using "==" instead of ".equals" where possible. * * @checker_framework.manual #interning-checker Interning Checker */ @@ -43,7 +39,8 @@ public void initChecker() { } @Override - public InterningVisitor createVisitor(InferenceChecker ichecker, BaseAnnotatedTypeFactory factory, boolean infer) { + public InterningVisitor createVisitor( + InferenceChecker ichecker, BaseAnnotatedTypeFactory factory, boolean infer) { return new InterningVisitor(this, ichecker, factory, infer); } @@ -51,5 +48,4 @@ public InterningVisitor createVisitor(InferenceChecker ichecker, BaseAnnotatedTy public InterningAnnotatedTypeFactory createRealTypeFactory(boolean infer) { return new InterningAnnotatedTypeFactory(this, infer); } - } diff --git a/src/interning/InterningVisitor.java b/src/interning/InterningVisitor.java index c16014bee..023af4db8 100644 --- a/src/interning/InterningVisitor.java +++ b/src/interning/InterningVisitor.java @@ -1,5 +1,26 @@ package interning; +import com.sun.source.tree.BinaryTree; +import com.sun.source.tree.BlockTree; +import com.sun.source.tree.ClassTree; +import com.sun.source.tree.ConditionalExpressionTree; +import com.sun.source.tree.ExpressionTree; +import com.sun.source.tree.IdentifierTree; +import com.sun.source.tree.IfTree; +import com.sun.source.tree.LiteralTree; +import com.sun.source.tree.MemberSelectTree; +import com.sun.source.tree.MethodInvocationTree; +import com.sun.source.tree.MethodTree; +import com.sun.source.tree.NewClassTree; +import com.sun.source.tree.ReturnTree; +import com.sun.source.tree.Scope; +import com.sun.source.tree.StatementTree; +import com.sun.source.tree.Tree; +import com.sun.source.util.TreePath; +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCAnnotation; + import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; import org.checkerframework.common.basetype.BaseTypeVisitor; import org.checkerframework.framework.type.AnnotatedTypeMirror; @@ -22,54 +43,39 @@ import javax.lang.model.util.ElementFilter; import javax.tools.Diagnostic.Kind; -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.BlockTree; -import com.sun.source.tree.ClassTree; -import com.sun.source.tree.ConditionalExpressionTree; -import com.sun.source.tree.ExpressionTree; -import com.sun.source.tree.IdentifierTree; -import com.sun.source.tree.IfTree; -import com.sun.source.tree.LiteralTree; -import com.sun.source.tree.MemberSelectTree; -import com.sun.source.tree.MethodInvocationTree; -import com.sun.source.tree.MethodTree; -import com.sun.source.tree.NewClassTree; -import com.sun.source.tree.ReturnTree; -import com.sun.source.tree.Scope; -import com.sun.source.tree.StatementTree; -import com.sun.source.tree.Tree; -import com.sun.source.util.TreePath; -import com.sun.tools.javac.code.Type; -import com.sun.tools.javac.tree.JCTree; -import com.sun.tools.javac.tree.JCTree.JCAnnotation; - import checkers.inference.InferenceChecker; import checkers.inference.InferenceVisitor; import interning.qual.Interned; import interning.qual.UsesObjectEquals; /** - * Typechecks source code for interning violations. A type is considered interned - * if its primary annotation is {@link Interned}. - * This visitor reports errors or warnings for violations for the following cases: + * Typechecks source code for interning violations. A type is considered interned if its primary + * annotation is {@link Interned}. This visitor reports errors or warnings for violations for the + * following cases: * *

    - *
  1. either argument to a "==" or "!=" comparison is not Interned (error - * "not.interned") - *
  2. the receiver and argument for a call to an equals method are both - * Interned (optional warning "unnecessary.equals") + *
  3. either argument to a "==" or "!=" comparison is not Interned (error + * "not.interned") + *
  4. the receiver and argument for a call to an equals method are both Interned + * (optional warning "unnecessary.equals") *
* * @see BaseTypeVisitor */ -public final class InterningVisitor extends InferenceVisitor { +public final class InterningVisitor + extends InferenceVisitor { /** The interned annotation. */ private final AnnotationMirror INTERNED; + /** See method typeToCheck() */ private final DeclaredType typeToCheck; - public InterningVisitor(InterningChecker checker, InferenceChecker ichecker, BaseAnnotatedTypeFactory factory, boolean infer) { + public InterningVisitor( + InterningChecker checker, + InferenceChecker ichecker, + BaseAnnotatedTypeFactory factory, + boolean infer) { super(checker, ichecker, factory, infer); this.INTERNED = AnnotationBuilder.fromClass(elements, Interned.class); @@ -77,10 +83,10 @@ public InterningVisitor(InterningChecker checker, InferenceChecker ichecker, Bas } /** - * @return true if interning should be verified for the input expression. By default, all classes are checked - * for interning unless -Acheckclass is specified. - * {@see http://types.cs.washington.edu/checker-framework/current/checker-framework-manual.html#interning-checks}. - */ + * @return true if interning should be verified for the input expression. By default, all + * classes are checked for interning unless -Acheckclass is specified. {@see + * http://types.cs.washington.edu/checker-framework/current/checker-framework-manual.html#interning-checks}. + */ private boolean shouldCheckExpression(ExpressionTree tree) { if (typeToCheck == null) return true; @@ -98,29 +104,25 @@ public Void visitIdentifier(IdentifierTree node, Void p) { } @Override - protected void checkConstructorResult(AnnotatedExecutableType constructorType, - ExecutableElement constructorElement) { + protected void checkConstructorResult( + AnnotatedExecutableType constructorType, ExecutableElement constructorElement) { // TODO: This check causes a null slot to be created. } - /** - * Checks comparison operators, == and !=, for INTERNING violations. - */ + /** Checks comparison operators, == and !=, for INTERNING violations. */ @Override public Void visitBinary(BinaryTree node, Void p) { // No checking unless the operator is "==" or "!=". - if (!(node.getKind() == Tree.Kind.EQUAL_TO || - node.getKind() == Tree.Kind.NOT_EQUAL_TO)) + if (!(node.getKind() == Tree.Kind.EQUAL_TO || node.getKind() == Tree.Kind.NOT_EQUAL_TO)) return super.visitBinary(node, p); ExpressionTree leftOp = node.getLeftOperand(); ExpressionTree rightOp = node.getRightOperand(); // Check passes if either arg is null. - if (leftOp.getKind() == Tree.Kind.NULL_LITERAL || - rightOp.getKind() == Tree.Kind.NULL_LITERAL) - return super.visitBinary(node, p); + if (leftOp.getKind() == Tree.Kind.NULL_LITERAL + || rightOp.getKind() == Tree.Kind.NULL_LITERAL) return super.visitBinary(node, p); AnnotatedTypeMirror left = atypeFactory.getAnnotatedType(leftOp); AnnotatedTypeMirror right = atypeFactory.getAnnotatedType(rightOp); @@ -149,7 +151,8 @@ public Void visitBinary(BinaryTree node, Void p) { // in order to assume this). // Now suppose the user passes -AcheckClass=A on the command-line. - // I is not a subtype or supertype of A, so shouldCheckExpression will not return true for I. + // I is not a subtype or supertype of A, so shouldCheckExpression will not return true for + // I. // But the interning check must be performed, given the argument above. Therefore if // shouldCheckExpression returns true for either the LHS or the RHS, this method proceeds // with the interning check. @@ -158,12 +161,9 @@ public Void visitBinary(BinaryTree node, Void p) { return super.visitBinary(node, p); // Syntactic checks for legal uses of == - if (suppressInsideComparison(node)) - return super.visitBinary(node, p); - if (suppressEarlyEquals(node)) - return super.visitBinary(node, p); - if (suppressEarlyCompareTo(node)) - return super.visitBinary(node, p); + if (suppressInsideComparison(node)) return super.visitBinary(node, p); + if (suppressEarlyEquals(node)) return super.visitBinary(node, p); + if (suppressEarlyCompareTo(node)) return super.visitBinary(node, p); if (suppressEqualsIfClassIsAnnotated(left, right)) { return super.visitBinary(node, p); @@ -172,10 +172,10 @@ public Void visitBinary(BinaryTree node, Void p) { Element leftElt = null; Element rightElt = null; if (left instanceof AnnotatedTypeMirror.AnnotatedDeclaredType) { - leftElt = ((DeclaredType)left.getUnderlyingType()).asElement(); + leftElt = ((DeclaredType) left.getUnderlyingType()).asElement(); } if (right instanceof AnnotatedTypeMirror.AnnotatedDeclaredType) { - rightElt = ((DeclaredType)right.getUnderlyingType()).asElement(); + rightElt = ((DeclaredType) right.getUnderlyingType()).asElement(); } // TODO: CODE REVIEW @@ -193,8 +193,8 @@ public Void visitBinary(BinaryTree node, Void p) { } /** - * If lint option "dotequals" is specified, warn if the .equals method is used - * where reference equality is safe. + * If lint option "dotequals" is specified, warn if the .equals method is used where reference + * equality is safe. */ @Override public Void visitMethodInvocation(MethodInvocationTree node, Void p) { @@ -202,10 +202,10 @@ public Void visitMethodInvocation(MethodInvocationTree node, Void p) { AnnotatedTypeMirror recv = atypeFactory.getReceiverType(node); AnnotatedTypeMirror comp = atypeFactory.getAnnotatedType(node.getArguments().get(0)); - if (!infer && - this.checker.getLintOption("dotequals", true) - && recv.hasEffectiveAnnotation(INTERNED) - && comp.hasEffectiveAnnotation(INTERNED)) + if (!infer + && this.checker.getLintOption("dotequals", true) + && recv.hasEffectiveAnnotation(INTERNED) + && comp.hasEffectiveAnnotation(INTERNED)) checker.reportWarning(node, "unnecessary.equals"); } @@ -223,10 +223,14 @@ public Void visitNewClass(NewClassTree node, Void p) { JCTree at = jcann.getAnnotationType(); Type cl = at.type; if (realChecker.INTERNED.getAnnotationType().equals(cl)) { - // Forbid "new @Interned myClass()". You can add a @SuppressWarnings for this. We could add an - // option that would relax this rule and not forbid it if it's common enough. The point is to issue - // an error if we see thigns like "new @Interned String("foo")" which is obviously not interned. - // Don't enforce this rule, however, if the class is annotated with @Interned or the constructor. + // Forbid "new @Interned myClass()". You can add a @SuppressWarnings for this. + // We could add an + // option that would relax this rule and not forbid it if it's common enough. + // The point is to issue + // an error if we see thigns like "new @Interned String("foo")" which is + // obviously not interned. + // Don't enforce this rule, however, if the class is annotated with @Interned or + // the constructor. mainIsNot(type, realChecker.INTERNED, "not.interned", node); break; } @@ -237,18 +241,19 @@ public Void visitNewClass(NewClassTree node, Void p) { } /** - * Method to implement the @UsesObjectEquals functionality. - * If a class is annotated with @UsesObjectEquals, it must: - * - * -not override .equals(Object) - * -be a subclass of Object or another class annotated with @UsesObjectEquals + * Method to implement the @UsesObjectEquals functionality. If a class is annotated + * with @UsesObjectEquals, it must: * - * If a class is not annotated with @UsesObjectEquals, it must: + *

-not override .equals(Object) -be a subclass of Object or another class annotated + * with @UsesObjectEquals * - * -not have a superclass annotated with @UsesObjectEquals + *

If a class is not annotated with @UsesObjectEquals, it must: * + *

-not have a superclass annotated with @UsesObjectEquals * - * @see org.checkerframework.common.basetype.BaseTypeVisitor#visitClass(com.sun.source.tree.ClassTree, java.lang.Object) + * @see + * org.checkerframework.common.basetype.BaseTypeVisitor#visitClass(com.sun.source.tree.ClassTree, + * java.lang.Object) */ @Override public void processClassTree(ClassTree node) { @@ -268,8 +273,10 @@ public void processClassTree(ClassTree node) { Tree superClass = node.getExtendsClause(); Element elmt = null; - if (superClass != null && (superClass instanceof IdentifierTree || superClass instanceof MemberSelectTree)) { - elmt = TreeUtils.elementFromUse((ExpressionTree)superClass); + if (superClass != null + && (superClass instanceof IdentifierTree + || superClass instanceof MemberSelectTree)) { + elmt = TreeUtils.elementFromUse((ExpressionTree) superClass); } // If @UsesObjectEquals is present, check to make sure the class does not override equals @@ -280,15 +287,17 @@ public void processClassTree(ClassTree node) { checker.reportError(node, "overrides.equals"); } - - if (!(superClass == null || (elmt != null && elmt.getAnnotation(UsesObjectEquals.class) != null))) { + if (!(superClass == null + || (elmt != null && elmt.getAnnotation(UsesObjectEquals.class) != null))) { checker.reportError(node, "superclass.notannotated"); } } else { - // The class is not annotated with @UsesObjectEquals -> make sure its superclass isn't either. + // The class is not annotated with @UsesObjectEquals -> make sure its superclass isn't + // either. // TODO: is this impossible after the design change making @UsesObjectEquals inherited? // This check is left behind in case of a future design change back to non-inherited. - if (superClass != null && (elmt != null && elmt.getAnnotation(UsesObjectEquals.class) != null)) { + if (superClass != null + && (elmt != null && elmt.getAnnotation(UsesObjectEquals.class) != null)) { checker.reportError(node, "superclass.annotated"); } } @@ -300,9 +309,7 @@ public void processClassTree(ClassTree node) { // Helper methods // ********************************************************************** - /** - * Returns true if a class overrides Object.equals - */ + /** Returns true if a class overrides Object.equals */ private boolean overridesEquals(ClassTree node) { List members = node.getMembers(); for (Tree member : members) { @@ -318,14 +325,12 @@ private boolean overridesEquals(ClassTree node) { } /** - * Tests whether a method invocation is an invocation of - * {@link #equals} that overrides or hides {@link Object#equals(Object)}. - *

+ * Tests whether a method invocation is an invocation of {@link #equals} that overrides or hides + * {@link Object#equals(Object)}. * - * Returns true even if a method does not override {@link Object.equals}, - * because of the common idiom of writing an equals method with a non-Object - * parameter, in addition to the equals method that overrides - * {@link Object.equals}. + *

Returns true even if a method does not override {@link Object.equals}, because of the + * common idiom of writing an equals method with a non-Object parameter, in addition to the + * equals method that overrides {@link Object.equals}. * * @param node a method invocation node * @return true iff {@code node} is a invocation of {@code equals()} @@ -340,8 +345,8 @@ private boolean isInvocationOfEquals(MethodInvocationTree node) { } /** - * Tests whether a method invocation is an invocation of - * {@link Comparable#compareTo}. + * Tests whether a method invocation is an invocation of {@link Comparable#compareTo}. + * *

* * @param node a method invocation node @@ -356,43 +361,35 @@ private boolean isInvocationOfCompareTo(MethodInvocationTree node) { } /** - * Pattern matches particular comparisons to avoid common false positives - * in the {@link Comparable#compareTo(Object)} and - * {@link Object#equals(Object)}. - * - * Specifically, this method tests if: the comparison is a == comparison, - * it is the test of an if statement that's the first statement in the - * method, and one of the following is true: - *

    - *
  1. the method overrides {@link Comparator#compare}, the "then" branch - * of the if statement returns zero, and the comparison tests equality - * of the method's two parameters
  2. + * Pattern matches particular comparisons to avoid common false positives in the {@link + * Comparable#compareTo(Object)} and {@link Object#equals(Object)}. * - *
  3. the method overrides {@link Object#equals(Object)} and the - * comparison tests "this" against the method's parameter
  4. + *

    Specifically, this method tests if: the comparison is a == comparison, it is the test of + * an if statement that's the first statement in the method, and one of the following is true: * - *

  5. the method overrides {@link Comparable#compareTo(Object)}, the - * "then" branch of the if statement returns zero, and the comparison - * tests "this" against the method's parameter
  6. + *
      + *
    1. the method overrides {@link Comparator#compare}, the "then" branch of the if statement + * returns zero, and the comparison tests equality of the method's two parameters + *
    2. the method overrides {@link Object#equals(Object)} and the comparison tests "this" + * against the method's parameter + *
    3. the method overrides {@link Comparable#compareTo(Object)}, the "then" branch of the if + * statement returns zero, and the comparison tests "this" against the method's parameter *
    * * @param node the comparison to check - * @return true if one of the supported heuristics is matched, false - * otherwise + * @return true if one of the supported heuristics is matched, false otherwise */ // TODO: handle != comparisons too! // TODO: handle more methods, such as early return from addAll when this == arg private boolean suppressInsideComparison(final BinaryTree node) { // Only handle == binary trees - if (node.getKind() != Tree.Kind.EQUAL_TO) - return false; + if (node.getKind() != Tree.Kind.EQUAL_TO) return false; Tree left = node.getLeftOperand(); Tree right = node.getRightOperand(); // Only valid if we're comparing identifiers. - if (!(left.getKind() == Tree.Kind.IDENTIFIER - && right.getKind() == Tree.Kind.IDENTIFIER)) + if (!(left.getKind() == Tree.Kind.IDENTIFIER && right.getKind() == Tree.Kind.IDENTIFIER)) return false; // If we're not directly in an if statement in a method (ignoring @@ -418,11 +415,17 @@ private boolean suppressInsideComparison(final BinaryTree node) { parentPath = parentPath.getParentPath(); } - assert ifStatementTree != null; // The call to Heuristics.matchParents already ensured there is an enclosing if statement - assert methodTree != null; // The call to Heuristics.matchParents already ensured there is an enclosing method + assert ifStatementTree + != null; // The call to Heuristics.matchParents already ensured there is an + // enclosing if statement + assert methodTree + != null; // The call to Heuristics.matchParents already ensured there is an + // enclosing method StatementTree stmnt = methodTree.getBody().getStatements().get(0); - assert stmnt != null; // The call to Heuristics.matchParents already ensured the enclosing method has at least one statement (an if statement) in the body + assert stmnt + != null; // The call to Heuristics.matchParents already ensured the enclosing method + // has at least one statement (an if statement) in the body if (stmnt != ifStatementTree) { return false; // The if statement is not the first statement in the method. @@ -431,48 +434,47 @@ private boolean suppressInsideComparison(final BinaryTree node) { ExecutableElement enclosing = TreeUtils.elementFromDeclaration(methodTree); assert enclosing != null; - final Element lhs = TreeUtils.elementFromUse((IdentifierTree)left); - final Element rhs = TreeUtils.elementFromUse((IdentifierTree)right); + final Element lhs = TreeUtils.elementFromUse((IdentifierTree) left); + final Element rhs = TreeUtils.elementFromUse((IdentifierTree) right); // Matcher to check for if statement that returns zero - Heuristics.Matcher matcherIfReturnsZero = new Heuristics.Matcher() { + Heuristics.Matcher matcherIfReturnsZero = + new Heuristics.Matcher() { - @Override - public Boolean visitIf (IfTree tree, Void p) { - return visit(tree.getThenStatement(), p); - } + @Override + public Boolean visitIf(IfTree tree, Void p) { + return visit(tree.getThenStatement(), p); + } - @Override - public Boolean visitBlock(BlockTree tree, Void p) { - if (tree.getStatements().size() > 0) - return visit(tree.getStatements().get(0), p); - return false; - } + @Override + public Boolean visitBlock(BlockTree tree, Void p) { + if (tree.getStatements().size() > 0) + return visit(tree.getStatements().get(0), p); + return false; + } - @Override - public Boolean visitReturn(ReturnTree tree, Void p) { - ExpressionTree expr = tree.getExpression(); - return (expr != null && - expr.getKind() == Tree.Kind.INT_LITERAL && - ((LiteralTree)expr).getValue().equals(0)); - } - }; + @Override + public Boolean visitReturn(ReturnTree tree, Void p) { + ExpressionTree expr = tree.getExpression(); + return (expr != null + && expr.getKind() == Tree.Kind.INT_LITERAL + && ((LiteralTree) expr).getValue().equals(0)); + } + }; // Determine whether or not the "then" statement of the if has a single // "return 0" statement (for the Comparator.compare heuristic). if (overrides(enclosing, Comparator.class, "compare")) { final boolean returnsZero = - new Heuristics.Within( - new Heuristics.OfKind(Tree.Kind.IF, matcherIfReturnsZero)).match(getCurrentPath()); + new Heuristics.Within(new Heuristics.OfKind(Tree.Kind.IF, matcherIfReturnsZero)) + .match(getCurrentPath()); - if (!returnsZero) - return false; + if (!returnsZero) return false; assert enclosing.getParameters().size() == 2; Element p1 = enclosing.getParameters().get(0); Element p2 = enclosing.getParameters().get(1); - return (p1.equals(lhs) && p2.equals(rhs)) - || (p2.equals(lhs) && p1.equals(rhs)); + return (p1.equals(lhs) && p2.equals(rhs)) || (p2.equals(lhs) && p1.equals(rhs)); } else if (overrides(enclosing, Object.class, "equals")) { assert enclosing.getParameters().size() == 1; @@ -480,13 +482,13 @@ public Boolean visitReturn(ReturnTree tree, Void p) { Element thisElt = getThis(trees.getScope(getCurrentPath())); assert thisElt != null; return (thisElt.equals(lhs) && param.equals(rhs)) - || (param.equals(lhs) && thisElt.equals(rhs)); + || (param.equals(lhs) && thisElt.equals(rhs)); } else if (overrides(enclosing, Comparable.class, "compareTo")) { final boolean returnsZero = - new Heuristics.Within( - new Heuristics.OfKind(Tree.Kind.IF, matcherIfReturnsZero)).match(getCurrentPath()); + new Heuristics.Within(new Heuristics.OfKind(Tree.Kind.IF, matcherIfReturnsZero)) + .match(getCurrentPath()); if (!returnsZero) { return false; @@ -497,262 +499,274 @@ public Boolean visitReturn(ReturnTree tree, Void p) { Element thisElt = getThis(trees.getScope(getCurrentPath())); assert thisElt != null; return (thisElt.equals(lhs) && param.equals(rhs)) - || (param.equals(lhs) && thisElt.equals(rhs)); - + || (param.equals(lhs) && thisElt.equals(rhs)); } return false; } /** - * Returns true if two expressions originating from the same scope are identical, - * i.e. they are syntactically represented in the same way (modulo parentheses) and - * represent the same value. + * Returns true if two expressions originating from the same scope are identical, i.e. they are + * syntactically represented in the same way (modulo parentheses) and represent the same value. * - * For example, given an expression - * (a == b) || a.equals(b) - * sameTree can be called to determine that the first 'a' and second 'a' refer - * to the same variable, which is the case since both expressions 'a' originate from - * the same scope. + *

    For example, given an expression (a == b) || a.equals(b) sameTree can be called to + * determine that the first 'a' and second 'a' refer to the same variable, which is the case + * since both expressions 'a' originate from the same scope. * - * If the expression includes one or more method calls, assumes the method calls - * are deterministic. + *

    If the expression includes one or more method calls, assumes the method calls are + * deterministic. * * @param expr1 the first expression to compare - * @param expr2 the second expression to compare - expr2 must originate from the same scope as expr1 + * @param expr2 the second expression to compare - expr2 must originate from the same scope as + * expr1 * @return true if the expressions expr1 and expr2 are identical */ private static boolean sameTree(ExpressionTree expr1, ExpressionTree expr2) { - return TreeUtils.withoutParens(expr1).toString().equals(TreeUtils.withoutParens(expr2).toString()); + return TreeUtils.withoutParens(expr1) + .toString() + .equals(TreeUtils.withoutParens(expr2).toString()); } /** * Pattern matches to prevent false positives of the forms: + * *

          *   (a == b) || a.equals(b)
          *   (a == b) || (a != null ? a.equals(b) : false)
          *   (a == b) || (a != null && a.equals(b))
          * 
    + * * Returns true iff the given node fits this pattern. * * @return true iff the node fits a pattern such as (a == b || a.equals(b)) */ private boolean suppressEarlyEquals(final BinaryTree node) { // Only handle == binary trees - if (node.getKind() != Tree.Kind.EQUAL_TO) - return false; + if (node.getKind() != Tree.Kind.EQUAL_TO) return false; // should strip parens final ExpressionTree left = TreeUtils.withoutParens(node.getLeftOperand()); final ExpressionTree right = TreeUtils.withoutParens(node.getRightOperand()); // looking for ((a == b || a.equals(b)) - Heuristics.Matcher matcherEqOrEquals = new Heuristics.Matcher() { - - // Returns true if e is either "e1 != null" or "e2 != null" - private boolean isNeqNull(ExpressionTree e, ExpressionTree e1, ExpressionTree e2) { - e = TreeUtils.withoutParens(e); - if (e.getKind() != Tree.Kind.NOT_EQUAL_TO) { - return false; + Heuristics.Matcher matcherEqOrEquals = + new Heuristics.Matcher() { + + // Returns true if e is either "e1 != null" or "e2 != null" + private boolean isNeqNull( + ExpressionTree e, ExpressionTree e1, ExpressionTree e2) { + e = TreeUtils.withoutParens(e); + if (e.getKind() != Tree.Kind.NOT_EQUAL_TO) { + return false; + } + ExpressionTree neqLeft = ((BinaryTree) e).getLeftOperand(); + ExpressionTree neqRight = ((BinaryTree) e).getRightOperand(); + return (((sameTree(neqLeft, e1) || sameTree(neqLeft, e2)) + && neqRight.getKind() == Tree.Kind.NULL_LITERAL) + // also check for "null != e1" and "null != e2" + || ((sameTree(neqRight, e1) || sameTree(neqRight, e2)) + && neqLeft.getKind() == Tree.Kind.NULL_LITERAL)); } - ExpressionTree neqLeft = ((BinaryTree) e).getLeftOperand(); - ExpressionTree neqRight = ((BinaryTree) e).getRightOperand(); - return (((sameTree(neqLeft, e1) || sameTree(neqLeft, e2)) - && neqRight.getKind() == Tree.Kind.NULL_LITERAL) - // also check for "null != e1" and "null != e2" - || ((sameTree(neqRight, e1) || sameTree(neqRight, e2)) - && neqLeft.getKind() == Tree.Kind.NULL_LITERAL)); - } - @Override - public Boolean visitBinary(BinaryTree tree, Void p) { - ExpressionTree leftTree = tree.getLeftOperand(); - ExpressionTree rightTree = tree.getRightOperand(); + @Override + public Boolean visitBinary(BinaryTree tree, Void p) { + ExpressionTree leftTree = tree.getLeftOperand(); + ExpressionTree rightTree = tree.getRightOperand(); + + if (tree.getKind() == Tree.Kind.CONDITIONAL_OR) { + if (sameTree(leftTree, node)) { + // left is "a==b" + // check right, which should be a.equals(b) or b.equals(a) or + // similar + return visit(rightTree, p); + } else { + return false; + } + } - if (tree.getKind() == Tree.Kind.CONDITIONAL_OR) { - if (sameTree(leftTree, node)) { - // left is "a==b" - // check right, which should be a.equals(b) or b.equals(a) or similar - return visit(rightTree, p); - } else { + if (tree.getKind() == Tree.Kind.CONDITIONAL_AND) { + // looking for: (a != null && a.equals(b))) + if (isNeqNull(leftTree, left, right)) { + return visit(rightTree, p); + } return false; } + + return false; } - if (tree.getKind() == Tree.Kind.CONDITIONAL_AND) { - // looking for: (a != null && a.equals(b))) - if (isNeqNull(leftTree, left, right)) { - return visit(rightTree, p); + @Override + public Boolean visitConditionalExpression( + ConditionalExpressionTree tree, Void p) { + // looking for: (a != null ? a.equals(b) : false) + ExpressionTree cond = tree.getCondition(); + ExpressionTree trueExp = tree.getTrueExpression(); + ExpressionTree falseExp = tree.getFalseExpression(); + if (isNeqNull(cond, left, right) + && (falseExp.getKind() == Tree.Kind.BOOLEAN_LITERAL) + && ((LiteralTree) falseExp).getValue().equals(false)) { + return visit(trueExp, p); } return false; } - return false; - } - - @Override - public Boolean visitConditionalExpression(ConditionalExpressionTree tree, Void p) { - // looking for: (a != null ? a.equals(b) : false) - ExpressionTree cond = tree.getCondition(); - ExpressionTree trueExp = tree.getTrueExpression(); - ExpressionTree falseExp = tree.getFalseExpression(); - if (isNeqNull(cond, left, right) - && (falseExp.getKind() == Tree.Kind.BOOLEAN_LITERAL) - && ((LiteralTree) falseExp).getValue().equals(false)) { - return visit(trueExp, p); - } - return false; - } + @Override + public Boolean visitMethodInvocation(MethodInvocationTree tree, Void p) { + if (!isInvocationOfEquals(tree)) { + return false; + } - @Override - public Boolean visitMethodInvocation(MethodInvocationTree tree, Void p) { - if (!isInvocationOfEquals(tree)) { - return false; - } + List args = tree.getArguments(); + if (args.size() != 1) { + return false; + } + ExpressionTree arg = args.get(0); + // if (arg.getKind() != Tree.Kind.IDENTIFIER) { + // return false; + // } + // Element argElt = TreeUtils.elementFromUse((IdentifierTree) arg); + + ExpressionTree exp = tree.getMethodSelect(); + if (exp.getKind() != Tree.Kind.MEMBER_SELECT) { + return false; + } + MemberSelectTree member = (MemberSelectTree) exp; + ExpressionTree receiver = member.getExpression(); + // Element refElt = TreeUtils.elementFromUse(receiver); - List args = tree.getArguments(); - if (args.size() != 1) { - return false; - } - ExpressionTree arg = args.get(0); - // if (arg.getKind() != Tree.Kind.IDENTIFIER) { - // return false; - // } - // Element argElt = TreeUtils.elementFromUse((IdentifierTree) arg); - - ExpressionTree exp = tree.getMethodSelect(); - if (exp.getKind() != Tree.Kind.MEMBER_SELECT) { - return false; - } - MemberSelectTree member = (MemberSelectTree) exp; - ExpressionTree receiver = member.getExpression(); - // Element refElt = TreeUtils.elementFromUse(receiver); + // if (!((refElt.equals(lhs) && argElt.equals(rhs)) || + // ((refElt.equals(rhs) && argElt.equals(lhs))))) { + // return false; + // } - // if (!((refElt.equals(lhs) && argElt.equals(rhs)) || - // ((refElt.equals(rhs) && argElt.equals(lhs))))) { - // return false; - // } + if (sameTree(receiver, left) && sameTree(arg, right)) { + return true; + } + if (sameTree(receiver, right) && sameTree(arg, left)) { + return true; + } - if (sameTree(receiver, left) && sameTree(arg, right)) { - return true; - } - if (sameTree(receiver, right) && sameTree(arg, left)) { - return true; + return false; } + }; - return false; - } - }; - - boolean okay = new Heuristics.Within( - new Heuristics.OfKind(Tree.Kind.CONDITIONAL_OR, matcherEqOrEquals)).match(getCurrentPath()); + boolean okay = + new Heuristics.Within( + new Heuristics.OfKind(Tree.Kind.CONDITIONAL_OR, matcherEqOrEquals)) + .match(getCurrentPath()); return okay; } /** - * Pattern matches to prevent false positives of the form - * {@code (a == b || a.compareTo(b) == 0)}. Returns true iff - * the given node fits this pattern. + * Pattern matches to prevent false positives of the form {@code (a == b || a.compareTo(b) == + * 0)}. Returns true iff the given node fits this pattern. * * @return true iff the node fits the pattern (a == b || a.compareTo(b) == 0) */ private boolean suppressEarlyCompareTo(final BinaryTree node) { // Only handle == binary trees - if (node.getKind() != Tree.Kind.EQUAL_TO) - return false; + if (node.getKind() != Tree.Kind.EQUAL_TO) return false; Tree left = TreeUtils.withoutParens(node.getLeftOperand()); Tree right = TreeUtils.withoutParens(node.getRightOperand()); // Only valid if we're comparing identifiers. - if (!(left.getKind() == Tree.Kind.IDENTIFIER - && right.getKind() == Tree.Kind.IDENTIFIER)) { + if (!(left.getKind() == Tree.Kind.IDENTIFIER && right.getKind() == Tree.Kind.IDENTIFIER)) { return false; } - final Element lhs = TreeUtils.elementFromUse((IdentifierTree)left); - final Element rhs = TreeUtils.elementFromUse((IdentifierTree)right); + final Element lhs = TreeUtils.elementFromUse((IdentifierTree) left); + final Element rhs = TreeUtils.elementFromUse((IdentifierTree) right); // looking for ((a == b || a.compareTo(b) == 0) - Heuristics.Matcher matcherEqOrCompareTo = new Heuristics.Matcher() { + Heuristics.Matcher matcherEqOrCompareTo = + new Heuristics.Matcher() { + + @Override + public Boolean visitBinary(BinaryTree tree, Void p) { + if (tree.getKind() == Tree.Kind.EQUAL_TO) { // a.compareTo(b) == 0 + ExpressionTree leftTree = + tree.getLeftOperand(); // looking for a.compareTo(b) or + // b.compareTo(a) + ExpressionTree rightTree = tree.getRightOperand(); // looking for 0 + + if (rightTree.getKind() != Tree.Kind.INT_LITERAL) { + return false; + } + LiteralTree rightLiteral = (LiteralTree) rightTree; + if (!rightLiteral.getValue().equals(0)) { + return false; + } + + return visit(leftTree, p); + } else { + // a == b || a.compareTo(b) == 0 + ExpressionTree leftTree = tree.getLeftOperand(); // looking for a==b + ExpressionTree rightTree = + tree.getRightOperand(); // looking for a.compareTo(b) == 0 + // or b.compareTo(a) == 0 + if (leftTree != node) { + return false; + } + if (rightTree.getKind() != Tree.Kind.EQUAL_TO) { + return false; + } + return visit(rightTree, p); + } + } - @Override - public Boolean visitBinary(BinaryTree tree, Void p) { - if (tree.getKind() == Tree.Kind.EQUAL_TO) { // a.compareTo(b) == 0 - ExpressionTree leftTree = tree.getLeftOperand(); // looking for a.compareTo(b) or b.compareTo(a) - ExpressionTree rightTree = tree.getRightOperand(); // looking for 0 + @Override + public Boolean visitMethodInvocation(MethodInvocationTree tree, Void p) { + if (!isInvocationOfCompareTo(tree)) { + return false; + } - if (rightTree.getKind() != Tree.Kind.INT_LITERAL) { + List args = tree.getArguments(); + if (args.size() != 1) { return false; } - LiteralTree rightLiteral = (LiteralTree) rightTree; - if (!rightLiteral.getValue().equals(0)) { + ExpressionTree arg = args.get(0); + if (arg.getKind() != Tree.Kind.IDENTIFIER) { return false; } + Element argElt = TreeUtils.elementFromUse(arg); - return visit(leftTree, p); - } else { - // a == b || a.compareTo(b) == 0 - ExpressionTree leftTree = tree.getLeftOperand(); // looking for a==b - ExpressionTree rightTree = tree.getRightOperand(); // looking for a.compareTo(b) == 0 or b.compareTo(a) == 0 - if (leftTree != node) { + ExpressionTree exp = tree.getMethodSelect(); + if (exp.getKind() != Tree.Kind.MEMBER_SELECT) { return false; } - if (rightTree.getKind() != Tree.Kind.EQUAL_TO) { + MemberSelectTree member = (MemberSelectTree) exp; + if (member.getExpression().getKind() != Tree.Kind.IDENTIFIER) { return false; } - return visit(rightTree, p); - } - } - - @Override - public Boolean visitMethodInvocation(MethodInvocationTree tree, Void p) { - if (!isInvocationOfCompareTo(tree)) { - return false; - } - - List args = tree.getArguments(); - if (args.size() != 1) { - return false; - } - ExpressionTree arg = args.get(0); - if (arg.getKind() != Tree.Kind.IDENTIFIER) { - return false; - } - Element argElt = TreeUtils.elementFromUse(arg); - ExpressionTree exp = tree.getMethodSelect(); - if (exp.getKind() != Tree.Kind.MEMBER_SELECT) { - return false; - } - MemberSelectTree member = (MemberSelectTree) exp; - if (member.getExpression().getKind() != Tree.Kind.IDENTIFIER) { - return false; - } - - Element refElt = TreeUtils.elementFromUse(member.getExpression()); + Element refElt = TreeUtils.elementFromUse(member.getExpression()); - if (!((refElt.equals(lhs) && argElt.equals(rhs)) || - ((refElt.equals(rhs) && argElt.equals(lhs))))) { - return false; + if (!((refElt.equals(lhs) && argElt.equals(rhs)) + || ((refElt.equals(rhs) && argElt.equals(lhs))))) { + return false; + } + return true; } - return true; - } - }; + }; - boolean okay = new Heuristics.Within( - new Heuristics.OfKind(Tree.Kind.CONDITIONAL_OR, matcherEqOrCompareTo)).match(getCurrentPath()); + boolean okay = + new Heuristics.Within( + new Heuristics.OfKind( + Tree.Kind.CONDITIONAL_OR, matcherEqOrCompareTo)) + .match(getCurrentPath()); return okay; } /** - * Given a == b, where a has type A and b has type B, - * don't issue a warning when either the declaration of A or that of B - * is annotated with @Interned - * because a == b will be true only if a's run-time type is B (or - * lower), in which case a is actually interned. + * Given a == b, where a has type A and b has type B, don't issue a warning when + * either the declaration of A or that of B is annotated with @Interned because a == b + * will be true only if a's run-time type is B (or lower), in which case a is actually + * interned. + * *

    */ - private boolean suppressEqualsIfClassIsAnnotated(AnnotatedTypeMirror left, AnnotatedTypeMirror right) { + private boolean suppressEqualsIfClassIsAnnotated( + AnnotatedTypeMirror left, AnnotatedTypeMirror right) { // It would be better to just test their greatest lower bound. // That could permit some comparisons that this forbids. return classIsAnnotated(left) || classIsAnnotated(right); @@ -773,13 +787,19 @@ private boolean classIsAnnotated(AnnotatedTypeMirror type) { return false; } if (tm.getKind() != TypeKind.DECLARED) { - checker.message(Kind.WARNING, - "InterningVisitor.classIsAnnotated: tm = %s (%s)%n", tm, tm.getClass()); + checker.message( + Kind.WARNING, + "InterningVisitor.classIsAnnotated: tm = %s (%s)%n", + tm, + tm.getClass()); } Element classElt = ((DeclaredType) tm).asElement(); if (classElt == null) { - checker.message(Kind.WARNING, - "InterningVisitor.classIsAnnotated: classElt = null for tm = %s (%s)%n", tm, tm.getClass()); + checker.message( + Kind.WARNING, + "InterningVisitor.classIsAnnotated: classElt = null for tm = %s (%s)%n", + tm, + tm.getClass()); } if (classElt != null) { AnnotatedTypeMirror classType = atypeFactory.fromElement(classElt); @@ -793,31 +813,27 @@ private boolean classIsAnnotated(AnnotatedTypeMirror type) { return false; } - /** - * Determines the element corresponding to "this" inside a scope. Returns - * null within static methods. + * Determines the element corresponding to "this" inside a scope. Returns null within static + * methods. * * @param scope the scope to search for the element corresponding to "this" in - * @return the element corresponding to "this" in the given scope, or null - * if not found + * @return the element corresponding to "this" in the given scope, or null if not found */ private Element getThis(Scope scope) { for (Element e : scope.getLocalElements()) - if (e.getSimpleName().contentEquals("this")) - return e; + if (e.getSimpleName().contentEquals("this")) return e; return null; } /** - * Determines whether or not the given element overrides the named method in - * the named class. + * Determines whether or not the given element overrides the named method in the named class. * * @param e an element for a method * @param clazz the class * @param method the name of a method - * @return true if the method given by {@code e} overrides the named method - * in the named class; false otherwise + * @return true if the method given by {@code e} overrides the named method in the named class; + * false otherwise */ private boolean overrides(ExecutableElement e, Class clazz, String method) { @@ -827,22 +843,18 @@ private boolean overrides(ExecutableElement e, Class clazz, String method) { // Check all of the methods in the class for name matches and overriding. for (ExecutableElement elt : ElementFilter.methodsIn(clazzElt.getEnclosedElements())) - if (elt.getSimpleName().contentEquals(method) - && elements.overrides(e, elt, clazzElt)) + if (elt.getSimpleName().contentEquals(method) && elements.overrides(e, elt, clazzElt)) return true; return false; } - /** - * Returns the declared type of which the equality tests should be tested, - * if the user explicitly passed one. The user can pass the class name - * via the {@code -Acheckclass=...} option. - * - * If no class is specified, or the class specified isn't in the - * classpath, it returns null. + * Returns the declared type of which the equality tests should be tested, if the user + * explicitly passed one. The user can pass the class name via the {@code -Acheckclass=...} + * option. * + *

    If no class is specified, or the class specified isn't in the classpath, it returns null. */ DeclaredType typeToCheck() { String className = infer ? null : checker.getOption("checkclass"); diff --git a/src/interning/qual/Interned.java b/src/interning/qual/Interned.java index 75370269a..438772095 100644 --- a/src/interning/qual/Interned.java +++ b/src/interning/qual/Interned.java @@ -1,14 +1,11 @@ package interning.qual; -import org.checkerframework.framework.qual.TypeKind; import org.checkerframework.framework.qual.DefaultFor; import org.checkerframework.framework.qual.LiteralKind; import org.checkerframework.framework.qual.QualifierForLiterals; import org.checkerframework.framework.qual.SubtypeOf; +import org.checkerframework.framework.qual.TypeKind; import org.checkerframework.framework.qual.TypeUseLocation; -import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedPrimitiveType; - -import interning.InterningChecker; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; @@ -16,23 +13,22 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import com.sun.source.tree.LiteralTree; +import interning.InterningChecker; /** - * Indicates that a variable has been interned, i.e., that the variable refers - * to the canonical representation of an object. - *

    + * Indicates that a variable has been interned, i.e., that the variable refers to the canonical + * representation of an object. + * + *

    To specify that all objects of a given type are interned, annotate the class declaration: * - * To specify that all objects of a given type are interned, annotate the class declaration: *

      *   public @Interned class MyInternedClass { ... }
      * 
    - * This is equivalent to annotating every use of MyInternedClass, in a - * declaration or elsewhere. For example, enum classes are implicitly so - * annotated. - *

    * - * This annotation is associated with the {@link InterningChecker}. + * This is equivalent to annotating every use of MyInternedClass, in a declaration or elsewhere. For + * example, enum classes are implicitly so annotated. + * + *

    This annotation is associated with the {@link InterningChecker}. * * @see InterningChecker * @checker_framework.manual #interning-checker Interning Checker @@ -40,9 +36,16 @@ @SubtypeOf(UnknownInterned.class) @QualifierForLiterals(LiteralKind.ALL) @DefaultFor( - typeKinds = {TypeKind.BOOLEAN, TypeKind.BYTE, TypeKind.CHAR, TypeKind.DOUBLE, - TypeKind.FLOAT, TypeKind.INT, TypeKind.LONG - }, value = {TypeUseLocation.LOWER_BOUND}) + typeKinds = { + TypeKind.BOOLEAN, + TypeKind.BYTE, + TypeKind.CHAR, + TypeKind.DOUBLE, + TypeKind.FLOAT, + TypeKind.INT, + TypeKind.LONG + }, + value = {TypeUseLocation.LOWER_BOUND}) @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) diff --git a/src/interning/qual/PolyInterned.java b/src/interning/qual/PolyInterned.java index 71736748e..cc0847c19 100644 --- a/src/interning/qual/PolyInterned.java +++ b/src/interning/qual/PolyInterned.java @@ -1,20 +1,19 @@ package interning.qual; +import org.checkerframework.framework.qual.PolymorphicQualifier; + import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import org.checkerframework.framework.qual.PolymorphicQualifier; - /** * A polymorphic qualifier for the Interning type system. * - *

    - * Any method written using @PolyInterned conceptually has two versions: one - * in which every instance of @PolyInterned has been replaced by @Interned, and - * one in which every instance of @PolyInterned has been erased. + *

    Any method written using @PolyInterned conceptually has two versions: one in which every + * instance of @PolyInterned has been replaced by @Interned, and one in which every instance + * of @PolyInterned has been erased. * * @checker_framework.manual #interning-checker Interning Checker */ diff --git a/src/interning/qual/UnknownInterned.java b/src/interning/qual/UnknownInterned.java index 7e570dfe3..7928ba610 100644 --- a/src/interning/qual/UnknownInterned.java +++ b/src/interning/qual/UnknownInterned.java @@ -1,5 +1,9 @@ package interning.qual; +import org.checkerframework.framework.qual.DefaultQualifierInHierarchy; +import org.checkerframework.framework.qual.InvisibleQualifier; +import org.checkerframework.framework.qual.SubtypeOf; + import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -7,16 +11,11 @@ import java.lang.annotation.Target; import interning.InterningChecker; -import org.checkerframework.framework.qual.DefaultQualifierInHierarchy; -import org.checkerframework.framework.qual.InvisibleQualifier; -import org.checkerframework.framework.qual.SubtypeOf; /** * The top qualifier for the Interning Checker. * - *

    - * - * This annotation is associated with the {@link InterningChecker}. + *

    This annotation is associated with the {@link InterningChecker}. * * @see InterningChecker * @checker_framework.manual #interning-checker Interning Checker diff --git a/src/interning/qual/UsesObjectEquals.java b/src/interning/qual/UsesObjectEquals.java index 8eb891f1b..cf7eeb6d3 100644 --- a/src/interning/qual/UsesObjectEquals.java +++ b/src/interning/qual/UsesObjectEquals.java @@ -10,23 +10,18 @@ import interning.InterningChecker; /** - * Class declaration to indicate the class does not override - * equals(Object), and therefore a.equals(b) and a == - * b behave identically. - *

    + * Class declaration to indicate the class does not override equals(Object), and therefore + * a.equals(b) and a == b behave identically. * - * A class may be annotated @UsesObjectEquals if neither it, nor any of its - * supertypes or subtypes, overrides equals. Therefore, it cannot - * be written on Object itself. It is - * most commonly written on a direct subclass of Object. - *

    + *

    A class may be annotated @UsesObjectEquals if neither it, nor any of its supertypes or + * subtypes, overrides equals. Therefore, it cannot be written on Object itself. + * It is most commonly written on a direct subclass of Object. * - * This annotation is associated with the {@link InterningChecker}. + *

    This annotation is associated with the {@link InterningChecker}. * * @see InterningChecker * @checker_framework.manual #interning-checker Interning Checker */ - @Documented @Inherited @Target(ElementType.TYPE) diff --git a/src/nninf/GameAnnotatedTypeFactory.java b/src/nninf/GameAnnotatedTypeFactory.java index 8bc6dc715..0d782a641 100644 --- a/src/nninf/GameAnnotatedTypeFactory.java +++ b/src/nninf/GameAnnotatedTypeFactory.java @@ -1,14 +1,13 @@ package nninf; -import checkers.inference.BaseInferenceRealTypeFactory; -import com.sun.source.tree.ClassTree; -import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; import org.checkerframework.common.basetype.BaseTypeChecker; import org.checkerframework.framework.flow.CFAbstractAnalysis; import org.checkerframework.framework.flow.CFStore; import org.checkerframework.framework.flow.CFTransfer; import org.checkerframework.framework.flow.CFValue; +import checkers.inference.BaseInferenceRealTypeFactory; + public class GameAnnotatedTypeFactory extends BaseInferenceRealTypeFactory { public GameAnnotatedTypeFactory(BaseTypeChecker checker, boolean isInfer) { @@ -18,27 +17,29 @@ public GameAnnotatedTypeFactory(BaseTypeChecker checker, boolean isInfer) { postInit(); } } -// -// @Override -// protected TypeHierarchy createTypeHierarchy() { -// return new TypeHierarchy(checker, getQualifierHierarchy()) { -// @Override -// public boolean isSubtype(AnnotatedTypeMirror sub, AnnotatedTypeMirror sup) { -// -// if (sub.getEffectiveAnnotations().isEmpty() || -// sup.getEffectiveAnnotations().isEmpty()) { -// // TODO: The super method complains about empty annotations. Prevent this. -// // TODO: Can we avoid getting into the state with empty annotations? -// assert false; -// return true; -// } -// return super.isSubtype(sub, sup); -// } -// }; -// } + + // + // @Override + // protected TypeHierarchy createTypeHierarchy() { + // return new TypeHierarchy(checker, getQualifierHierarchy()) { + // @Override + // public boolean isSubtype(AnnotatedTypeMirror sub, AnnotatedTypeMirror sup) { + // + // if (sub.getEffectiveAnnotations().isEmpty() || + // sup.getEffectiveAnnotations().isEmpty()) { + // // TODO: The super method complains about empty annotations. Prevent this. + // // TODO: Can we avoid getting into the state with empty annotations? + // assert false; + // return true; + // } + // return super.isSubtype(sub, sup); + // } + // }; + // } @Override - public CFTransfer createFlowTransferFunction(CFAbstractAnalysis analysis) { + public CFTransfer createFlowTransferFunction( + CFAbstractAnalysis analysis) { return new CFTransfer(analysis); } } diff --git a/src/nninf/MapGetHeuristics.java b/src/nninf/MapGetHeuristics.java index b85a6987b..e95213858 100644 --- a/src/nninf/MapGetHeuristics.java +++ b/src/nninf/MapGetHeuristics.java @@ -1,11 +1,16 @@ package nninf; +import com.sun.source.tree.BinaryTree; +import com.sun.source.tree.ExpressionTree; +import com.sun.source.tree.MethodInvocationTree; +import com.sun.source.tree.Tree; +import com.sun.source.util.TreePath; + import org.checkerframework.framework.type.AnnotatedTypeFactory; import org.checkerframework.framework.type.AnnotatedTypeMirror; import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType; import org.checkerframework.javacutil.AnnotationUtils; import org.checkerframework.javacutil.ElementUtils; -import org.checkerframework.javacutil.Resolver; import org.checkerframework.javacutil.TreeUtils; import java.util.List; @@ -16,49 +21,32 @@ import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.VariableElement; -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.ExpressionTree; -import com.sun.source.tree.MethodInvocationTree; -import com.sun.source.tree.Tree; -import com.sun.source.util.TreePath; - import nninf.qual.KeyFor; /** * Utilities class for handling {@code Map.get()} invocations. * - * The heuristics cover the following cases: + *

    The heuristics cover the following cases: * *

      - *
    1. Within the true condition of a map.containsKey() if statement: - *
      if (map.containsKey(key)) { Object v = map.get(key); }
      - *
    2. - * - *
    3. Within an enhanced-for loop of the map.keySet(): - *
      for (Object key: map.keySet()) { Object v = map.get(key); }
      - *
    4. - * - *
    5. Preceded by an assertion of contains or nullness get check: - *
      assert map.containsKey(key);
      + *   
    6. Within the true condition of a map.containsKey() if statement: + *
      if (map.containsKey(key)) { Object v = map.get(key); }
      + *
    7. Within an enhanced-for loop of the map.keySet(): + *
      for (Object key: map.keySet()) { Object v = map.get(key); }
      + *
    8. Preceded by an assertion of contains or nullness get check: + *
      assert map.containsKey(key);
        * Object v = map.get(key);
      - * - * Or - * - *
      assert map.get(key) != null;
      + *       Or
      + *       
      assert map.get(key) != null;
        * Object v = map.get(key);
      - * - *
    9. Preceded by an check of contains or nullness if - * test that throws an exception, in the first line: - * - *
      if (!map.contains(key)) throw new Exception();
      + *   
    10. Preceded by an check of contains or nullness if test that throws an exception, in + * the first line: + *
      if (!map.contains(key)) throw new Exception();
        * Object v = map.get(key);
        * 
      - * - *
    11. Preceded by a put-if-absent pattern convention: - * - *
      if (!map.contains(key)) map.put(key, DEFAULT_VALUE);
      + *   
    12. Preceded by a put-if-absent pattern convention: + *
      if (!map.contains(key)) map.put(key, DEFAULT_VALUE);
        * Object v = map.get(key);
      - * *
    */ /*package-scope*/ class MapGetHeuristics { @@ -69,7 +57,8 @@ private final ExecutableElement mapGet; - public MapGetHeuristics(ProcessingEnvironment env, + public MapGetHeuristics( + ProcessingEnvironment env, NninfAnnotatedTypeFactory factory, AnnotatedTypeFactory keyForFactory) { this.env = env; @@ -80,7 +69,7 @@ public MapGetHeuristics(ProcessingEnvironment env, } public void handle(TreePath path, AnnotatedExecutableType method) { - MethodInvocationTree tree = (MethodInvocationTree)path.getLeaf(); + MethodInvocationTree tree = (MethodInvocationTree) path.getLeaf(); if (TreeUtils.isMethodInvocation(tree, mapGet, env)) { AnnotatedTypeMirror type = method.getReturnType(); type.removeAnnotationInHierarchy(factory.checker.NULLABLE); @@ -93,56 +82,54 @@ public void handle(TreePath path, AnnotatedExecutableType method) { } /** - * Checks whether the key passed to {@code Map.get(K key)} is known - * to be in the map. + * Checks whether the key passed to {@code Map.get(K key)} is known to be in the map. * - * TODO: Document when this method returns true + *

    TODO: Document when this method returns true */ private boolean isSuppressable(TreePath path) { - MethodInvocationTree tree = (MethodInvocationTree)path.getLeaf(); + MethodInvocationTree tree = (MethodInvocationTree) path.getLeaf(); Element elt = getSite(tree); if (elt instanceof VariableElement) { ExpressionTree arg = tree.getArguments().get(0); return keyForInMap(arg, elt, path) - || keyForInMap(arg, ((VariableElement)elt).getSimpleName().toString()) - || keyForInMap(arg, String.valueOf(TreeUtils.getReceiverTree(tree))); + || keyForInMap(arg, ((VariableElement) elt).getSimpleName().toString()) + || keyForInMap(arg, String.valueOf(TreeUtils.getReceiverTree(tree))); } return false; } - /** - * Returns true if the key is a member of the specified map - */ - private boolean keyForInMap(ExpressionTree key, - String mapName) { + /** Returns true if the key is a member of the specified map */ + private boolean keyForInMap(ExpressionTree key, String mapName) { AnnotatedTypeMirror keyForType = keyForFactory.getAnnotatedType(key); AnnotationMirror anno = keyForType.getAnnotation(KeyFor.class); - if (anno == null) - return false; + if (anno == null) return false; - List maps = AnnotationUtils.getElementValueArray(anno, factory.keyForValueElement, String.class); + List maps = + AnnotationUtils.getElementValueArray( + anno, factory.keyForValueElement, String.class); return maps.contains(mapName); } - private boolean keyForInMap(ExpressionTree key, - Element mapElement, TreePath path) { + private boolean keyForInMap(ExpressionTree key, Element mapElement, TreePath path) { AnnotatedTypeMirror keyForType = keyForFactory.getAnnotatedType(key); AnnotationMirror anno = keyForType.getAnnotation(KeyFor.class); - if (anno == null) - return false; + if (anno == null) return false; - List maps = AnnotationUtils.getElementValueArray(anno, factory.keyForValueElement, String.class); - for (String map: maps) { + List maps = + AnnotationUtils.getElementValueArray( + anno, factory.keyForValueElement, String.class); + for (String map : maps) { // TODO: this whole class should be re-implemented Element elt = null; // resolver.findVariable(map, path); - if (elt != null && - elt.equals(mapElement) && - !isSiteRequired(TreeUtils.getReceiverTree((ExpressionTree)path.getLeaf()), elt)) { + if (elt != null + && elt.equals(mapElement) + && !isSiteRequired( + TreeUtils.getReceiverTree((ExpressionTree) path.getLeaf()), elt)) { return true; } } @@ -151,38 +138,36 @@ private boolean keyForInMap(ExpressionTree key, } /** - * Helper function to determine if the passed element is sufficient - * to resolve a reference at compile time, without needing to - * represent the call/dereference site. + * Helper function to determine if the passed element is sufficient to resolve a reference at + * compile time, without needing to represent the call/dereference site. */ private boolean isSiteRequired(ExpressionTree node, Element elt) { - boolean r = ElementUtils.isStatic(elt) || - !elt.getKind().isField() || - factory.isMostEnclosingThisDeref(node); + boolean r = + ElementUtils.isStatic(elt) + || !elt.getKind().isField() + || factory.isMostEnclosingThisDeref(node); return !r; } private Element getSite(MethodInvocationTree tree) { // TODO: Check this behavior for implicit receivers/outer receivers - return TreeUtils.elementFromUse( TreeUtils.getReceiverTree(tree) ); + return TreeUtils.elementFromUse(TreeUtils.getReceiverTree(tree)); } private boolean isCheckOfGet(Element key, VariableElement map, ExpressionTree tree) { tree = TreeUtils.withoutParens(tree); if (tree.getKind() != Tree.Kind.NOT_EQUAL_TO - || ((BinaryTree)tree).getRightOperand().getKind() != Tree.Kind.NULL_LITERAL) + || ((BinaryTree) tree).getRightOperand().getKind() != Tree.Kind.NULL_LITERAL) return false; - Tree right = TreeUtils.withoutParens(((BinaryTree)tree).getLeftOperand()); + Tree right = TreeUtils.withoutParens(((BinaryTree) tree).getLeftOperand()); if (right instanceof MethodInvocationTree) { - MethodInvocationTree invok = (MethodInvocationTree)right; + MethodInvocationTree invok = (MethodInvocationTree) right; if (TreeUtils.isMethodInvocation(invok, mapGet, env)) { Element containsArgument = TreeUtils.elementFromTree(invok.getArguments().get(0)); - if (key.equals(containsArgument) && map.equals(getSite(invok))) - return true; + if (key.equals(containsArgument) && map.equals(getSite(invok))) return true; } } return false; } } - diff --git a/src/nninf/NninfAnnotatedTypeFactory.java b/src/nninf/NninfAnnotatedTypeFactory.java index 30598bf9e..d62d2a77c 100644 --- a/src/nninf/NninfAnnotatedTypeFactory.java +++ b/src/nninf/NninfAnnotatedTypeFactory.java @@ -3,31 +3,31 @@ import com.sun.source.tree.ClassTree; import com.sun.source.tree.ExpressionTree; import com.sun.source.tree.IdentifierTree; +import com.sun.source.tree.MethodInvocationTree; import com.sun.source.tree.Tree; -import nninf.qual.KeyFor; +import com.sun.source.util.TreePath; + import org.checkerframework.checker.nullness.KeyForAnnotatedTypeFactory; import org.checkerframework.framework.qual.TypeUseLocation; import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType; +import org.checkerframework.javacutil.ElementUtils; +import org.checkerframework.javacutil.TreePathUtil; +import org.checkerframework.javacutil.TreeUtils; import java.lang.annotation.Annotation; import java.util.HashSet; import java.util.Set; -import com.sun.source.tree.MethodInvocationTree; -import com.sun.source.util.TreePath; - -import nninf.qual.NonNull; -import nninf.qual.Nullable; -import nninf.qual.PolyNull; -import org.checkerframework.javacutil.ElementUtils; -import org.checkerframework.javacutil.TreePathUtil; -import org.checkerframework.javacutil.TreeUtils; - import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Name; import javax.lang.model.element.TypeElement; +import nninf.qual.KeyFor; +import nninf.qual.NonNull; +import nninf.qual.Nullable; +import nninf.qual.PolyNull; + public class NninfAnnotatedTypeFactory extends GameAnnotatedTypeFactory { NninfChecker checker; MapGetHeuristics mapGetHeuristics; @@ -44,14 +44,19 @@ public NninfAnnotatedTypeFactory(NninfChecker checker, boolean isInfer) { KeyForAnnotatedTypeFactory mapGetFactory = new KeyForAnnotatedTypeFactory(checker); mapGetHeuristics = new MapGetHeuristics(processingEnv, this, mapGetFactory); - addAliasedTypeAnnotation(org.checkerframework.checker.nullness.qual.NonNull.class, checker.NONNULL); - addAliasedTypeAnnotation(org.checkerframework.checker.nullness.qual.Nullable.class, checker.NULLABLE); - addAliasedTypeAnnotation(org.checkerframework.checker.nullness.qual.KeyFor.class, checker.KEYFOR); - addAliasedTypeAnnotation(org.checkerframework.common.subtyping.qual.Unqualified.class, checker.UNKNOWNKEYFOR); + addAliasedTypeAnnotation( + org.checkerframework.checker.nullness.qual.NonNull.class, checker.NONNULL); + addAliasedTypeAnnotation( + org.checkerframework.checker.nullness.qual.Nullable.class, checker.NULLABLE); + addAliasedTypeAnnotation( + org.checkerframework.checker.nullness.qual.KeyFor.class, checker.KEYFOR); + addAliasedTypeAnnotation( + org.checkerframework.common.subtyping.qual.Unqualified.class, + checker.UNKNOWNKEYFOR); postInit(); - defaults.addCheckedCodeDefault(checker.NONNULL, TypeUseLocation.OTHERWISE); + defaults.addCheckedCodeDefault(checker.NONNULL, TypeUseLocation.OTHERWISE); defaults.addCheckedCodeDefault(checker.NULLABLE, TypeUseLocation.LOCAL_VARIABLE); } @@ -80,7 +85,8 @@ public ParameterizedExecutableType methodFromUse(MethodInvocationTree tree) { } // TODO(Zhiping): try overriding getselftype and remove these deprecated methods copied - // TODO(Zhiping): from the Checker Framework: isMostEnclosingThisDeref, isSubtype, isAnyEnclosingThisDeref + // TODO(Zhiping): from the Checker Framework: isMostEnclosingThisDeref, isSubtype, + // isAnyEnclosingThisDeref /** * Determine whether the tree dereferences the most enclosing "this" object. That is, we have an * expression like "f.g" and want to know whether it is an access "this.f.g". Returns false if f diff --git a/src/nninf/NninfChecker.java b/src/nninf/NninfChecker.java index 50fe868c5..1ab69bc5e 100644 --- a/src/nninf/NninfChecker.java +++ b/src/nninf/NninfChecker.java @@ -1,7 +1,5 @@ package nninf; -import nninf.qual.KeyFor; -import nninf.qual.UnknownKeyFor; import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; import org.checkerframework.framework.flow.CFTransfer; import org.checkerframework.javacutil.AnnotationBuilder; @@ -12,8 +10,10 @@ import checkers.inference.BaseInferrableChecker; import checkers.inference.InferenceChecker; import checkers.inference.dataflow.InferenceAnalysis; +import nninf.qual.KeyFor; import nninf.qual.NonNull; import nninf.qual.Nullable; +import nninf.qual.UnknownKeyFor; public class NninfChecker extends BaseInferrableChecker { public AnnotationMirror NULLABLE, NONNULL, UNKNOWNKEYFOR, KEYFOR; @@ -22,19 +22,20 @@ public class NninfChecker extends BaseInferrableChecker { public void initChecker() { final Elements elements = processingEnv.getElementUtils(); NULLABLE = AnnotationBuilder.fromClass(elements, Nullable.class); - NONNULL = AnnotationBuilder.fromClass(elements, NonNull.class); + NONNULL = AnnotationBuilder.fromClass(elements, NonNull.class); UNKNOWNKEYFOR = AnnotationBuilder.fromClass(elements, UnknownKeyFor.class); - KEYFOR = AnnotationBuilder.fromClass( - elements, - KeyFor.class, - AnnotationBuilder.elementNamesValues("value", new String[0]) - ); + KEYFOR = + AnnotationBuilder.fromClass( + elements, + KeyFor.class, + AnnotationBuilder.elementNamesValues("value", new String[0])); super.initChecker(); } @Override - public NninfVisitor createVisitor(InferenceChecker ichecker, BaseAnnotatedTypeFactory factory, boolean infer) { + public NninfVisitor createVisitor( + InferenceChecker ichecker, BaseAnnotatedTypeFactory factory, boolean infer) { return new NninfVisitor(this, ichecker, factory, infer); } @@ -47,4 +48,4 @@ public NninfAnnotatedTypeFactory createRealTypeFactory(boolean infer) { public CFTransfer createInferenceTransferFunction(InferenceAnalysis analysis) { return new NninfTransfer(analysis); } -} \ No newline at end of file +} diff --git a/src/nninf/NninfTransfer.java b/src/nninf/NninfTransfer.java index 845c49acf..3d06b5f53 100644 --- a/src/nninf/NninfTransfer.java +++ b/src/nninf/NninfTransfer.java @@ -11,25 +11,26 @@ public NninfTransfer(InferenceAnalysis analysis) { } // TODO(Zhiping): try adding x != null refinement in inference -//package nninf +// package nninf // -//import checkers.flow._ -//import dataflow.cfg.node._ -//import dataflow.analysis.{RegularTransferResult, ConditionalTransferResult, TransferResult, TransferInput, FlowExpressions} -//import com.sun.source.tree._ +// import checkers.flow._ +// import dataflow.cfg.node._ +// import dataflow.analysis.{RegularTransferResult, ConditionalTransferResult, TransferResult, +// TransferInput, FlowExpressions} +// import com.sun.source.tree._ // -//import checkers.inference.InferenceMain.{slotMgr, constraintMgr} -//import javacutils.{TreeUtils, AnnotationUtils} -//import scala.collection.JavaConversions._ -//import dataflow.cfg.UnderlyingAST -//import dataflow.cfg.UnderlyingAST.{CFGMethod, Kind} -//import javax.lang.model.`type`.TypeMirror -//import javax.lang.model.element.AnnotationMirror -//import com.sun.source.tree.AssignmentTree -//import com.sun.source.tree.Tree -//import checkers.inference._ +// import checkers.inference.InferenceMain.{slotMgr, constraintMgr} +// import javacutils.{TreeUtils, AnnotationUtils} +// import scala.collection.JavaConversions._ +// import dataflow.cfg.UnderlyingAST +// import dataflow.cfg.UnderlyingAST.{CFGMethod, Kind} +// import javax.lang.model.`type`.TypeMirror +// import javax.lang.model.element.AnnotationMirror +// import com.sun.source.tree.AssignmentTree +// import com.sun.source.tree.Tree +// import checkers.inference._ // -///** +/// ** // * NninfTransfer creates a BallSizeTestConstraint constraint when a variable is compared // * to a literal null with == or !=. // * @@ -46,11 +47,13 @@ public NninfTransfer(InferenceAnalysis analysis) { // * // */ // -//class NninfTransferImpl(analysis : CFAbstractAnalysis[CFValue, CFStore, CFTransfer]) extends InferenceTransfer(analysis) { +// class NninfTransferImpl(analysis : CFAbstractAnalysis[CFValue, CFStore, CFTransfer]) extends +// InferenceTransfer(analysis) { // // override def strengthenAnnotationOfEqualTo(res: TransferResult[CFValue,CFStore], // firstNode: Node, secondNode: Node, -// firstValue: CFValue, secondValue: CFValue, notEqualTo: Boolean) : TransferResult[CFValue, CFStore] = { +// firstValue: CFValue, secondValue: CFValue, notEqualTo: Boolean) : TransferResult[CFValue, +// CFStore] = { // // val infChecker = InferenceMain.inferenceChecker // val typeFactory = analysis.getTypeFactory.asInstanceOf[InferenceAnnotatedTypeFactory] @@ -69,7 +72,8 @@ public NninfTransfer(InferenceAnalysis analysis) { // var anno2: AnnotationMirror = null // // If we have already created a BSTest, use the same RefinementVariables // if (!infChecker.ballSizeTestCache.contains(tree)) { -// val astPathStr = InferenceUtils.convertASTPathToAFUFormat(InferenceUtils.getASTPathToNode(typeFactory, tree)) +// val astPathStr = +// InferenceUtils.convertASTPathToAFUFormat(InferenceUtils.getASTPathToNode(typeFactory, tree)) // anno1 = slotMgr.createRefinementVariableAnnotation(typeFactory, tree, astPathStr, true) // anno2 = slotMgr.createRefinementVariableAnnotation(typeFactory, tree, astPathStr, true) // val subtypeSlot = slotMgr.extractSlot(anno1).asInstanceOf[RefinementVariable] @@ -87,7 +91,8 @@ public NninfTransfer(InferenceAnalysis analysis) { // anno2 = bsTest.supertype.getAnnotation // if (inputVar != bsTest.input) { // infChecker.ballSizeTestCache += (tree -> new BallSizeTestConstraint( -// input = inputVar, supertype = bsTest.supertype, subtype = bsTest.subtype, cycle = true)) +// input = inputVar, supertype = bsTest.supertype, subtype = bsTest.subtype, cycle = +// true)) // } // } // @@ -99,16 +104,20 @@ public NninfTransfer(InferenceAnalysis analysis) { // supertypeAtm.addAnnotation(anno2) // if (notEqualTo) { // // (a != null) { NonNull } else { Nullable } -// thenStore.replaceValue(FlowExpressions.internalReprOf(typeFactory, secondNode), analysis.createAbstractValue(subtypeAtm)) -// elseStore.replaceValue(FlowExpressions.internalReprOf(typeFactory, secondNode), analysis.createAbstractValue(supertypeAtm)) +// thenStore.replaceValue(FlowExpressions.internalReprOf(typeFactory, secondNode), +// analysis.createAbstractValue(subtypeAtm)) +// elseStore.replaceValue(FlowExpressions.internalReprOf(typeFactory, secondNode), +// analysis.createAbstractValue(supertypeAtm)) // } else { // // (a == null) { Nullable } else { NonNull } -// thenStore.replaceValue(FlowExpressions.internalReprOf(typeFactory, secondNode), analysis.createAbstractValue(supertypeAtm)) -// elseStore.replaceValue(FlowExpressions.internalReprOf(typeFactory, secondNode), analysis.createAbstractValue(subtypeAtm)) +// thenStore.replaceValue(FlowExpressions.internalReprOf(typeFactory, secondNode), +// analysis.createAbstractValue(supertypeAtm)) +// elseStore.replaceValue(FlowExpressions.internalReprOf(typeFactory, secondNode), +// analysis.createAbstractValue(subtypeAtm)) // } // return new ConditionalTransferResult(res.getResultValue(), thenStore, elseStore); // } // // return res // } -//} \ No newline at end of file +// } diff --git a/src/nninf/NninfVisitor.java b/src/nninf/NninfVisitor.java index 3491ce3f7..d0d348b71 100644 --- a/src/nninf/NninfVisitor.java +++ b/src/nninf/NninfVisitor.java @@ -1,27 +1,5 @@ package nninf; -import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; -import org.checkerframework.framework.type.AnnotatedTypeMirror; -import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType; -import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType; -import org.checkerframework.javacutil.TreeUtils; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.TypeElement; -import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.PrimitiveType; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; - -import checkers.inference.InferenceChecker; -import checkers.inference.InferenceVisitor; - import com.sun.source.tree.ArrayAccessTree; import com.sun.source.tree.BinaryTree; import com.sun.source.tree.BlockTree; @@ -48,19 +26,43 @@ import com.sun.source.tree.WhileLoopTree; import com.sun.source.util.Trees; +import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; +import org.checkerframework.framework.type.AnnotatedTypeMirror; +import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType; +import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType; +import org.checkerframework.javacutil.TreeUtils; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.PrimitiveType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; + +import checkers.inference.InferenceChecker; +import checkers.inference.InferenceVisitor; + public class NninfVisitor extends InferenceVisitor { private final TypeMirror stringType; - public NninfVisitor(NninfChecker checker, InferenceChecker ichecker, BaseAnnotatedTypeFactory factory, boolean infer) { + public NninfVisitor( + NninfChecker checker, + InferenceChecker ichecker, + BaseAnnotatedTypeFactory factory, + boolean infer) { super(checker, ichecker, factory, infer); this.stringType = elements.getTypeElement("java.lang.String").asType(); } - /** - * Ensure that the type is not of nullable. - */ + /** Ensure that the type is not of nullable. */ private void checkForNullability(ExpressionTree tree, String errMsg) { AnnotatedTypeMirror type = atypeFactory.getAnnotatedType(tree); mainIsNot(type, realChecker.NULLABLE, errMsg, tree); @@ -72,11 +74,14 @@ public Void visitBlock(BlockTree node, Void p) { Trees trees = Trees.instance(checker.getProcessingEnvironment()); Scope scope = trees.getScope(getCurrentPath()); System.out.println(); - Set variables = new HashSet(); // Variables accessible from within the block + Set variables = + new HashSet(); // Variables accessible from within the block Set maps = new HashSet(); // Maps accessible within the block TypeElement mapElt = - checker.getProcessingEnvironment().getElementUtils().getTypeElement("java.util.Map"); + checker.getProcessingEnvironment() + .getElementUtils() + .getTypeElement("java.util.Map"); TypeMirror mapType = types.erasure(mapElt.asType()); // Variables within the block. @@ -121,7 +126,7 @@ public Void visitBlock(BlockTree node, Void p) { TypeMirror type = var.asType(); // Check for boxed types. Ex. int can be a key for Map. if (type.getKind().isPrimitive()) { - PrimitiveType pType= (PrimitiveType) type; + PrimitiveType pType = (PrimitiveType) type; keyElement = types.boxedClass(pType); } else { keyElement = var; @@ -129,7 +134,7 @@ public Void visitBlock(BlockTree node, Void p) { for (Element map : maps) { if (map.asType().getKind() == TypeKind.DECLARED) { DeclaredType dType = (DeclaredType) map.asType(); - List list= dType.getTypeArguments(); + List list = dType.getTypeArguments(); if (list.size() > 0) { if (types.isSubtype(keyElement.asType(), list.get(0))) { // log possible KeyFor constraint. @@ -137,21 +142,19 @@ public Void visitBlock(BlockTree node, Void p) { } } } - } } } return super.visitBlock(node, p); } - /** - * Nninf does not use receiver annotations, forbid them. - */ + /** Nninf does not use receiver annotations, forbid them. */ @Override public Void visitMethod(MethodTree node, Void p) { // final VariableTree receiverParam = node.getReceiverParameter(); - // TODO: Talk to mike, this is a problem because calling getAnnotatedType in different locations leads + // TODO: Talk to mike, this is a problem because calling getAnnotatedType in different + // locations leads // TODO: to Different variablePositions // TODO JB: Put this back in and disable receiver additions for Nninf /*if(receiverParam != null) { // TODO: CAN THIS BE NULL? Only if this is a constructor? @@ -165,21 +168,15 @@ public Void visitMethod(MethodTree node, Void p) { return super.visitMethod(node, p); } - /** - * Ignore method receiver annotations. - */ + /** Ignore method receiver annotations. */ @Override - protected void checkMethodInvocability(AnnotatedExecutableType method, - MethodInvocationTree node) { - } + protected void checkMethodInvocability( + AnnotatedExecutableType method, MethodInvocationTree node) {} - /** - * Ignore constructor receiver annotations. - */ + /** Ignore constructor receiver annotations. */ @Override - protected void checkConstructorInvocation(AnnotatedDeclaredType dt, - AnnotatedExecutableType constructor, NewClassTree src) { - } + protected void checkConstructorInvocation( + AnnotatedDeclaredType dt, AnnotatedExecutableType constructor, NewClassTree src) {} @Override protected void checkConstructorResult( @@ -191,27 +188,24 @@ protected void checkConstructorResult( @Override public Void visitMemberSelect(MemberSelectTree node, Void p) { // TODO JB: Talk to Werner/Mike about class A extends OtherClass.InnerClass -// if( InferenceUtils.isInExtendsImplements( node, atypeFactory )) { -// return null; -// } - + // if( InferenceUtils.isInExtendsImplements( node, atypeFactory )) { + // return null; + // } - // Note that the ordering is important! First receiver expression, then create field access, then inequality. + // Note that the ordering is important! First receiver expression, then create field access, + // then inequality. super.visitMemberSelect(node, p); // TODO: How do I decide whether something is a field read or update? // We currently create an access and then a set constraint. - // TODO: determining whether something is "this" doesn't seem to work correctly, - // as I still get constraints with LiteralThis. + // TODO: determining whether something is "this" doesn't seem to work correctly, + // as I still get constraints with LiteralThis. // TODO(Zhiping): verify if we are handling this properly checkForNullability(node.getExpression(), "dereference.of.nullable"); -// logFieldAccess(node); + // logFieldAccess(node); return null; } - - /** Class instantiation is always non-null. - * TODO: resolve this automatically? - */ + /** Class instantiation is always non-null. TODO: resolve this automatically? */ @Override public Void visitNewClass(NewClassTree node, Void p) { super.visitNewClass(node, p); @@ -219,7 +213,6 @@ public Void visitNewClass(NewClassTree node, Void p) { return null; } - /** Check for implicit {@code .iterator} call */ @Override public Void visitEnhancedForLoop(EnhancedForLoopTree node, Void p) { @@ -284,7 +277,7 @@ public Void visitWhileLoop(WhileLoopTree node, Void p) { @Override public Void visitForLoop(ForLoopTree node, Void p) { super.visitForLoop(node, p); - if (node.getCondition()!=null) { + if (node.getCondition() != null) { // Condition is null e.g. in "for (;;) {...}" checkForNullability(node.getCondition(), "condition.nullable"); } @@ -299,9 +292,7 @@ public Void visitSwitch(SwitchTree node, Void p) { return null; } - /** - * Unboxing case: primitive operations - */ + /** Unboxing case: primitive operations */ @Override public Void visitBinary(BinaryTree node, Void p) { super.visitBinary(node, p); @@ -352,14 +343,14 @@ public Void visitTypeCast(TypeCastTree node, Void p) { } // TODO: These TWO are from NonNullInfVisitor but are no longer static - /** @return true if binary operation could cause an unboxing operation */ + /** + * @return true if binary operation could cause an unboxing operation + */ private final boolean isUnboxingOperation(BinaryTree tree) { - if (tree.getKind() == Tree.Kind.EQUAL_TO - || tree.getKind() == Tree.Kind.NOT_EQUAL_TO) { + if (tree.getKind() == Tree.Kind.EQUAL_TO || tree.getKind() == Tree.Kind.NOT_EQUAL_TO) { // it is valid to check equality between two reference types, even // if one (or both) of them is null - return isPrimitive(tree.getLeftOperand()) != isPrimitive(tree - .getRightOperand()); + return isPrimitive(tree.getLeftOperand()) != isPrimitive(tree.getRightOperand()); } else { // All BinaryTree's are of type String, a primitive type or the // reference type equivalent of a primitive type. Furthermore, @@ -371,7 +362,7 @@ private final boolean isUnboxingOperation(BinaryTree tree) { /** * @return true if the type of the tree is a super of String - * */ + */ private final boolean isString(ExpressionTree tree) { TypeMirror type = TreeUtils.typeOf(tree); return types.isAssignable(stringType, type); diff --git a/src/nninf/qual/KeyFor.java b/src/nninf/qual/KeyFor.java index ff389651a..e774ef734 100644 --- a/src/nninf/qual/KeyFor.java +++ b/src/nninf/qual/KeyFor.java @@ -1,19 +1,18 @@ package nninf.qual; +import org.checkerframework.framework.qual.SubtypeOf; + import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import org.checkerframework.framework.qual.SubtypeOf; - /** * Indicates that the annotated reference of an Object that is a key in a map. * - *

    - * The value of the annotation should be the reference name of the map. The - * following declaration for example: + *

    The value of the annotation should be the reference name of the map. The following declaration + * for example: * *

    
      *   Map<String, String> config = ...;
    @@ -22,14 +21,11 @@
      *   String hostname = config.get(key);     // known to be non-null
      * 
    * - * indicates that "HOSTNAME" is a key in config. The Nullness - * checker deduce this information to deduce that {@code hostname} reference - * is a nonnull reference. + * indicates that "HOSTNAME" is a key in config. The Nullness checker deduce this information to + * deduce that {@code hostname} reference is a nonnull reference. * - *

    - * Limitation: The Nullness checker trusts the user and doesn't - * validate the annotations. Future releases will check for the presence of - * the key in the map (when possible). + *

    Limitation: The Nullness checker trusts the user and doesn't validate the annotations. + * Future releases will check for the presence of the key in the map (when possible). */ @Documented @Retention(RetentionPolicy.RUNTIME) @@ -38,7 +34,10 @@ public @interface KeyFor { /** * Java expression(s) that evaluate to a map for which the annotated type is a key. - * @see Syntax of Java expressions + * + * @see Syntax + * of Java expressions */ public String[] value(); } diff --git a/src/nninf/qual/NonNull.java b/src/nninf/qual/NonNull.java index 94ec09a4d..f49d2e86a 100644 --- a/src/nninf/qual/NonNull.java +++ b/src/nninf/qual/NonNull.java @@ -1,13 +1,13 @@ package nninf.qual; import org.checkerframework.framework.qual.DefaultFor; +import org.checkerframework.framework.qual.DefaultQualifierInHierarchy; import org.checkerframework.framework.qual.LiteralKind; import org.checkerframework.framework.qual.QualifierForLiterals; import org.checkerframework.framework.qual.SubtypeOf; +import org.checkerframework.framework.qual.TypeKind; import org.checkerframework.framework.qual.TypeUseLocation; -import org.checkerframework.framework.qual.DefaultQualifierInHierarchy; import org.checkerframework.framework.qual.UpperBoundFor; -import org.checkerframework.framework.qual.TypeKind; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; @@ -28,14 +28,14 @@ @DefaultQualifierInHierarchy @UpperBoundFor( typeKinds = { - TypeKind.PACKAGE, - TypeKind.INT, - TypeKind.BOOLEAN, - TypeKind.CHAR, - TypeKind.DOUBLE, - TypeKind.FLOAT, - TypeKind.LONG, - TypeKind.SHORT, - TypeKind.BYTE + TypeKind.PACKAGE, + TypeKind.INT, + TypeKind.BOOLEAN, + TypeKind.CHAR, + TypeKind.DOUBLE, + TypeKind.FLOAT, + TypeKind.LONG, + TypeKind.SHORT, + TypeKind.BYTE }) public @interface NonNull {} diff --git a/src/nninf/qual/PolyNull.java b/src/nninf/qual/PolyNull.java index e22ff9773..acd82e615 100644 --- a/src/nninf/qual/PolyNull.java +++ b/src/nninf/qual/PolyNull.java @@ -7,11 +7,10 @@ /** * A polymorphic qualifier for the non-null type system. * - *

    - * Any method written using {@link PolyNull} conceptually has two versions: one - * in which every instance of {@link PolyNull} has been replaced by - * {@link org.checkerframework.checker.nullness.qual.NonNull}, and one in which every instance of {@link PolyNull} has been - * replaced by {@link org.checkerframework.checker.nullness.qual.Nullable}. + *

    Any method written using {@link PolyNull} conceptually has two versions: one in which every + * instance of {@link PolyNull} has been replaced by {@link + * org.checkerframework.checker.nullness.qual.NonNull}, and one in which every instance of {@link + * PolyNull} has been replaced by {@link org.checkerframework.checker.nullness.qual.Nullable}. * * @checker_framework_manual #nullness-checker Nullness Checker */ @@ -19,5 +18,4 @@ @PolymorphicQualifier(Nullable.class) @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) -public @interface PolyNull { -} +public @interface PolyNull {} diff --git a/src/nninf/qual/UnknownKeyFor.java b/src/nninf/qual/UnknownKeyFor.java index 2215307e0..a8cc260e2 100644 --- a/src/nninf/qual/UnknownKeyFor.java +++ b/src/nninf/qual/UnknownKeyFor.java @@ -1,16 +1,15 @@ package nninf.qual; -import java.lang.annotation.Target; - import org.checkerframework.framework.qual.DefaultQualifierInHierarchy; import org.checkerframework.framework.qual.InvisibleQualifier; import org.checkerframework.framework.qual.SubtypeOf; +import java.lang.annotation.Target; + /** * A reference for which we don't know whether it's a key for a map or not. * - *

    - * Programmers cannot write this in source code. + *

    Programmers cannot write this in source code. */ @InvisibleQualifier @SubtypeOf({}) diff --git a/src/ostrusted/OsTrustedChecker.java b/src/ostrusted/OsTrustedChecker.java index 55768846d..bafd5570e 100644 --- a/src/ostrusted/OsTrustedChecker.java +++ b/src/ostrusted/OsTrustedChecker.java @@ -9,17 +9,17 @@ import trusted.TrustedChecker; /** - * - * @author sdietzel - * [2] CWE-78 Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection') + * @author sdietzel [2] CWE-78 Improper Neutralization of Special Elements used in an OS Command + * ('OS Command Injection') */ public class OsTrustedChecker extends TrustedChecker { @Override protected void setAnnotations() { - final Elements elements = processingEnv.getElementUtils(); // TODO: Makes you think a utils is being returned + final Elements elements = + processingEnv.getElementUtils(); // TODO: Makes you think a utils is being returned UNTRUSTED = AnnotationBuilder.fromClass(elements, OsUntrusted.class); - TRUSTED = AnnotationBuilder.fromClass(elements, OsTrusted.class); + TRUSTED = AnnotationBuilder.fromClass(elements, OsTrusted.class); } -} \ No newline at end of file +} diff --git a/src/ostrusted/qual/OsTrusted.java b/src/ostrusted/qual/OsTrusted.java index c09961c90..116a51905 100644 --- a/src/ostrusted/qual/OsTrusted.java +++ b/src/ostrusted/qual/OsTrusted.java @@ -11,27 +11,26 @@ import java.lang.annotation.Target; /** - * Represents data that has been verified as suitable to pass to OS commands, - * such as exec.

    + * Represents data that has been verified as suitable to pass to OS commands, such as exec. * - * The included JDK stub file requires that arguments to certain JDK methods be - * {@code OsTrusted Strings}.

    + *

    The included JDK stub file requires that arguments to certain JDK methods be {@code OsTrusted + * Strings}. * - * The user must determine for himself what constitutes a verified piece of - * data. For example, it is a good idea to consider data coming from the network - * to be {@link OsUntrusted}, and subject it to some sort of verification - * routine to sanitize it.

    + *

    The user must determine for himself what constitutes a verified piece of data. For example, it + * is a good idea to consider data coming from the network to be {@link OsUntrusted}, and subject it + * to some sort of verification routine to sanitize it. * - * This type annotation is intended to be used primarily with {@code String}s, - * but it is conceivable that it could be useful for other types.

    + *

    This type annotation is intended to be used primarily with {@code String}s, but it is + * conceivable that it could be useful for other types. * - * All literals are considered {@code OsTrusted}.

    + *

    All literals are considered {@code OsTrusted}. * - * The concatenation of two {@code OsTrusted String}s via the + operator results - * in an {@code OsTrusted String}. The use of the + operator on other {@code - * OsTrusted} types also results in an {@code OsTrusted} type. This behavior - * should be made consistent, either by restricting it to {@code String}s only - * or by extending it to also apply to other arithmetic operations.

    + *

    The concatenation of two {@code OsTrusted String}s via the + operator results in an {@code + * OsTrusted String}. The use of the + operator on other {@code OsTrusted} types also results in an + * {@code OsTrusted} type. This behavior should be made consistent, either by restricting it to + * {@code String}s only or by extending it to also apply to other arithmetic operations. + * + *

    * * @see OsUntrusted * @see PolyOsTrusted @@ -44,13 +43,13 @@ // SHOULD WE HAVE A WAY TO SPECIFY ENUMS @QualifierForLiterals({ - LiteralKind.BOOLEAN, - LiteralKind.CHAR, - LiteralKind.DOUBLE, - LiteralKind.FLOAT, - LiteralKind.INT, - LiteralKind.LONG, - LiteralKind.NULL, - LiteralKind.STRING - }) + LiteralKind.BOOLEAN, + LiteralKind.CHAR, + LiteralKind.DOUBLE, + LiteralKind.FLOAT, + LiteralKind.INT, + LiteralKind.LONG, + LiteralKind.NULL, + LiteralKind.STRING +}) public @interface OsTrusted {} diff --git a/src/ostrusted/qual/OsUntrusted.java b/src/ostrusted/qual/OsUntrusted.java index 088b86553..58487477d 100644 --- a/src/ostrusted/qual/OsUntrusted.java +++ b/src/ostrusted/qual/OsUntrusted.java @@ -1,19 +1,18 @@ package ostrusted.qual; +import org.checkerframework.framework.qual.DefaultQualifierInHierarchy; +import org.checkerframework.framework.qual.SubtypeOf; + import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import org.checkerframework.framework.qual.DefaultQualifierInHierarchy; -import org.checkerframework.framework.qual.SubtypeOf; - /** - * Represents data that may not be suitable to pass to OS commands such as - * exec.

    + * Represents data that may not be suitable to pass to OS commands such as exec. * - * Types are implicitly {@code OsUntrusted}. + *

    Types are implicitly {@code OsUntrusted}. * * @see OsTrusted * @see PolyOsTrusted diff --git a/src/ostrusted/qual/PolyOsTrusted.java b/src/ostrusted/qual/PolyOsTrusted.java index 38edc9e74..7def333cd 100644 --- a/src/ostrusted/qual/PolyOsTrusted.java +++ b/src/ostrusted/qual/PolyOsTrusted.java @@ -1,20 +1,21 @@ package ostrusted.qual; +import org.checkerframework.framework.qual.PolymorphicQualifier; + import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import org.checkerframework.framework.qual.PolymorphicQualifier; - /** - * A Polymorphic qualifier for {@code OsTrusted}.

    + * A Polymorphic qualifier for {@code OsTrusted}. * - * See {@link + *

    See {@link * http://types.cs.washington.edu/checker-framework/current/checkers-manual.html#qualifier-polymorphism} - * for information on the semantics of polymorphic qualifiers in the checker - * framework.

    + * for information on the semantics of polymorphic qualifiers in the checker framework. + * + *

    * * @see OsTrusted * @see OsUntrusted diff --git a/src/sparta/checkers/IFlowSinkChecker.java b/src/sparta/checkers/IFlowSinkChecker.java index 412c7c566..75948927c 100644 --- a/src/sparta/checkers/IFlowSinkChecker.java +++ b/src/sparta/checkers/IFlowSinkChecker.java @@ -1,17 +1,16 @@ package sparta.checkers; -import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; -import org.checkerframework.framework.qual.StubFiles; - import com.sun.source.tree.LiteralTree; import com.sun.source.tree.Tree; +import org.checkerframework.framework.qual.StubFiles; + import checkers.inference.BaseInferrableChecker; /** * Checker for inferring @Sink annotations for SPARTA. * - * Only standard subtyping rules are needed so no methods are overridden. + *

    Only standard subtyping rules are needed so no methods are overridden. */ @StubFiles("information_flow.astub") public class IFlowSinkChecker extends BaseInferrableChecker { diff --git a/src/sparta/checkers/IFlowSourceChecker.java b/src/sparta/checkers/IFlowSourceChecker.java index 46f908295..71f55cbaa 100644 --- a/src/sparta/checkers/IFlowSourceChecker.java +++ b/src/sparta/checkers/IFlowSourceChecker.java @@ -3,7 +3,6 @@ import com.sun.source.tree.LiteralTree; import com.sun.source.tree.Tree; -import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; import org.checkerframework.framework.qual.StubFiles; import checkers.inference.BaseInferrableChecker; @@ -11,7 +10,7 @@ /** * Checker for inferring @Source annotations for SPARTA. * - * Only standard subtyping rules are needed so no methods are overridden. + *

    Only standard subtyping rules are needed so no methods are overridden. */ @StubFiles("information_flow.astub") public class IFlowSourceChecker extends BaseInferrableChecker { @@ -30,4 +29,4 @@ public SimpleFlowAnnotatedTypeFactory createRealTypeFactory(boolean infer) { public boolean shouldStoreConstantSlots() { return false; } -} \ No newline at end of file +} diff --git a/src/sparta/checkers/SimpleFlowAnnotatedTypeFactory.java b/src/sparta/checkers/SimpleFlowAnnotatedTypeFactory.java index 07bcc2c4a..3d99b856f 100644 --- a/src/sparta/checkers/SimpleFlowAnnotatedTypeFactory.java +++ b/src/sparta/checkers/SimpleFlowAnnotatedTypeFactory.java @@ -1,6 +1,8 @@ package sparta.checkers; -import checkers.inference.BaseInferenceRealTypeFactory; +import com.sun.source.tree.NewClassTree; +import com.sun.source.tree.Tree; + import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.common.basetype.BaseTypeChecker; import org.checkerframework.framework.qual.LiteralKind; @@ -36,6 +38,7 @@ import javax.lang.model.type.TypeKind; import javax.lang.model.util.Elements; +import checkers.inference.BaseInferenceRealTypeFactory; import sparta.checkers.iflow.util.IFlowUtils; import sparta.checkers.iflow.util.PFPermission; import sparta.checkers.qual.FlowPermission; @@ -46,12 +49,7 @@ import sparta.checkers.qual.Sink; import sparta.checkers.qual.Source; -import com.sun.source.tree.NewClassTree; -import com.sun.source.tree.Tree; - -/** - * Created by mcarthur on 4/3/14. - */ +/** Created by mcarthur on 4/3/14. */ public class SimpleFlowAnnotatedTypeFactory extends BaseInferenceRealTypeFactory { static AnnotationMirror ANYSOURCE, NOSOURCE, ANYSINK, NOSINK; @@ -67,25 +65,23 @@ public class SimpleFlowAnnotatedTypeFactory extends BaseInferenceRealTypeFactory public final IFlowUtils flowUtils; /** - * Constructs a factory from the given {@link ProcessingEnvironment} - * instance and syntax tree root. (These parameters are required so that the - * factory may conduct the appropriate annotation-gathering analyses on - * certain tree types.) - *

    - * Root can be {@code null} if the factory does not operate on trees. - *

    - * A subclass must call postInit at the end of its constructor. + * Constructs a factory from the given {@link ProcessingEnvironment} instance and syntax tree + * root. (These parameters are required so that the factory may conduct the appropriate + * annotation-gathering analyses on certain tree types.) + * + *

    Root can be {@code null} if the factory does not operate on trees. * - * @param checker - * the {@link SourceChecker} to which this factory belongs - * @throws IllegalArgumentException - * if either argument is {@code null} + *

    A subclass must call postInit at the end of its constructor. + * + * @param checker the {@link SourceChecker} to which this factory belongs + * @throws IllegalArgumentException if either argument is {@code null} */ public SimpleFlowAnnotatedTypeFactory(BaseTypeChecker checker, boolean isInfer) { super(checker, isInfer); NOSOURCE = buildAnnotationMirrorFlowPermission(Source.class); - ANYSOURCE = buildAnnotationMirrorFlowPermission(Source.class, FlowPermission.ANY.toString()); + ANYSOURCE = + buildAnnotationMirrorFlowPermission(Source.class, FlowPermission.ANY.toString()); NOSINK = buildAnnotationMirrorFlowPermission(Sink.class); ANYSINK = buildAnnotationMirrorFlowPermission(Sink.class, FlowPermission.ANY.toString()); POLYSOURCE = buildAnnotationMirror(PolySource.class); @@ -117,8 +113,7 @@ protected Set> createSupportedTypeQualifiers() { } private AnnotationMirror buildAnnotationMirrorFlowPermission( - Class clazz, - String... flowPermission) { + Class clazz, String... flowPermission) { AnnotationBuilder builder = new AnnotationBuilder(processingEnv, clazz); builder.setValue("value", flowPermission); return builder.build(); @@ -138,48 +133,52 @@ protected TreeAnnotator createTreeAnnotator() { implicits.addLiteralKind(LiteralKind.ALL, NOSOURCE); implicits.addLiteralKind(LiteralKind.ALL, ANYSINK); - return new ListTreeAnnotator(new PropagationTreeAnnotator(this), + return new ListTreeAnnotator( + new PropagationTreeAnnotator(this), implicits, new TreeAnnotator(this) { - @Override - public Void visitNewClass(NewClassTree node, AnnotatedTypeMirror p) { - // This is a horrible hack around the bad implementation of constructor results - // (CF treats annotations on constructor results in stub files as if it were a - // default and therefore ignores it.) - AnnotatedTypeMirror defaulted = atypeFactory.constructorFromUse(node).executableType.getReturnType(); - Set defaultedSet = defaulted.getAnnotations(); - // The default of OTHERWISE locations such as constructor results - // is {}{}, but for constructor results we really want bottom. - // So if the result is {}{}, then change it to {}->ANY (bottom) - - boolean empty = true; - for (AnnotationMirror am: defaultedSet) { - List s = Collections.emptyList(); - if (IFlowUtils.isSink(am)) { - s = flowUtils.getRawSinks(am); - } else if (IFlowUtils.isSource(am)) { - s = flowUtils.getRawSources(am); + @Override + public Void visitNewClass(NewClassTree node, AnnotatedTypeMirror p) { + // This is a horrible hack around the bad implementation of constructor + // results + // (CF treats annotations on constructor results in stub files as if it were + // a + // default and therefore ignores it.) + AnnotatedTypeMirror defaulted = + atypeFactory + .constructorFromUse(node) + .executableType + .getReturnType(); + Set defaultedSet = defaulted.getAnnotations(); + // The default of OTHERWISE locations such as constructor results + // is {}{}, but for constructor results we really want bottom. + // So if the result is {}{}, then change it to {}->ANY (bottom) + + boolean empty = true; + for (AnnotationMirror am : defaultedSet) { + List s = Collections.emptyList(); + if (IFlowUtils.isSink(am)) { + s = flowUtils.getRawSinks(am); + } else if (IFlowUtils.isSource(am)) { + s = flowUtils.getRawSources(am); + } + + empty = s.isEmpty() && empty; + } + + if (empty) { + defaultedSet = new AnnotationMirrorSet(); + defaultedSet.add(NOSOURCE); + defaultedSet.add(ANYSINK); + } + + p.replaceAnnotations(defaultedSet); + return null; } - - empty = s.isEmpty() && empty; - } - - if (empty) { - defaultedSet = new AnnotationMirrorSet(); - defaultedSet.add(NOSOURCE); - defaultedSet.add(ANYSINK); - } - - p.replaceAnnotations(defaultedSet); - return null; - } }); - } - /** - * Initializes qualifier defaults for @PolyFlow, @PolyFlowReceiver, and @FromByteCode - */ + /** Initializes qualifier defaults for @PolyFlow, @PolyFlowReceiver, and @FromByteCode */ private void initQualifierDefaults() { // Final fields from byte code are {} -> ANY byteCodeFieldDefault.addCheckedCodeDefault(NOSOURCE, TypeUseLocation.OTHERWISE); @@ -192,14 +191,15 @@ private void initQualifierDefaults() { // Use poly flow sources and sinks for return types and // parameter types (This is excluding receivers). - TypeUseLocation[] polyFlowLoc = { TypeUseLocation.RETURN, TypeUseLocation.PARAMETER }; + TypeUseLocation[] polyFlowLoc = {TypeUseLocation.RETURN, TypeUseLocation.PARAMETER}; polyFlowDefaults.addCheckedCodeDefaults(POLYSOURCE, polyFlowLoc); polyFlowDefaults.addCheckedCodeDefaults(POLYSINK, polyFlowLoc); // Use poly flow sources and sinks for return types and // parameter types and receivers). - TypeUseLocation[] polyFlowReceiverLoc = { TypeUseLocation.RETURN, TypeUseLocation.PARAMETER, - TypeUseLocation.RECEIVER }; + TypeUseLocation[] polyFlowReceiverLoc = { + TypeUseLocation.RETURN, TypeUseLocation.PARAMETER, TypeUseLocation.RECEIVER + }; polyFlowReceiverDefaults.addCheckedCodeDefaults(POLYSOURCE, polyFlowReceiverLoc); polyFlowReceiverDefaults.addCheckedCodeDefaults(POLYSINK, polyFlowReceiverLoc); } @@ -207,19 +207,23 @@ private void initQualifierDefaults() { @Override protected void addCheckedCodeDefaults(QualifierDefaults defaults) { // CLIMB-to-the-top defaults - TypeUseLocation[] topLocations = { TypeUseLocation.LOCAL_VARIABLE, TypeUseLocation.RESOURCE_VARIABLE, - TypeUseLocation.UPPER_BOUND }; + TypeUseLocation[] topLocations = { + TypeUseLocation.LOCAL_VARIABLE, + TypeUseLocation.RESOURCE_VARIABLE, + TypeUseLocation.UPPER_BOUND + }; defaults.addCheckedCodeDefaults(ANYSOURCE, topLocations); defaults.addCheckedCodeDefaults(NOSINK, topLocations); // Default for receivers is top - TypeUseLocation[] conditionalSinkLocs = { TypeUseLocation.RECEIVER, TypeUseLocation.PARAMETER, - TypeUseLocation.EXCEPTION_PARAMETER }; + TypeUseLocation[] conditionalSinkLocs = { + TypeUseLocation.RECEIVER, TypeUseLocation.PARAMETER, TypeUseLocation.EXCEPTION_PARAMETER + }; defaults.addCheckedCodeDefaults(ANYSOURCE, conditionalSinkLocs); defaults.addCheckedCodeDefaults(NOSINK, conditionalSinkLocs); // Default for returns and fields is {}->ANY (bottom) - TypeUseLocation[] bottomLocs = { TypeUseLocation.RETURN, TypeUseLocation.FIELD }; + TypeUseLocation[] bottomLocs = {TypeUseLocation.RETURN, TypeUseLocation.FIELD}; defaults.addCheckedCodeDefaults(NOSOURCE, bottomLocs); defaults.addCheckedCodeDefaults(ANYSINK, bottomLocs); @@ -229,8 +233,8 @@ protected void addCheckedCodeDefaults(QualifierDefaults defaults) { } @Override - protected void addComputedTypeAnnotations(Tree tree, AnnotatedTypeMirror type, - boolean useFlow) { + protected void addComputedTypeAnnotations( + Tree tree, AnnotatedTypeMirror type, boolean useFlow) { Element element = TreeUtils.elementFromTree(tree); handleDefaulting(element, type); super.addComputedTypeAnnotations(tree, type, useFlow); @@ -243,8 +247,7 @@ public void addComputedTypeAnnotations(Element element, AnnotatedTypeMirror type } protected void handleDefaulting(final Element element, final AnnotatedTypeMirror type) { - if (element == null) - return; + if (element == null) return; handlePolyFlow(element, type); if (isFromByteCode(element) @@ -281,8 +284,7 @@ private void handlePolyFlow(Element element, AnnotatedTypeMirror type) { } if (iter instanceof PackageElement) { - iter = ElementUtils.parentPackage((PackageElement) iter, - this.elements); + iter = ElementUtils.parentPackage((PackageElement) iter, this.elements); } else { iter = iter.getEnclosingElement(); } @@ -297,17 +299,14 @@ protected QualifierHierarchy createQualifierHierarchy() { protected class FlowQualifierHierarchy extends ElementQualifierHierarchy { public FlowQualifierHierarchy( - Collection> qualifierClasses, - Elements elements - ) { + Collection> qualifierClasses, Elements elements) { super(qualifierClasses, elements, SimpleFlowAnnotatedTypeFactory.this); } @Override public AnnotationMirrorSet getTopAnnotations() { - return AnnotationMirrorSet.singleton(checker instanceof IFlowSinkChecker ? - NOSINK : - ANYSOURCE); + return AnnotationMirrorSet.singleton( + checker instanceof IFlowSinkChecker ? NOSINK : ANYSOURCE); } @Override @@ -321,9 +320,8 @@ public AnnotationMirror getTopAnnotation(AnnotationMirror start) { @Override public AnnotationMirrorSet getBottomAnnotations() { - return AnnotationMirrorSet.singleton(checker instanceof IFlowSinkChecker ? - ANYSINK : - NOSOURCE); + return AnnotationMirrorSet.singleton( + checker instanceof IFlowSinkChecker ? ANYSINK : NOSOURCE); } @Override @@ -336,7 +334,8 @@ public AnnotationMirror getBottomAnnotation(AnnotationMirror start) { } @Override - public @Nullable AnnotationMirror leastUpperBoundQualifiers(AnnotationMirror a1, AnnotationMirror a2) { + public @Nullable AnnotationMirror leastUpperBoundQualifiers( + AnnotationMirror a1, AnnotationMirror a2) { if (!AnnotationUtils.areSameByName(getTopAnnotation(a1), getTopAnnotation(a2))) { return null; } else if (isSubtypeQualifiersOnly(a1, a2)) { @@ -347,19 +346,22 @@ public AnnotationMirror getBottomAnnotation(AnnotationMirror start) { // Since the two annotations are same by name, they are both source qualifier. Set lubPermissions = getSources(a1); lubPermissions.addAll(getSources(a2)); - return buildAnnotationMirrorFlowPermission(Source.class, toPermissionArray(lubPermissions)); + return buildAnnotationMirrorFlowPermission( + Source.class, toPermissionArray(lubPermissions)); } else { // Since the two annotations are same by name, they are both sink qualifier. assert isSinkQualifier(a1); Set lubPermissions = getSinks(a1); lubPermissions.retainAll(getSinks(a2)); - return buildAnnotationMirrorFlowPermission(Sink.class, toPermissionArray(lubPermissions)); + return buildAnnotationMirrorFlowPermission( + Sink.class, toPermissionArray(lubPermissions)); } } @Override - public @Nullable AnnotationMirror greatestLowerBoundQualifiers(AnnotationMirror a1, AnnotationMirror a2) { + public @Nullable AnnotationMirror greatestLowerBoundQualifiers( + AnnotationMirror a1, AnnotationMirror a2) { if (!AnnotationUtils.areSameByName(getTopAnnotation(a1), getTopAnnotation(a2))) { return null; } else if (isSubtypeQualifiersOnly(a1, a2)) { @@ -370,14 +372,16 @@ public AnnotationMirror getBottomAnnotation(AnnotationMirror start) { // Since the two annotations are same by name, they are both source qualifier. Set glbPermissions = getSources(a1); glbPermissions.retainAll(getSources(a2)); - return buildAnnotationMirrorFlowPermission(Source.class, toPermissionArray(glbPermissions)); + return buildAnnotationMirrorFlowPermission( + Source.class, toPermissionArray(glbPermissions)); } else { // Since the two annotations are same by name, they are both sink qualifier. assert isSinkQualifier(a1); Set glbPermissions = getSinks(a1); glbPermissions.addAll(getSinks(a2)); - return buildAnnotationMirrorFlowPermission(Sink.class, toPermissionArray(glbPermissions)); + return buildAnnotationMirrorFlowPermission( + Sink.class, toPermissionArray(glbPermissions)); } } @@ -432,8 +436,7 @@ private boolean isSuperSet(Set superset, Set subset) } private boolean isSourceQualifier(AnnotationMirror anno) { - return IFlowUtils.isSource(anno) - || isPolySourceQualifier(anno); + return IFlowUtils.isSource(anno) || isPolySourceQualifier(anno); } private boolean isPolySourceQualifier(AnnotationMirror anno) { diff --git a/src/sparta/checkers/iflow/util/IFlowUtils.java b/src/sparta/checkers/iflow/util/IFlowUtils.java index a47ba6b13..022f1f16e 100644 --- a/src/sparta/checkers/iflow/util/IFlowUtils.java +++ b/src/sparta/checkers/iflow/util/IFlowUtils.java @@ -3,6 +3,7 @@ import org.checkerframework.framework.type.AnnotatedTypeMirror; import org.checkerframework.javacutil.AnnotationBuilder; import org.checkerframework.javacutil.AnnotationUtils; +import org.checkerframework.javacutil.TreeUtils; import java.util.ArrayList; import java.util.Arrays; @@ -15,9 +16,7 @@ import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.ExecutableElement; -import org.checkerframework.javacutil.TreeUtils; import sparta.checkers.qual.FlowPermission; -import sparta.checkers.qual.PolyFlow; import sparta.checkers.qual.PolySink; import sparta.checkers.qual.PolySource; import sparta.checkers.qual.Sink; @@ -75,7 +74,8 @@ public Set getSinks(final AnnotationMirror am) { } public List getRawSinks(final AnnotationMirror am) { - return AnnotationUtils.getElementValueArray(am, sinkValueElement, String.class, Collections.emptyList()); + return AnnotationUtils.getElementValueArray( + am, sinkValueElement, String.class, Collections.emptyList()); } public Set getSources(final AnnotationMirror am) { @@ -93,17 +93,19 @@ public Set getSources(final AnnotationMirror am) { } public List getRawSources(final AnnotationMirror am) { - return AnnotationUtils.getElementValueArray(am, sourceValueElement, String.class, Collections.emptyList()); + return AnnotationUtils.getElementValueArray( + am, sourceValueElement, String.class, Collections.emptyList()); } /** * Replace ANY with the list of all possible sinks + * * @param sinks * @param inPlace * @return */ - private static Set convertAnyToAllSinks(final Set sinks, - boolean inPlace) { + private static Set convertAnyToAllSinks( + final Set sinks, boolean inPlace) { final Set retSet = (inPlace) ? sinks : new TreeSet(sinks); if (sinks.contains(ANY)) { retSet.addAll(getSetOfAllSinks()); @@ -114,14 +116,14 @@ private static Set convertAnyToAllSinks(final Set si /** * Replace ANY with the list of all possible sources + * * @param sources * @param inPlace * @return */ - private static Set convertAnytoAllSources(final Set sources, - boolean inPlace) { - final Set retSet = (inPlace) ? sources : new TreeSet( - sources); + private static Set convertAnytoAllSources( + final Set sources, boolean inPlace) { + final Set retSet = (inPlace) ? sources : new TreeSet(sources); if (sources.contains(ANY)) { retSet.addAll(getSetOfAllSinks()); retSet.remove(ANY); @@ -130,8 +132,9 @@ private static Set convertAnytoAllSources(final Set } /** - * All possible sources, excluding ANY - * TODO: This returns all sources and sinks, not just sources...fix this + * All possible sources, excluding ANY TODO: This returns all sources and sinks, not just + * sources...fix this + * * @return */ public static Set getSetOfAllSources() { @@ -145,17 +148,18 @@ public static Set getSetOfAllSources() { } return setOfAllSources; } + static Set setOfAllSources = new TreeSet<>(); /** - * All possible sinks, excluding ANY - * TODO: This returns all sources and sinks, not just sinks...fix this + * All possible sinks, excluding ANY TODO: This returns all sources and sinks, not just + * sinks...fix this + * * @return */ public static Set getSetOfAllSinks() { if (setOfAllSinks.isEmpty()) { - List coarseFlowList = Arrays.asList(FlowPermission - .values()); + List coarseFlowList = Arrays.asList(FlowPermission.values()); for (FlowPermission permission : coarseFlowList) { if (permission != FlowPermission.ANY) { setOfAllSinks.add(new PFPermission(permission)); @@ -167,16 +171,16 @@ public static Set getSetOfAllSinks() { static Set setOfAllSinks = new TreeSet<>(); - /** - * If sources contains all possible sources, then return ANY. - * If sources contains ANY and some other sources, then return ANY + * If sources contains all possible sources, then return ANY. If sources contains ANY and some + * other sources, then return ANY + * * @param sources * @param inPlace * @return */ - public static Set convertToAnySource(final Set sources, - boolean inPlace) { + public static Set convertToAnySource( + final Set sources, boolean inPlace) { final Set retSet = (inPlace) ? sources : new TreeSet(sources); if (retSet.equals(getSetOfAllSources())) { retSet.clear(); @@ -189,15 +193,17 @@ public static Set convertToAnySource(final Set sourc } /** - * If sinks contains all possible sinks, then return ANY. - * If sinks contains ANY and some other sinks, then return ANY + * If sinks contains all possible sinks, then return ANY. If sinks contains ANY and some other + * sinks, then return ANY + * * @param sinks * @param inPlace * @return either {ANY} or sinks */ - public static Set convertToAnySink(final Set sinks, boolean inPlace) { + public static Set convertToAnySink( + final Set sinks, boolean inPlace) { final Set retSet = (inPlace) ? sinks : new TreeSet(sinks); - if(sinks.equals(getSetOfAllSinks())) { + if (sinks.equals(getSetOfAllSinks())) { retSet.clear(); retSet.add(ANY); } else if (retSet.contains(ANY)) { @@ -218,9 +224,11 @@ public boolean isBottom(AnnotatedTypeMirror atm) { Set sinks = getSinks(atm); return sinks.contains(ANY) && sources.isEmpty(); } + /** - * Return the set of sources that both annotations have. - * If the intersection is all possible sources, {ANY} is returned + * Return the set of sources that both annotations have. If the intersection is all possible + * sources, {ANY} is returned + * * @param a1 AnnotationMirror, could be {ANY} * @param a2 AnnotationMirror, could be {ANY} * @return intersection of a1 and a2 @@ -229,51 +237,53 @@ public Set intersectSources(AnnotationMirror a1, AnnotationMirror final Set a1Set = getSources(a1); final Set a2Set = getSources(a2); return intersectSources(a1Set, a2Set); - - } - public static Set intersectSources(Set a1Set, - Set a2Set) { - if(a1Set == null || a2Set == null) return new TreeSet<>(); - Set retSet = new TreeSet(); - Set a1All = convertAnytoAllSources(a1Set, false); - Set a2All = convertAnytoAllSources(a2Set, false); - for (PFPermission a1permission : a1All) { - for (PFPermission a2permission : a2All) { - // Match permission and match all parameters such that a2 is subsumed in a1 - if (a1permission.getPermission() == a2permission.getPermission() && - allParametersMatch(a1permission.getParameters(), a2permission.getParameters())) { - retSet.add(a2permission); - } - } - } - return convertToAnySource(retSet, false); } - + public static Set intersectSources( + Set a1Set, Set a2Set) { + if (a1Set == null || a2Set == null) return new TreeSet<>(); + Set retSet = new TreeSet(); + Set a1All = convertAnytoAllSources(a1Set, false); + Set a2All = convertAnytoAllSources(a2Set, false); + for (PFPermission a1permission : a1All) { + for (PFPermission a2permission : a2All) { + // Match permission and match all parameters such that a2 is subsumed in a1 + if (a1permission.getPermission() == a2permission.getPermission() + && allParametersMatch( + a1permission.getParameters(), a2permission.getParameters())) { + retSet.add(a2permission); + } + } + } + return convertToAnySource(retSet, false); + } /** - * Return the set of sinks that both annotations have. - * If the intersection is all possible sinks, {ANY} is returned + * Return the set of sinks that both annotations have. If the intersection is all possible + * sinks, {ANY} is returned + * * @param a1 AnnotationMirror, could be {ANY} * @param a2 AnnotationMirror, could be {ANY} * @return intersection of a1 and a2 */ - public Set intersectSinks(AnnotationMirror a1, AnnotationMirror a2){ + public Set intersectSinks(AnnotationMirror a1, AnnotationMirror a2) { final Set a1Set = getSinks(a1); final Set a2Set = getSinks(a2); return intersectSinks(a1Set, a2Set); } - public static Set intersectSinks(Set a1Set, - Set a2Set) { - if(a1Set == null || a2Set == null) return new TreeSet<>(); + + public static Set intersectSinks( + Set a1Set, Set a2Set) { + if (a1Set == null || a2Set == null) return new TreeSet<>(); Set retSet = new TreeSet(); a1Set = convertAnyToAllSinks(a1Set, false); a2Set = convertAnyToAllSinks(a2Set, false); for (PFPermission a1permission : a1Set) { for (PFPermission a2permission : a2Set) { // Match permission and match all parameters such that a2 is subsumed in a1 - if (a1permission.getPermission() == a2permission.getPermission() && - allParametersMatch(a2permission.getParameters(), a1permission.getParameters())) { + if (a1permission.getPermission() == a2permission.getPermission() + && allParametersMatch( + a2permission.getParameters(), a1permission.getParameters())) { retSet.add(a2permission); } } @@ -282,46 +292,48 @@ public static Set intersectSinks(Set a1Set, } /** - * Returns the union of a1 and a2. - * If the union is {ANY, ...} then just {ANY} is returned + * Returns the union of a1 and a2. If the union is {ANY, ...} then just {ANY} is returned + * * @param a1 * @param a2 * @return */ - public Set unionSources(AnnotationMirror a1, AnnotationMirror a2){ + public Set unionSources(AnnotationMirror a1, AnnotationMirror a2) { return unionSources(getSources(a1), getSources(a2)); } - public static Set unionSources(Set a1, Set a2){ + + public static Set unionSources(Set a1, Set a2) { a1.addAll(a2); convertToAnySource(a1, true); return a1; } - /** - * Returns the union of a1 and a2. - * If the union is {ANY, ...} then just {ANY} is returned + * Returns the union of a1 and a2. If the union is {ANY, ...} then just {ANY} is returned + * * @param a1 * @param a2 * @return */ - public Set unionSinks(AnnotationMirror a1, AnnotationMirror a2){ + public Set unionSinks(AnnotationMirror a1, AnnotationMirror a2) { return unionSinks(getSinks(a1), getSinks(a2)); } + /** - * Returns the union of a1 and a2. - * If the union is {ANY, ...} then just {ANY} is returned + * Returns the union of a1 and a2. If the union is {ANY, ...} then just {ANY} is returned + * * @param a1 * @param a2 * @return */ - public static Set unionSinks(Set a1, Set a2){ + public static Set unionSinks(Set a1, Set a2) { a1.addAll(a2); convertToAnySink(a1, true); return a1; } - public static Set convertToParameterizedFlowPermission(Set permissions) { + public static Set convertToParameterizedFlowPermission( + Set permissions) { Set flowPermissions = new TreeSet(); for (FlowPermission p : permissions) { flowPermissions.add(new PFPermission(p)); @@ -329,7 +341,8 @@ public static Set convertToParameterizedFlowPermission(Set convertFromParameterizedFlowPermission(Set permissions) { + public static Set convertFromParameterizedFlowPermission( + Set permissions) { Set coarsePermissions = new TreeSet(); for (PFPermission p : permissions) { coarsePermissions.add(p.getPermission()); @@ -371,17 +384,15 @@ public static boolean wildcardMatch(String child, String parent) { return child.matches(regex); } - public static AnnotationMirror createAnnoFromSink(final Set sinks, - ProcessingEnvironment processingEnv) { - final AnnotationBuilder builder = new AnnotationBuilder(processingEnv, - Sink.class); + public static AnnotationMirror createAnnoFromSink( + final Set sinks, ProcessingEnvironment processingEnv) { + final AnnotationBuilder builder = new AnnotationBuilder(processingEnv, Sink.class); return createIFlowAnnotation(sinks, builder); } - public static AnnotationMirror createAnnoFromSource(Set sources, - ProcessingEnvironment processingEnv) { - final AnnotationBuilder builder = new AnnotationBuilder(processingEnv, - Source.class); + public static AnnotationMirror createAnnoFromSource( + Set sources, ProcessingEnvironment processingEnv) { + final AnnotationBuilder builder = new AnnotationBuilder(processingEnv, Source.class); return createIFlowAnnotation(sources, builder); } diff --git a/src/sparta/checkers/iflow/util/PFPermission.java b/src/sparta/checkers/iflow/util/PFPermission.java index 189623e3f..8f9693502 100644 --- a/src/sparta/checkers/iflow/util/PFPermission.java +++ b/src/sparta/checkers/iflow/util/PFPermission.java @@ -10,22 +10,21 @@ import sparta.checkers.qual.FlowPermission; public class PFPermission implements Comparable { - public static final Pattern PARAMETERIZED_PERMISSION_REGEX = Pattern.compile("([A-Z_]*)[(](.*)[)]"); + public static final Pattern PARAMETERIZED_PERMISSION_REGEX = + Pattern.compile("([A-Z_]*)[(](.*)[)]"); - public static final PFPermission ANY = new PFPermission( - FlowPermission.ANY); + public static final PFPermission ANY = new PFPermission(FlowPermission.ANY); private final FlowPermission permission; private final List parameters; public PFPermission(FlowPermission permission) { - this( permission, new ArrayList()); + this(permission, new ArrayList()); } - public PFPermission(FlowPermission permission, List parameters) { this.permission = permission; this.parameters = parameters; - if(parameters.isEmpty()) { + if (parameters.isEmpty()) { this.parameters.add("*"); } Collections.sort(this.parameters); @@ -39,7 +38,6 @@ public List getParameters() { return Collections.unmodifiableList(parameters); } - @Override public String toString() { // Easy case, not parameterized @@ -63,36 +61,27 @@ public String toString() { public int hashCode() { final int prime = 31; int result = 1; - result = prime * result - + ((parameters == null) ? 0 : parameters.hashCode()); - result = prime * result - + ((permission == null) ? 0 : permission.hashCode()); + result = prime * result + ((parameters == null) ? 0 : parameters.hashCode()); + result = prime * result + ((permission == null) ? 0 : permission.hashCode()); return result; } @Override public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; PFPermission other = (PFPermission) obj; if (parameters == null) { - if (other.parameters != null) - return false; - } else if (!parameters.equals(other.parameters)) - return false; - if (permission != other.permission) - return false; + if (other.parameters != null) return false; + } else if (!parameters.equals(other.parameters)) return false; + if (permission != other.permission) return false; return true; } /** - * {@inheritDoc} - * null first, then by FlowPermission, then by size of - * parameters, then by String compare of sorted parameters. + * {@inheritDoc} null first, then by FlowPermission, then by size of parameters, then by String + * compare of sorted parameters. */ @Override public int compareTo(PFPermission other) { @@ -100,8 +89,7 @@ public int compareTo(PFPermission other) { return 1; } if (this.permission != other.permission) { - return this.permission.toString().compareTo( - other.permission.toString()); + return this.permission.toString().compareTo(other.permission.toString()); } if (this.parameters.size() != other.parameters.size()) { return this.parameters.size() - other.parameters.size(); @@ -118,9 +106,10 @@ public int compareTo(PFPermission other) { } // TODO: Ask where this method belongs. Static method in another class? - static public boolean coarsePermissionExists(PFPermission target, Set permissions) { + public static boolean coarsePermissionExists( + PFPermission target, Set permissions) { for (PFPermission permission : permissions) { - if (permission.equals(target) ) { + if (permission.equals(target)) { return true; } } @@ -131,12 +120,10 @@ public boolean isSink() { return getPermission().isSink(); } - public void removeStar() { this.parameters.remove("*"); } - public void addParameters(List params) { this.parameters.addAll(params); } @@ -151,13 +138,12 @@ public static boolean isValidPFPermission(String perm) { } return false; } + /** - * Must call isValidPFPermission first. - * Takes a string of the form PERMISSION(param1, param2) and returns - * the corresponding PFPermission object. - * PERMISSION - * PERMISSION("param1") - * Parameters cannot contain quotes or commas + * Must call isValidPFPermission first. Takes a string of the form PERMISSION(param1, param2) + * and returns the corresponding PFPermission object. PERMISSION PERMISSION("param1") Parameters + * cannot contain quotes or commas + * * @param pfpString * @return */ @@ -178,11 +164,9 @@ public static PFPermission convertStringToPFPermission(String pfpString) { } } - FlowPermission fPermission = FlowPermission - .getFlowPermission(pfpString); + FlowPermission fPermission = FlowPermission.getFlowPermission(pfpString); if (fPermission != null) { - return new PFPermission(FlowPermission.valueOf(pfpString), - formattedParams); + return new PFPermission(FlowPermission.valueOf(pfpString), formattedParams); } else { // Shouldn't get here, because isValidPermission should be called first. return null; diff --git a/src/sparta/checkers/propagation/IFlowSinkSolver.java b/src/sparta/checkers/propagation/IFlowSinkSolver.java index a68c651e7..2bc59c30e 100644 --- a/src/sparta/checkers/propagation/IFlowSinkSolver.java +++ b/src/sparta/checkers/propagation/IFlowSinkSolver.java @@ -3,8 +3,7 @@ /** * Solver class for solving @Sink annotations. * - * This is its own class so that is can be referenced from the command line. - * + *

    This is its own class so that is can be referenced from the command line. */ public class IFlowSinkSolver extends IFlowSolver { diff --git a/src/sparta/checkers/propagation/IFlowSolver.java b/src/sparta/checkers/propagation/IFlowSolver.java index f4193c60f..facf67903 100644 --- a/src/sparta/checkers/propagation/IFlowSolver.java +++ b/src/sparta/checkers/propagation/IFlowSolver.java @@ -1,8 +1,5 @@ package sparta.checkers.propagation; -import checkers.inference.DefaultInferenceResult; -import checkers.inference.InferenceResult; -import checkers.inference.model.VariableSlot; import org.checkerframework.framework.type.QualifierHierarchy; import org.checkerframework.javacutil.AnnotationBuilder; @@ -22,6 +19,8 @@ import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.ExecutableElement; +import checkers.inference.DefaultInferenceResult; +import checkers.inference.InferenceResult; import checkers.inference.InferenceSolver; import checkers.inference.model.ConstantSlot; import checkers.inference.model.Constraint; @@ -29,31 +28,30 @@ import checkers.inference.model.Slot; import checkers.inference.model.Slot.Kind; import checkers.inference.model.SubtypeConstraint; +import checkers.inference.model.VariableSlot; import sparta.checkers.qual.Sink; import sparta.checkers.qual.Source; /** * Solver for solving Strings for @Source and @Sink annotations. * - * This solver finds the Set of Strings that a VariableSlot should have. - * There is both a sink solving mode and a source solving mode. + *

    This solver finds the Set of Strings that a VariableSlot should have. There is both a sink + * solving mode and a source solving mode. * - * For sink solving, subtype constraints cause all of the annotations from the LHS to be added to the RHS. - * For example: - * @Sink(INTERNET) String a = b; - * The inferred sinks for b should now include INTERNET. + *

    For sink solving, subtype constraints cause all of the annotations from the LHS to be added to + * the RHS. For example: @Sink(INTERNET) String a = b; The inferred sinks for b should now include + * INTERNET. * - * For source solving, subtype constraints cause all of the annotations from the RHS to be added to the LHS. - * @Source(INTERNET) String a; - * b = a; - * The inferred sources for b should now include INTERNET. + *

    For source solving, subtype constraints cause all of the annotations from the RHS to be added + * to the LHS. @Source(INTERNET) String a; b = a; The inferred sources for b should now include + * INTERNET. * - * For both modes, an equality constraint causes the Sets for both involved Slots - * to be equal and include all Strings from either set. + *

    For both modes, an equality constraint causes the Sets for both involved Slots to be equal and + * include all Strings from either set. * - * The algorithm processes list of constraints, adding the Strings to the inferredValues - * map as needed. The entire list of constraints is processed repeatedly until the inferredValues map - * no longer changes. + *

    The algorithm processes list of constraints, adding the Strings to the inferredValues map as + * needed. The entire list of constraints is processed repeatedly until the inferredValues map no + * longer changes. * * @author mcarthur */ @@ -61,15 +59,13 @@ public abstract class IFlowSolver implements InferenceSolver { private static final Logger logger = Logger.getLogger(Logger.class.getName()); - private static final String PRINT_EMPTY_SINKS_KEY="print-empty-sinks"; - private static final String PRINT_EMPTY_SOURCES_KEY="print-empty-sources"; + private static final String PRINT_EMPTY_SINKS_KEY = "print-empty-sinks"; + private static final String PRINT_EMPTY_SOURCES_KEY = "print-empty-sources"; private ProcessingEnvironment processingEnvironment; private Map configuration; - /** - * Map of inferred Strings for an VariableSlot's id. - */ + /** Map of inferred Strings for an VariableSlot's id. */ private final Map> inferredValues = new HashMap<>(); // private final Map> flowPolicy = new HashMap<>(); @@ -92,8 +88,8 @@ public InferenceResult solve( for (Constraint constraint : constraints) { if (constraint instanceof SubtypeConstraint) { - Slot subtype = ((SubtypeConstraint)constraint).getSubtype(); - Slot supertype = ((SubtypeConstraint)constraint).getSupertype(); + Slot subtype = ((SubtypeConstraint) constraint).getSubtype(); + Slot supertype = ((SubtypeConstraint) constraint).getSupertype(); Set subtypePerms = getInferredSlotPermissions(subtype); Set supertypePerms = getInferredSlotPermissions(supertype); @@ -108,8 +104,8 @@ public InferenceResult solve( } } } else if (constraint instanceof EqualityConstraint) { - Slot first = ((EqualityConstraint)constraint).getFirst(); - Slot second = ((EqualityConstraint)constraint).getSecond(); + Slot first = ((EqualityConstraint) constraint).getFirst(); + Slot second = ((EqualityConstraint) constraint).getSecond(); Set firstPerms = getInferredSlotPermissions(first); Set secondPerms = getInferredSlotPermissions(second); @@ -141,12 +137,15 @@ private Map createAnnotations() { strings.remove("ANY"); AnnotationMirror atm; if (isSinkSolver()) { - if (strings.size() == 0 && "false".equalsIgnoreCase(configuration.get(PRINT_EMPTY_SINKS_KEY))) { + if (strings.size() == 0 + && "false".equalsIgnoreCase(configuration.get(PRINT_EMPTY_SINKS_KEY))) { continue; } atm = createAnnotationMirror(strings, Sink.class); } else { - if (strings.size() == 0 && "false".equalsIgnoreCase(configuration.get(PRINT_EMPTY_SOURCES_KEY))) { + if (strings.size() == 0 + && "false" + .equalsIgnoreCase(configuration.get(PRINT_EMPTY_SOURCES_KEY))) { continue; } atm = createAnnotationMirror(strings, Source.class); @@ -157,14 +156,13 @@ private Map createAnnotations() { return solutions; } - /** * Look up the set of inferred Strings for a Slot. * - * If the Slot is a VariableSlot, return its entry in inferredValues. + *

    If the Slot is a VariableSlot, return its entry in inferredValues. * - * If the Slot is a ConstantSlot, return an unmodifiable set based - * on the Strings used in the constant slots value. + *

    If the Slot is a ConstantSlot, return an unmodifiable set based on the Strings used in the + * constant slots value. * * @param slot The slot to lookup * @return The slots current Set of Strings. @@ -184,7 +182,8 @@ private Set getInferredSlotPermissions(Slot slot) { List values = (List) entry.getValue().getValue(); for (Object elem : values) { String flowPermString = elem.toString(); - flowPermString = flowPermString.substring(flowPermString.lastIndexOf(".") + 1); + flowPermString = + flowPermString.substring(flowPermString.lastIndexOf(".") + 1); flowPermString = flowPermString.replace("\"", ""); constantSet.add(String.valueOf(flowPermString).intern()); } @@ -194,19 +193,21 @@ private Set getInferredSlotPermissions(Slot slot) { return Collections.unmodifiableSet(constantSet); } else { return new HashSet<>(); -// throw new BugInCF("Found slot that was neither a variable or a constant: " + slot); + // throw new BugInCF("Found slot that was neither a variable or a constant: " + // + slot); } } - private AnnotationMirror createAnnotationMirror(Set strings, Class clazz) { - AnnotationBuilder builder = new AnnotationBuilder( processingEnvironment, clazz); + private AnnotationMirror createAnnotationMirror( + Set strings, Class clazz) { + AnnotationBuilder builder = new AnnotationBuilder(processingEnvironment, clazz); builder.setValue("value", strings.toArray()); return builder.build(); } /** - * Get the Set of Strings in aggregatedValues map for the given id. - * Create the Set and add it to the map if it does not already exist. + * Get the Set of Strings in aggregatedValues map for the given id. Create the Set and add it to + * the map if it does not already exist. * * @param id The id of the VariableSlot * @return The set of Strings for the id diff --git a/src/sparta/checkers/propagation/IFlowSourceSolver.java b/src/sparta/checkers/propagation/IFlowSourceSolver.java index b5bc26147..ebd62de97 100644 --- a/src/sparta/checkers/propagation/IFlowSourceSolver.java +++ b/src/sparta/checkers/propagation/IFlowSourceSolver.java @@ -3,8 +3,7 @@ /** * Solver class for solving @Source annotations. * - * This is its own class so that is can be referenced from the command line. - * + *

    This is its own class so that is can be referenced from the command line. */ public class IFlowSourceSolver extends IFlowSolver { diff --git a/src/sparta/checkers/qual/FlowPermission.java b/src/sparta/checkers/qual/FlowPermission.java index 6275a2717..ee8feb250 100644 --- a/src/sparta/checkers/qual/FlowPermission.java +++ b/src/sparta/checkers/qual/FlowPermission.java @@ -1,49 +1,46 @@ package sparta.checkers.qual; - /** * This enum contains the possible sources or sinks. * - * Most of them are exactly the Android permission used to grant access to - * sensitive system resources. The rest of them govern the access to source or - * sinks determined to be sensitive for security purposes. - * - * Each permission is either a source of sensitive information or a sensitive - * sink. Some permissions are both. Tip: you can statically import the enum - * constants so that you don't have to write FlowPermission in the annotations. - * (@Sink(EMAIL) rather than @Sink(FlowPermission.EMAIL)) import static - * sparta.org.checkerframework.framework.qual.FlowPermission.*; + *

    Most of them are exactly the Android permission used to grant access to sensitive system + * resources. The rest of them govern the access to source or sinks determined to be sensitive for + * security purposes. * + *

    Each permission is either a source of sensitive information or a sensitive sink. Some + * permissions are both. Tip: you can statically import the enum constants so that you don't have to + * write FlowPermission in the annotations. (@Sink(EMAIL) rather than @Sink(FlowPermission.EMAIL)) + * import static sparta.org.checkerframework.framework.qual.FlowPermission.*; */ public enum FlowPermission { /** - * The following is a dummy permission used as the default - * for the source and sink of an @Extra. + * The following is a dummy permission used as the default for the source and sink of an @Extra. */ EXTRA_DEFAULT(T.BOTH), /** - * This special constant is shorthand for all sources, that is, the data can - * come from any possible source. Using this constant is preferred to - * listing all constants, because it's future safe. + * This special constant is shorthand for all sources, that is, the data can come from any + * possible source. Using this constant is preferred to listing all constants, because it's + * future safe. */ ANY(T.BOTH), /** - * The following are special permissions added by SPARTA Make sure that - * whatever permission you add is not the same as any permission already - * added. + * The following are special permissions added by SPARTA Make sure that whatever permission you + * add is not the same as any permission already added. */ - - CAMERA_SETTINGS(T.BOTH), DISPLAY(T.SINK), FILESYSTEM(T.BOTH), RANDOM(T.SOURCE), READ_TIME( - T.SOURCE), // WRITE_TIME is an Android Permission, but read time - // isn't + CAMERA_SETTINGS(T.BOTH), + DISPLAY(T.SINK), + FILESYSTEM(T.BOTH), + RANDOM(T.SOURCE), + READ_TIME(T.SOURCE), // WRITE_TIME is an Android Permission, but read time + // isn't USER_INPUT(T.SOURCE), WRITE_LOGS(T.SINK), // READ_LOGS is an Android Permission, but there is no - // WRITE_LOGS + // WRITE_LOGS DATABASE(T.BOTH), // This is an Android database that could be any of the - // Content database. + // Content database. SYSTEM_PROPERTIES(T.BOTH), // This is for java.lang.System MEDIA(T.SOURCE), READ_EMAIL(T.SOURCE), @@ -54,32 +51,29 @@ public enum FlowPermission { SENSOR(T.SOURCE), // See android.hardware.Sensor PACKAGE_INFO(T.BOTH), // For data from/to android.content.pm.PackageManager - /** - * These are old sources or sinks that may or may not be of use - */ + /** These are old sources or sinks that may or may not be of use */ PHONE_NUMBER(T.SOURCE), SHARED_PREFERENCES(T.BOTH), ACCELEROMETER(T.SOURCE), /** - * The following permissions are temporary and implemented now in a simple - * way for an upcoming engagement. + * The following permissions are temporary and implemented now in a simple way for an upcoming + * engagement. */ - REFLECTION(T.BOTH), // The caller of the invoke method should have this - // permission. + // permission. INTENT(T.BOTH), BUNDLE(T.SOURCE), PROCESS_BUILDER(T.BOTH), // The ProcessBuilder variable should have this - // permission. + // permission. PARCEL(T.BOTH), SECURE_HASH(T.BOTH), // Use only for one way hashes (MD5 for example) CONTENT_PROVIDER(T.BOTH), /** - * Android Manifest.permissions (Do not add new permissions below here) I - * was mostly guessing whether the permissions should be source, sink or - * both, so feel free to change the T of the permission. -SOM + * Android Manifest.permissions (Do not add new permissions below here) I was mostly guessing + * whether the permissions should be source, sink or both, so feel free to change the T of the + * permission. -SOM */ // Allows read/write access to the "properties" table in the checkin // database, to change values that get uploaded. @@ -393,9 +387,7 @@ public enum FlowPermission { // Allows an application to write to the user dictionary. WRITE_USER_DICTIONARY(T.SINK), - /** - * SuSi Sources and Sinks - */ + /** SuSi Sources and Sinks */ SUSI_UNIQUE_IDENTIFIER(T.SOURCE), SUSI_LOCATION_INFORMATION(T.BOTH), SUSI_NETWORK_INFORMATION(T.SOURCE), @@ -423,101 +415,102 @@ public enum FlowPermission { SUSI_FILE(T.SINK), SUSI_LOG(T.SINK), - /** - * Old Source or Sink These are the names of previous sinks and sources. - * They are the names of permissions that have been truncated - */ - /* - NETWORK (T.BOTH), now INTERNET - TIME (T.SOURCE), now READ_TIME or SET_TIME - SERIAL_NUMBER (T.SOURCE), now READ_PHONE_STATE - IMEI (T.SOURCE), now READ_PHONE_STATE - MICROPHONE (T.SOURCE), now RECORD_AUDIO - APP_TOKENS (T.UNKNOWN), now MANAGE_APP_TOKENS - AUDIO_SETTINGS (T.UNKNOWN), now MODIFY_AUDIO_SETTINGS - AUDIO (T.UNKNOWN), now RECORD_AUDIO - BOOT_COMPLETED (T.UNKNOWN), now RECEIVE_BOOT_COMPLETED - CALENDAR (T.UNKNOWN), now WRITE_CALENDAR or READ_CALENDAR - CALL_LOG (T.UNKNOWN), now READ_CALL_LOG or WRITE_CALL_LOG - CHECKIN_PROPERTIES (T.UNKNOWN), now ACCESS_CHECKIN_PROPERTIES - COARSE_LOCATION (T.UNKNOWN), now ACCESS_COARSE_LOCATION - CONTACTS (T.UNKNOWN), now READ_CONTACTS or WRITE_CONTACTS - CREDENTIALS (T.UNKNOWN), now USE_CREDENTIALS - EXTERNAL_STORAGE (T.UNKNOWN), now READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE - FINE_LOCATION (T.UNKNOWN), now ACCESS_FINE_LOCATION - FRAME_BUFFER (T.UNKNOWN), now READ_FRAME_BUFFER - HISTORY_BOOKMARKS (T.UNKNOWN), now READ_HISTORY_BOOKMARKS - INPUT_STATE (T.UNKNOWN), now READ_INPUT_STATE - LOCATION_EXTRA_COMMANDS (T.UNKNOWN), now ACCESS_LOCATION_EXTRA_COMMANDS - LOCATION (T.UNKNOWN), now ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION +/** + * Old Source or Sink These are the names of previous sinks and sources. They are the names of + * permissions that have been truncated + */ +/* + NETWORK (T.BOTH), now INTERNET + TIME (T.SOURCE), now READ_TIME or SET_TIME + SERIAL_NUMBER (T.SOURCE), now READ_PHONE_STATE + IMEI (T.SOURCE), now READ_PHONE_STATE + MICROPHONE (T.SOURCE), now RECORD_AUDIO + APP_TOKENS (T.UNKNOWN), now MANAGE_APP_TOKENS + AUDIO_SETTINGS (T.UNKNOWN), now MODIFY_AUDIO_SETTINGS + AUDIO (T.UNKNOWN), now RECORD_AUDIO + BOOT_COMPLETED (T.UNKNOWN), now RECEIVE_BOOT_COMPLETED + CALENDAR (T.UNKNOWN), now WRITE_CALENDAR or READ_CALENDAR + CALL_LOG (T.UNKNOWN), now READ_CALL_LOG or WRITE_CALL_LOG + CHECKIN_PROPERTIES (T.UNKNOWN), now ACCESS_CHECKIN_PROPERTIES + COARSE_LOCATION (T.UNKNOWN), now ACCESS_COARSE_LOCATION + CONTACTS (T.UNKNOWN), now READ_CONTACTS or WRITE_CONTACTS + CREDENTIALS (T.UNKNOWN), now USE_CREDENTIALS + EXTERNAL_STORAGE (T.UNKNOWN), now READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE + FINE_LOCATION (T.UNKNOWN), now ACCESS_FINE_LOCATION + FRAME_BUFFER (T.UNKNOWN), now READ_FRAME_BUFFER + HISTORY_BOOKMARKS (T.UNKNOWN), now READ_HISTORY_BOOKMARKS + INPUT_STATE (T.UNKNOWN), now READ_INPUT_STATE + LOCATION_EXTRA_COMMANDS (T.UNKNOWN), now ACCESS_LOCATION_EXTRA_COMMANDS + LOCATION (T.UNKNOWN), now ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION - MMS (T.UNKNOWN), now RECEIVE_MMS - MOCK_LOCATION (T.UNKNOWN), now ACCESS_MOCK_LOCATION - NETWORK_STATE (T.UNKNOWN), now ACCESS_NETWORK_STATE or CHANGE_NETWORK_STATE - NETWORK (T.UNKNOWN), now INTERNET - OUTGOING_CALLS (T.UNKNOWN), now PROCESS_OUTGOING_CALLS - PACKAGE_SIZE (T.UNKNOWN), now GET_PACKAGE_SIZE - PACKAGES (T.UNKNOWN), now DELETE_PACKAGES or INSTALL_PACKAGES or RESTART_PACKAGES - , - PHONE_STATE (T.UNKNOWN), now MODIFY_PHONE_STATE or READ_PHONE_STATE - PROFILE (T.UNKNOWN), now READ_PROFILE or WRITE_PROFILE + MMS (T.UNKNOWN), now RECEIVE_MMS + MOCK_LOCATION (T.UNKNOWN), now ACCESS_MOCK_LOCATION + NETWORK_STATE (T.UNKNOWN), now ACCESS_NETWORK_STATE or CHANGE_NETWORK_STATE + NETWORK (T.UNKNOWN), now INTERNET + OUTGOING_CALLS (T.UNKNOWN), now PROCESS_OUTGOING_CALLS + PACKAGE_SIZE (T.UNKNOWN), now GET_PACKAGE_SIZE + PACKAGES (T.UNKNOWN), now DELETE_PACKAGES or INSTALL_PACKAGES or RESTART_PACKAGES +, + PHONE_STATE (T.UNKNOWN), now MODIFY_PHONE_STATE or READ_PHONE_STATE + PROFILE (T.UNKNOWN), now READ_PROFILE or WRITE_PROFILE - SIP (T.UNKNOWN), now USE_SIP - SMS (T.UNKNOWN), now BROADCAST_SMS or READ_SMS or WRITE_SMS or RECEIVE_SMS or SEND_SMS - SOCIAL_STREAM (T.UNKNOWN), now READ_SOCIAL_STREAM or WRITE_SOCIAL_STREAM - SUBSCRIBED_FEEDS (T.UNKNOWN), now READ_SUBSCRIBED_FEEDS or WRITE_SUBSCRIBED_FEEDS - SURFACE_FLINGER (T.UNKNOWN), now ACCESS_SURFACE_FLINGER - SYNC_SETTINGS (T.UNKNOWN), now READ_SYNC_SETTINGS or WRITE_SYNC_SETTINGS - SYNC_STATS (T.UNKNOWN), now READ_SYNC_STATS - TASKS (T.UNKNOWN), now GET_TASK or REORDER_TASKS - USER_DICTIONARY (T.UNKNOWN), now READ_USER_DICTIONARY or WRITE_USER_DICTIONARY - WAP_PUSH (T.UNKNOWN), now BROADCAST_WAP_PUSH or RECEIVE_WAP_PUSH - WIFI_STATE (T.UNKNOWN), now CHANGE_WIFI_STATE or ACCESS_WIFI_STATE + SIP (T.UNKNOWN), now USE_SIP + SMS (T.UNKNOWN), now BROADCAST_SMS or READ_SMS or WRITE_SMS or RECEIVE_SMS or SEND_SMS + SOCIAL_STREAM (T.UNKNOWN), now READ_SOCIAL_STREAM or WRITE_SOCIAL_STREAM + SUBSCRIBED_FEEDS (T.UNKNOWN), now READ_SUBSCRIBED_FEEDS or WRITE_SUBSCRIBED_FEEDS + SURFACE_FLINGER (T.UNKNOWN), now ACCESS_SURFACE_FLINGER + SYNC_SETTINGS (T.UNKNOWN), now READ_SYNC_SETTINGS or WRITE_SYNC_SETTINGS + SYNC_STATS (T.UNKNOWN), now READ_SYNC_STATS + TASKS (T.UNKNOWN), now GET_TASK or REORDER_TASKS + USER_DICTIONARY (T.UNKNOWN), now READ_USER_DICTIONARY or WRITE_USER_DICTIONARY + WAP_PUSH (T.UNKNOWN), now BROADCAST_WAP_PUSH or RECEIVE_WAP_PUSH + WIFI_STATE (T.UNKNOWN), now CHANGE_WIFI_STATE or ACCESS_WIFI_STATE - ACTIVITY_WATCHER (T.UNKNOWN), now SET_ACTIVITY_WATCHER - ALARM (T.UNKNOWN), now SET_ALARM - ALWAYS_FINISH (T.UNKNOWN), now SET_ALWAYS_FINISH - ANIMATION_SCALE (T.UNKNOWN), now SET_ANIMATION_SCALE - APN_SETTINGS (T.UNKNOWN), now WRITE_APN_SETTINGS - CACHE_FILES (T.UNKNOWN), now DELETE_CACHE_FILES - COMPONENT_ENABLED_STATE (T.UNKNOWN), now CHANGE_COMPONENT_ENABLED_STATE - CONFIGURATION (T.UNKNOWN), now CHANGE_CONFIGURATION - DEBUG_APP (T.UNKNOWN), now SET_DEBUG_APP - GSERVICES (T.UNKNOWN), now WRITE_GSERVICES - LOCATION_UPDATES (T.UNKNOWN), now CONTROL_LOCATION_UPDATES - ORIENTATION (T.UNKNOWN), now SET_ORIENATION - POINTER_SPEED (T.UNKNOWN), now SET_POINTER_SPEED - PREFERRED_APPLICATIONS (T.UNKNOWN), now SET_PREFERRED_APPLICATIONS - PROCESS_LIMIT (T.UNKNOWN), now SET_PROCESS_LIMIT - SECURE_SETTINGS (T.UNKNOWN), now WRITE_SECURE_SETTINGS - SETTINGS (T.UNKNOWN), now WRITE_SETTINGS - TIME_ZONE (T.UNKNOWN), now SET_TIME_ZONE - VOICEMAIL (T.UNKNOWN), now ADD_VOICEMAIL - WALLPAPER_HINTS (T.UNKNOWN), now WALLPAPER_HINTS - WALLPAPER (T.UNKNOWN), now BIND_WALLPAPER or SET_WALLPAPER - WIFI_MULTICAST_STATE (T.UNKNOWN), now CHANGE_WIFI_MULTICAST_STATE - */ + ACTIVITY_WATCHER (T.UNKNOWN), now SET_ACTIVITY_WATCHER + ALARM (T.UNKNOWN), now SET_ALARM + ALWAYS_FINISH (T.UNKNOWN), now SET_ALWAYS_FINISH + ANIMATION_SCALE (T.UNKNOWN), now SET_ANIMATION_SCALE + APN_SETTINGS (T.UNKNOWN), now WRITE_APN_SETTINGS + CACHE_FILES (T.UNKNOWN), now DELETE_CACHE_FILES + COMPONENT_ENABLED_STATE (T.UNKNOWN), now CHANGE_COMPONENT_ENABLED_STATE + CONFIGURATION (T.UNKNOWN), now CHANGE_CONFIGURATION + DEBUG_APP (T.UNKNOWN), now SET_DEBUG_APP + GSERVICES (T.UNKNOWN), now WRITE_GSERVICES + LOCATION_UPDATES (T.UNKNOWN), now CONTROL_LOCATION_UPDATES + ORIENTATION (T.UNKNOWN), now SET_ORIENATION + POINTER_SPEED (T.UNKNOWN), now SET_POINTER_SPEED + PREFERRED_APPLICATIONS (T.UNKNOWN), now SET_PREFERRED_APPLICATIONS + PROCESS_LIMIT (T.UNKNOWN), now SET_PROCESS_LIMIT + SECURE_SETTINGS (T.UNKNOWN), now WRITE_SECURE_SETTINGS + SETTINGS (T.UNKNOWN), now WRITE_SETTINGS + TIME_ZONE (T.UNKNOWN), now SET_TIME_ZONE + VOICEMAIL (T.UNKNOWN), now ADD_VOICEMAIL + WALLPAPER_HINTS (T.UNKNOWN), now WALLPAPER_HINTS + WALLPAPER (T.UNKNOWN), now BIND_WALLPAPER or SET_WALLPAPER + WIFI_MULTICAST_STATE (T.UNKNOWN), now CHANGE_WIFI_MULTICAST_STATE + */ - ; +; // TODO: implement checks using this. - private final T sourceOrSink; + private final T sourceOrSink; FlowPermission(T sourceOrSink) { this.sourceOrSink = sourceOrSink; } public boolean isSink() { - return (sourceOrSink == T.SINK) || sourceOrSink == T.BOTH ; + return (sourceOrSink == T.SINK) || sourceOrSink == T.BOTH; } public boolean isSource() { - return (sourceOrSink == T.SOURCE) || sourceOrSink == T.BOTH ; + return (sourceOrSink == T.SOURCE) || sourceOrSink == T.BOTH; } /** - * If the input string contains a FlowPermission, that FlowPermission is returned. - * Otherwise null is return + * If the input string contains a FlowPermission, that FlowPermission is returned. Otherwise + * null is return + * * @param input String to convert to FlowPermission * @return FlowPermission that the input string contains, or null. */ @@ -530,34 +523,25 @@ public static FlowPermission getFlowPermission(String input) { return null; } - /** - * enum used to indicate if a permission is a source, sink, both, neither. - * - */ + /** enum used to indicate if a permission is a source, sink, both, neither. */ enum T { /** - * The permission is for sure a source further investigation might show - * that is also as sink + * The permission is for sure a source further investigation might show that is also as sink */ SOURCE, /** - * The permission is for sure a sink further investigation might show - * that is also as source + * The permission is for sure a sink further investigation might show that is also as source */ SINK, - /** - * The permission is both a source and a sink TODO:refactor to - * SOURCE_SINK for clarity - */ + /** The permission is both a source and a sink TODO:refactor to SOURCE_SINK for clarity */ BOTH, /** - * The permission is neither a source nor a sink If a permission is of - * this type, it should be removed from the enum, but we might want to - * keep all of the Android Permissions that fall into this type for - * completeness + * The permission is neither a source nor a sink If a permission is of this type, it should + * be removed from the enum, but we might want to keep all of the Android Permissions that + * fall into this type for completeness */ NONE; } diff --git a/src/sparta/checkers/qual/FlowPermissionString.java b/src/sparta/checkers/qual/FlowPermissionString.java index 927a1119f..35af2ad0d 100644 --- a/src/sparta/checkers/qual/FlowPermissionString.java +++ b/src/sparta/checkers/qual/FlowPermissionString.java @@ -1,14 +1,15 @@ package sparta.checkers.qual; + /** - * This class contains constant that correspond to the FlowPermission. - * These are to be used in @Source or @Sink annotations. - * @author smillst + * This class contains constant that correspond to the FlowPermission. These are to be used + * in @Source or @Sink annotations. * + * @author smillst */ public class FlowPermissionString { public static final String EXTRA_DEFAULT = "EXTRA_DEFAULT"; public static final String ANY = "ANY"; - + public static final String CAMERA_SETTINGS = "CAMERA_SETTINGS"; public static final String DISPLAY = "DISPLAY"; public static final String FILESYSTEM = "FILESYSTEM"; @@ -29,26 +30,27 @@ public class FlowPermissionString { public static final String PHONE_NUMBER = "PHONE_NUMBER"; public static final String SHARED_PREFERENCES = "SHARED_PREFERENCES"; public static final String ACCELEROMETER = "ACCELEROMETER"; - + /** - * The following permissions are temporary and implemented now in a simple - * way for an upcoming engagement. + * The following permissions are temporary and implemented now in a simple way for an upcoming + * engagement. */ public static final String REFLECTION = "REFLECTION"; + public static final String INTENT = "INTENT"; public static final String BUNDLE = "BUNDLE"; public static final String PROCESS_BUILDER = "PROCESS_BUILDER"; public static final String PARCEL = "PARCEL"; public static final String SECURE_HASH = "SECURE_HASH"; public static final String CONTENT_PROVIDER = "CONTENT_PROVIDER"; - + /** - * Android Manifest.permissions (Do not add new permissions below here) I - * was mostly guessing whether the permissions should be source, sink or - * both, so feel free to change the T of the permission. -SOM + * Android Manifest.permissions (Do not add new permissions below here) I was mostly guessing + * whether the permissions should be source, sink or both, so feel free to change the T of the + * permission. -SOM */ - public static final String ACCESS_CHECKIN_PROPERTIES = "ACCESS_CHECKIN_PROPERTIES"; + public static final String ACCESS_COARSE_LOCATION = "ACCESS_COARSE_LOCATION"; public static final String ACCESS_FINE_LOCATION = "ACCESS_FINE_LOCATION"; public static final String ACCESS_LOCATION_EXTRA_COMMANDS = "ACCESS_LOCATION_EXTRA_COMMANDS"; @@ -205,5 +207,4 @@ public class FlowPermissionString { public static final String SUSI_NETWORK = "SUSI_NETWORK"; public static final String SUSI_FILE = "SUSI_FILE"; public static final String SUSI_LOG = "SUSI_LOG"; - } diff --git a/src/sparta/checkers/qual/PolyFlow.java b/src/sparta/checkers/qual/PolyFlow.java index 5dccb18bb..12499e4ba 100644 --- a/src/sparta/checkers/qual/PolyFlow.java +++ b/src/sparta/checkers/qual/PolyFlow.java @@ -8,14 +8,12 @@ /** * Annotation @PolyFlow expresses that each contained method should be annotated - * as @PolySource @PolySink for both the return types and all parameters. It - * should be used to express a relationship between the parameters and the - * return types. - * + * as @PolySource @PolySink for both the return types and all parameters. It should be used to + * express a relationship between the parameters and the return types. + * * @see @PolyFlowReceiver */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.TYPE, ElementType.PACKAGE}) -public @interface PolyFlow { -} +public @interface PolyFlow {} diff --git a/src/sparta/checkers/qual/PolyFlowReceiver.java b/src/sparta/checkers/qual/PolyFlowReceiver.java index af71e6b64..73952421c 100644 --- a/src/sparta/checkers/qual/PolyFlowReceiver.java +++ b/src/sparta/checkers/qual/PolyFlowReceiver.java @@ -7,14 +7,12 @@ import java.lang.annotation.Target; /** - * A declaration annotation to mark that all the parameters, the return the - * receiver as polymorphic. This is shorthand for specifying @PolySource @PolySink - * on all parameters, returns and receivers - * + * A declaration annotation to mark that all the parameters, the return the receiver as polymorphic. + * This is shorthand for specifying @PolySource @PolySink on all parameters, returns and receivers + * * @see PolyFlow */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.TYPE, ElementType.PACKAGE}) -public @interface PolyFlowReceiver { -} +public @interface PolyFlowReceiver {} diff --git a/src/sparta/checkers/qual/PolySink.java b/src/sparta/checkers/qual/PolySink.java index 71ca11187..d7c4dfbef 100644 --- a/src/sparta/checkers/qual/PolySink.java +++ b/src/sparta/checkers/qual/PolySink.java @@ -4,12 +4,9 @@ import java.lang.annotation.*; -/** - * Polymorphic qualifier for flow sinks. - */ +/** Polymorphic qualifier for flow sinks. */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) @PolymorphicQualifier(Sink.class) -public @interface PolySink { -} +public @interface PolySink {} diff --git a/src/sparta/checkers/qual/PolySource.java b/src/sparta/checkers/qual/PolySource.java index eea040bea..ad5438ba3 100644 --- a/src/sparta/checkers/qual/PolySource.java +++ b/src/sparta/checkers/qual/PolySource.java @@ -4,12 +4,9 @@ import java.lang.annotation.*; -/** - * Polymorphic qualifier for flow sources. - */ +/** Polymorphic qualifier for flow sources. */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) @PolymorphicQualifier(Source.class) -public @interface PolySource { -} +public @interface PolySource {} diff --git a/src/sparta/checkers/qual/Sink.java b/src/sparta/checkers/qual/Sink.java index f47ca20c0..1c45af676 100644 --- a/src/sparta/checkers/qual/Sink.java +++ b/src/sparta/checkers/qual/Sink.java @@ -1,16 +1,16 @@ package sparta.checkers.qual; +import org.checkerframework.framework.qual.SubtypeOf; + import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import org.checkerframework.framework.qual.SubtypeOf; - /** - * List of data flow sinks that are attached to a certain piece of data. - * FlowPermission.ANY is the bottom type. The empty set is the top type. + * List of data flow sinks that are attached to a certain piece of data. FlowPermission.ANY is the + * bottom type. The empty set is the top type. */ @Documented @Retention(RetentionPolicy.RUNTIME) @@ -19,8 +19,8 @@ public @interface Sink { /** - * By default we allow no sinks. There is always a @Sink annotation and this - * default ensures that the annotation has no effect. + * By default we allow no sinks. There is always a @Sink annotation and this default ensures + * that the annotation has no effect. */ String[] value() default {}; } diff --git a/src/sparta/checkers/qual/Source.java b/src/sparta/checkers/qual/Source.java index d37a07a28..4a34ccdd1 100644 --- a/src/sparta/checkers/qual/Source.java +++ b/src/sparta/checkers/qual/Source.java @@ -1,16 +1,16 @@ package sparta.checkers.qual; +import org.checkerframework.framework.qual.SubtypeOf; + import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import org.checkerframework.framework.qual.SubtypeOf; - /** - * List of data flow sources that are attached to a certain piece of data. - * FlowPermission.ANY is the top type. The empty set is the bottom type. + * List of data flow sources that are attached to a certain piece of data. FlowPermission.ANY is the + * top type. The empty set is the bottom type. */ @Documented @Retention(RetentionPolicy.RUNTIME) @@ -19,8 +19,8 @@ public @interface Source { /** - * By default we allow no sources. There is always a @Source annotation and - * this default ensures that the annotation has no effect. + * By default we allow no sources. There is always a @Source annotation and this default ensures + * that the annotation has no effect. */ String[] value() default {}; } diff --git a/src/sparta/checkers/sat/IFlowResult.java b/src/sparta/checkers/sat/IFlowResult.java index a8a691632..77fb6bbad 100644 --- a/src/sparta/checkers/sat/IFlowResult.java +++ b/src/sparta/checkers/sat/IFlowResult.java @@ -14,14 +14,13 @@ import checkers.inference.InferenceMain; import sparta.checkers.iflow.util.PFPermission; -/** - * Created by smillst on 9/21/15. - */ +/** Created by smillst on 9/21/15. */ public abstract class IFlowResult extends DefaultInferenceResult { protected final Map> tempResults; protected final Map idToExistance; - public IFlowResult(Collection solutions, ProcessingEnvironment processingEnv) { + public IFlowResult( + Collection solutions, ProcessingEnvironment processingEnv) { // Legacy solver doesn't support explanation super(); this.tempResults = new HashMap<>(); @@ -71,7 +70,8 @@ private void createAnnotations(ProcessingEnvironment processingEnv) { } } - protected abstract AnnotationMirror createAnnotationFromPermissions(ProcessingEnvironment processingEnv, Set permissions); + protected abstract AnnotationMirror createAnnotationFromPermissions( + ProcessingEnvironment processingEnv, Set permissions); private void mergeIdToExistance(PermissionSolution solution) { for (Map.Entry entry : solution.getResult().entrySet()) { @@ -80,7 +80,9 @@ private void mergeIdToExistance(PermissionSolution solution) { if (idToExistance.containsKey(id)) { boolean alreadyExists = idToExistance.get(id); if (alreadyExists ^ existsPermission) { - InferenceMain.getInstance().logger.log(Level.INFO, "Mismatch between existance of annotation"); + InferenceMain.getInstance() + .logger + .log(Level.INFO, "Mismatch between existance of annotation"); } } else { idToExistance.put(id, existsPermission); @@ -95,5 +97,4 @@ private void mergeIdToExistance(PermissionSolution solution) { public boolean containsSolutionForVariable(int varId) { return idToExistance.containsKey(varId); } - } diff --git a/src/sparta/checkers/sat/IFlowSerializer.java b/src/sparta/checkers/sat/IFlowSerializer.java index fab6d5e68..c5a665785 100644 --- a/src/sparta/checkers/sat/IFlowSerializer.java +++ b/src/sparta/checkers/sat/IFlowSerializer.java @@ -4,9 +4,7 @@ import checkers.inference.model.serialization.CnfVecIntSerializer; import sparta.checkers.iflow.util.PFPermission; -/** - * Created by smillst on 9/16/15. - */ +/** Created by smillst on 9/16/15. */ public abstract class IFlowSerializer extends CnfVecIntSerializer { protected PFPermission permission; diff --git a/src/sparta/checkers/sat/IFlowSolver.java b/src/sparta/checkers/sat/IFlowSolver.java index f8c9e51c3..8b5b97fe0 100644 --- a/src/sparta/checkers/sat/IFlowSolver.java +++ b/src/sparta/checkers/sat/IFlowSolver.java @@ -1,28 +1,28 @@ package sparta.checkers.sat; +import org.checkerframework.framework.type.QualifierHierarchy; + +import java.util.*; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.AnnotationMirror; + import checkers.inference.InferenceResult; import checkers.inference.InferenceSolver; import checkers.inference.model.ConstantSlot; import checkers.inference.model.Constraint; import checkers.inference.model.Slot; -import org.checkerframework.framework.type.QualifierHierarchy; import sparta.checkers.iflow.util.PFPermission; -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.AnnotationMirror; -import java.util.*; - -/** - * Created by smillst on 9/17/15. - */ +/** Created by smillst on 9/17/15. */ public abstract class IFlowSolver implements InferenceSolver { - - public InferenceResult solve(Map configuration, - Collection slots, - Collection constraints, - QualifierHierarchy qualHierarchy, - ProcessingEnvironment processingEnvironment) { + public InferenceResult solve( + Map configuration, + Collection slots, + Collection constraints, + QualifierHierarchy qualHierarchy, + ProcessingEnvironment processingEnvironment) { Collection permissionsUsed = getPermissionsUsed(slots); List permissionSolvers = new ArrayList<>(); @@ -58,8 +58,8 @@ private Collection getPermissionsUsed(Collection solts) { protected abstract IFlowSerializer getSerializer(PFPermission permission); - protected abstract InferenceResult getMergedResultFromSolutions(ProcessingEnvironment processingEnvironment, List solutions); + protected abstract InferenceResult getMergedResultFromSolutions( + ProcessingEnvironment processingEnvironment, List solutions); protected abstract Set getPermissionList(AnnotationMirror anno); - } diff --git a/src/sparta/checkers/sat/PermissionSolution.java b/src/sparta/checkers/sat/PermissionSolution.java index f678e15c4..34bfaef04 100644 --- a/src/sparta/checkers/sat/PermissionSolution.java +++ b/src/sparta/checkers/sat/PermissionSolution.java @@ -1,19 +1,20 @@ package sparta.checkers.sat; -import sparta.checkers.iflow.util.PFPermission; - import java.util.HashMap; import java.util.Map; -/** - * Created by smillst on 9/19/15. - */ +import sparta.checkers.iflow.util.PFPermission; + +/** Created by smillst on 9/19/15. */ public class PermissionSolution { Map result; Map idToExistence; PFPermission permission; - public PermissionSolution(Map result, Map idToExistence, PFPermission permission) { + public PermissionSolution( + Map result, + Map idToExistence, + PFPermission permission) { this.result = result; this.idToExistence = idToExistence; this.permission = permission; diff --git a/src/sparta/checkers/sat/PermissionSolver.java b/src/sparta/checkers/sat/PermissionSolver.java index c0ac9e9b3..5029b8725 100644 --- a/src/sparta/checkers/sat/PermissionSolver.java +++ b/src/sparta/checkers/sat/PermissionSolver.java @@ -1,16 +1,17 @@ package sparta.checkers.sat; -import checkers.inference.*; -import checkers.inference.model.Constraint; import org.sat4j.core.VecInt; import org.sat4j.maxsat.WeightedMaxSatDecorator; -import sparta.checkers.iflow.util.PFPermission; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import checkers.inference.*; +import checkers.inference.model.Constraint; +import sparta.checkers.iflow.util.PFPermission; + public class PermissionSolver { private SlotManager slotManager; @@ -37,14 +38,15 @@ public PermissionSolution solve() { Map idToExistence = new HashMap<>(); Map result = new HashMap<>(); - final int totalVars = slotManager.getNumberOfSlots(); final int totalClauses = clauses.size(); try { // **** Prep Solver **** - // org.sat4j.pb.SolverFactory.newBoth() Runs both of sat4j solves and uses the result of the first to finish - final WeightedMaxSatDecorator solver = new WeightedMaxSatDecorator(org.sat4j.pb.SolverFactory.newBoth()); + // org.sat4j.pb.SolverFactory.newBoth() Runs both of sat4j solves and uses the result of + // the first to finish + final WeightedMaxSatDecorator solver = + new WeightedMaxSatDecorator(org.sat4j.pb.SolverFactory.newBoth()); solver.newVar(totalVars); solver.setExpectedNumberOfClauses(totalClauses); @@ -60,7 +62,8 @@ public PermissionSolution solve() { if (hasSolution) { // **** Remove exatential vars from solution - final Map existentialToPotentialIds = serializer.getExistentialToPotentialVar(); + final Map existentialToPotentialIds = + serializer.getExistentialToPotentialVar(); int[] solution = solver.model(); for (Integer var : solution) { diff --git a/src/sparta/checkers/sat/SinkResult.java b/src/sparta/checkers/sat/SinkResult.java index bfced5d50..8ca5672d8 100644 --- a/src/sparta/checkers/sat/SinkResult.java +++ b/src/sparta/checkers/sat/SinkResult.java @@ -1,19 +1,19 @@ package sparta.checkers.sat; -import sparta.checkers.iflow.util.IFlowUtils; -import sparta.checkers.iflow.util.PFPermission; - -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.AnnotationMirror; import java.util.Collection; import java.util.Map; import java.util.Set; -/** - * Created by smillst on 9/21/15. - */ +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.AnnotationMirror; + +import sparta.checkers.iflow.util.IFlowUtils; +import sparta.checkers.iflow.util.PFPermission; + +/** Created by smillst on 9/21/15. */ public class SinkResult extends IFlowResult { - public SinkResult(Collection solutions, ProcessingEnvironment processingEnv) { + public SinkResult( + Collection solutions, ProcessingEnvironment processingEnv) { super(solutions, processingEnv); } @@ -24,7 +24,8 @@ protected boolean shouldContainPermission(Map.Entry entry) { } @Override - protected AnnotationMirror createAnnotationFromPermissions(ProcessingEnvironment processingEnv, Set permissions) { + protected AnnotationMirror createAnnotationFromPermissions( + ProcessingEnvironment processingEnv, Set permissions) { return IFlowUtils.createAnnoFromSink(permissions, processingEnv); } } diff --git a/src/sparta/checkers/sat/SinkSerializer.java b/src/sparta/checkers/sat/SinkSerializer.java index 5526c1c71..49e6e160e 100644 --- a/src/sparta/checkers/sat/SinkSerializer.java +++ b/src/sparta/checkers/sat/SinkSerializer.java @@ -1,25 +1,23 @@ package sparta.checkers.sat; +import java.util.Set; + +import javax.lang.model.element.AnnotationMirror; + import checkers.inference.InferenceMain; import checkers.inference.model.ConstantSlot; -import org.checkerframework.javacutil.AnnotationUtils; import sparta.checkers.iflow.util.IFlowUtils; import sparta.checkers.iflow.util.PFPermission; -import sparta.checkers.qual.PolySink; - -import javax.lang.model.element.AnnotationMirror; -import java.util.Set; -/** - * Created by smillst on 9/21/15. - */ +/** Created by smillst on 9/21/15. */ public class SinkSerializer extends IFlowSerializer { protected final IFlowUtils flowUtils; public SinkSerializer(PFPermission permission) { super(permission); - flowUtils = new IFlowUtils(InferenceMain.getInstance().getRealTypeFactory().getProcessingEnv()); + flowUtils = + new IFlowUtils(InferenceMain.getInstance().getRealTypeFactory().getProcessingEnv()); } @Override diff --git a/src/sparta/checkers/sat/SinkSolver.java b/src/sparta/checkers/sat/SinkSolver.java index 096dcfb4f..517925666 100644 --- a/src/sparta/checkers/sat/SinkSolver.java +++ b/src/sparta/checkers/sat/SinkSolver.java @@ -1,25 +1,23 @@ package sparta.checkers.sat; -import checkers.inference.InferenceResult; -import checkers.inference.model.Constraint; -import checkers.inference.model.Slot; import org.checkerframework.framework.type.QualifierHierarchy; -import org.checkerframework.javacutil.AnnotationUtils; -import sparta.checkers.iflow.util.IFlowUtils; -import sparta.checkers.iflow.util.PFPermission; -import sparta.checkers.qual.PolySink; -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.AnnotationMirror; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -/** - * Created by smillst on 9/21/15. - */ +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.AnnotationMirror; + +import checkers.inference.InferenceResult; +import checkers.inference.model.Constraint; +import checkers.inference.model.Slot; +import sparta.checkers.iflow.util.IFlowUtils; +import sparta.checkers.iflow.util.PFPermission; + +/** Created by smillst on 9/21/15. */ public class SinkSolver extends IFlowSolver { protected IFlowUtils flowUtils; @@ -30,8 +28,7 @@ public InferenceResult solve( Collection slots, Collection constraints, QualifierHierarchy qualHierarchy, - ProcessingEnvironment processingEnvironment - ) { + ProcessingEnvironment processingEnvironment) { flowUtils = new IFlowUtils(processingEnvironment); return super.solve(configuration, slots, constraints, qualHierarchy, processingEnvironment); } @@ -50,7 +47,8 @@ protected IFlowSerializer getSerializer(PFPermission permission) { } @Override - protected InferenceResult getMergedResultFromSolutions(ProcessingEnvironment processingEnvironment, List solutions) { + protected InferenceResult getMergedResultFromSolutions( + ProcessingEnvironment processingEnvironment, List solutions) { return new SinkResult(solutions, processingEnvironment); } } diff --git a/src/sparta/checkers/sat/SourceResult.java b/src/sparta/checkers/sat/SourceResult.java index 6067ec550..f23b03bf2 100644 --- a/src/sparta/checkers/sat/SourceResult.java +++ b/src/sparta/checkers/sat/SourceResult.java @@ -1,18 +1,18 @@ package sparta.checkers.sat; -import sparta.checkers.iflow.util.IFlowUtils; -import sparta.checkers.iflow.util.PFPermission; +import java.util.*; import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.AnnotationMirror; -import java.util.*; -/** - * Created by smillst on 9/21/15. - */ +import sparta.checkers.iflow.util.IFlowUtils; +import sparta.checkers.iflow.util.PFPermission; + +/** Created by smillst on 9/21/15. */ public class SourceResult extends IFlowResult { - public SourceResult(Collection solutions, ProcessingEnvironment processingEnv) { + public SourceResult( + Collection solutions, ProcessingEnvironment processingEnv) { super(solutions, processingEnv); } @@ -23,7 +23,8 @@ protected boolean shouldContainPermission(Map.Entry entry) { } @Override - protected AnnotationMirror createAnnotationFromPermissions(ProcessingEnvironment processingEnv, Set permissions) { + protected AnnotationMirror createAnnotationFromPermissions( + ProcessingEnvironment processingEnv, Set permissions) { return IFlowUtils.createAnnoFromSource(permissions, processingEnv); } } diff --git a/src/sparta/checkers/sat/SourceSerializer.java b/src/sparta/checkers/sat/SourceSerializer.java index 399365ccf..d938ca5c2 100644 --- a/src/sparta/checkers/sat/SourceSerializer.java +++ b/src/sparta/checkers/sat/SourceSerializer.java @@ -1,25 +1,23 @@ package sparta.checkers.sat; +import java.util.Set; + +import javax.lang.model.element.AnnotationMirror; + import checkers.inference.InferenceMain; import checkers.inference.model.ConstantSlot; -import org.checkerframework.javacutil.AnnotationUtils; import sparta.checkers.iflow.util.IFlowUtils; import sparta.checkers.iflow.util.PFPermission; -import sparta.checkers.qual.PolySource; - -import javax.lang.model.element.AnnotationMirror; -import java.util.Set; -/** - * Created by smillst on 9/21/15. - */ +/** Created by smillst on 9/21/15. */ public class SourceSerializer extends IFlowSerializer { protected final IFlowUtils flowUtils; public SourceSerializer(PFPermission permission) { super(permission); - flowUtils = new IFlowUtils(InferenceMain.getInstance().getRealTypeFactory().getProcessingEnv()); + flowUtils = + new IFlowUtils(InferenceMain.getInstance().getRealTypeFactory().getProcessingEnv()); } @Override @@ -30,7 +28,7 @@ public boolean isTop(ConstantSlot constantSlot) { private boolean annoHasPermission(AnnotationMirror anno) { if (IFlowUtils.isPolySource(anno)) { - return true; // Treat as top + return true; // Treat as top } Set sources = flowUtils.getSources(anno); return sources.contains(PFPermission.ANY) || sources.contains(permission); diff --git a/src/sparta/checkers/sat/SourceSolver.java b/src/sparta/checkers/sat/SourceSolver.java index a9f8ee333..865f65c0e 100644 --- a/src/sparta/checkers/sat/SourceSolver.java +++ b/src/sparta/checkers/sat/SourceSolver.java @@ -1,21 +1,19 @@ package sparta.checkers.sat; +import org.checkerframework.framework.type.QualifierHierarchy; + +import java.util.*; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.AnnotationMirror; + import checkers.inference.InferenceResult; import checkers.inference.model.Constraint; import checkers.inference.model.Slot; -import org.checkerframework.framework.type.QualifierHierarchy; -import org.checkerframework.javacutil.AnnotationUtils; import sparta.checkers.iflow.util.IFlowUtils; import sparta.checkers.iflow.util.PFPermission; -import sparta.checkers.qual.PolySource; - -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.AnnotationMirror; -import java.util.*; -/** - * Created by smillst on 9/17/15. - */ +/** Created by smillst on 9/17/15. */ public class SourceSolver extends IFlowSolver { protected IFlowUtils flowUtils; @@ -26,8 +24,7 @@ public InferenceResult solve( Collection slots, Collection constraints, QualifierHierarchy qualHierarchy, - ProcessingEnvironment processingEnvironment - ) { + ProcessingEnvironment processingEnvironment) { flowUtils = new IFlowUtils(processingEnvironment); return super.solve(configuration, slots, constraints, qualHierarchy, processingEnvironment); } @@ -44,7 +41,8 @@ protected IFlowSerializer getSerializer(PFPermission permission) { return new SourceSerializer(permission); } - protected InferenceResult getMergedResultFromSolutions(ProcessingEnvironment processingEnvironment, List solutions) { + protected InferenceResult getMergedResultFromSolutions( + ProcessingEnvironment processingEnvironment, List solutions) { return new SourceResult(solutions, processingEnvironment); } } diff --git a/src/trusted/TrustedAnnotatedTypeFactory.java b/src/trusted/TrustedAnnotatedTypeFactory.java index 856758312..f38b3a60e 100644 --- a/src/trusted/TrustedAnnotatedTypeFactory.java +++ b/src/trusted/TrustedAnnotatedTypeFactory.java @@ -1,14 +1,14 @@ package trusted; -import checkers.inference.BaseInferenceRealTypeFactory; -import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; +import com.sun.source.tree.BinaryTree; + import org.checkerframework.common.basetype.BaseTypeChecker; import org.checkerframework.framework.type.*; import org.checkerframework.framework.type.treeannotator.ListTreeAnnotator; import org.checkerframework.framework.type.treeannotator.TreeAnnotator; import org.checkerframework.javacutil.TreeUtils; -import com.sun.source.tree.BinaryTree; +import checkers.inference.BaseInferenceRealTypeFactory; public class TrustedAnnotatedTypeFactory extends BaseInferenceRealTypeFactory { @@ -19,10 +19,7 @@ public TrustedAnnotatedTypeFactory(BaseTypeChecker checker, boolean isInfer) { @Override public TreeAnnotator createTreeAnnotator() { - return new ListTreeAnnotator( - super.createTreeAnnotator(), - new TrustedTreeAnnotator() - ); + return new ListTreeAnnotator(super.createTreeAnnotator(), new TrustedTreeAnnotator()); } private class TrustedTreeAnnotator extends TreeAnnotator { @@ -31,8 +28,8 @@ public TrustedTreeAnnotator() { } /** - * Handles String concatenation; only @Trusted + @Trusted = @Trusted. - * Any other concatenation results in @Untrusted. + * Handles String concatenation; only @Trusted + @Trusted = @Trusted. Any other + * concatenation results in @Untrusted. */ @Override public Void visitBinary(BinaryTree tree, AnnotatedTypeMirror type) { @@ -41,7 +38,8 @@ public Void visitBinary(BinaryTree tree, AnnotatedTypeMirror type) { AnnotatedTypeMirror rExpr = getAnnotatedType(tree.getRightOperand()); final TrustedChecker trustedChecker = (TrustedChecker) checker; - if (lExpr.hasAnnotation(trustedChecker.TRUSTED) && rExpr.hasAnnotation(trustedChecker.TRUSTED)) { + if (lExpr.hasAnnotation(trustedChecker.TRUSTED) + && rExpr.hasAnnotation(trustedChecker.TRUSTED)) { type.replaceAnnotation(trustedChecker.TRUSTED); } else { type.replaceAnnotation(trustedChecker.UNTRUSTED); diff --git a/src/trusted/TrustedChecker.java b/src/trusted/TrustedChecker.java index 49bc1ee0c..1236727c2 100644 --- a/src/trusted/TrustedChecker.java +++ b/src/trusted/TrustedChecker.java @@ -1,5 +1,12 @@ package trusted; +import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; +import org.checkerframework.framework.flow.CFTransfer; +import org.checkerframework.javacutil.AnnotationBuilder; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.util.Elements; + import checkers.inference.BaseInferrableChecker; import checkers.inference.InferenceChecker; import checkers.inference.dataflow.InferenceAnalysis; @@ -7,20 +14,10 @@ import trusted.qual.Trusted; import trusted.qual.Untrusted; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.util.Elements; - -import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; -import org.checkerframework.framework.flow.CFTransfer; -import org.checkerframework.javacutil.AnnotationBuilder; - /** - * - * The Trusted checker is a generic checker for expressing objects as "trusted" or not. - * It should most likely be only used abstractly; specific subtypes with their own - * qualifiers should be created to represent most categories of trusted (e.g. for SQL - * or OS commands). - * + * The Trusted checker is a generic checker for expressing objects as "trusted" or not. It should + * most likely be only used abstractly; specific subtypes with their own qualifiers should be + * created to represent most categories of trusted (e.g. for SQL or OS commands). */ public class TrustedChecker extends BaseInferrableChecker { public AnnotationMirror UNTRUSTED, TRUSTED; @@ -34,11 +31,12 @@ public void initChecker() { protected void setAnnotations() { final Elements elements = processingEnv.getElementUtils(); UNTRUSTED = AnnotationBuilder.fromClass(elements, Untrusted.class); - TRUSTED = AnnotationBuilder.fromClass(elements, Trusted.class); + TRUSTED = AnnotationBuilder.fromClass(elements, Trusted.class); } @Override - public TrustedVisitor createVisitor(InferenceChecker ichecker, BaseAnnotatedTypeFactory factory, boolean infer) { + public TrustedVisitor createVisitor( + InferenceChecker ichecker, BaseAnnotatedTypeFactory factory, boolean infer) { return new TrustedVisitor(this, ichecker, factory, infer); } @@ -51,4 +49,4 @@ public TrustedAnnotatedTypeFactory createRealTypeFactory(boolean infer) { public CFTransfer createInferenceTransferFunction(InferenceAnalysis analysis) { return new InferenceTransfer(analysis); } -} \ No newline at end of file +} diff --git a/src/trusted/TrustedVisitor.java b/src/trusted/TrustedVisitor.java index 2ccf101b6..e3b2ba0ea 100644 --- a/src/trusted/TrustedVisitor.java +++ b/src/trusted/TrustedVisitor.java @@ -7,7 +7,11 @@ public class TrustedVisitor extends InferenceVisitor { - public TrustedVisitor(TrustedChecker checker, InferenceChecker ichecker, BaseAnnotatedTypeFactory factory, boolean infer) { + public TrustedVisitor( + TrustedChecker checker, + InferenceChecker ichecker, + BaseAnnotatedTypeFactory factory, + boolean infer) { super(checker, ichecker, factory, infer); } } diff --git a/src/trusted/qual/PolyTrusted.java b/src/trusted/qual/PolyTrusted.java index 182202eb1..31a367ac3 100644 --- a/src/trusted/qual/PolyTrusted.java +++ b/src/trusted/qual/PolyTrusted.java @@ -9,12 +9,13 @@ import java.lang.annotation.Target; /** - * A Polymorphic qualifier for {@code Trusted}.

    + * A Polymorphic qualifier for {@code Trusted}. * - * See {@link + *

    See {@link * http://types.cs.washington.edu/checker-framework/current/checkers-manual.html#qualifier-polymorphism} - * for information on the semantics of polymorphic qualifiers in the checker - * framework.

    + * for information on the semantics of polymorphic qualifiers in the checker framework. + * + *

    * * @see Trusted * @see Untrusted diff --git a/src/trusted/qual/Trusted.java b/src/trusted/qual/Trusted.java index 2c89cd115..f7027834d 100644 --- a/src/trusted/qual/Trusted.java +++ b/src/trusted/qual/Trusted.java @@ -11,21 +11,21 @@ import java.lang.annotation.Target; /** - * A type annotation indicating that the contained value is to be trusted.

    + * A type annotation indicating that the contained value is to be trusted. * - * It is up to the user to determine what, exactly, she wants {@code Trusted} to - * represent. Similar type systems with prescribed meanings are available in - * other packages.

    + *

    It is up to the user to determine what, exactly, she wants {@code Trusted} to represent. + * Similar type systems with prescribed meanings are available in other packages. * - * All literals are {@code Trusted} by default.

    + *

    All literals are {@code Trusted} by default. * - * The concatenation of two {@code Trusted} Strings with the + operator is - * itself a {@code Trusted} String.

    + *

    The concatenation of two {@code Trusted} Strings with the + operator is itself a {@code + * Trusted} String. * - * Addition of other {@code Trusted} types also results in a {@code Trusted} - * type. For example, (trusted int + trusted int) gives a trusted int. For - * consistency, we should either restrict this behavior to Strings, or extend it - * to include other operators.

    + *

    Addition of other {@code Trusted} types also results in a {@code Trusted} type. For example, + * (trusted int + trusted int) gives a trusted int. For consistency, we should either restrict this + * behavior to Strings, or extend it to include other operators. + * + *

    * * @see Untrusted */ @@ -34,13 +34,13 @@ @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @SubtypeOf(Untrusted.class) @QualifierForLiterals({ - LiteralKind.BOOLEAN, - LiteralKind.CHAR, - LiteralKind.DOUBLE, - LiteralKind.FLOAT, - LiteralKind.INT, - LiteralKind.LONG, - LiteralKind.NULL, - LiteralKind.STRING, - }) + LiteralKind.BOOLEAN, + LiteralKind.CHAR, + LiteralKind.DOUBLE, + LiteralKind.FLOAT, + LiteralKind.INT, + LiteralKind.LONG, + LiteralKind.NULL, + LiteralKind.STRING, +}) public @interface Trusted {} diff --git a/src/trusted/qual/Untrusted.java b/src/trusted/qual/Untrusted.java index 56f896cdc..b8179c910 100644 --- a/src/trusted/qual/Untrusted.java +++ b/src/trusted/qual/Untrusted.java @@ -1,23 +1,23 @@ package trusted.qual; +import org.checkerframework.framework.qual.DefaultQualifierInHierarchy; +import org.checkerframework.framework.qual.SubtypeOf; + import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import org.checkerframework.framework.qual.DefaultQualifierInHierarchy; -import org.checkerframework.framework.qual.SubtypeOf; - /** - * A type annotation indicating that the contained value cannot be proven to be - * trustworthy.

    + * A type annotation indicating that the contained value cannot be proven to be trustworthy. + * + *

    Variables with no annotation are considered {@code Untrusted}. * - * Variables with no annotation are considered {@code Untrusted}.

    + *

    It is up to the user to determine what, exactly, she wants {@code Untrusted} to represent. + * Similar type systems with prescribed meanings are available in other packages. * - * It is up to the user to determine what, exactly, she wants {@code Untrusted} - * to represent. Similar type systems with prescribed meanings are available in - * other packages.

    + *

    * * @see Trusted */ diff --git a/tests/checkers/inference/DataflowInferenceTest.java b/tests/checkers/inference/DataflowInferenceTest.java index 2d4a82cb4..ff0092b25 100644 --- a/tests/checkers/inference/DataflowInferenceTest.java +++ b/tests/checkers/inference/DataflowInferenceTest.java @@ -1,27 +1,32 @@ package checkers.inference; +import org.checkerframework.framework.test.TestUtilities; +import org.junit.runners.Parameterized.Parameters; +import org.plumelib.util.IPair; + import java.io.File; import java.util.ArrayList; import java.util.List; -import org.checkerframework.framework.test.TestUtilities; -import org.plumelib.util.IPair; -import org.junit.runners.Parameterized.Parameters; - import checkers.inference.test.CFInferenceTest; import dataflow.solvers.general.DataflowSolverEngine; public class DataflowInferenceTest extends CFInferenceTest { public DataflowInferenceTest(File testFile) { - super(testFile, dataflow.DataflowChecker.class, "dataflow", - "-Anomsgtext", "-d", "tests/build/outputdir"); + super( + testFile, + dataflow.DataflowChecker.class, + "dataflow", + "-Anomsgtext", + "-d", + "tests/build/outputdir"); } @Override public IPair> getSolverNameAndOptions() { - return IPair.> of(DataflowSolverEngine.class.getCanonicalName(), - new ArrayList()); + return IPair.>of( + DataflowSolverEngine.class.getCanonicalName(), new ArrayList()); } @Override @@ -30,9 +35,10 @@ public boolean useHacks() { } @Parameters - public static List getTestFiles(){ - List testfiles = new ArrayList<>();//InferenceTestUtilities.findAllSystemTests(); - testfiles.addAll(TestUtilities.findRelativeNestedJavaFiles("testing", "dataflow-inferrable-test")); + public static List getTestFiles() { + List testfiles = new ArrayList<>(); // InferenceTestUtilities.findAllSystemTests(); + testfiles.addAll( + TestUtilities.findRelativeNestedJavaFiles("testing", "dataflow-inferrable-test")); return testfiles; } } diff --git a/tests/checkers/inference/DefaultSlotManagerTest.java b/tests/checkers/inference/DefaultSlotManagerTest.java index 719222364..006810f8d 100644 --- a/tests/checkers/inference/DefaultSlotManagerTest.java +++ b/tests/checkers/inference/DefaultSlotManagerTest.java @@ -1,13 +1,9 @@ package checkers.inference; - import org.junit.Test; public class DefaultSlotManagerTest { - - @Test - public void nextIdTest() { - } + public void nextIdTest() {} } diff --git a/tests/checkers/inference/IFlowSinkPropTest.java b/tests/checkers/inference/IFlowSinkPropTest.java index fbed0004c..3a28ed638 100644 --- a/tests/checkers/inference/IFlowSinkPropTest.java +++ b/tests/checkers/inference/IFlowSinkPropTest.java @@ -1,31 +1,39 @@ package checkers.inference; -import checkers.inference.test.CFInferenceTest; import org.checkerframework.framework.test.TestUtilities; -import org.plumelib.util.IPair; import org.junit.runners.Parameterized.Parameters; -import sparta.checkers.IFlowSinkChecker; -import sparta.checkers.propagation.IFlowSinkSolver; +import org.plumelib.util.IPair; import java.io.File; import java.util.ArrayList; import java.util.List; +import checkers.inference.test.CFInferenceTest; +import sparta.checkers.IFlowSinkChecker; +import sparta.checkers.propagation.IFlowSinkSolver; + public class IFlowSinkPropTest extends CFInferenceTest { public IFlowSinkPropTest(File testFile) { - super(testFile, IFlowSinkChecker.class, "sparta"+File.separator+"checkers", - "-Anomsgtext", "-Astubs=src/sparta/checkers/information_flow.astub", "-d", "tests/build/outputdir"); + super( + testFile, + IFlowSinkChecker.class, + "sparta" + File.separator + "checkers", + "-Anomsgtext", + "-Astubs=src/sparta/checkers/information_flow.astub", + "-d", + "tests/build/outputdir"); } @Override public IPair> getSolverNameAndOptions() { - return IPair.>of(IFlowSinkSolver.class.getCanonicalName(), new ArrayList()); + return IPair.>of( + IFlowSinkSolver.class.getCanonicalName(), new ArrayList()); } @Parameters - public static List getTestFiles(){ - List testfiles = new ArrayList<>();//InferenceTestUtilities.findAllSystemTests(); + public static List getTestFiles() { + List testfiles = new ArrayList<>(); // InferenceTestUtilities.findAllSystemTests(); if (isAtMost7Jvm) { testfiles.addAll(TestUtilities.findRelativeNestedJavaFiles("testdata", "iflowsink")); } diff --git a/tests/checkers/inference/IFlowSinkSatTest.java b/tests/checkers/inference/IFlowSinkSatTest.java index 89f8219e5..41222aaf4 100644 --- a/tests/checkers/inference/IFlowSinkSatTest.java +++ b/tests/checkers/inference/IFlowSinkSatTest.java @@ -1,31 +1,39 @@ package checkers.inference; -import checkers.inference.test.CFInferenceTest; import org.checkerframework.framework.test.TestUtilities; -import org.plumelib.util.IPair; import org.junit.runners.Parameterized.Parameters; -import sparta.checkers.IFlowSinkChecker; -import sparta.checkers.sat.SinkSolver; +import org.plumelib.util.IPair; import java.io.File; import java.util.ArrayList; import java.util.List; +import checkers.inference.test.CFInferenceTest; +import sparta.checkers.IFlowSinkChecker; +import sparta.checkers.sat.SinkSolver; + public class IFlowSinkSatTest extends CFInferenceTest { public IFlowSinkSatTest(File testFile) { - super(testFile, IFlowSinkChecker.class, "sparta"+File.separator+"checkers", - "-Anomsgtext", "-Astubs=src/sparta/checkers/information_flow.astub", "-d", "tests/build/outputdir"); + super( + testFile, + IFlowSinkChecker.class, + "sparta" + File.separator + "checkers", + "-Anomsgtext", + "-Astubs=src/sparta/checkers/information_flow.astub", + "-d", + "tests/build/outputdir"); } @Override public IPair> getSolverNameAndOptions() { - return IPair.>of(SinkSolver.class.getCanonicalName(), new ArrayList()); + return IPair.>of( + SinkSolver.class.getCanonicalName(), new ArrayList()); } @Parameters - public static List getTestFiles(){ - List testfiles = new ArrayList<>();//InferenceTestUtilities.findAllSystemTests(); + public static List getTestFiles() { + List testfiles = new ArrayList<>(); // InferenceTestUtilities.findAllSystemTests(); if (isAtMost7Jvm) { testfiles.addAll(TestUtilities.findRelativeNestedJavaFiles("testdata", "iflowsink")); } diff --git a/tests/checkers/inference/IFlowSourcePropTest.java b/tests/checkers/inference/IFlowSourcePropTest.java index c48e5a336..f4eca3bde 100644 --- a/tests/checkers/inference/IFlowSourcePropTest.java +++ b/tests/checkers/inference/IFlowSourcePropTest.java @@ -1,31 +1,39 @@ package checkers.inference; -import checkers.inference.test.CFInferenceTest; import org.checkerframework.framework.test.TestUtilities; -import org.plumelib.util.IPair; import org.junit.runners.Parameterized.Parameters; -import sparta.checkers.IFlowSourceChecker; -import sparta.checkers.propagation.IFlowSourceSolver; +import org.plumelib.util.IPair; import java.io.File; import java.util.ArrayList; import java.util.List; +import checkers.inference.test.CFInferenceTest; +import sparta.checkers.IFlowSourceChecker; +import sparta.checkers.propagation.IFlowSourceSolver; + public class IFlowSourcePropTest extends CFInferenceTest { public IFlowSourcePropTest(File testFile) { - super(testFile, IFlowSourceChecker.class, "sparta"+File.separator+"checkers", - "-Anomsgtext", "-Astubs=src/sparta/checkers/information_flow.astub", "-d", "tests/build/outputdir"); + super( + testFile, + IFlowSourceChecker.class, + "sparta" + File.separator + "checkers", + "-Anomsgtext", + "-Astubs=src/sparta/checkers/information_flow.astub", + "-d", + "tests/build/outputdir"); } @Override public IPair> getSolverNameAndOptions() { - return IPair.>of(IFlowSourceSolver.class.getCanonicalName(), new ArrayList()); + return IPair.>of( + IFlowSourceSolver.class.getCanonicalName(), new ArrayList()); } @Parameters - public static List getTestFiles(){ - List testfiles = new ArrayList<>();//InferenceTestUtilities.findAllSystemTests(); + public static List getTestFiles() { + List testfiles = new ArrayList<>(); // InferenceTestUtilities.findAllSystemTests(); if (isAtMost7Jvm) { testfiles.addAll(TestUtilities.findRelativeNestedJavaFiles("testdata", "iflowsource")); } diff --git a/tests/checkers/inference/IFlowSourceSatTest.java b/tests/checkers/inference/IFlowSourceSatTest.java index 16fcd997f..ada8f35fe 100644 --- a/tests/checkers/inference/IFlowSourceSatTest.java +++ b/tests/checkers/inference/IFlowSourceSatTest.java @@ -1,31 +1,39 @@ package checkers.inference; -import checkers.inference.test.CFInferenceTest; import org.checkerframework.framework.test.TestUtilities; -import org.plumelib.util.IPair; import org.junit.runners.Parameterized.Parameters; -import sparta.checkers.IFlowSourceChecker; -import sparta.checkers.sat.SourceSolver; +import org.plumelib.util.IPair; import java.io.File; import java.util.ArrayList; import java.util.List; +import checkers.inference.test.CFInferenceTest; +import sparta.checkers.IFlowSourceChecker; +import sparta.checkers.sat.SourceSolver; + public class IFlowSourceSatTest extends CFInferenceTest { public IFlowSourceSatTest(File testFile) { - super(testFile, IFlowSourceChecker.class, "sparta"+File.separator+"checkers", - "-Anomsgtext", "-Astubs=src/sparta/checkers/information_flow.astub", "-d", "tests/build/outputdir"); + super( + testFile, + IFlowSourceChecker.class, + "sparta" + File.separator + "checkers", + "-Anomsgtext", + "-Astubs=src/sparta/checkers/information_flow.astub", + "-d", + "tests/build/outputdir"); } @Override public IPair> getSolverNameAndOptions() { - return IPair.>of(SourceSolver.class.getCanonicalName(), new ArrayList()); + return IPair.>of( + SourceSolver.class.getCanonicalName(), new ArrayList()); } @Parameters - public static List getTestFiles(){ - List testfiles = new ArrayList<>();//InferenceTestUtilities.findAllSystemTests(); + public static List getTestFiles() { + List testfiles = new ArrayList<>(); // InferenceTestUtilities.findAllSystemTests(); if (isAtMost7Jvm) { testfiles.addAll(TestUtilities.findRelativeNestedJavaFiles("testdata", "iflowsource")); } diff --git a/tests/checkers/inference/InterningTest.java b/tests/checkers/inference/InterningTest.java index 77da94088..46e60def3 100644 --- a/tests/checkers/inference/InterningTest.java +++ b/tests/checkers/inference/InterningTest.java @@ -1,30 +1,37 @@ package checkers.inference; -import checkers.inference.solver.MaxSat2TypeSolver; -import checkers.inference.test.CFInferenceTest; import org.checkerframework.framework.test.TestUtilities; -import org.plumelib.util.IPair; import org.junit.runners.Parameterized.Parameters; +import org.plumelib.util.IPair; import java.io.File; import java.util.ArrayList; import java.util.List; +import checkers.inference.solver.MaxSat2TypeSolver; +import checkers.inference.test.CFInferenceTest; + public class InterningTest extends CFInferenceTest { public InterningTest(File testFile) { - super(testFile, interning.InterningChecker.class, "interning", - "-Anomsgtext", "-d", "tests/build/outputdir"); + super( + testFile, + interning.InterningChecker.class, + "interning", + "-Anomsgtext", + "-d", + "tests/build/outputdir"); } @Override public IPair> getSolverNameAndOptions() { - return IPair.>of(MaxSat2TypeSolver.class.getCanonicalName(), new ArrayList()); + return IPair.>of( + MaxSat2TypeSolver.class.getCanonicalName(), new ArrayList()); } @Parameters public static List getTestFiles() { - List testfiles = new ArrayList<>();//InferenceTestUtilities.findAllSystemTests(); + List testfiles = new ArrayList<>(); // InferenceTestUtilities.findAllSystemTests(); testfiles.addAll(TestUtilities.findRelativeNestedJavaFiles("testdata", "interning")); return testfiles; } diff --git a/tests/checkers/inference/NninfTest.java b/tests/checkers/inference/NninfTest.java index a09341ab9..79fc19acc 100644 --- a/tests/checkers/inference/NninfTest.java +++ b/tests/checkers/inference/NninfTest.java @@ -1,20 +1,26 @@ package checkers.inference; -import checkers.inference.solver.MaxSat2TypeSolver; -import checkers.inference.test.CFInferenceTest; import org.checkerframework.framework.test.TestUtilities; -import org.plumelib.util.IPair; import org.junit.runners.Parameterized.Parameters; +import org.plumelib.util.IPair; import java.io.File; import java.util.ArrayList; import java.util.List; +import checkers.inference.solver.MaxSat2TypeSolver; +import checkers.inference.test.CFInferenceTest; + public class NninfTest extends CFInferenceTest { public NninfTest(File testFile) { - super(testFile, nninf.NninfChecker.class, "nninf", - "-Anomsgtext", "-d", "tests/build/outputdir"); + super( + testFile, + nninf.NninfChecker.class, + "nninf", + "-Anomsgtext", + "-d", + "tests/build/outputdir"); } @Override diff --git a/tests/checkers/inference/OsTrustedTest.java b/tests/checkers/inference/OsTrustedTest.java index 73c00f6c2..d04753296 100644 --- a/tests/checkers/inference/OsTrustedTest.java +++ b/tests/checkers/inference/OsTrustedTest.java @@ -1,31 +1,40 @@ package checkers.inference; -import checkers.inference.solver.MaxSat2TypeSolver; -import checkers.inference.test.CFInferenceTest; import org.checkerframework.framework.test.TestUtilities; -import org.plumelib.util.IPair; import org.junit.runners.Parameterized.Parameters; +import org.plumelib.util.IPair; import java.io.File; import java.util.ArrayList; import java.util.List; +import checkers.inference.solver.MaxSat2TypeSolver; +import checkers.inference.test.CFInferenceTest; + public class OsTrustedTest extends CFInferenceTest { public OsTrustedTest(File testFile) { - super(testFile, ostrusted.OsTrustedChecker.class, "ostrusted", - "-Anomsgtext", "-Astubs=src/ostrusted/jdk.astub", "-d", "tests/build/outputdir"); + super( + testFile, + ostrusted.OsTrustedChecker.class, + "ostrusted", + "-Anomsgtext", + "-Astubs=src/ostrusted/jdk.astub", + "-d", + "tests/build/outputdir"); } @Override public IPair> getSolverNameAndOptions() { - return IPair.>of(MaxSat2TypeSolver.class.getCanonicalName(), new ArrayList()); + return IPair.>of( + MaxSat2TypeSolver.class.getCanonicalName(), new ArrayList()); } @Parameters - public static List getTestFiles(){ - List testfiles = new ArrayList<>();//InferenceTestUtilities.findAllSystemTests(); - testfiles.addAll(TestUtilities.findRelativeNestedJavaFiles("testdata", "ostrusted-inferrable-test")); + public static List getTestFiles() { + List testfiles = new ArrayList<>(); // InferenceTestUtilities.findAllSystemTests(); + testfiles.addAll( + TestUtilities.findRelativeNestedJavaFiles("testdata", "ostrusted-inferrable-test")); return testfiles; } } diff --git a/tests/checkers/inference/test/CFInferenceTest.java b/tests/checkers/inference/test/CFInferenceTest.java index 7383b8747..af673f87c 100644 --- a/tests/checkers/inference/test/CFInferenceTest.java +++ b/tests/checkers/inference/test/CFInferenceTest.java @@ -3,6 +3,9 @@ import org.checkerframework.framework.test.CheckerFrameworkPerFileTest; import org.checkerframework.framework.test.TestUtilities; import org.checkerframework.javacutil.SystemUtil; +import org.junit.Test; +import org.plumelib.util.IPair; +import org.plumelib.util.SystemPlume; import java.io.File; import java.util.ArrayList; @@ -10,10 +13,6 @@ import javax.annotation.processing.AbstractProcessor; -import org.plumelib.util.IPair; -import org.plumelib.util.SystemPlume; -import org.junit.Test; - public abstract class CFInferenceTest extends CheckerFrameworkPerFileTest { public static final boolean isAtMost7Jvm; @@ -22,8 +21,11 @@ public abstract class CFInferenceTest extends CheckerFrameworkPerFileTest { isAtMost7Jvm = SystemUtil.jreVersion <= 7; } - public CFInferenceTest(File testFile, Class checker, - String testDir, String... checkerOptions) { + public CFInferenceTest( + File testFile, + Class checker, + String testDir, + String... checkerOptions) { super(testFile, checker, testDir, checkerOptions); } @@ -53,9 +55,20 @@ public void run() { final File testDataDir = new File("testdata"); - InferenceTestConfiguration config = InferenceTestConfigurationBuilder.buildDefaultConfiguration(testDir, - testFile, testDataDir, checker, checkerOptions, getAdditionalInferenceOptions(), solverArgs.first, - solverArgs.second, useHacks(), shouldEmitDebugInfo, getPathToAfuScripts(), getPathToInferenceScript()); + InferenceTestConfiguration config = + InferenceTestConfigurationBuilder.buildDefaultConfiguration( + testDir, + testFile, + testDataDir, + checker, + checkerOptions, + getAdditionalInferenceOptions(), + solverArgs.first, + solverArgs.second, + useHacks(), + shouldEmitDebugInfo, + getPathToAfuScripts(), + getPathToInferenceScript()); InferenceTestResult testResult = new InferenceTestExecutor().runTest(config); InferenceTestUtilities.assertResultsAreValid(testResult); diff --git a/tests/checkers/inference/test/ImmutableInferenceTestConfiguration.java b/tests/checkers/inference/test/ImmutableInferenceTestConfiguration.java index f44fcf090..4893986b3 100644 --- a/tests/checkers/inference/test/ImmutableInferenceTestConfiguration.java +++ b/tests/checkers/inference/test/ImmutableInferenceTestConfiguration.java @@ -8,7 +8,7 @@ import java.util.List; import java.util.Map; -public class ImmutableInferenceTestConfiguration implements InferenceTestConfiguration{ +public class ImmutableInferenceTestConfiguration implements InferenceTestConfiguration { private final File outputJaif; private final File testDataDir; private final File annotatedSourceDir; @@ -20,10 +20,17 @@ public class ImmutableInferenceTestConfiguration implements InferenceTestConfigu private final String pathToInferenceScript; private final TestConfiguration initialConfig; - public ImmutableInferenceTestConfiguration(File outputJaif, File testDataDir, File annotatedSourceDir, - Map inferenceJavacArgs, String solver, - Map solverArgs, boolean shouldUseHacks, String pathToAfuScripts, - String pathToInferenceScript, TestConfiguration initialConfig) { + public ImmutableInferenceTestConfiguration( + File outputJaif, + File testDataDir, + File annotatedSourceDir, + Map inferenceJavacArgs, + String solver, + Map solverArgs, + boolean shouldUseHacks, + String pathToAfuScripts, + String pathToInferenceScript, + TestConfiguration initialConfig) { this.outputJaif = outputJaif; this.testDataDir = testDataDir; this.annotatedSourceDir = annotatedSourceDir; @@ -95,11 +102,16 @@ public List getFlatSolverArgs() { @Override public TestConfiguration getFinalTypecheckConfig() { List translatedDiagnostics = - InferenceTestUtilities.replaceParentDirs(annotatedSourceDir, initialConfig.getDiagnosticFiles()); + InferenceTestUtilities.replaceParentDirs( + annotatedSourceDir, initialConfig.getDiagnosticFiles()); List translatedFiles = - InferenceTestUtilities.replaceParentDirs(annotatedSourceDir, initialConfig.getTestSourceFiles()); - return new ImmutableTestConfiguration(translatedDiagnostics, translatedFiles, initialConfig.getProcessors(), - initialConfig.getOptions(), initialConfig.shouldEmitDebugInfo()); + InferenceTestUtilities.replaceParentDirs( + annotatedSourceDir, initialConfig.getTestSourceFiles()); + return new ImmutableTestConfiguration( + translatedDiagnostics, + translatedFiles, + initialConfig.getProcessors(), + initialConfig.getOptions(), + initialConfig.shouldEmitDebugInfo()); } - } diff --git a/tests/checkers/inference/test/InferenceResult.java b/tests/checkers/inference/test/InferenceResult.java index 5f2786633..557ab4089 100644 --- a/tests/checkers/inference/test/InferenceResult.java +++ b/tests/checkers/inference/test/InferenceResult.java @@ -2,16 +2,13 @@ import org.plumelib.util.StringsPlume; -/** - * This is the output from running inference NOT the result of a test. - */ +/** This is the output from running inference NOT the result of a test. */ public class InferenceResult { private final InferenceTestConfiguration configuration; private final String output; private final boolean failed; - public InferenceResult(InferenceTestConfiguration config, - String output, boolean failed) { + public InferenceResult(InferenceTestConfiguration config, String output, boolean failed) { this.configuration = config; this.output = output; this.failed = failed; @@ -30,9 +27,13 @@ public String getOutput() { } public String summarize() { - return "Inference process: " + (failed ? "failed" : "succeeded") - + "\n\nOutput\n\n" + getOutput() - + "\n\nWhile inferring over source files: \n" - + StringsPlume.join("\n", configuration.getInitialTypecheckConfig().getTestSourceFiles()) + "\n\n"; + return "Inference process: " + + (failed ? "failed" : "succeeded") + + "\n\nOutput\n\n" + + getOutput() + + "\n\nWhile inferring over source files: \n" + + StringsPlume.join( + "\n", configuration.getInitialTypecheckConfig().getTestSourceFiles()) + + "\n\n"; } } diff --git a/tests/checkers/inference/test/InferenceTestConfiguration.java b/tests/checkers/inference/test/InferenceTestConfiguration.java index b084f7bf7..c3244c8d8 100644 --- a/tests/checkers/inference/test/InferenceTestConfiguration.java +++ b/tests/checkers/inference/test/InferenceTestConfiguration.java @@ -9,20 +9,28 @@ public interface InferenceTestConfiguration { File getOutputJaif(); + File getAnnotatedSourceDir(); + File getTestDataDir(); Map getInferenceJavacArgs(); + List getFlatInferenceJavacArgs(); String getSolver(); + Map getSolverArgs(); + List getFlatSolverArgs(); boolean shouldUseHacks(); + String getPathToAfuScripts(); + String getPathToInferenceScript(); TestConfiguration getInitialTypecheckConfig(); + TestConfiguration getFinalTypecheckConfig(); } diff --git a/tests/checkers/inference/test/InferenceTestConfigurationBuilder.java b/tests/checkers/inference/test/InferenceTestConfigurationBuilder.java index 1d2962091..f9e788e45 100644 --- a/tests/checkers/inference/test/InferenceTestConfigurationBuilder.java +++ b/tests/checkers/inference/test/InferenceTestConfigurationBuilder.java @@ -17,14 +17,13 @@ public class InferenceTestConfigurationBuilder { private File testDataDir = null; private String solver = null; private boolean shouldUseHacks; - private String pathToAfuScripts=""; - private String pathToInferenceScript=""; + private String pathToAfuScripts = ""; + private String pathToInferenceScript = ""; private SimpleOptionMap inferenceJavacArgs = new SimpleOptionMap(); private SimpleOptionMap solverArgs = new SimpleOptionMap(); - public InferenceTestConfigurationBuilder() { - } + public InferenceTestConfigurationBuilder() {} public InferenceTestConfigurationBuilder(TestConfiguration initialConfiguration) { this.initialConfiguration = initialConfiguration; @@ -35,7 +34,8 @@ public InferenceTestConfigurationBuilder setOutputJaif(File outputJaif) { return this; } - public InferenceTestConfigurationBuilder setInitialConfiguration(TestConfiguration initialConfiguration) { + public InferenceTestConfigurationBuilder setInitialConfiguration( + TestConfiguration initialConfiguration) { this.initialConfiguration = initialConfiguration; return this; } @@ -65,7 +65,8 @@ public InferenceTestConfigurationBuilder setPathToAfuScripts(String pathToAfuScr return this; } - public InferenceTestConfigurationBuilder setPathToInferenceScript(String pathToInferenceScript) { + public InferenceTestConfigurationBuilder setPathToInferenceScript( + String pathToInferenceScript) { this.pathToInferenceScript = pathToInferenceScript; return this; } @@ -73,7 +74,8 @@ public InferenceTestConfigurationBuilder setPathToInferenceScript(String pathToI // --------------------------------- // Infernece Javac Options Delegation Methods - public InferenceTestConfigurationBuilder addToInferenceJavacPathOption(String key, String toAppend) { + public InferenceTestConfigurationBuilder addToInferenceJavacPathOption( + String key, String toAppend) { inferenceJavacArgs.addOption(key, toAppend); return this; } @@ -88,8 +90,8 @@ public InferenceTestConfigurationBuilder addInferenceJavacOption(String option, return this; } - - public InferenceTestConfigurationBuilder addInferenceJavacOptionIfValueNonEmpty(String option, String value) { + public InferenceTestConfigurationBuilder addInferenceJavacOptionIfValueNonEmpty( + String option, String value) { inferenceJavacArgs.addOptionIfValueNonEmpty(option, value); return this; } @@ -122,7 +124,8 @@ public InferenceTestConfigurationBuilder addSolverOption(String option, String v return this; } - public InferenceTestConfigurationBuilder addSolverOptionIfValueNonEmpty(String option, String value) { + public InferenceTestConfigurationBuilder addSolverOptionIfValueNonEmpty( + String option, String value) { solverArgs.addOptionIfValueNonEmpty(option, value); return this; } @@ -145,55 +148,76 @@ private void ensureNotNull(Object reference, final String name, List err public List validate() { List errors = new ArrayList<>(); - //Note: The initial config should be validated before being passed to InferenceTestConfigurationBuilder + // Note: The initial config should be validated before being passed to + // InferenceTestConfigurationBuilder ensureNotNull(initialConfiguration, "initialConfiguration", errors); - ensureNotNull(outputJaif, "outputJaif", errors); + ensureNotNull(outputJaif, "outputJaif", errors); ensureNotNull(testDataDir, "testDataDir", errors); ensureNotNull(annotatedSourceDir, "annotatedSourceDir", errors); return errors; } public InferenceTestConfiguration build() { - return new ImmutableInferenceTestConfiguration(outputJaif, testDataDir, - annotatedSourceDir, new LinkedHashMap<>(inferenceJavacArgs.getOptions()), - solver, new LinkedHashMap<>(solverArgs.getOptions()), shouldUseHacks,pathToAfuScripts, - pathToInferenceScript, initialConfiguration); + return new ImmutableInferenceTestConfiguration( + outputJaif, + testDataDir, + annotatedSourceDir, + new LinkedHashMap<>(inferenceJavacArgs.getOptions()), + solver, + new LinkedHashMap<>(solverArgs.getOptions()), + shouldUseHacks, + pathToAfuScripts, + pathToInferenceScript, + initialConfiguration); } public InferenceTestConfiguration validateThenBuild() { - List errors = validate() ; + List errors = validate(); if (errors.isEmpty()) { return build(); } - throw new RuntimeException("Attempted to build invalid inference test configuration:\n" - + "Errors:\n" - + String.join("\n", errors) + "\n" - + this.toString() + "\n"); + throw new RuntimeException( + "Attempted to build invalid inference test configuration:\n" + + "Errors:\n" + + String.join("\n", errors) + + "\n" + + this.toString() + + "\n"); } public static InferenceTestConfiguration buildDefaultConfiguration( - String testSourcePath, File testFile, File testDataRoot, Class checker, List typecheckOptions, - List inferenceOptions, String solverName, List solverOptions, - boolean shouldUseHacks, boolean shouldEmitDebugInfo, String pathToAfuScripts, String pathToInferenceScript) { + String testSourcePath, + File testFile, + File testDataRoot, + Class checker, + List typecheckOptions, + List inferenceOptions, + String solverName, + List solverOptions, + boolean shouldUseHacks, + boolean shouldEmitDebugInfo, + String pathToAfuScripts, + String pathToInferenceScript) { final File defaultInferenceOutDir = new File("testdata/tmp"); final File defaultOutputJaif = new File(defaultInferenceOutDir, "default.jaif"); final File defaultAnnotatedSourceDir = new File(defaultInferenceOutDir, "annotated-source"); - TestConfiguration initialConfig = TestConfigurationBuilder.buildDefaultConfiguration( - testSourcePath, testFile, checker, typecheckOptions, shouldEmitDebugInfo); + TestConfiguration initialConfig = + TestConfigurationBuilder.buildDefaultConfiguration( + testSourcePath, testFile, checker, typecheckOptions, shouldEmitDebugInfo); InferenceTestConfigurationBuilder configBuilder = - new InferenceTestConfigurationBuilder() - .setInitialConfiguration(initialConfig) - .setOutputJaif(defaultOutputJaif) - .setTestDataDir(testDataRoot) - .setAnnotatedSourceDir(defaultAnnotatedSourceDir) - .setSolver(solverName) - .setShouldUseHacks(shouldUseHacks) - .setPathToAfuScripts(pathToAfuScripts) - .setPathToInferenceScript(pathToInferenceScript); + new InferenceTestConfigurationBuilder() + .setInitialConfiguration(initialConfig) + .setOutputJaif(defaultOutputJaif) + .setTestDataDir(testDataRoot) + .setAnnotatedSourceDir(defaultAnnotatedSourceDir) + .setSolver(solverName) + .setShouldUseHacks(shouldUseHacks) + .setPathToAfuScripts(pathToAfuScripts) + .setPathToInferenceScript(pathToInferenceScript); if (inferenceOptions != null) { configBuilder.addInferenceJavacOptions(inferenceOptions); diff --git a/tests/checkers/inference/test/InferenceTestExecutor.java b/tests/checkers/inference/test/InferenceTestExecutor.java index 14345bf9b..102dcb987 100644 --- a/tests/checkers/inference/test/InferenceTestExecutor.java +++ b/tests/checkers/inference/test/InferenceTestExecutor.java @@ -1,6 +1,5 @@ package checkers.inference.test; - import org.checkerframework.framework.test.CompilationResult; import org.checkerframework.framework.test.TestConfiguration; import org.checkerframework.framework.test.TypecheckExecutor; @@ -15,25 +14,23 @@ import java.util.ArrayList; import java.util.List; -/** - * - */ +/** */ public class InferenceTestExecutor { - public InferenceTestExecutor() { - } + public InferenceTestExecutor() {} public InferenceTestResult runTest(InferenceTestConfiguration config) { InferenceTestPhase lastPhaseRun; boolean failed; - //first run the checker on the source files and ensure that the typechecker returns the expected errors + // first run the checker on the source files and ensure that the typechecker returns the + // expected errors TypecheckResult initialTypecheckResult = initialTypecheck(config); failed = initialTypecheckResult.didTestFail(); lastPhaseRun = InferenceTestPhase.INITIAL_TYPECHECK; - //run inference over the java files + // run inference over the java files InferenceResult inferenceResult = null; if (!failed) { inferenceResult = infer(config); @@ -55,8 +52,13 @@ public InferenceTestResult runTest(InferenceTestConfiguration config) { lastPhaseRun = InferenceTestPhase.FINAL_TYPECHECK; } - return new InferenceTestResult(config, initialTypecheckResult, inferenceResult, - insertionResult, finalTypecheckResult, lastPhaseRun); + return new InferenceTestResult( + config, + initialTypecheckResult, + inferenceResult, + insertionResult, + finalTypecheckResult, + lastPhaseRun); } public static InferenceResult infer(InferenceTestConfiguration configuration) { @@ -87,9 +89,11 @@ public static InferenceResult infer(InferenceTestConfiguration configuration) { List solverArgs = configuration.getFlatSolverArgs(); if (!solverArgs.isEmpty()) { - options.add("--solverArgs=\"" + String.join(" ", configuration.getFlatSolverArgs()) + "\""); + options.add( + "--solverArgs=\"" + String.join(" ", configuration.getFlatSolverArgs()) + "\""); } - if (configuration.getPathToAfuScripts() != null && !configuration.getPathToAfuScripts().equals("")) { + if (configuration.getPathToAfuScripts() != null + && !configuration.getPathToAfuScripts().equals("")) { options.add("--pathToAfuScripts=" + configuration.getPathToAfuScripts()); } @@ -105,7 +109,7 @@ public static InferenceResult infer(InferenceTestConfiguration configuration) { options.add(sourceFile.getAbsolutePath()); } - String [] args = options.toArray(new String[options.size()]); + String[] args = options.toArray(new String[options.size()]); if (configuration.getInitialTypecheckConfig().shouldEmitDebugInfo()) { System.out.println("Running command: \n" + String.join(" ", args)); @@ -120,11 +124,14 @@ public static InferenceResult infer(InferenceTestConfiguration configuration) { } public static InsertionResult insertAnnotations(InferenceTestConfiguration configuration) { - String pathToAfuScripts = configuration.getPathToAfuScripts().equals("") ? "":configuration.getPathToAfuScripts()+File.separator; - String insertAnnotationsScript = pathToAfuScripts+"insert-annotations-to-source"; + String pathToAfuScripts = + configuration.getPathToAfuScripts().equals("") + ? "" + : configuration.getPathToAfuScripts() + File.separator; + String insertAnnotationsScript = pathToAfuScripts + "insert-annotations-to-source"; List sourceFiles = configuration.getInitialTypecheckConfig().getTestSourceFiles(); - String [] options = new String [5 + sourceFiles.size()]; + String[] options = new String[5 + sourceFiles.size()]; options[0] = insertAnnotationsScript; options[1] = "-v"; options[2] = "-d"; @@ -157,7 +164,8 @@ private static void ensureDirectoryExists(File path) { } } - private static List filterOutFixables(List expectedDiagnostics) { + private static List filterOutFixables( + List expectedDiagnostics) { List filteredDiagnostics = new ArrayList<>(expectedDiagnostics.size()); for (TestDiagnostic diagnostic : expectedDiagnostics) { if (!diagnostic.isFixable()) { @@ -171,11 +179,13 @@ private static List filterOutFixables(List expec private static TypecheckResult initialTypecheck(InferenceTestConfiguration configuration) { TestConfiguration typecheckConfig = configuration.getInitialTypecheckConfig(); - List expectedDiagnostics = JavaDiagnosticReader.readJavaSourceFiles(typecheckConfig.getTestSourceFiles()); + List expectedDiagnostics = + JavaDiagnosticReader.readJavaSourceFiles(typecheckConfig.getTestSourceFiles()); TypecheckExecutor typecheckExecutor = new TypecheckExecutor(); CompilationResult compilationResult = typecheckExecutor.compile(typecheckConfig); - return TypecheckResult.fromCompilationResults(typecheckConfig, compilationResult, expectedDiagnostics); + return TypecheckResult.fromCompilationResults( + typecheckConfig, compilationResult, expectedDiagnostics); } private static TypecheckResult finalTypecheck(InferenceTestConfiguration configuration) { @@ -186,11 +196,14 @@ private static TypecheckResult finalTypecheck(InferenceTestConfiguration configu } List expectedDiagnostics = - filterOutFixables(JavaDiagnosticReader.readJavaSourceFiles(typecheckConfig.getTestSourceFiles())); + filterOutFixables( + JavaDiagnosticReader.readJavaSourceFiles( + typecheckConfig.getTestSourceFiles())); TypecheckExecutor typecheckExecutor = new TypecheckExecutor(); CompilationResult compilationResult = typecheckExecutor.compile(typecheckConfig); - return TypecheckResult.fromCompilationResults(typecheckConfig, compilationResult, expectedDiagnostics); + return TypecheckResult.fromCompilationResults( + typecheckConfig, compilationResult, expectedDiagnostics); } } diff --git a/tests/checkers/inference/test/InferenceTestPhase.java b/tests/checkers/inference/test/InferenceTestPhase.java index e929b5211..052364e5a 100644 --- a/tests/checkers/inference/test/InferenceTestPhase.java +++ b/tests/checkers/inference/test/InferenceTestPhase.java @@ -1,6 +1,5 @@ package checkers.inference.test; - public enum InferenceTestPhase { INITIAL_TYPECHECK, INFER, diff --git a/tests/checkers/inference/test/InferenceTestResult.java b/tests/checkers/inference/test/InferenceTestResult.java index da6106098..af715ad9e 100644 --- a/tests/checkers/inference/test/InferenceTestResult.java +++ b/tests/checkers/inference/test/InferenceTestResult.java @@ -11,9 +11,13 @@ public class InferenceTestResult { private final TypecheckResult finalTypecheckResult; private final InferenceTestPhase lastPhaseRun; - public InferenceTestResult(InferenceTestConfiguration configuration, TypecheckResult initialTypecheckingResult, - InferenceResult inferenceResult, InsertionResult insertionResult, - TypecheckResult finalTypecheckResult, InferenceTestPhase lastPhaseRun) { + public InferenceTestResult( + InferenceTestConfiguration configuration, + TypecheckResult initialTypecheckingResult, + InferenceResult inferenceResult, + InsertionResult insertionResult, + TypecheckResult finalTypecheckResult, + InferenceTestPhase lastPhaseRun) { this.configuration = configuration; this.initialTypecheckingResult = initialTypecheckingResult; this.inferenceResult = inferenceResult; diff --git a/tests/checkers/inference/test/InferenceTestUtilities.java b/tests/checkers/inference/test/InferenceTestUtilities.java index c55606bfa..9c44e36f1 100644 --- a/tests/checkers/inference/test/InferenceTestUtilities.java +++ b/tests/checkers/inference/test/InferenceTestUtilities.java @@ -2,6 +2,7 @@ import org.checkerframework.framework.test.TestUtilities; import org.checkerframework.framework.test.TypecheckResult; +import org.junit.Assert; import java.io.BufferedReader; import java.io.BufferedWriter; @@ -14,11 +15,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.junit.Assert; - -/** - * Created by jburke on 7/7/15. - */ +/** Created by jburke on 7/7/15. */ public class InferenceTestUtilities { public static List replaceParentDirs(File newParent, List testSourceFiles) { @@ -29,7 +26,8 @@ public static List replaceParentDirs(File newParent, List testSource return outFiles; } - public static List replacePath(File testDataDir, File annotatedSourceDir, List testSourceFiles) { + public static List replacePath( + File testDataDir, File annotatedSourceDir, List testSourceFiles) { final String testDataPath = testDataDir.getAbsolutePath(); final String annotatedSrcPath = annotatedSourceDir.getAbsolutePath(); @@ -91,8 +89,7 @@ public static void assertIsDir(File file) { } public static void assertFail(InferenceTestPhase lastPhase, String summary) { - String message = - "Test failed during " + lastPhase + " phase!\n" + summary; + String message = "Test failed during " + lastPhase + " phase!\n" + summary; Assert.fail(message); } @@ -101,7 +98,9 @@ public static void assertResultsAreValid(InferenceTestResult testResult) { switch (lastPhaseRun) { case INITIAL_TYPECHECK: - assertFail(InferenceTestPhase.INITIAL_TYPECHECK, testResult.getInitialTypecheckingResult().summarize()); + assertFail( + InferenceTestPhase.INITIAL_TYPECHECK, + testResult.getInitialTypecheckingResult().summarize()); break; case INFER: @@ -115,23 +114,25 @@ public static void assertResultsAreValid(InferenceTestResult testResult) { case FINAL_TYPECHECK: TypecheckResult finalTypecheckResult = testResult.getFinalTypecheckResult(); if (finalTypecheckResult.didTestFail()) { - assertFail(InferenceTestPhase.FINAL_TYPECHECK, finalTypecheckResult.summarize()); + assertFail( + InferenceTestPhase.FINAL_TYPECHECK, finalTypecheckResult.summarize()); } break; } } public static List findAllSystemTests() { - File frameworkTestsDir = InferenceTestUtilities.findInCheckerFrameworkDir("framework/tests"); + File frameworkTestsDir = + InferenceTestUtilities.findInCheckerFrameworkDir("framework/tests"); InferenceTestUtilities.assertIsDir(frameworkTestsDir); return TestUtilities.findRelativeNestedJavaFiles(frameworkTestsDir, "all-systems"); } /** - * The Annotation File Utility has adds annotations followed by a new line for - * fields/methods. This will cause diagnostics that were on those fields and methods to - * point to the wrong line. This method detects any location where there is an annotation - * on a line by itself followed by a non-empty line. It moves that annotation onto the next line. + * The Annotation File Utility has adds annotations followed by a new line for fields/methods. + * This will cause diagnostics that were on those fields and methods to point to the wrong line. + * This method detects any location where there is an annotation on a line by itself followed by + * a non-empty line. It moves that annotation onto the next line. * * @param javaFile */ @@ -158,26 +159,27 @@ public static List inlineAnnotationsAfterDiagnostics(List lines) Matcher nonWhitespaceMatcher = nonWhitespacePattern.matcher(nextLine); if (!nonWhitespaceMatcher.find()) { - i += 2; //skip this line and the blank line + i += 2; // skip this line and the blank line outputLines.add(currentLine); outputLines.add(nextLine); continue; - } //else + } // else int firstNonWhitespaceIndex = nonWhitespaceMatcher.start(); String withoutIndent = nextLine.substring(firstNonWhitespaceIndex); - boolean isCommented = withoutIndent.startsWith("\\\\") || withoutIndent.startsWith("\\*"); + boolean isCommented = + withoutIndent.startsWith("\\\\") || withoutIndent.startsWith("\\*"); if (isCommented) { - i += 2; //skip this line and the comment line + i += 2; // skip this line and the comment line outputLines.add(currentLine); outputLines.add(nextLine); continue; - } //else + } // else String indent = nextLine.substring(0, firstNonWhitespaceIndex); String nextLineWithAnno = indent + currentLine.trim() + " " + withoutIndent; - i += 2; //skip this line and the next line + i += 2; // skip this line and the next line outputLines.add(nextLineWithAnno); } else { @@ -188,7 +190,7 @@ public static List inlineAnnotationsAfterDiagnostics(List lines) if (i == lines.size() - 1) { outputLines.add(lines.get(i)); - } //else this was consumed in the while loop above + } // else this was consumed in the while loop above return outputLines; } @@ -205,7 +207,6 @@ public static List getLines(File javaFile) { } else { break; } - } lineReader.close(); return lines; diff --git a/tests/checkers/inference/test/InsertionResult.java b/tests/checkers/inference/test/InsertionResult.java index a507daf8b..a721e062d 100644 --- a/tests/checkers/inference/test/InsertionResult.java +++ b/tests/checkers/inference/test/InsertionResult.java @@ -2,16 +2,16 @@ public class InsertionResult { private boolean failed; - private String [] options; + private String[] options; private String output; - public InsertionResult(String [] options, boolean failed, String output) { + public InsertionResult(String[] options, boolean failed, String output) { this.failed = failed; this.output = output; this.options = options; } - public String [] getOptions() { + public String[] getOptions() { return options; } @@ -24,8 +24,12 @@ public boolean didFail() { } public String summarize() { - return "AFU Insertion " + (didFail() ? " succeeeded " : " failed\n") - + "Output\n\n" + output + "\non command: " + getCommand() + "\n\n"; + return "AFU Insertion " + + (didFail() ? " succeeeded " : " failed\n") + + "Output\n\n" + + output + + "\non command: " + + getCommand() + + "\n\n"; } - } diff --git a/tests/checkers/system/StatisticsMultithreadTest.java b/tests/checkers/system/StatisticsMultithreadTest.java index 4069db51e..5b9881422 100644 --- a/tests/checkers/system/StatisticsMultithreadTest.java +++ b/tests/checkers/system/StatisticsMultithreadTest.java @@ -1,5 +1,7 @@ package checkers.system; +import org.junit.Test; + import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -8,8 +10,6 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import org.junit.Test; - import checkers.inference.model.Constraint; import checkers.inference.model.Serializer; import checkers.inference.model.Slot; @@ -41,7 +41,8 @@ protected void tearDown() throws Exception { /** * Functional interface for creating threads. * - * Each thread is given a unique threadID and the return object must implement {@link Runnable}. + *

    Each thread is given a unique threadID and the return object must implement {@link + * Runnable}. */ @FunctionalInterface private interface ThreadMaker { @@ -52,8 +53,7 @@ private interface ThreadMaker { * Helper which runs a number of threads, using the given lambda to create threads, and waits * until all threads have completed. * - * @param threadMaker - * lambda parameter which should return newly created threads + * @param threadMaker lambda parameter which should return newly created threads */ private void runThreads(ThreadMaker threadMaker) { // create and execute 100 threads, each trying to add or update an entry to the statistics @@ -163,7 +163,6 @@ public Kind getKind() { public boolean isInsertable() { return false; } - } private class DummyTwoSlot extends Slot { @@ -185,7 +184,6 @@ public Kind getKind() { public boolean isInsertable() { return false; } - } // ======================================= @@ -204,7 +202,8 @@ public void testRecordConstraintsStatistics() { Map finalStatistics = Statistics.getStatistics(); checkEqual(finalStatistics, classStatsKeyName(DummyOneTestConstraint.class), numOfThreads); - checkEqual(finalStatistics, classStatsKeyName(DummyTwoTestConstraint.class), 2 * numOfThreads); + checkEqual( + finalStatistics, classStatsKeyName(DummyTwoTestConstraint.class), 2 * numOfThreads); } private class RecordConstraintsTestThread implements Runnable { @@ -237,4 +236,3 @@ public T serialize(Serializer serializer) { } } } - diff --git a/tests/checkers/typecheck/DataflowTypecheckTest.java b/tests/checkers/typecheck/DataflowTypecheckTest.java index 560a439f2..0606d0993 100644 --- a/tests/checkers/typecheck/DataflowTypecheckTest.java +++ b/tests/checkers/typecheck/DataflowTypecheckTest.java @@ -11,14 +11,21 @@ public class DataflowTypecheckTest extends CheckerFrameworkPerFileTest { public DataflowTypecheckTest(File testFile) { - super(testFile, dataflow.DataflowChecker.class, "dataflow", - "-Anomsgtext", "-d", "tests/build/outputdir"); + super( + testFile, + dataflow.DataflowChecker.class, + "dataflow", + "-Anomsgtext", + "-d", + "tests/build/outputdir"); } @Parameters - public static List getTestFiles(){ + public static List getTestFiles() { List testfiles = new ArrayList<>(); - testfiles.addAll(TestUtilities.findRelativeNestedJavaFiles("testing", "dataflow-not-inferrable-test")); + testfiles.addAll( + TestUtilities.findRelativeNestedJavaFiles( + "testing", "dataflow-not-inferrable-test")); return testfiles; } } diff --git a/tests/checkers/typecheck/OstrustedTest.java b/tests/checkers/typecheck/OstrustedTest.java index 77444f50a..83f13c333 100644 --- a/tests/checkers/typecheck/OstrustedTest.java +++ b/tests/checkers/typecheck/OstrustedTest.java @@ -11,14 +11,22 @@ public class OstrustedTest extends CheckerFrameworkPerFileTest { public OstrustedTest(File testFile) { - super(testFile, ostrusted.OsTrustedChecker.class, "ostrusted", - "-Anomsgtext", "-Astubs=src/ostrusted/jdk.astub", "-d", "tests/build/outputdir"); + super( + testFile, + ostrusted.OsTrustedChecker.class, + "ostrusted", + "-Anomsgtext", + "-Astubs=src/ostrusted/jdk.astub", + "-d", + "tests/build/outputdir"); } @Parameters - public static List getTestFiles(){ + public static List getTestFiles() { List testfiles = new ArrayList<>(); - testfiles.addAll(TestUtilities.findRelativeNestedJavaFiles("testdata", "ostrusted-not-inferrable-test")); + testfiles.addAll( + TestUtilities.findRelativeNestedJavaFiles( + "testdata", "ostrusted-not-inferrable-test")); return testfiles; } }