Skip to content

Commit

Permalink
Prevent certain insertions based on annotation target type; fixes #216
Browse files Browse the repository at this point in the history
  • Loading branch information
mernst authored Jun 16, 2019
1 parent 1776438 commit ccf7fd0
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package annotator.find;

import scenelib.annotations.Annotation;
import org.plumelib.util.Pair;

/**
Expand All @@ -22,6 +23,13 @@ public class AnnotationInsertion extends Insertion {
*/
private final String fullyQualifiedAnnotationName;

/**
* The annotation being inserted.
*
* Used to look up target types.
*/
private final Annotation annotation;

private String type;
private boolean generateBound;
private boolean generateExtends;
Expand All @@ -36,12 +44,26 @@ public class AnnotationInsertion extends Insertion {
* @param separateLine whether to insert the annotation on its own
*/
public AnnotationInsertion(String fullyQualifiedAnnotationText, Criteria criteria, boolean separateLine) {
this(fullyQualifiedAnnotationText, criteria, separateLine, null);
}

/**
* Creates a new insertion.
*
* @param fullyQualifiedAnnotationText the annotation text to be inserted into source code;
* starts with "@", and must be a fully-qualified name
* @param criteria where to insert the annotation
* @param separateLine whether to insert the annotation on its own
* @param annotation the annotation being inserted
*/
public AnnotationInsertion(String fullyQualifiedAnnotationText, Criteria criteria, boolean separateLine, Annotation annotation) {
super(criteria, separateLine);
assert fullyQualifiedAnnotationText.startsWith("@") : fullyQualifiedAnnotationText;
// A fully-qualified name in the default package does not contain a period
// assert fullyQualifiedAnnotationText.contains(".") : fullyQualifiedAnnotationText;
this.fullyQualifiedAnnotationText = fullyQualifiedAnnotationText;
this.fullyQualifiedAnnotationName = extractAnnotationFullyQualifiedName();
this.annotation = annotation;
type = null;
generateBound = false;
generateExtends = false;
Expand Down Expand Up @@ -182,4 +204,13 @@ public String toString() {
public void setType(String s) {
this.type = s;
}

/**
* Returns the annotation being inserted.
*
* @return the annotation being inserted.
*/
public Annotation getAnnotation() {
return annotation;
}
}
37 changes: 34 additions & 3 deletions annotation-file-utilities/src/annotator/find/TreeFinder.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package annotator.find;

import annotator.find.Insertion.Kind;

import scenelib.annotations.el.AnnotationDef;
import scenelib.annotations.Annotation;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
Expand Down Expand Up @@ -223,7 +227,8 @@ private int getNthInstanceInRange(char c, int start, int end, int n) {

// Find a node's parent in the current source tree.
private Tree parent(Tree node) {
return getPath(node).getParentPath().getLeaf();
TreePath parentPath = getPath(node).getParentPath();
return (parentPath == null) ? null : parentPath.getLeaf();
}

/**
Expand Down Expand Up @@ -958,7 +963,7 @@ private boolean wildcardLast(List<TypePathEntry> location) {
* Scans this tree, using the list of insertions to generate the source
* position to insertion text mapping. Insertions are removed from the
* list when positions are found for them. Thus, they are inserted at the
* first location (the one highest in the tree) that they match.
* first location (the leftmost highest in the tree) that they match.
*
* <p>When a match is found, this routine removes the insertion from p and
* adds it to the insertions map as a value, with a key that is a pair.
Expand Down Expand Up @@ -1028,7 +1033,33 @@ public Void scan(Tree node, List<Insertion> p) {
dbug.debug(" Type of node: %s%n", node.getClass());

ASTPath astPath = i.getCriteria().getASTPath();
dbug.debug(" astPath = %s%n", astPath);
dbug.debug(" astPath = %s [%s]%n", astPath, (astPath == null) ? null : astPath.getClass());

// If the annotation is not applicable to this location, then
// continue looking elsewhere for a match.
// This is a hack, because the design of Criteria is broken.
if (i.getKind() == Insertion.Kind.ANNOTATION) {
AnnotationDef adef = ((AnnotationInsertion) i).getAnnotation().def();
boolean isTypeAnnotation = adef.isTypeAnnotation();

switch (node.getKind()) {
case NEW_CLASS:
if (! isTypeAnnotation) {
continue;
}
break;
case IDENTIFIER:
Tree parent = parent(node);
Tree.Kind parentKind = parent.getKind();
if (parentKind == Tree.Kind.NEW_CLASS) {
continue;
}
break;
default:
// TODO: make this switch statement exhaustive and check each case.
}
}

Integer pos = astPath == null ? findPosition(path, i)
: Main.convert_jaifs ? null // already in correct form
: findPositionByASTPath(astPath, path, i);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ private List<Insertion> parseElement(CriterionList clist, AElement element,
criteria.add(new IntersectionTypeLocationCriterion(loc));
}
Insertion ins = new AnnotationInsertion(annotationString, criteria,
!isTypeAnnotationOnly);
!isTypeAnnotationOnly, annotation);
debug("parsed: " + ins);
if (!isCastInsertion) {
// Annotations on compound types of a cast insertion will be
Expand Down
1 change: 1 addition & 0 deletions annotation-file-utilities/tests/Issue216.goal
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
class Issue216 {

Object value;
Object value2 = new Object();

@org.checkerframework.dataflow.qual.SideEffectFree
public Issue216() {}
Expand Down
1 change: 1 addition & 0 deletions annotation-file-utilities/tests/Issue216.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
class Issue216 {

Object value;
Object value2 = new Object();

public Issue216() {}
}

0 comments on commit ccf7fd0

Please sign in to comment.