Search in sources :

Example 1 with TryStatement

use of org.eclipse.jdt.internal.compiler.ast.TryStatement in project lombok by rzwitserloot.

the class HandleSneakyThrows method buildTryCatchBlock.

public Statement buildTryCatchBlock(Statement[] contents, DeclaredException exception, ASTNode source, AbstractMethodDeclaration method) {
    int methodStart = method.bodyStart;
    int methodEnd = method.bodyEnd;
    long methodPosEnd = ((long) methodEnd) << 32 | (methodEnd & 0xFFFFFFFFL);
    TryStatement tryStatement = new TryStatement();
    setGeneratedBy(tryStatement, source);
    tryStatement.tryBlock = new Block(0);
    // Positions for in-method generated nodes are special
    tryStatement.tryBlock.sourceStart = methodStart;
    tryStatement.tryBlock.sourceEnd = methodEnd;
    setGeneratedBy(tryStatement.tryBlock, source);
    tryStatement.tryBlock.statements = contents;
    TypeReference typeReference;
    if (exception.exceptionName.indexOf('.') == -1) {
        typeReference = new SingleTypeReference(exception.exceptionName.toCharArray(), methodPosEnd);
        typeReference.statementEnd = methodEnd;
    } else {
        String[] x = exception.exceptionName.split("\\.");
        char[][] elems = new char[x.length][];
        long[] poss = new long[x.length];
        Arrays.fill(poss, methodPosEnd);
        for (int i = 0; i < x.length; i++) {
            elems[i] = x[i].trim().toCharArray();
        }
        typeReference = new QualifiedTypeReference(elems, poss);
    }
    setGeneratedBy(typeReference, source);
    Argument catchArg = new Argument("$ex".toCharArray(), methodPosEnd, typeReference, Modifier.FINAL);
    setGeneratedBy(catchArg, source);
    catchArg.declarationSourceEnd = catchArg.declarationEnd = catchArg.sourceEnd = methodEnd;
    catchArg.declarationSourceStart = catchArg.modifiersSourceStart = catchArg.sourceStart = methodEnd;
    tryStatement.catchArguments = new Argument[] { catchArg };
    MessageSend sneakyThrowStatement = new MessageSend();
    setGeneratedBy(sneakyThrowStatement, source);
    sneakyThrowStatement.receiver = new QualifiedNameReference(new char[][] { "lombok".toCharArray(), "Lombok".toCharArray() }, new long[2], methodEnd, methodEnd);
    setGeneratedBy(sneakyThrowStatement.receiver, source);
    sneakyThrowStatement.receiver.statementEnd = methodEnd;
    sneakyThrowStatement.selector = "sneakyThrow".toCharArray();
    SingleNameReference exRef = new SingleNameReference("$ex".toCharArray(), methodPosEnd);
    setGeneratedBy(exRef, source);
    exRef.statementEnd = methodEnd;
    sneakyThrowStatement.arguments = new Expression[] { exRef };
    // This is the magic fix for rendering issues
    // In org.eclipse.jdt.core.dom.ASTConverter#convert(org.eclipse.jdt.internal.compiler.ast.MessageSend)
    // a new SimpleName is created and the setSourceRange should receive -1, 0. That's why we provide -2L :-)
    sneakyThrowStatement.nameSourcePosition = -2L;
    sneakyThrowStatement.sourceStart = methodEnd;
    sneakyThrowStatement.sourceEnd = sneakyThrowStatement.statementEnd = methodEnd;
    Statement rethrowStatement = new ThrowStatement(sneakyThrowStatement, methodEnd, methodEnd);
    setGeneratedBy(rethrowStatement, source);
    Block block = new Block(0);
    block.sourceStart = methodEnd;
    block.sourceEnd = methodEnd;
    setGeneratedBy(block, source);
    block.statements = new Statement[] { rethrowStatement };
    tryStatement.catchBlocks = new Block[] { block };
    // Positions for in-method generated nodes are special
    tryStatement.sourceStart = method.bodyStart;
    tryStatement.sourceEnd = method.bodyEnd;
    return tryStatement;
}
Also used : Argument(org.eclipse.jdt.internal.compiler.ast.Argument) Statement(org.eclipse.jdt.internal.compiler.ast.Statement) ThrowStatement(org.eclipse.jdt.internal.compiler.ast.ThrowStatement) TryStatement(org.eclipse.jdt.internal.compiler.ast.TryStatement) SingleNameReference(org.eclipse.jdt.internal.compiler.ast.SingleNameReference) MessageSend(org.eclipse.jdt.internal.compiler.ast.MessageSend) TryStatement(org.eclipse.jdt.internal.compiler.ast.TryStatement) SingleTypeReference(org.eclipse.jdt.internal.compiler.ast.SingleTypeReference) QualifiedTypeReference(org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference) Block(org.eclipse.jdt.internal.compiler.ast.Block) SingleTypeReference(org.eclipse.jdt.internal.compiler.ast.SingleTypeReference) TypeReference(org.eclipse.jdt.internal.compiler.ast.TypeReference) QualifiedTypeReference(org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference) ThrowStatement(org.eclipse.jdt.internal.compiler.ast.ThrowStatement) QualifiedNameReference(org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference)

Example 2 with TryStatement

use of org.eclipse.jdt.internal.compiler.ast.TryStatement in project lombok by rzwitserloot.

the class HandleCleanup method handle.

public void handle(AnnotationValues<Cleanup> annotation, Annotation ast, EclipseNode annotationNode) {
    handleFlagUsage(annotationNode, ConfigurationKeys.CLEANUP_FLAG_USAGE, "@Cleanup");
    String cleanupName = annotation.getInstance().value();
    if (cleanupName.length() == 0) {
        annotationNode.addError("cleanupName cannot be the empty string.");
        return;
    }
    if (annotationNode.up().getKind() != Kind.LOCAL) {
        annotationNode.addError("@Cleanup is legal only on local variable declarations.");
        return;
    }
    LocalDeclaration decl = (LocalDeclaration) annotationNode.up().get();
    if (decl.initialization == null) {
        annotationNode.addError("@Cleanup variable declarations need to be initialized.");
        return;
    }
    EclipseNode ancestor = annotationNode.up().directUp();
    ASTNode blockNode = ancestor.get();
    final boolean isSwitch;
    final Statement[] statements;
    if (blockNode instanceof AbstractMethodDeclaration) {
        isSwitch = false;
        statements = ((AbstractMethodDeclaration) blockNode).statements;
    } else if (blockNode instanceof Block) {
        isSwitch = false;
        statements = ((Block) blockNode).statements;
    } else if (blockNode instanceof SwitchStatement) {
        isSwitch = true;
        statements = ((SwitchStatement) blockNode).statements;
    } else {
        annotationNode.addError("@Cleanup is legal only on a local variable declaration inside a block.");
        return;
    }
    if (statements == null) {
        annotationNode.addError("LOMBOK BUG: Parent block does not contain any statements.");
        return;
    }
    int start = 0;
    for (; start < statements.length; start++) {
        if (statements[start] == decl)
            break;
    }
    if (start == statements.length) {
        annotationNode.addError("LOMBOK BUG: Can't find this local variable declaration inside its parent.");
        return;
    }
    //We start with try{} *AFTER* the var declaration.
    start++;
    int end;
    if (isSwitch) {
        end = start + 1;
        for (; end < statements.length; end++) {
            if (statements[end] instanceof CaseStatement) {
                break;
            }
        }
    } else
        end = statements.length;
    //At this point:
    //  start-1 = Local Declaration marked with @Cleanup
    //  start = first instruction that needs to be wrapped into a try block
    //  end = last instruction of the scope -OR- last instruction before the next case label in switch statements.
    //  hence:
    //  [start, end) = statements for the try block.
    Statement[] tryBlock = new Statement[end - start];
    System.arraycopy(statements, start, tryBlock, 0, end - start);
    //Remove the stuff we just dumped into the tryBlock, and then leave room for the try node.
    //Remove room for every statement moved into try block...
    int newStatementsLength = statements.length - (end - start);
    //But add room for the TryStatement node itself.
    newStatementsLength += 1;
    Statement[] newStatements = new Statement[newStatementsLength];
    //copy all statements before the try block verbatim.
    System.arraycopy(statements, 0, newStatements, 0, start);
    //For switch statements.
    System.arraycopy(statements, end, newStatements, start + 1, statements.length - end);
    doAssignmentCheck(annotationNode, tryBlock, decl.name);
    TryStatement tryStatement = new TryStatement();
    setGeneratedBy(tryStatement, ast);
    tryStatement.tryBlock = new Block(0);
    tryStatement.tryBlock.statements = tryBlock;
    setGeneratedBy(tryStatement.tryBlock, ast);
    // Positions for in-method generated nodes are special
    int ss = decl.declarationSourceEnd + 1;
    int se = ss;
    if (tryBlock.length > 0) {
        //+1 for the closing semicolon. Yes, there could be spaces. Bummer.
        se = tryBlock[tryBlock.length - 1].sourceEnd + 1;
        tryStatement.sourceStart = ss;
        tryStatement.sourceEnd = se;
        tryStatement.tryBlock.sourceStart = ss;
        tryStatement.tryBlock.sourceEnd = se;
    }
    newStatements[start] = tryStatement;
    Statement[] finallyBlock = new Statement[1];
    MessageSend unsafeClose = new MessageSend();
    setGeneratedBy(unsafeClose, ast);
    unsafeClose.sourceStart = ast.sourceStart;
    unsafeClose.sourceEnd = ast.sourceEnd;
    SingleNameReference receiver = new SingleNameReference(decl.name, 0);
    setGeneratedBy(receiver, ast);
    unsafeClose.receiver = receiver;
    long nameSourcePosition = (long) ast.sourceStart << 32 | ast.sourceEnd;
    if (ast.memberValuePairs() != null)
        for (MemberValuePair pair : ast.memberValuePairs()) {
            if (pair.name != null && new String(pair.name).equals("value")) {
                nameSourcePosition = (long) pair.value.sourceStart << 32 | pair.value.sourceEnd;
                break;
            }
        }
    unsafeClose.nameSourcePosition = nameSourcePosition;
    unsafeClose.selector = cleanupName.toCharArray();
    int pS = ast.sourceStart, pE = ast.sourceEnd;
    long p = (long) pS << 32 | pE;
    SingleNameReference varName = new SingleNameReference(decl.name, p);
    setGeneratedBy(varName, ast);
    NullLiteral nullLiteral = new NullLiteral(pS, pE);
    setGeneratedBy(nullLiteral, ast);
    MessageSend preventNullAnalysis = preventNullAnalysis(ast, varName);
    EqualExpression equalExpression = new EqualExpression(preventNullAnalysis, nullLiteral, OperatorIds.NOT_EQUAL);
    equalExpression.sourceStart = pS;
    equalExpression.sourceEnd = pE;
    setGeneratedBy(equalExpression, ast);
    Block closeBlock = new Block(0);
    closeBlock.statements = new Statement[1];
    closeBlock.statements[0] = unsafeClose;
    setGeneratedBy(closeBlock, ast);
    IfStatement ifStatement = new IfStatement(equalExpression, closeBlock, 0, 0);
    setGeneratedBy(ifStatement, ast);
    finallyBlock[0] = ifStatement;
    tryStatement.finallyBlock = new Block(0);
    // Positions for in-method generated nodes are special
    if (!isSwitch) {
        tryStatement.finallyBlock.sourceStart = blockNode.sourceEnd;
        tryStatement.finallyBlock.sourceEnd = blockNode.sourceEnd;
    }
    setGeneratedBy(tryStatement.finallyBlock, ast);
    tryStatement.finallyBlock.statements = finallyBlock;
    tryStatement.catchArguments = null;
    tryStatement.catchBlocks = null;
    if (blockNode instanceof AbstractMethodDeclaration) {
        ((AbstractMethodDeclaration) blockNode).statements = newStatements;
    } else if (blockNode instanceof Block) {
        ((Block) blockNode).statements = newStatements;
    } else if (blockNode instanceof SwitchStatement) {
        ((SwitchStatement) blockNode).statements = newStatements;
    }
    ancestor.rebuild();
}
Also used : LocalDeclaration(org.eclipse.jdt.internal.compiler.ast.LocalDeclaration) Statement(org.eclipse.jdt.internal.compiler.ast.Statement) IfStatement(org.eclipse.jdt.internal.compiler.ast.IfStatement) SwitchStatement(org.eclipse.jdt.internal.compiler.ast.SwitchStatement) CaseStatement(org.eclipse.jdt.internal.compiler.ast.CaseStatement) TryStatement(org.eclipse.jdt.internal.compiler.ast.TryStatement) CaseStatement(org.eclipse.jdt.internal.compiler.ast.CaseStatement) EqualExpression(org.eclipse.jdt.internal.compiler.ast.EqualExpression) SingleNameReference(org.eclipse.jdt.internal.compiler.ast.SingleNameReference) MessageSend(org.eclipse.jdt.internal.compiler.ast.MessageSend) IfStatement(org.eclipse.jdt.internal.compiler.ast.IfStatement) SwitchStatement(org.eclipse.jdt.internal.compiler.ast.SwitchStatement) MemberValuePair(org.eclipse.jdt.internal.compiler.ast.MemberValuePair) TryStatement(org.eclipse.jdt.internal.compiler.ast.TryStatement) ASTNode(org.eclipse.jdt.internal.compiler.ast.ASTNode) EclipseNode(lombok.eclipse.EclipseNode) Block(org.eclipse.jdt.internal.compiler.ast.Block) AbstractMethodDeclaration(org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration) NullLiteral(org.eclipse.jdt.internal.compiler.ast.NullLiteral)

Example 3 with TryStatement

use of org.eclipse.jdt.internal.compiler.ast.TryStatement in project lombok by rzwitserloot.

the class HandleNonNull method handle.

@Override
public void handle(AnnotationValues<NonNull> annotation, Annotation ast, EclipseNode annotationNode) {
    handleFlagUsage(annotationNode, ConfigurationKeys.NON_NULL_FLAG_USAGE, "@NonNull");
    if (annotationNode.up().getKind() == Kind.FIELD) {
        try {
            if (isPrimitive(((AbstractVariableDeclaration) annotationNode.up().get()).type)) {
                annotationNode.addWarning("@NonNull is meaningless on a primitive.");
            }
        } catch (Exception ignore) {
        }
        return;
    }
    if (annotationNode.up().getKind() != Kind.ARGUMENT)
        return;
    Argument arg;
    AbstractMethodDeclaration declaration;
    try {
        arg = (Argument) annotationNode.up().get();
        declaration = (AbstractMethodDeclaration) annotationNode.up().up().get();
    } catch (Exception e) {
        return;
    }
    if (isGenerated(declaration))
        return;
    if (declaration.isAbstract()) {
        // 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.
    Statement nullCheck = generateNullCheck(arg, annotationNode);
    if (nullCheck == null) {
        // @NonNull applied to a primitive. Kinda pointless. Let's generate a warning.
        annotationNode.addWarning("@NonNull is meaningless on a primitive.");
        return;
    }
    if (declaration.statements == null) {
        declaration.statements = new Statement[] { nullCheck };
    } else {
        char[] expectedName = arg.name;
        /* Abort if the null check is already there, delving into try and synchronized statements */
        {
            Statement[] stats = declaration.statements;
            int idx = 0;
            while (stats != null && stats.length > idx) {
                Statement stat = stats[idx++];
                if (stat instanceof TryStatement) {
                    stats = ((TryStatement) stat).tryBlock.statements;
                    idx = 0;
                    continue;
                }
                if (stat instanceof SynchronizedStatement) {
                    stats = ((SynchronizedStatement) stat).block.statements;
                    idx = 0;
                    continue;
                }
                char[] varNameOfNullCheck = returnVarNameIfNullCheck(stat);
                if (varNameOfNullCheck == null)
                    break;
                if (Arrays.equals(varNameOfNullCheck, expectedName))
                    return;
            }
        }
        Statement[] newStatements = new Statement[declaration.statements.length + 1];
        int skipOver = 0;
        for (Statement stat : declaration.statements) {
            if (isGenerated(stat) && isNullCheck(stat))
                skipOver++;
            else
                break;
        }
        System.arraycopy(declaration.statements, 0, newStatements, 0, skipOver);
        System.arraycopy(declaration.statements, skipOver, newStatements, skipOver + 1, declaration.statements.length - skipOver);
        newStatements[skipOver] = nullCheck;
        declaration.statements = newStatements;
    }
    annotationNode.up().up().rebuild();
}
Also used : Argument(org.eclipse.jdt.internal.compiler.ast.Argument) TryStatement(org.eclipse.jdt.internal.compiler.ast.TryStatement) Statement(org.eclipse.jdt.internal.compiler.ast.Statement) IfStatement(org.eclipse.jdt.internal.compiler.ast.IfStatement) SynchronizedStatement(org.eclipse.jdt.internal.compiler.ast.SynchronizedStatement) ThrowStatement(org.eclipse.jdt.internal.compiler.ast.ThrowStatement) TryStatement(org.eclipse.jdt.internal.compiler.ast.TryStatement) SynchronizedStatement(org.eclipse.jdt.internal.compiler.ast.SynchronizedStatement) AbstractMethodDeclaration(org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration)

Aggregations

Statement (org.eclipse.jdt.internal.compiler.ast.Statement)3 TryStatement (org.eclipse.jdt.internal.compiler.ast.TryStatement)3 AbstractMethodDeclaration (org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration)2 Argument (org.eclipse.jdt.internal.compiler.ast.Argument)2 Block (org.eclipse.jdt.internal.compiler.ast.Block)2 IfStatement (org.eclipse.jdt.internal.compiler.ast.IfStatement)2 MessageSend (org.eclipse.jdt.internal.compiler.ast.MessageSend)2 SingleNameReference (org.eclipse.jdt.internal.compiler.ast.SingleNameReference)2 ThrowStatement (org.eclipse.jdt.internal.compiler.ast.ThrowStatement)2 EclipseNode (lombok.eclipse.EclipseNode)1 ASTNode (org.eclipse.jdt.internal.compiler.ast.ASTNode)1 CaseStatement (org.eclipse.jdt.internal.compiler.ast.CaseStatement)1 EqualExpression (org.eclipse.jdt.internal.compiler.ast.EqualExpression)1 LocalDeclaration (org.eclipse.jdt.internal.compiler.ast.LocalDeclaration)1 MemberValuePair (org.eclipse.jdt.internal.compiler.ast.MemberValuePair)1 NullLiteral (org.eclipse.jdt.internal.compiler.ast.NullLiteral)1 QualifiedNameReference (org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference)1 QualifiedTypeReference (org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference)1 SingleTypeReference (org.eclipse.jdt.internal.compiler.ast.SingleTypeReference)1 SwitchStatement (org.eclipse.jdt.internal.compiler.ast.SwitchStatement)1