use of org.checkerframework.javacutil.Pair in project checker-framework by typetools.
the class TypeArgumentMapper method mapTypeArgumentIndices.
/**
* Returns a mapping from subtype's type parameter indices to the indices of corresponding type
* parameters in supertype.
*/
public static Set<Pair<Integer, Integer>> mapTypeArgumentIndices(final TypeElement subtype, final TypeElement supertype, final Types types) {
Set<Pair<Integer, Integer>> result = new HashSet<>();
if (subtype.equals(supertype)) {
for (int i = 0; i < subtype.getTypeParameters().size(); i++) {
result.add(Pair.of(Integer.valueOf(i), Integer.valueOf(i)));
}
} else {
Map<TypeParameterElement, Set<TypeParameterElement>> subToSuperElements = mapTypeArguments(subtype, supertype, types);
Map<TypeParameterElement, Integer> supertypeIndexes = getElementToIndex(supertype);
final List<? extends TypeParameterElement> subtypeParams = subtype.getTypeParameters();
for (int subtypeIndex = 0; subtypeIndex < subtypeParams.size(); subtypeIndex++) {
final TypeParameterElement subtypeParam = subtypeParams.get(subtypeIndex);
final Set<TypeParameterElement> correspondingSuperArgs = subToSuperElements.get(subtypeParam);
if (correspondingSuperArgs != null) {
for (TypeParameterElement supertypeParam : subToSuperElements.get(subtypeParam)) {
result.add(Pair.of(subtypeIndex, supertypeIndexes.get(supertypeParam)));
}
}
}
}
return result;
}
use of org.checkerframework.javacutil.Pair in project checker-framework by typetools.
the class AnnotatedTypeFactory method getDeclAnnotationWithMetaAnnotation.
/**
* Returns a list of all declaration annotations used to annotate the element, which have a
* meta-annotation (i.e., an annotation on that annotation) with class {@code
* metaAnnotationClass}.
*
* @param element the element for which to determine annotations
* @param metaAnnotationClass the class of the meta-annotation that needs to be present
* @return a list of pairs {@code (anno, metaAnno)} where {@code anno} is the annotation mirror at
* {@code element}, and {@code metaAnno} is the annotation mirror (of type {@code
* metaAnnotationClass}) used to meta-annotate the declaration of {@code anno}
*/
public List<Pair<AnnotationMirror, AnnotationMirror>> getDeclAnnotationWithMetaAnnotation(Element element, Class<? extends Annotation> metaAnnotationClass) {
List<Pair<AnnotationMirror, AnnotationMirror>> result = new ArrayList<>();
Set<AnnotationMirror> annotationMirrors = getDeclAnnotations(element);
for (AnnotationMirror candidate : annotationMirrors) {
List<? extends AnnotationMirror> metaAnnotationsOnAnnotation;
try {
metaAnnotationsOnAnnotation = candidate.getAnnotationType().asElement().getAnnotationMirrors();
} catch (com.sun.tools.javac.code.Symbol.CompletionFailure cf) {
// Fix for Issue 309: If a CompletionFailure occurs, issue a warning.
// I didn't find a nicer alternative to check whether the Symbol can be completed.
// The completer field of a Symbol might be non-null also in successful cases.
// Issue a warning (exception only happens once) and continue.
checker.reportWarning(candidate.getAnnotationType().asElement(), "annotation.not.completed", ElementUtils.getQualifiedName(element), candidate);
continue;
}
// First call copier, if exception, continue normal modula laws.
for (AnnotationMirror ma : metaAnnotationsOnAnnotation) {
if (areSameByClass(ma, metaAnnotationClass)) {
// It might be a real contract, or a list of contracts.
if (isListForRepeatedAnnotation(candidate)) {
// concrete annotation class is not known
@SuppressWarnings("deprecation") List<AnnotationMirror> wrappedCandidates = AnnotationUtils.getElementValueArray(candidate, "value", AnnotationMirror.class, false);
for (AnnotationMirror wrappedCandidate : wrappedCandidates) {
result.add(Pair.of(wrappedCandidate, ma));
}
} else {
result.add(Pair.of(candidate, ma));
}
}
}
}
return result;
}
use of org.checkerframework.javacutil.Pair in project checker-framework by typetools.
the class AnnotatedTypeFactory method getAnnotationWithMetaAnnotation.
/**
* Returns a list of all annotations used to annotate this element, which have a meta-annotation
* (i.e., an annotation on that annotation) with class {@code metaAnnotationClass}.
*
* @param element the element at which to look for annotations
* @param metaAnnotationClass the class of the meta-annotation that needs to be present
* @return a list of pairs {@code (anno, metaAnno)} where {@code anno} is the annotation mirror at
* {@code element}, and {@code metaAnno} is the annotation mirror used to annotate {@code
* anno}.
*/
public List<Pair<AnnotationMirror, AnnotationMirror>> getAnnotationWithMetaAnnotation(Element element, Class<? extends Annotation> metaAnnotationClass) {
Set<AnnotationMirror> annotationMirrors = AnnotationUtils.createAnnotationSet();
// Consider real annotations.
annotationMirrors.addAll(getAnnotatedType(element).getAnnotations());
// Consider declaration annotations
annotationMirrors.addAll(getDeclAnnotations(element));
List<Pair<AnnotationMirror, AnnotationMirror>> result = new ArrayList<>();
// Go through all annotations found.
for (AnnotationMirror annotation : annotationMirrors) {
List<? extends AnnotationMirror> annotationsOnAnnotation = annotation.getAnnotationType().asElement().getAnnotationMirrors();
for (AnnotationMirror a : annotationsOnAnnotation) {
if (areSameByClass(a, metaAnnotationClass)) {
result.add(Pair.of(annotation, a));
}
}
}
return result;
}
use of org.checkerframework.javacutil.Pair in project checker-framework by typetools.
the class GenericAnnotatedTypeFactory method performFlowAnalysis.
/**
* Perform a org.checkerframework.dataflow analysis over a single class tree and its nested
* classes.
*
* @param classTree the class to analyze
*/
protected void performFlowAnalysis(ClassTree classTree) {
if (flowResult == null) {
regularExitStores = new IdentityHashMap<>();
exceptionalExitStores = new IdentityHashMap<>();
returnStatementStores = new IdentityHashMap<>();
flowResult = new AnalysisResult<>(flowResultAnalysisCaches);
}
// no need to scan annotations
if (classTree.getKind() == Tree.Kind.ANNOTATION_TYPE) {
// Mark finished so that default annotations will be applied.
scannedClasses.put(classTree, ScanState.FINISHED);
return;
}
Queue<Pair<ClassTree, Store>> queue = new ArrayDeque<>();
List<FieldInitialValue<Value>> fieldValues = new ArrayList<>();
// No captured store for top-level classes.
queue.add(Pair.of(classTree, null));
while (!queue.isEmpty()) {
final Pair<ClassTree, Store> qel = queue.remove();
final ClassTree ct = qel.first;
final Store capturedStore = qel.second;
scannedClasses.put(ct, ScanState.IN_PROGRESS);
TreePath preTreePath = getVisitorTreePath();
// Don't use getPath, because that depends on the assignmentContext path.
setVisitorTreePath(TreePath.getPath(this.root, ct));
// start with the captured store as initialization store
initializationStaticStore = capturedStore;
initializationStore = capturedStore;
Queue<Pair<LambdaExpressionTree, Store>> lambdaQueue = new ArrayDeque<>();
try {
List<CFGMethod> methods = new ArrayList<>();
List<? extends Tree> members = ct.getMembers();
if (!Ordering.from(sortVariablesFirst).isOrdered(members)) {
members = new ArrayList<>(members);
// Process variables before methods, so all field initializers are observed before the
// constructor is analyzed and reports uninitialized variables.
members.sort(sortVariablesFirst);
}
for (Tree m : members) {
switch(TreeUtils.getKindRecordAsClass(m)) {
case METHOD:
MethodTree mt = (MethodTree) m;
// Skip abstract and native methods because they have no body.
Set<Modifier> flags = mt.getModifiers().getFlags();
if (flags.contains(Modifier.ABSTRACT) || flags.contains(Modifier.NATIVE)) {
break;
}
// ABSTRACT flag.
if (mt.getBody() == null) {
break;
}
// Wait with scanning the method until all other members
// have been processed.
CFGMethod met = new CFGMethod(mt, ct);
methods.add(met);
break;
case VARIABLE:
VariableTree vt = (VariableTree) m;
ExpressionTree initializer = vt.getInitializer();
AnnotatedTypeMirror declaredType = getAnnotatedTypeLhs(vt);
Value declaredValue = analysis.createAbstractValue(declaredType);
FieldAccess fieldExpr = (FieldAccess) JavaExpression.fromVariableTree(vt);
// analyze initializer if present
if (initializer != null) {
boolean isStatic = vt.getModifiers().getFlags().contains(Modifier.STATIC);
analyze(queue, lambdaQueue, new CFGStatement(vt, ct), fieldValues, classTree, true, true, isStatic, capturedStore);
Value initializerValue = flowResult.getValue(initializer);
if (initializerValue != null) {
fieldValues.add(new FieldInitialValue<>(fieldExpr, declaredValue, initializerValue));
break;
}
}
fieldValues.add(new FieldInitialValue<>(fieldExpr, declaredValue, null));
break;
// Including RECORD
case CLASS:
case ANNOTATION_TYPE:
case INTERFACE:
case ENUM:
// Visit inner and nested class trees.
// TODO: Use no store for them? What can be captured?
queue.add(Pair.of((ClassTree) m, capturedStore));
break;
case BLOCK:
BlockTree b = (BlockTree) m;
analyze(queue, lambdaQueue, new CFGStatement(b, ct), fieldValues, ct, true, true, b.isStatic(), capturedStore);
break;
default:
assert false : "Unexpected member: " + m.getKind();
break;
}
}
// fields of superclasses.
for (CFGMethod met : methods) {
analyze(queue, lambdaQueue, met, fieldValues, classTree, TreeUtils.isConstructor(met.getMethod()), false, false, capturedStore);
}
while (!lambdaQueue.isEmpty()) {
Pair<LambdaExpressionTree, Store> lambdaPair = lambdaQueue.poll();
MethodTree mt = (MethodTree) TreePathUtil.enclosingOfKind(getPath(lambdaPair.first), Tree.Kind.METHOD);
analyze(queue, lambdaQueue, new CFGLambda(lambdaPair.first, classTree, mt), fieldValues, classTree, false, false, false, lambdaPair.second);
}
// See InitializationVisitor.visitClass().
if (initializationStaticStore == null) {
regularExitStores.put(ct, emptyStore);
} else {
regularExitStores.put(ct, initializationStaticStore);
}
} finally {
setVisitorTreePath(preTreePath);
}
scannedClasses.put(ct, ScanState.FINISHED);
}
}
use of org.checkerframework.javacutil.Pair in project checker-framework by typetools.
the class CFGTranslationPhaseOne method visitTry.
@Override
public Node visitTry(TryTree tree, Void p) {
List<? extends CatchTree> catches = tree.getCatches();
BlockTree finallyBlock = tree.getFinallyBlock();
extendWithNode(new MarkerNode(tree, "start of try statement #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
List<Pair<TypeMirror, Label>> catchLabels = CollectionsPlume.mapList((CatchTree c) -> {
return Pair.of(TreeUtils.typeOf(c.getParameter().getType()), new Label());
}, catches);
// Store return/break/continue labels, just in case we need them for a finally block.
TryFinallyScopeCell oldReturnTargetL = returnTargetL;
TryFinallyScopeCell oldBreakTargetL = breakTargetL;
Map<Name, Label> oldBreakLabels = breakLabels;
TryFinallyScopeCell oldContinueTargetL = continueTargetL;
Map<Name, Label> oldContinueLabels = continueLabels;
Label finallyLabel = null;
Label exceptionalFinallyLabel = null;
if (finallyBlock != null) {
finallyLabel = new Label();
exceptionalFinallyLabel = new Label();
tryStack.pushFrame(new TryFinallyFrame(exceptionalFinallyLabel));
returnTargetL = new TryFinallyScopeCell();
breakTargetL = new TryFinallyScopeCell();
breakLabels = new TryFinallyScopeMap();
continueTargetL = new TryFinallyScopeCell();
continueLabels = new TryFinallyScopeMap();
}
Label doneLabel = new Label();
tryStack.pushFrame(new TryCatchFrame(types, catchLabels));
// Must scan the resources *after* we push frame to tryStack. Otherwise we can lose catch
// blocks.
// TODO: Should we handle try-with-resources blocks by also generating code for automatically
// closing the resources?
List<? extends Tree> resources = tree.getResources();
for (Tree resource : resources) {
scan(resource, p);
}
extendWithNode(new MarkerNode(tree, "start of try block #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
scan(tree.getBlock(), p);
extendWithNode(new MarkerNode(tree, "end of try block #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
extendWithExtendedNode(new UnconditionalJump(CFGBuilder.firstNonNull(finallyLabel, doneLabel)));
tryStack.popFrame();
int catchIndex = 0;
for (CatchTree c : catches) {
addLabelForNextNode(catchLabels.get(catchIndex).second);
extendWithNode(new MarkerNode(tree, "start of catch block for " + c.getParameter().getType() + " #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
scan(c, p);
extendWithNode(new MarkerNode(tree, "end of catch block for " + c.getParameter().getType() + " #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
catchIndex++;
extendWithExtendedNode(new UnconditionalJump(CFGBuilder.firstNonNull(finallyLabel, doneLabel)));
}
if (finallyLabel != null) {
// Reset values before analyzing the finally block!
tryStack.popFrame();
{
// Scan 'finallyBlock' for only 'finallyLabel' (a successful path)
addLabelForNextNode(finallyLabel);
extendWithNode(new MarkerNode(tree, "start of finally block #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
scan(finallyBlock, p);
extendWithNode(new MarkerNode(tree, "end of finally block #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
extendWithExtendedNode(new UnconditionalJump(doneLabel));
}
if (hasExceptionalPath(exceptionalFinallyLabel)) {
// If an exceptional path exists, scan 'finallyBlock' for 'exceptionalFinallyLabel', and
// scan copied 'finallyBlock' for 'finallyLabel' (a successful path). If there is no
// successful path, it will be removed in later phase.
// TODO: Don't we need a separate finally block for each kind of exception?
addLabelForNextNode(exceptionalFinallyLabel);
extendWithNode(new MarkerNode(tree, "start of finally block for Throwable #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
scan(finallyBlock, p);
NodeWithExceptionsHolder throwing = extendWithNodeWithException(new MarkerNode(tree, "end of finally block for Throwable #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()), throwableType);
throwing.setTerminatesExecution(true);
}
if (returnTargetL.wasAccessed()) {
addLabelForNextNode(returnTargetL.peekLabel());
returnTargetL = oldReturnTargetL;
extendWithNode(new MarkerNode(tree, "start of finally block for return #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
scan(finallyBlock, p);
extendWithNode(new MarkerNode(tree, "end of finally block for return #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
extendWithExtendedNode(new UnconditionalJump(returnTargetL.accessLabel()));
} else {
returnTargetL = oldReturnTargetL;
}
if (breakTargetL.wasAccessed()) {
addLabelForNextNode(breakTargetL.peekLabel());
breakTargetL = oldBreakTargetL;
extendWithNode(new MarkerNode(tree, "start of finally block for break #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
scan(finallyBlock, p);
extendWithNode(new MarkerNode(tree, "end of finally block for break #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
extendWithExtendedNode(new UnconditionalJump(breakTargetL.accessLabel()));
} else {
breakTargetL = oldBreakTargetL;
}
Map<Name, Label> accessedBreakLabels = ((TryFinallyScopeMap) breakLabels).getAccessedNames();
if (!accessedBreakLabels.isEmpty()) {
breakLabels = oldBreakLabels;
for (Map.Entry<Name, Label> access : accessedBreakLabels.entrySet()) {
addLabelForNextNode(access.getValue());
extendWithNode(new MarkerNode(tree, "start of finally block for break label " + access.getKey() + " #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
scan(finallyBlock, p);
extendWithNode(new MarkerNode(tree, "end of finally block for break label " + access.getKey() + " #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
extendWithExtendedNode(new UnconditionalJump(breakLabels.get(access.getKey())));
}
} else {
breakLabels = oldBreakLabels;
}
if (continueTargetL.wasAccessed()) {
addLabelForNextNode(continueTargetL.peekLabel());
continueTargetL = oldContinueTargetL;
extendWithNode(new MarkerNode(tree, "start of finally block for continue #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
scan(finallyBlock, p);
extendWithNode(new MarkerNode(tree, "end of finally block for continue #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
extendWithExtendedNode(new UnconditionalJump(continueTargetL.accessLabel()));
} else {
continueTargetL = oldContinueTargetL;
}
Map<Name, Label> accessedContinueLabels = ((TryFinallyScopeMap) continueLabels).getAccessedNames();
if (!accessedContinueLabels.isEmpty()) {
continueLabels = oldContinueLabels;
for (Map.Entry<Name, Label> access : accessedContinueLabels.entrySet()) {
addLabelForNextNode(access.getValue());
extendWithNode(new MarkerNode(tree, "start of finally block for continue label " + access.getKey() + " #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
scan(finallyBlock, p);
extendWithNode(new MarkerNode(tree, "end of finally block for continue label " + access.getKey() + " #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
extendWithExtendedNode(new UnconditionalJump(continueLabels.get(access.getKey())));
}
} else {
continueLabels = oldContinueLabels;
}
}
addLabelForNextNode(doneLabel);
return null;
}
Aggregations