Search in sources :

Example 6 with JCMethodDecl

use of com.sun.tools.javac.tree.JCTree.JCMethodDecl in project lombok by rzwitserloot.

the class HandleNonNull method handle.

@Override
public void handle(AnnotationValues<NonNull> annotation, JCAnnotation ast, JavacNode annotationNode) {
    handleFlagUsage(annotationNode, ConfigurationKeys.NON_NULL_FLAG_USAGE, "@NonNull");
    if (annotationNode.up().getKind() == Kind.FIELD) {
        try {
            if (isPrimitive(((JCVariableDecl) annotationNode.up().get()).vartype)) {
                annotationNode.addWarning("@NonNull is meaningless on a primitive.");
            }
        } catch (Exception ignore) {
        }
        return;
    }
    if (annotationNode.up().getKind() != Kind.ARGUMENT)
        return;
    JCMethodDecl declaration;
    try {
        declaration = (JCMethodDecl) annotationNode.up().up().get();
    } catch (Exception e) {
        return;
    }
    if (declaration.body == null) {
        // This used to be a warning, but as @NonNull also has a documentary purpose, better to not warn about this. Since 1.16.7
        return;
    }
    // Possibly, if 'declaration instanceof ConstructorDeclaration', fetch declaration.constructorCall, search it for any references to our parameter,
    // and if they exist, create a new method in the class: 'private static <T> T lombok$nullCheck(T expr, String msg) {if (expr == null) throw NPE; return expr;}' and
    // wrap all references to it in the super/this to a call to this method.
    JCStatement nullCheck = recursiveSetGeneratedBy(generateNullCheck(annotationNode.getTreeMaker(), annotationNode.up(), annotationNode), ast, annotationNode.getContext());
    if (nullCheck == null) {
        // @NonNull applied to a primitive. Kinda pointless. Let's generate a warning.
        annotationNode.addWarning("@NonNull is meaningless on a primitive.");
        return;
    }
    List<JCStatement> statements = declaration.body.stats;
    String expectedName = annotationNode.up().getName();
    /* Abort if the null check is already there, delving into try and synchronized statements */
    {
        List<JCStatement> stats = statements;
        int idx = 0;
        while (stats.size() > idx) {
            JCStatement stat = stats.get(idx++);
            if (JavacHandlerUtil.isConstructorCall(stat))
                continue;
            if (stat instanceof JCTry) {
                stats = ((JCTry) stat).body.stats;
                idx = 0;
                continue;
            }
            if (stat instanceof JCSynchronized) {
                stats = ((JCSynchronized) stat).body.stats;
                idx = 0;
                continue;
            }
            String varNameOfNullCheck = returnVarNameIfNullCheck(stat);
            if (varNameOfNullCheck == null)
                break;
            if (varNameOfNullCheck.equals(expectedName))
                return;
        }
    }
    List<JCStatement> tail = statements;
    List<JCStatement> head = List.nil();
    for (JCStatement stat : statements) {
        if (JavacHandlerUtil.isConstructorCall(stat) || (JavacHandlerUtil.isGenerated(stat) && isNullCheck(stat))) {
            tail = tail.tail;
            head = head.prepend(stat);
            continue;
        }
        break;
    }
    List<JCStatement> newList = tail.prepend(nullCheck);
    for (JCStatement stat : head) newList = newList.prepend(stat);
    declaration.body.stats = newList;
    annotationNode.getAst().setChanged();
}
Also used : JCTry(com.sun.tools.javac.tree.JCTree.JCTry) JCMethodDecl(com.sun.tools.javac.tree.JCTree.JCMethodDecl) List(com.sun.tools.javac.util.List) JCSynchronized(com.sun.tools.javac.tree.JCTree.JCSynchronized) JCStatement(com.sun.tools.javac.tree.JCTree.JCStatement)

Example 7 with JCMethodDecl

use of com.sun.tools.javac.tree.JCTree.JCMethodDecl in project lombok by rzwitserloot.

the class HandleSetter method createSetter.

public static JCMethodDecl createSetter(long access, JavacNode field, JavacTreeMaker treeMaker, String setterName, boolean shouldReturnThis, JavacNode source, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) {
    if (setterName == null)
        return null;
    JCVariableDecl fieldDecl = (JCVariableDecl) field.get();
    JCExpression fieldRef = createFieldAccessor(treeMaker, field, FieldAccess.ALWAYS_FIELD);
    JCAssign assign = treeMaker.Assign(fieldRef, treeMaker.Ident(fieldDecl.name));
    ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>();
    List<JCAnnotation> nonNulls = findAnnotations(field, NON_NULL_PATTERN);
    List<JCAnnotation> nullables = findAnnotations(field, NULLABLE_PATTERN);
    Name methodName = field.toName(setterName);
    List<JCAnnotation> annsOnParam = copyAnnotations(onParam).appendList(nonNulls).appendList(nullables);
    long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, field.getContext());
    JCVariableDecl param = treeMaker.VarDef(treeMaker.Modifiers(flags, annsOnParam), fieldDecl.name, fieldDecl.vartype, null);
    if (nonNulls.isEmpty()) {
        statements.append(treeMaker.Exec(assign));
    } else {
        JCStatement nullCheck = generateNullCheck(treeMaker, field, source);
        if (nullCheck != null)
            statements.append(nullCheck);
        statements.append(treeMaker.Exec(assign));
    }
    JCExpression methodType = null;
    if (shouldReturnThis) {
        methodType = cloneSelfType(field);
    }
    if (methodType == null) {
        //WARNING: Do not use field.getSymbolTable().voidType - that field has gone through non-backwards compatible API changes within javac1.6.
        methodType = treeMaker.Type(Javac.createVoidType(field.getSymbolTable(), CTC_VOID));
        shouldReturnThis = false;
    }
    if (shouldReturnThis) {
        JCReturn returnStatement = treeMaker.Return(treeMaker.Ident(field.toName("this")));
        statements.append(returnStatement);
    }
    JCBlock methodBody = treeMaker.Block(0, statements.toList());
    List<JCTypeParameter> methodGenericParams = List.nil();
    List<JCVariableDecl> parameters = List.of(param);
    List<JCExpression> throwsClauses = List.nil();
    JCExpression annotationMethodDefaultValue = null;
    List<JCAnnotation> annsOnMethod = copyAnnotations(onMethod);
    if (isFieldDeprecated(field)) {
        annsOnMethod = annsOnMethod.prepend(treeMaker.Annotation(genJavaLangTypeRef(field, "Deprecated"), List.<JCExpression>nil()));
    }
    JCMethodDecl decl = recursiveSetGeneratedBy(treeMaker.MethodDef(treeMaker.Modifiers(access, annsOnMethod), methodName, methodType, methodGenericParams, parameters, throwsClauses, methodBody, annotationMethodDefaultValue), source.get(), field.getContext());
    copyJavadoc(field, decl, CopyJavadoc.SETTER);
    return decl;
}
Also used : JCReturn(com.sun.tools.javac.tree.JCTree.JCReturn) JCBlock(com.sun.tools.javac.tree.JCTree.JCBlock) JCMethodDecl(com.sun.tools.javac.tree.JCTree.JCMethodDecl) JCAssign(com.sun.tools.javac.tree.JCTree.JCAssign) ListBuffer(com.sun.tools.javac.util.ListBuffer) JCStatement(com.sun.tools.javac.tree.JCTree.JCStatement) JCVariableDecl(com.sun.tools.javac.tree.JCTree.JCVariableDecl) Name(com.sun.tools.javac.util.Name) JCTypeParameter(com.sun.tools.javac.tree.JCTree.JCTypeParameter) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) JCAnnotation(com.sun.tools.javac.tree.JCTree.JCAnnotation)

Example 8 with JCMethodDecl

use of com.sun.tools.javac.tree.JCTree.JCMethodDecl in project lombok by rzwitserloot.

the class HandleSynchronized method handle.

@Override
public void handle(AnnotationValues<Synchronized> annotation, JCAnnotation ast, JavacNode annotationNode) {
    handleFlagUsage(annotationNode, ConfigurationKeys.SYNCHRONIZED_FLAG_USAGE, "@Synchronized");
    if (inNetbeansEditor(annotationNode))
        return;
    deleteAnnotationIfNeccessary(annotationNode, Synchronized.class);
    JavacNode methodNode = annotationNode.up();
    if (methodNode == null || methodNode.getKind() != Kind.METHOD || !(methodNode.get() instanceof JCMethodDecl)) {
        annotationNode.addError("@Synchronized is legal only on methods.");
        return;
    }
    JCMethodDecl method = (JCMethodDecl) methodNode.get();
    if ((method.mods.flags & Flags.ABSTRACT) != 0) {
        annotationNode.addError("@Synchronized is legal only on concrete methods.");
        return;
    }
    boolean isStatic = (method.mods.flags & Flags.STATIC) != 0;
    String lockName = annotation.getInstance().value();
    boolean autoMake = false;
    if (lockName.length() == 0) {
        autoMake = true;
        lockName = isStatic ? STATIC_LOCK_NAME : INSTANCE_LOCK_NAME;
    }
    JavacTreeMaker maker = methodNode.getTreeMaker().at(ast.pos);
    Context context = methodNode.getContext();
    if (fieldExists(lockName, methodNode) == MemberExistsResult.NOT_EXISTS) {
        if (!autoMake) {
            annotationNode.addError("The field " + lockName + " does not exist.");
            return;
        }
        JCExpression objectType = genJavaLangTypeRef(methodNode, ast.pos, "Object");
        //We use 'new Object[0];' because unlike 'new Object();', empty arrays *ARE* serializable!
        JCNewArray newObjectArray = maker.NewArray(genJavaLangTypeRef(methodNode, ast.pos, "Object"), List.<JCExpression>of(maker.Literal(CTC_INT, 0)), null);
        JCVariableDecl fieldDecl = recursiveSetGeneratedBy(maker.VarDef(maker.Modifiers(Flags.PRIVATE | Flags.FINAL | (isStatic ? Flags.STATIC : 0)), methodNode.toName(lockName), objectType, newObjectArray), ast, context);
        injectFieldAndMarkGenerated(methodNode.up(), fieldDecl);
    }
    if (method.body == null)
        return;
    JCExpression lockNode;
    if (isStatic) {
        lockNode = chainDots(methodNode, ast.pos, methodNode.up().getName(), lockName);
    } else {
        lockNode = maker.Select(maker.Ident(methodNode.toName("this")), methodNode.toName(lockName));
    }
    recursiveSetGeneratedBy(lockNode, ast, context);
    method.body = setGeneratedBy(maker.Block(0, List.<JCStatement>of(setGeneratedBy(maker.Synchronized(lockNode, method.body), ast, context))), ast, context);
    methodNode.rebuild();
}
Also used : Context(com.sun.tools.javac.util.Context) JCMethodDecl(com.sun.tools.javac.tree.JCTree.JCMethodDecl) JavacTreeMaker(lombok.javac.JavacTreeMaker) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) JavacNode(lombok.javac.JavacNode) JCNewArray(com.sun.tools.javac.tree.JCTree.JCNewArray) JCVariableDecl(com.sun.tools.javac.tree.JCTree.JCVariableDecl)

Example 9 with JCMethodDecl

use of com.sun.tools.javac.tree.JCTree.JCMethodDecl in project lombok by rzwitserloot.

the class HandleToString method generateToString.

public void generateToString(JavacNode typeNode, JavacNode source, List<String> excludes, List<String> includes, boolean includeFieldNames, Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess) {
    boolean notAClass = true;
    if (typeNode.get() instanceof JCClassDecl) {
        long flags = ((JCClassDecl) typeNode.get()).mods.flags;
        notAClass = (flags & (Flags.INTERFACE | Flags.ANNOTATION)) != 0;
    }
    if (callSuper == null) {
        try {
            callSuper = ((Boolean) ToString.class.getMethod("callSuper").getDefaultValue()).booleanValue();
        } catch (Exception ignore) {
        }
    }
    if (notAClass) {
        source.addError("@ToString is only supported on a class or enum.");
        return;
    }
    ListBuffer<JavacNode> nodesForToString = new ListBuffer<JavacNode>();
    if (includes != null) {
        for (JavacNode child : typeNode.down()) {
            if (child.getKind() != Kind.FIELD)
                continue;
            JCVariableDecl fieldDecl = (JCVariableDecl) child.get();
            if (includes.contains(fieldDecl.name.toString()))
                nodesForToString.append(child);
        }
    } else {
        for (JavacNode child : typeNode.down()) {
            if (child.getKind() != Kind.FIELD)
                continue;
            JCVariableDecl fieldDecl = (JCVariableDecl) child.get();
            //Skip static fields.
            if ((fieldDecl.mods.flags & Flags.STATIC) != 0)
                continue;
            //Skip excluded fields.
            if (excludes != null && excludes.contains(fieldDecl.name.toString()))
                continue;
            //Skip fields that start with $.
            if (fieldDecl.name.toString().startsWith("$"))
                continue;
            nodesForToString.append(child);
        }
    }
    switch(methodExists("toString", typeNode, 0)) {
        case NOT_EXISTS:
            JCMethodDecl method = createToString(typeNode, nodesForToString.toList(), includeFieldNames, callSuper, fieldAccess, source.get());
            injectMethod(typeNode, method);
            break;
        case EXISTS_BY_LOMBOK:
            break;
        default:
        case EXISTS_BY_USER:
            if (whineIfExists) {
                source.addWarning("Not generating toString(): A method with that name already exists");
            }
            break;
    }
}
Also used : JCClassDecl(com.sun.tools.javac.tree.JCTree.JCClassDecl) JCMethodDecl(com.sun.tools.javac.tree.JCTree.JCMethodDecl) JavacNode(lombok.javac.JavacNode) ListBuffer(com.sun.tools.javac.util.ListBuffer) ToString(lombok.ToString) JCVariableDecl(com.sun.tools.javac.tree.JCTree.JCVariableDecl)

Example 10 with JCMethodDecl

use of com.sun.tools.javac.tree.JCTree.JCMethodDecl in project lombok by rzwitserloot.

the class HandleUtilityClass method createPrivateDefaultConstructor.

private void createPrivateDefaultConstructor(JavacNode typeNode) {
    JavacTreeMaker maker = typeNode.getTreeMaker();
    JCModifiers mods = maker.Modifiers(Flags.PRIVATE, List.<JCAnnotation>nil());
    Name name = typeNode.toName("<init>");
    JCBlock block = maker.Block(0L, createThrowStatement(typeNode, maker));
    JCMethodDecl methodDef = maker.MethodDef(mods, name, null, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), block, null);
    JCMethodDecl constructor = recursiveSetGeneratedBy(methodDef, typeNode.get(), typeNode.getContext());
    JavacHandlerUtil.injectMethod(typeNode, constructor, List.<Type>nil(), Javac.createVoidType(typeNode.getSymbolTable(), CTC_VOID));
}
Also used : JCBlock(com.sun.tools.javac.tree.JCTree.JCBlock) JavacTreeMaker(lombok.javac.JavacTreeMaker) JCMethodDecl(com.sun.tools.javac.tree.JCTree.JCMethodDecl) JCModifiers(com.sun.tools.javac.tree.JCTree.JCModifiers) Name(com.sun.tools.javac.util.Name)

Aggregations

JCMethodDecl (com.sun.tools.javac.tree.JCTree.JCMethodDecl)45 JCVariableDecl (com.sun.tools.javac.tree.JCTree.JCVariableDecl)31 JCExpression (com.sun.tools.javac.tree.JCTree.JCExpression)20 Name (com.sun.tools.javac.util.Name)17 JCBlock (com.sun.tools.javac.tree.JCTree.JCBlock)16 JCStatement (com.sun.tools.javac.tree.JCTree.JCStatement)16 JCTypeParameter (com.sun.tools.javac.tree.JCTree.JCTypeParameter)15 ListBuffer (com.sun.tools.javac.util.ListBuffer)14 JCClassDecl (com.sun.tools.javac.tree.JCTree.JCClassDecl)13 JCModifiers (com.sun.tools.javac.tree.JCTree.JCModifiers)13 JavacNode (lombok.javac.JavacNode)13 JCTree (com.sun.tools.javac.tree.JCTree)12 SuggestedFix (com.google.errorprone.fixes.SuggestedFix)5 Type (com.sun.tools.javac.code.Type)5 JCAnnotation (com.sun.tools.javac.tree.JCTree.JCAnnotation)5 JCFieldAccess (com.sun.tools.javac.tree.JCTree.JCFieldAccess)5 JCNewClass (com.sun.tools.javac.tree.JCTree.JCNewClass)5 ClassSymbol (com.sun.tools.javac.code.Symbol.ClassSymbol)4 JavacTreeMaker (lombok.javac.JavacTreeMaker)4 JCExpressionStatement (com.sun.tools.javac.tree.JCTree.JCExpressionStatement)3