@Override public Void visitTypeCast(TypeCastTree tree, EnumSet<UseTypes> d) { Tree expr = tree.getExpression(); if (expr.getKind() == Kind.IDENTIFIER) { handlePossibleIdentifier(new TreePath(getCurrentPath(), expr), EnumSet.of(UseTypes.READ)); } Tree cast = tree.getType(); if (cast.getKind() == Kind.IDENTIFIER) { handlePossibleIdentifier(new TreePath(getCurrentPath(), cast), EnumSet.of(UseTypes.READ)); } super.visitTypeCast(tree, d); return null; }
@Override protected void performRewrite(TransformationContext ctx) throws Exception { // path should be the typecast expression TreePath path = ctx.getPath(); TreePath exprPath = exprHandle.resolve(ctx.getWorkingCopy()); if (path.getLeaf().getKind() != Tree.Kind.TYPE_CAST || exprPath == null || !EXPRESSION_KINDS.contains(exprPath.getLeaf().getKind())) { // PENDING - some message ? return; } WorkingCopy copy = ctx.getWorkingCopy(); TreeMaker make = ctx.getWorkingCopy().getTreeMaker(); TypeCastTree cast = (TypeCastTree)path.getLeaf(); // rewrite the type cast to the casted Math.random() copy.rewrite(path.getLeaf(), cast.getExpression()); // rewrite the outermost expression to a typecast of it ExpressionTree expr = (ExpressionTree)exprPath.getLeaf(); if (expr.getKind() != Tree.Kind.PARENTHESIZED) { expr = make.Parenthesized(expr); } copy.rewrite(exprPath.getLeaf(), make.TypeCast(cast.getType(), (ExpressionTree)expr)); }
@Override protected void performRewrite(TransformationContext ctx) { WorkingCopy wc = ctx.getWorkingCopy(); TreePath path = ctx.getPath(); TypeCastTree tct = (TypeCastTree) path.getLeaf(); ExpressionTree expression = tct.getExpression(); while (expression.getKind() == Kind.PARENTHESIZED && !JavaFixUtilities.requiresParenthesis(((ParenthesizedTree) expression).getExpression(), tct, path.getParentPath().getLeaf())) { expression = ((ParenthesizedTree) expression).getExpression(); } while (path.getParentPath().getLeaf().getKind() == Kind.PARENTHESIZED && !JavaFixUtilities.requiresParenthesis(expression, path.getLeaf(), path.getParentPath().getParentPath().getLeaf())) { path = path.getParentPath(); } wc.rewrite(path.getLeaf(), expression); }
@Override protected void performRewrite(JavaFix.TransformationContext ctx) throws Exception { TreePath castPath = ctx.getPath(); if (castPath.getLeaf().getKind() != Tree.Kind.TYPE_CAST) { return; } TypeCastTree tct = (TypeCastTree)castPath.getLeaf(); Tree inside = tct.getExpression(); Tree outside; TreePath upper = upto.resolve(ctx.getWorkingCopy()); if (upper != null) { outside = upper.getLeaf(); } else { outside = tct; } ctx.getWorkingCopy().rewrite(outside, inside); }
/** * strip out enclosing parentheses and type casts. * * @param expr * @return */ private static ExpressionTree stripParensAndCasts(ExpressionTree expr) { boolean someChange = true; while (someChange) { someChange = false; if (expr.getKind().equals(PARENTHESIZED)) { expr = ((ParenthesizedTree) expr).getExpression(); someChange = true; } if (expr.getKind().equals(TYPE_CAST)) { expr = ((TypeCastTree) expr).getExpression(); someChange = true; } } return expr; }
/** * Matches if this is a narrowing integral cast between signed types where the expression is a * subtract. */ private boolean matches(TypeCastTree tree, VisitorState state) { Type treeType = ASTHelpers.getType(tree.getType()); // If the cast isn't narrowing to an int then don't implicate it in the bug pattern. if (treeType.getTag() != TypeTag.INT) { return false; } // The expression should be a subtract but remove parentheses. ExpressionTree expression = ASTHelpers.stripParentheses(tree.getExpression()); if (expression.getKind() != Kind.MINUS) { return false; } // Ensure the expression type is wider and signed (ie a long) than the cast type ignoring // boxing. Type expressionType = getTypeOfSubtract((BinaryTree) expression); TypeTag expressionTypeTag = state.getTypes().unboxedTypeOrType(expressionType).getTag(); return (expressionTypeTag == TypeTag.LONG); }
@Override public Description matchTypeCast(TypeCastTree typeCastTree, VisitorState visitorState) { CastingMatcher castingMatcher = new CastingMatcher(); if (!(typeCastTree.getExpression() instanceof IdentifierTree || typeCastTree.getExpression() instanceof ArrayAccessTree)) { return Description.NO_MATCH; } if (castingMatcher.matches(typeCastTree, visitorState)) { return buildDescription(typeCastTree) .addFix( SuggestedFix.replace(castingMatcher.nodeToReplace, typeCastTree.getType().toString())) .build(); } return Description.NO_MATCH; }
@Override public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) { if (!MATCHER.matches(tree, state)) { return NO_MATCH; } Tree parent = state.getPath().getParentPath().getLeaf(); if (!(parent instanceof TypeCastTree)) { return NO_MATCH; } if (!((TypeCastTree) parent).getExpression().equals(tree)) { return NO_MATCH; } Type type = ASTHelpers.getType(parent); if (type == null || !INTEGRAL.contains(type.getKind())) { return NO_MATCH; } return describeMatch(tree); }
@Override public Void visitTypeCast(TypeCastTree node, AnnotatedTypeMirror type) { // TODO: should we perform default action to get trees/tree kinds/...? // defaultAction(node, type); AnnotatedTypeMirror exprType = atypeFactory.getAnnotatedType(node.getExpression()); if (type.getKind() == TypeKind.TYPEVAR ) { if (exprType.getKind() == TypeKind.TYPEVAR) { // If both types are type variables, take the direct annotations. type.addMissingAnnotations(exprType.getAnnotations()); } // else do nothing // TODO: What should we do if the type is a type variable, but the expression // is not? } else { // Use effective annotations from the expression, to get upper bound // of type variables. type.addMissingAnnotations(exprType.getEffectiveAnnotations()); } return super.visitTypeCast(node, type); }
@Override public Tree visitTypeCast(TypeCastTree tree, Void p) { TypeCastTree n = make.TypeCast(tree.getType(), tree.getExpression()); model.setType(n, model.getType(tree)); comments.copyComments(tree, n); model.setPos(n, model.getPos(tree)); return n; }
public Boolean visitTypeCast(TypeCastTree node, TreePath p) { if (p == null) return super.visitTypeCast(node, p); TypeCastTree t = (TypeCastTree) p.getLeaf(); if (!scan(node.getType(), t.getType(), p)) return false; return scan(node.getExpression(), t.getExpression(), p); }
@Override public Void visitTypeCast(TypeCastTree tree, List<Node> d) { List<Node> below = new ArrayList<Node>(); addCorrespondingType(below); addCorrespondingComments(below); super.visitTypeCast(tree, below); d.add(new TreeNode(info, getCurrentPath(), below)); return null; }
private static ErrorDescription reportUselessCast(HintContext ctx, TypeCastTree tct, CharSequence currentTypeName, CompilationInfo info, ExpectedTypeResolver exp, TypeMirror castType) { if (!Utilities.isValidType(castType)) { return null; } if (castType.getKind().isPrimitive()) { TreePath binParent = findBinaryParent(ctx.getPath().getParentPath()); if (binParent != null) { Map<Tree, TypeMirror> exclusions = (Map<Tree,TypeMirror>)ctx.getInfo().getCachedValue(RemoveCast.class); if (exclusions == null) { exclusions = new HashMap<>(); ctx.getInfo().putCachedValue(RemoveCast.class, exclusions, CompilationInfo.CacheClearPolicy.ON_TASK_END); } else { TypeMirror x = exclusions.get(binParent.getLeaf()); if (x != null && ctx.getInfo().getTypes().isSameType(x, castType)) { return null; } } exclusions.put(binParent.getLeaf(), castType); } } return ErrorDescriptionFactory.forTree(ctx, tct.getType(), TEXT_UnnecessaryCast( currentTypeName), new RemoveCast(info, ctx.getPath(), exp.getTheExpression(), currentTypeName). toEditorFix()); }
@Override protected void performRewrite(TransformationContext ctx) throws Exception { TreePath castPath = ctx.getPath(); if (castPath.getLeaf().getKind() != Tree.Kind.TYPE_CAST) { return; } TypeCastTree tct = (TypeCastTree)castPath.getLeaf(); TypeMirror targetType = handle.resolve(ctx.getWorkingCopy()); Tree tt = ctx.getWorkingCopy().getTreeMaker().Type(targetType); ctx.getWorkingCopy().rewrite(tct.getType(), tt); }
private Element getElement(Tree tree) { TreePath expPath = TreePath.getPath(cut, tree); Element e = trees.getElement(expPath); if (e == null) { if (tree instanceof ParenthesizedTree) { e = getElement(((ParenthesizedTree) tree).getExpression()); //if (e == null) { // System.err.println("Have null element for "+tree); //} //System.err.println("\nHAVE "+e.asType().toString()+" for ParenthesizedTree "+tree); } else if (tree instanceof TypeCastTree) { e = getElement(((TypeCastTree) tree).getType()); //if (e == null) { // System.err.println("Have null element for "+tree); //} //System.err.println("\nHAVE "+e.asType().toString()+" for TypeCastTree "+tree); } else if (tree instanceof AssignmentTree) { e = getElement(((AssignmentTree) tree).getVariable()); } else if (tree instanceof ArrayAccessTree) { e = getElement(((ArrayAccessTree) tree).getExpression()); if (e != null) { TypeMirror tm = e.asType(); if (tm.getKind() == TypeKind.ARRAY) { tm = ((ArrayType) tm).getComponentType(); e = types.asElement(tm); } } //System.err.println("ArrayAccessTree = "+((ArrayAccessTree) tree).getExpression()+", element = "+getElement(((ArrayAccessTree) tree).getExpression())+", type = "+getElement(((ArrayAccessTree) tree).getExpression()).asType()); } } return e; }
@Override public Void visitTypeCast(TypeCastTree node, Void unused) { sync(node); builder.open(plusFour); token("("); scan(node.getType(), null); token(")"); builder.breakOp(" "); scan(node.getExpression(), null); builder.close(); return null; }
@Override public Void visitTypeCast(TypeCastTree node, Void p) { if (!done) { index++; } if (tree == node) { done = true; return p; } return super.visitTypeCast(node, p); }
/** * Matches a type cast AST node if both of the given matchers match. * * @param typeMatcher The matcher to apply to the type. * @param expressionMatcher The matcher to apply to the expression. */ public static Matcher<TypeCastTree> typeCast( final Matcher<Tree> typeMatcher, final Matcher<ExpressionTree> expressionMatcher) { return new Matcher<TypeCastTree>() { @Override public boolean matches(TypeCastTree t, VisitorState state) { return typeMatcher.matches(t.getType(), state) && expressionMatcher.matches(t.getExpression(), state); } }; }
@Override public Void visitTypeCast(TypeCastTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (TypeCastTreeMatcher matcher : typeCastMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchTypeCast(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitTypeCast(tree, state); }
@Override public Choice<State<JCTypeCast>> visitTypeCast(final TypeCastTree node, State<?> state) { return chooseSubtrees( state, s -> unifyExpression(node.getExpression(), s), expr -> maker().TypeCast((JCTree) node.getType(), expr)); }
@Override public Number visitTypeCast(TypeCastTree node, Void p) { Number value = node.getExpression().accept(this, null); if (value == null) { return null; } if (!(node.getType() instanceof PrimitiveTypeTree)) { return null; } TypeKind kind = ((PrimitiveTypeTree) node.getType()).getPrimitiveTypeKind(); return cast(kind, value); }
@Override public Description matchTypeCast(TypeCastTree tree, VisitorState state) { // Check for a narrowing match first as its simplest match to test. if (!matches(tree, state)) { return Description.NO_MATCH; } // Test that the match is in a Comparable.compareTo or Comparator.compare method. ClassTree declaringClass = ASTHelpers.findEnclosingNode(state.getPath(), ClassTree.class); if (!COMPARABLE_CLASS_MATCHER.matches(declaringClass, state) && !COMPARATOR_CLASS_MATCHER.matches(declaringClass, state)) { return Description.NO_MATCH; } MethodTree method = ASTHelpers.findEnclosingNode(state.getPath(), MethodTree.class); if (method == null) { return Description.NO_MATCH; } if (!COMPARABLE_METHOD_MATCHER.matches(method, state) && !COMPARATOR_METHOD_MATCHER.matches(method, state)) { return Description.NO_MATCH; } // Get the unparenthesized expression. BinaryTree subtract = (BinaryTree) ASTHelpers.stripParentheses(tree.getExpression()); ExpressionTree lhs = subtract.getLeftOperand(); ExpressionTree rhs = subtract.getRightOperand(); Fix fix; if (ASTHelpers.getType(lhs).isPrimitive()) { fix = SuggestedFix.replace(tree, "Long.compare(" + lhs + ", " + rhs + ")"); } else { fix = SuggestedFix.replace(tree, lhs + ".compareTo(" + rhs + ")"); } return describeMatch(tree, fix); }
private Description getDescriptionForType(TypeCastTree tree, String baseType) { String targetType = tree.getType().toString(); return buildDescription(tree) .setMessage( String.format( "When serialized in Bundle, %s may be transformed into an arbitrary subclass of %s." + " Please cast to %s.", targetType, baseType, baseType)) .build(); }
@Override public Description matchTypeCast(TypeCastTree tree, VisitorState state) { if (!boxingCast.matches(tree, state)) { return Description.NO_MATCH; } return buildDescription(tree) .setMessage( "Casting a primitive value to a non-primitive type will autobox the value," + " which " + COMMON_MESSAGE_SUFFIX) .build(); }
/** * Returns true if the tree is a tree that 'looks like' either an access * of a field or an invocation of a method that are owned by the same * accessing instance. * * It would only return true if the access tree is of the form: * <pre> * field * this.field * * method() * this.method() * </pre> * * It does not perform any semantical check to differentiate between * fields and local variables; local methods or imported static methods. * * @param tree expression tree representing an access to object member * @return {@code true} iff the member is a member of {@code this} instance */ public static boolean isSelfAccess(final ExpressionTree tree) { ExpressionTree tr = TreeUtils.skipParens(tree); // If method invocation check the method select if (tr.getKind() == Tree.Kind.ARRAY_ACCESS) return false; if (tree.getKind() == Tree.Kind.METHOD_INVOCATION) { tr = ((MethodInvocationTree)tree).getMethodSelect(); } tr = TreeUtils.skipParens(tr); if (tr.getKind() == Tree.Kind.TYPE_CAST) tr = ((TypeCastTree)tr).getExpression(); tr = TreeUtils.skipParens(tr); if (tr.getKind() == Tree.Kind.IDENTIFIER) return true; if (tr.getKind() == Tree.Kind.MEMBER_SELECT) { tr = ((MemberSelectTree)tr).getExpression(); if (tr.getKind() == Tree.Kind.IDENTIFIER) { Name ident = ((IdentifierTree)tr).getName(); return ident.contentEquals("this") || ident.contentEquals("super"); } } return false; }
@Override public Node visitTypeCast(TypeCastTree tree, Void p) { Node operand = scan(tree.getExpression(), p); TypeMirror type = InternalUtils.typeOf(tree.getType()); return extendWithNode(new TypeCastNode(tree, operand, type)); }
@Override public Void visitTypeCast(TypeCastTree node, AnnotatedTypeMirror p) { if (!hasImmutabilityAnnotation(p)) { AnnotatedTypeMirror castedType = getAnnotatedType(node.getExpression()); p.addAnnotations(castedType.getAnnotations()); } return null; }
/** Case 7: unboxing case: casting to a primitive */ @Override public Void visitTypeCast(TypeCastTree node, Void p) { if (isPrimitive(node) && !isPrimitive(node.getExpression())) { checkForNullability(node.getExpression(), UNBOXING_OF_NULLABLE); } return super.visitTypeCast(node, p); }
protected void checkTypecastRedundancy(TypeCastTree node, Void p) { if (!checker.getLintOption("cast:redundant", false)) return; AnnotatedTypeMirror castType = atypeFactory.getAnnotatedType(node); AnnotatedTypeMirror exprType = atypeFactory.getAnnotatedType(node.getExpression()); if (AnnotatedTypes.areSame(castType, exprType)) { checker.report(Result.warning("cast.redundant", castType), node); } }
@Override public Void visitTypeCast(TypeCastTree node, Void p) { // validate "node" instead of "node.getType()" to prevent duplicate errors. boolean valid = validateTypeOf(node) && validateTypeOf(node.getExpression()); if (valid) { checkTypecastSafety(node, p); checkTypecastRedundancy(node, p); } return super.visitTypeCast(node, p); // return scan(node.getExpression(), p); }
@Override public Void visitTypeCast(TypeCastTree tree, AnnotatedTypeMirror type) { if (isClassCovered(type)) { String castedToString = type.getUnderlyingType().toString(); handleCast(tree.getExpression(), castedToString, type); } return super.visitTypeCast(tree, type); }
@Override public AnnotatedTypeMirror visitTypeCast(TypeCastTree node, AnnotatedTypeFactory f) { // Use the annotated type of the type in the cast. return f.fromTypeTree(node.getType()); }
/** * Returns true if the tree is a tree that 'looks like' either an access of a field or an * invocation of a method that are owned by the same accessing instance. * * <p>It would only return true if the access tree is of the form: * * <pre> * field * this.field * * method() * this.method() * </pre> * * It does not perform any semantical check to differentiate between fields and local variables; * local methods or imported static methods. * * @param tree expression tree representing an access to object member * @return {@code true} iff the member is a member of {@code this} instance */ public static boolean isSelfAccess(final ExpressionTree tree) { ExpressionTree tr = TreeUtils.skipParens(tree); // If method invocation check the method select if (tr.getKind() == Tree.Kind.ARRAY_ACCESS) { return false; } if (tree.getKind() == Tree.Kind.METHOD_INVOCATION) { tr = ((MethodInvocationTree) tree).getMethodSelect(); } tr = TreeUtils.skipParens(tr); if (tr.getKind() == Tree.Kind.TYPE_CAST) { tr = ((TypeCastTree) tr).getExpression(); } tr = TreeUtils.skipParens(tr); if (tr.getKind() == Tree.Kind.IDENTIFIER) { return true; } if (tr.getKind() == Tree.Kind.MEMBER_SELECT) { tr = ((MemberSelectTree) tr).getExpression(); if (tr.getKind() == Tree.Kind.IDENTIFIER) { Name ident = ((IdentifierTree) tr).getName(); return ident.contentEquals("this") || ident.contentEquals("super"); } } return false; }
@Override public Node visitTypeCast(TypeCastTree tree, Void p) { final Node operand = scan(tree.getExpression(), p); final TypeMirror type = InternalUtils.typeOf(tree.getType()); final Node node = new TypeCastNode(tree, operand, type); final TypeElement cceElement = elements.getTypeElement("java.lang.ClassCastException"); extendWithNodeWithException(node, cceElement.asType()); return node; }
@Override public Void visitTypeCast(TypeCastTree expected, Tree actual) { Optional<TypeCastTree> other = checkTypeAndCast(expected, actual); if (!other.isPresent()) { addTypeMismatch(expected, actual); return null; } scan(expected.getType(), other.get().getType()); scan(expected.getExpression(), other.get().getExpression()); return null; }
@Override public Object visitTypeCast(TypeCastTree node, Object p) { return scan(node.getExpression(), p); }
/** * type cast adds dependency on the casted-to type */ @Override public Object visitTypeCast(TypeCastTree node, Object p) { addDependency(node.getType()); return super.visitTypeCast(node, p); }
private Object resolveTypeCast(TypeCastTree node, TypeMirror target, Object result, Void p) { if (target.getKind() != TypeKind.DECLARED) { return null; } DeclaredType dt = (DeclaredType)target; TypeElement e = (TypeElement)dt.asElement(); if (enhanceProcessing) { // accept null constant typecasted to anything as null if (result == NULL) { return NULL; } else if (result == NOT_NULL) { // some unspecified reference type... return result; } } String qn = e.getQualifiedName().toString(); // type casts to String are permitted by JLS 15.28 if ("java.lang.String".equals(qn)) { // NOI18N return result instanceof String ? result : null; } else if (!enhanceProcessing) { // other typecasts are not lised in JLS 15.28 return null; } TypeMirror castee = info.getTrees().getTypeMirror(new TreePath(getCurrentPath(), node.getExpression())); if (!Utilities.isValidType(castee)) { return null; } if (info.getTypes().isAssignable(castee, target)) { return result; } // a constant of primitive type may be casted / wrapped to the wrapper type switch (qn) { case "java.lang.Boolean": // NOI18N if (result instanceof Boolean) return result; break; case "java.lang.Byte": // NOI18N // the casted expression may be typed as Byte or byte; if (result instanceof Number && castee != null && castee.getKind() == TypeKind.BYTE) return ((Number)result).byteValue(); break; case "java.lang.Character": // NOI18N if (result instanceof Number && castee != null && castee.getKind() == TypeKind.CHAR) return Character.valueOf((char)((Number)result).intValue()); break; case "java.lang.Double": // NOI18N if (result instanceof Number && castee != null && castee.getKind() == TypeKind.DOUBLE) return ((Number)result).doubleValue(); break; case "java.lang.Float": // NOI18N if (result instanceof Number && castee != null && castee.getKind() == TypeKind.FLOAT) return ((Number)result).floatValue(); break; case "java.lang.Integer": // NOI18N if (result instanceof Number && castee != null && castee.getKind() == TypeKind.INT) return ((Number)result).intValue(); break; case "java.lang.Long": // NOI18N if (result instanceof Number && castee != null && castee.getKind() == TypeKind.LONG) return ((Number)result).longValue(); break; case "java.lang.Short": // NOI18N if (result instanceof Number && castee != null && castee.getKind() == TypeKind.SHORT) return ((Number)result).shortValue(); break; } return null; }