use of com.sun.source.tree.UnionTypeTree in project error-prone by google.
the class ClassNewInstance method fixExceptions.
// if the match occurrs inside the body of a try statement with existing catch clauses
// update or add a catch block to handle the new exceptions
private boolean fixExceptions(final VisitorState state, SuggestedFix.Builder fix) {
TryTree tryTree = null;
OUTER: for (TreePath path = state.getPath(); path != null; path = path.getParentPath()) {
if (path.getLeaf() instanceof CatchTree) {
// don't add more catch blocks if newInstance() was called in a catch block
return false;
} else if (path.getLeaf() instanceof TryTree && !((TryTree) path.getLeaf()).getCatches().isEmpty()) {
tryTree = (TryTree) path.getLeaf();
break;
}
}
if (tryTree == null) {
return false;
}
ImmutableMap.Builder<Type, CatchTree> catches = ImmutableMap.builder();
for (CatchTree c : tryTree.getCatches()) {
catches.put(ASTHelpers.getType(c.getParameter().getType()), c);
}
UnhandledResult<CatchTree> result = unhandled(catches.build(), state);
if (result.unhandled.isEmpty()) {
// no fix needed
return true;
}
{
// if there's an existing multi-catch at the end that handles reflective exceptions,
// replace all of them with ROE and leave any non-reflective exceptions.
// earlier catch blocks are left unchanged.
CatchTree last = Iterables.getLast(tryTree.getCatches());
Tree lastType = last.getParameter().getType();
if (lastType.getKind() == Tree.Kind.UNION_TYPE) {
Type roe = state.getTypeFromString(ReflectiveOperationException.class.getName());
Set<String> exceptions = new LinkedHashSet<>();
boolean foundReflective = false;
for (Tree alternate : ((UnionTypeTree) lastType).getTypeAlternatives()) {
if (ASTHelpers.isSubtype(ASTHelpers.getType(alternate), roe, state)) {
foundReflective = true;
exceptions.add("ReflectiveOperationException");
} else {
exceptions.add(state.getSourceForNode(alternate));
}
}
if (foundReflective) {
fix.replace(lastType, Joiner.on(" | ").join(exceptions));
return true;
}
}
}
// check for duplicated catch blocks that handle reflective exceptions exactly the same way,
// and merge them into a single block that catches ROE
Set<String> uniq = new HashSet<>();
for (CatchTree ct : result.handles.values()) {
uniq.add(state.getSourceForNode(ct.getBlock()));
}
// the catch blocks are all unique, append a new fresh one
if (uniq.size() != 1) {
CatchTree last = Iterables.getLast(tryTree.getCatches());
// borrow the variable name of the previous catch variable, in case the naive 'e' conflicts
// with something in the current scope
String name = last.getParameter().getName().toString();
fix.postfixWith(last, String.format("catch (ReflectiveOperationException %s) {" + " throw new LinkageError(%s.getMessage(), %s); }", name, name, name));
return true;
}
// if the catch blocks contain calls to newInstance, don't delete any of them to avoid
// overlapping fixes
final AtomicBoolean newInstanceInCatch = new AtomicBoolean(false);
((JCTree) result.handles.values().iterator().next()).accept(new TreeScanner() {
@Override
public void visitApply(JCTree.JCMethodInvocation tree) {
if (NEW_INSTANCE.matches(tree, state)) {
newInstanceInCatch.set(true);
}
}
});
if (newInstanceInCatch.get()) {
fix.replace(Iterables.getLast(result.handles.values()).getParameter().getType(), "ReflectiveOperationException");
return true;
}
// otherwise, merge the duplicated catch blocks into a single block that
// handles ROE
boolean first = true;
for (CatchTree ct : result.handles.values()) {
if (first) {
fix.replace(ct.getParameter().getType(), "ReflectiveOperationException");
first = false;
} else {
fix.delete(ct);
}
}
return true;
}
Aggregations