Example usage for org.eclipse.jdt.internal.compiler.ast Javadoc sourceEnd

List of usage examples for org.eclipse.jdt.internal.compiler.ast Javadoc sourceEnd

Introduction

In this page you can find the example usage for org.eclipse.jdt.internal.compiler.ast Javadoc sourceEnd.

Prototype

public int sourceEnd() 

Source Link

Usage

From source file:spoon.support.compiler.jdt.PositionBuilder.java

License:Open Source License

SourcePosition buildPositionCtElement(CtElement e, ASTNode node) {
    if (e instanceof CtCatch) {
        //we cannot compute position of CtCatch, because we do not know position of it's body yet
        //it is computed later by #buildPosition(CtCatch)
        return SourcePosition.NOPOSITION;
    }/*w w  w .  j ava2 s. c  om*/
    CoreFactory cf = this.jdtTreeBuilder.getFactory().Core();
    CompilationUnit cu = this.jdtTreeBuilder.getContextBuilder().compilationUnitSpoon;
    int[] lineSeparatorPositions = jdtTreeBuilder.getContextBuilder()
            .getCompilationUnitLineSeparatorPositions();
    char[] contents = jdtTreeBuilder.getContextBuilder().getCompilationUnitContents();

    int sourceStart = node.sourceStart;
    int sourceEnd = node.sourceEnd;
    if ((node instanceof Annotation)) {
        Annotation ann = (Annotation) node;
        int declEnd = ann.declarationSourceEnd;

        if (declEnd > 0) {
            sourceEnd = declEnd;
        }
    } else if ((node instanceof Expression)) {
        Expression expression = (Expression) node;
        int statementEnd = expression.statementEnd;

        if (statementEnd > 0) {
            sourceEnd = statementEnd;
        }

        if (this.jdtTreeBuilder.getContextBuilder().isBuildTypeCast && e instanceof CtTypeReference) {
            //the type cast reference must be enclosed with brackets
            int declarationSourceStart = sourceStart;
            int declarationSourceEnd = sourceEnd;
            declarationSourceStart = findPrevNonWhitespace(contents, getParentsSourceStart(),
                    declarationSourceStart - 1);
            if (contents[declarationSourceStart] != '(') {
                return handlePositionProblem("Unexpected character \'" + contents[declarationSourceStart]
                        + "\' at start of cast expression on offset: " + declarationSourceStart);
            }
            declarationSourceEnd = findNextNonWhitespace(contents, contents.length - 1,
                    declarationSourceEnd + 1);
            if (contents[declarationSourceEnd] != ')') {
                return handlePositionProblem("Unexpected character \'" + contents[declarationSourceStart]
                        + "\' at end of cast expression on offset: " + declarationSourceEnd);
            }
            return cf.createCompoundSourcePosition(cu, sourceStart, sourceEnd, declarationSourceStart,
                    declarationSourceEnd, lineSeparatorPositions);
        }

        List<CastInfo> casts = this.jdtTreeBuilder.getContextBuilder().casts;

        if (!casts.isEmpty() && e instanceof CtExpression) {
            int declarationSourceStart = sourceStart;
            int declarationSourceEnd = sourceEnd;
            SourcePosition pos = casts.get(0).typeRef.getPosition();
            if (pos.isValidPosition()) {
                declarationSourceStart = pos.getSourceStart();
                int nrOfBrackets = getNrOfFirstCastExpressionBrackets();
                while (nrOfBrackets > 0) {
                    declarationSourceStart = findPrevNonWhitespace(contents, getParentsSourceStart(),
                            declarationSourceStart - 1);
                    if (declarationSourceStart < 0) {
                        return handlePositionProblem("Cannot found beginning of cast expression until offset: "
                                + getParentsSourceStart());
                    }
                    if (contents[declarationSourceStart] != '(') {
                        return handlePositionProblem(
                                "Unexpected character \'" + contents[declarationSourceStart]
                                        + "\' at start of expression on offset: " + declarationSourceStart);
                    }
                    nrOfBrackets--;
                }
                nrOfBrackets = getNrOfCastExpressionBrackets();
                while (nrOfBrackets > 0) {
                    declarationSourceEnd = findNextNonWhitespace(contents, contents.length - 1,
                            declarationSourceEnd + 1);
                    if (contents[declarationSourceEnd] != ')') {
                        return handlePositionProblem(
                                "Unexpected character \'" + contents[declarationSourceStart]
                                        + "\' at end of expression on offset: " + declarationSourceEnd);
                    }
                    nrOfBrackets--;
                }
            }
            return cf.createCompoundSourcePosition(cu, sourceStart, sourceEnd, declarationSourceStart,
                    declarationSourceEnd, lineSeparatorPositions);
        }
    }

    if (node instanceof TypeParameter) {
        TypeParameter typeParameter = (TypeParameter) node;
        sourceStart = typeParameter.declarationSourceStart;
        sourceEnd = typeParameter.declarationSourceEnd;
        if (typeParameter.type != null) {
            sourceEnd = getSourceEndOfTypeReference(contents, typeParameter.type, sourceEnd);
        }
    } else if (node instanceof AbstractVariableDeclaration) {
        AbstractVariableDeclaration variableDeclaration = (AbstractVariableDeclaration) node;
        int modifiersSourceStart = variableDeclaration.modifiersSourceStart;
        int declarationSourceStart = variableDeclaration.declarationSourceStart;
        int declarationSourceEnd = variableDeclaration.declarationSourceEnd;
        if (declarationSourceStart == 0 && declarationSourceEnd == 0) {
            return SourcePosition.NOPOSITION;
        }
        if (e instanceof CtCatchVariable) {
            /* compiler delivers wrong declarationSourceStart in case like: */
            //... catch/*2*/ ( /*3*/ final @Deprecated /*4*/ ClassCastException /*5*/ e /*6*/) /*7*/ {
            /*
             * the declarationSourceStart should be after the '(', but sometime it is before
             * So we have to compute correct offset here
             */
            CtTry tryStatement = this.jdtTreeBuilder.getContextBuilder().getParentElementOfType(CtTry.class);
            int endOfTry = tryStatement.getPosition().getSourceEnd();
            //offset of the bracket before catch
            int lastBracket = getEndOfLastTryBlock(tryStatement, 0);
            int catchStart = findNextNonWhitespace(contents, endOfTry, lastBracket + 1);
            if (CATCH.equals(new String(contents, catchStart, CATCH.length())) == false) {
                return handlePositionProblem(
                        "Unexpected beginning of catch statement on offset: " + catchStart);
            }
            int bracketStart = findNextNonWhitespace(contents, endOfTry, catchStart + CATCH.length());
            if (bracketStart < 0) {
                return handlePositionProblem(
                        "Unexpected end of file instead of \'(\' after catch statement on offset: "
                                + catchStart);
            }
            if (contents[bracketStart] != '(') {
                return handlePositionProblem("Unexpected character " + contents[bracketStart]
                        + " instead of \'(\' after catch statement on offset: " + bracketStart);
            }
            declarationSourceStart = bracketStart + 1;
        }
        CtElement parent = this.jdtTreeBuilder.getContextBuilder().getContextElementOnLevel(1);
        if (parent instanceof CtForEach) {
            CtForEach forEach = (CtForEach) parent;
            //compiler deliver wrong local variable position when for(...:...) starts with line comment
            int parentStart = parent.getPosition().getSourceStart();
            if (contents[parentStart] != 'f' || contents[parentStart + 1] != 'o'
                    || contents[parentStart + 2] != 'r') {
                return handlePositionProblem("Expected keyword for at offset: " + parentStart);
            }
            int bracketOff = findNextNonWhitespace(contents, forEach.getPosition().getSourceEnd(),
                    parentStart + 3);
            if (bracketOff < 0 || contents[bracketOff] != '(') {
                return handlePositionProblem(
                        "Expected character after \'for\' instead of \'(\' at offset: " + (parentStart + 3));
            }
            declarationSourceStart = bracketOff + 1;
            declarationSourceEnd = sourceEnd;
        }

        if (variableDeclaration instanceof Argument && variableDeclaration.type instanceof ArrayTypeReference) {
            //handle type declarations like `String[] arg` `String arg[]` and `String []arg[]`
            ArrayTypeReference arrTypeRef = (ArrayTypeReference) variableDeclaration.type;
            int dimensions = arrTypeRef.dimensions();
            if (dimensions > 0) {
                //count number of brackets between type and variable name
                int foundDimensions = getNrOfDimensions(contents, declarationSourceStart, declarationSourceEnd);
                while (dimensions > foundDimensions) {
                    //some brackets are after the variable name
                    declarationSourceEnd = findNextChar(contents, contents.length, declarationSourceEnd + 1,
                            ']');
                    if (declarationSourceEnd < 0) {
                        return handlePositionProblem(
                                "Unexpected array type declaration on offset: " + declarationSourceStart);
                    }
                    foundDimensions++;
                }
            }
        }

        // Handle lambda parameters without explicit type
        if (variableDeclaration instanceof Argument && variableDeclaration.type == null) {
            declarationSourceStart = findPrevNonWhitespace(contents, 0, declarationSourceStart - 1);
            declarationSourceEnd = findNextNonWhitespace(contents, contents.length - 1,
                    declarationSourceEnd + 1);
        }

        if (modifiersSourceStart <= 0) {
            modifiersSourceStart = findNextNonWhitespace(contents, contents.length - 1, declarationSourceStart);
        }
        int modifiersSourceEnd;
        if (variableDeclaration.type != null) {
            modifiersSourceEnd = findPrevNonWhitespace(contents, declarationSourceStart,
                    variableDeclaration.type.sourceStart() - 1);
        } else if (variableDeclaration instanceof Initializer) {
            modifiersSourceEnd = ((Initializer) variableDeclaration).block.sourceStart - 1;
        } else {
            // variable that has no type such as TypeParameter
            modifiersSourceEnd = declarationSourceStart - 1;
        }

        // when no modifier
        if (modifiersSourceStart > modifiersSourceEnd) {
            modifiersSourceEnd = modifiersSourceStart - 1;
        } else if (e instanceof CtModifiable) {
            setModifiersPosition((CtModifiable) e, modifiersSourceStart, modifiersSourceEnd);
        }

        return cf.createDeclarationSourcePosition(cu, sourceStart, sourceEnd, modifiersSourceStart,
                modifiersSourceEnd, declarationSourceStart, declarationSourceEnd, lineSeparatorPositions);
    } else if (node instanceof TypeDeclaration && e instanceof CtPackage) {
        // the position returned by JTD is equals to 0
        return cf.createSourcePosition(cu, 0, contents.length - 1, lineSeparatorPositions);
    } else if (node instanceof TypeDeclaration) {
        TypeDeclaration typeDeclaration = (TypeDeclaration) node;

        int declarationSourceStart = typeDeclaration.declarationSourceStart;
        int declarationSourceEnd = typeDeclaration.declarationSourceEnd;
        int modifiersSourceStart = typeDeclaration.modifiersSourceStart;
        int bodyStart = typeDeclaration.bodyStart;
        int bodyEnd = typeDeclaration.bodyEnd;

        int modifiersSourceEnd;
        if (typeDeclaration.name.length == 0) {
            //it is anonymous type
            if (contents[bodyStart] != '{') {
                //adjust bodyStart of annonymous type in definition of enum value
                if (bodyStart < 1 || contents[bodyStart - 1] != '{') {
                    throw new SpoonException("Cannot found body start at offset " + bodyStart
                            + " of annonymous class with sources:\n" + new String(contents));
                }
                bodyStart--;
            }
            declarationSourceStart = modifiersSourceStart = sourceStart = bodyStart;
            if (contents[bodyEnd] != '}') {
                //adjust bodyEnd of annonymous type in definition of enum value
                if (contents[bodyEnd + 1] != '}') {
                    throw new SpoonException("Cannot found body end at offset " + bodyEnd
                            + " of annonymous class with sources:\n" + new String(contents));
                }
                bodyEnd++;
            }
            declarationSourceEnd = bodyEnd;
            //there is no name of annonymous class
            sourceEnd = sourceStart - 1;
            //there are no modifiers of annonymous class
            modifiersSourceEnd = modifiersSourceStart - 1;
            bodyStart++;
        } else {
            if (modifiersSourceStart <= 0) {
                modifiersSourceStart = declarationSourceStart;
            }
            //look for start of first keyword before the type keyword e.g. "class". `sourceStart` points at first char of type name
            modifiersSourceEnd = findPrevNonWhitespace(contents, modifiersSourceStart - 1,
                    findPrevWhitespace(contents, modifiersSourceStart - 1,
                            findPrevNonWhitespace(contents, modifiersSourceStart - 1, sourceStart - 1)));
            if (e instanceof CtModifiable) {
                setModifiersPosition((CtModifiable) e, modifiersSourceStart, modifiersSourceEnd);
            }
            if (modifiersSourceEnd < modifiersSourceStart) {
                //there is no modifier
                modifiersSourceEnd = modifiersSourceStart - 1;
            }
        }

        return cf.createBodyHolderSourcePosition(cu, sourceStart, sourceEnd, modifiersSourceStart,
                modifiersSourceEnd, declarationSourceStart, declarationSourceEnd, bodyStart - 1, bodyEnd,
                lineSeparatorPositions);
    } else if (node instanceof AbstractMethodDeclaration) {
        AbstractMethodDeclaration methodDeclaration = (AbstractMethodDeclaration) node;
        int bodyStart = methodDeclaration.bodyStart;
        int bodyEnd = methodDeclaration.bodyEnd;
        int declarationSourceStart = methodDeclaration.declarationSourceStart;
        int declarationSourceEnd = methodDeclaration.declarationSourceEnd;
        int modifiersSourceStart = methodDeclaration.modifiersSourceStart;

        if (modifiersSourceStart <= 0) {
            modifiersSourceStart = declarationSourceStart;
        }

        if (node instanceof AnnotationMethodDeclaration && bodyStart == bodyEnd) {
            //The ";" at the end of annotation method declaration is not part of body
            //let it behave same like in abstract MethodDeclaration
            bodyEnd--;
        }

        Javadoc javadoc = methodDeclaration.javadoc;
        if (javadoc != null && javadoc.sourceEnd() > declarationSourceStart) {
            modifiersSourceStart = javadoc.sourceEnd() + 1;
        }

        int modifiersSourceEnd = sourceStart - 1;

        if (e instanceof CtModifiable) {
            setModifiersPosition((CtModifiable) e, modifiersSourceStart, declarationSourceEnd);
        }

        if (methodDeclaration instanceof MethodDeclaration
                && ((MethodDeclaration) methodDeclaration).returnType != null) {
            modifiersSourceEnd = ((MethodDeclaration) methodDeclaration).returnType.sourceStart() - 2;
        }

        TypeParameter[] typeParameters = methodDeclaration.typeParameters();
        if (typeParameters != null && typeParameters.length > 0) {
            modifiersSourceEnd = typeParameters[0].declarationSourceStart - 3;
        }

        if (getModifiers(methodDeclaration.modifiers, false, true).isEmpty()) {
            modifiersSourceEnd = modifiersSourceStart - 1;
        }

        sourceEnd = sourceStart + methodDeclaration.selector.length - 1;
        if (bodyStart == 0) {
            return cf.createPartialSourcePosition(cu);
        }
        if (e instanceof CtStatementList) {
            return cf.createSourcePosition(cu, bodyStart - 1, bodyEnd + 1, lineSeparatorPositions);
        } else {
            //include brackets if they are there
            if (contents[bodyStart - 1] == '{') {
                bodyStart--;
                if (contents[bodyEnd + 1] == '}') {
                    bodyEnd++;
                } else {
                    if (bodyStart < bodyEnd) {
                        return handlePositionProblem("Missing body end in\n"
                                + new String(contents, sourceStart, sourceEnd - sourceStart));
                    }
                }
            }
            return cf.createBodyHolderSourcePosition(cu, sourceStart, sourceEnd, modifiersSourceStart,
                    modifiersSourceEnd, declarationSourceStart, declarationSourceEnd, bodyStart, bodyEnd,
                    lineSeparatorPositions);
        }
    } else if (e instanceof CtCatchVariable) {
        ASTPair pair = this.jdtTreeBuilder.getContextBuilder().getParentContextOfType(CtCatch.class);
        if (pair == null) {
            return handlePositionProblem("There is no CtCatch parent for CtCatchVariable");
        }
        //build position with appropriate context
        return buildPositionCtElement(e, (Argument) pair.node);
    } else if (node instanceof TypeReference) {
        sourceEnd = getSourceEndOfTypeReference(contents, (TypeReference) node, sourceEnd);
    } else if (node instanceof AllocationExpression) {
        AllocationExpression allocationExpression = (AllocationExpression) node;
        if (allocationExpression.enumConstant != null) {
            FieldDeclaration fieldDeclaration = allocationExpression.enumConstant;
            //1) skip comments
            sourceStart = findNextNonWhitespace(contents, sourceEnd, sourceStart);
            //2) move to beginning of enum construction
            sourceStart += fieldDeclaration.name.length;
        }
    } else if (node instanceof CaseStatement) {
        sourceEnd = findNextNonWhitespace(contents, contents.length - 1, sourceEnd + 1);
        if (sourceEnd < 0) {
            return handlePositionProblem("Unexpected end of file in CtCase on: " + sourceStart);
        }
        if (contents[sourceEnd] != ':') {
            return handlePositionProblem("Unexpected character " + contents[sourceEnd]
                    + " instead of \':\' in CtCase on: " + sourceEnd);
        }
    }

    if (e instanceof CtModifiable) {
        setModifiersPosition((CtModifiable) e, sourceStart, sourceEnd);
    }
    if (sourceStart == 0 && sourceEnd == 0) {
        return SourcePosition.NOPOSITION;
    }
    return cf.createSourcePosition(cu, sourceStart, sourceEnd, lineSeparatorPositions);
}