Skip to content

Commit

Permalink
Handle extends/implements clauses. Fixes #326. (#327)
Browse files Browse the repository at this point in the history
  • Loading branch information
d367wang authored May 21, 2021
1 parent 8f47886 commit 2ea2665
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 36 deletions.
13 changes: 13 additions & 0 deletions src/checkers/inference/InferenceAnnotatedTypeFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -579,5 +579,18 @@ public Set<AnnotationMirror> getTypeDeclarationBounds(TypeMirror type) {
// If the declaration bound of the underlying type is not cached, use default
return (Set<AnnotationMirror>) getDefaultTypeDeclarationBounds();
}

/**
* 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
*/
@Override
public AnnotatedTypeMirror getTypeOfExtendsImplements(Tree clause) {
return getAnnotatedTypeFromTypeTree(clause);
}
}

7 changes: 6 additions & 1 deletion src/checkers/inference/InferenceTreeAnnotator.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public InferenceTreeAnnotator(final InferenceAnnotatedTypeFactory atypeFactory,

@Override
public Void visitAnnotatedType(AnnotatedTypeTree node, AnnotatedTypeMirror atm) {
visit(node.getUnderlyingType(), atm);
variableAnnotator.visit(atm, node);
return null;
}

Expand Down Expand Up @@ -155,6 +155,11 @@ public Void visitIdentifier(IdentifierTree node, AnnotatedTypeMirror identifierT
}
}

} else if (parentNode.getKind() == Kind.CLASS) {
// This happens when a class explicitly extends another class or implements
// another interface
variableAnnotator.visit(identifierType, node);

}
}
}
Expand Down
32 changes: 23 additions & 9 deletions src/checkers/inference/VariableAnnotator.java
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,7 @@ private Slot addPrimaryVariable(AnnotatedTypeMirror atm, final Tree tree) {
treeToVarAnnoPair.put(tree, varATMPair);
}

atm.removeAnnotationInHierarchy(realTop);
atm.replaceAnnotation(slotManager.getAnnotation(variable));

return variable;
Expand Down Expand Up @@ -570,6 +571,11 @@ private Slot replaceOrCreateEquivalentVarAnno(AnnotatedTypeMirror atm, Tree tree
varSlot = createVariable(location, atm.getUnderlyingType());
}

if (realQualifier != null) {
// Remove the real qualifier in the atm, to make sure the source code
// is only annotated with @VarAnnot
atm.removeAnnotation(realQualifier);
}
atm.replaceAnnotation(slotManager.getAnnotation(varSlot));
return varSlot;
}
Expand Down Expand Up @@ -773,8 +779,16 @@ private void handleClassDeclaration(AnnotatedDeclaredType classType, ClassTree c
superTypes.get(0).replaceAnnotation(slotManager.getAnnotation(extendsSlot));

} else {
final AnnotatedTypeMirror extendsType = inferenceTypeFactory.getAnnotatedTypeFromTypeTree(extendsTree);
visit(extendsType, extendsTree);
// Since only extends trees with a non-null tree path are handled (see
// checkers.inference.InferenceTreeAnnotator#visitIdentifier for more details),
// here don't dig deeper onto the extends tree when the classTree path is null.
// Note: the classTree path is null when the variableAnnotater is visiting it from
// a different compilation unit. The extends tree should be annotated when the
// compiler moves forward to the compilation unit containing the class definition.
if (inferenceTypeFactory.getPath(classTree) != null) {
final AnnotatedTypeMirror extendsType = inferenceTypeFactory.getAnnotatedTypeFromTypeTree(extendsTree);
visit(extendsType, extendsTree);
}
}

// // TODO: NOT SURE THIS HANDLES MEMBER SELECT CORRECTLY
Expand Down Expand Up @@ -1617,16 +1631,16 @@ protected Boolean scan(AnnotatedTypeMirror type, Void aVoid) {
* If it does not already exist, this method creates the annotation and stores it in classDeclAnnos.
*/
private Slot getOrCreateDeclBound(AnnotatedDeclaredType type) {

TypeElement classDecl = (TypeElement) type.getUnderlyingType().asElement();
TypeElement classElt = (TypeElement) type.getUnderlyingType().asElement();

Slot topConstant = getTopConstant();
Slot declSlot = classDeclAnnos.get(classDecl);
Slot declSlot = classDeclAnnos.get(classElt);
if (declSlot == null) {
Tree decl = inferenceTypeFactory.declarationFromElement(classDecl);
if (decl != null) {
declSlot = createVariable(decl);
classDeclAnnos.put(classDecl, (SourceVariableSlot) declSlot);
Tree classTree = inferenceTypeFactory.declarationFromElement(classElt);
if (classTree != null) {
final AnnotatedDeclaredType declType = inferenceTypeFactory.fromElement(classElt);
declSlot = replaceOrCreateEquivalentVarAnno(declType, classTree, treeToLocation(classTree));
classDeclAnnos.put(classElt, (SourceVariableSlot) declSlot);

} else {
declSlot = topConstant;
Expand Down
29 changes: 3 additions & 26 deletions src/ostrusted/jdk.astub
Original file line number Diff line number Diff line change
Expand Up @@ -29,29 +29,6 @@ class System {
public static void loadLibrary(@OsTrusted String libname);
}



























public class Object {
public @OsTrusted Object() {}
}
9 changes: 9 additions & 0 deletions testdata/ostrusted-inferrable-test/Bounds.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Test case for issue 326:
// https://github.com/opprop/checker-framework-inference/issues/326

import ostrusted.qual.OsTrusted;

@SuppressWarnings("inconsistent.constructor.type")
// :: fixable-error: (declaration.inconsistent.with.extends.clause)
class A extends @OsTrusted Object {}

0 comments on commit 2ea2665

Please sign in to comment.