Search in sources :

Example 6 with List

use of org.eclipse.ceylon.langtools.tools.javac.util.List in project ceylon by eclipse.

the class Attr method checkMethod.

/**
 * Check that method arguments conform to its instantiation.
 */
public Type checkMethod(Type site, final Symbol sym, ResultInfo resultInfo, Env<AttrContext> env, final List<JCExpression> argtrees, List<Type> argtypes, List<Type> typeargtypes) {
    // an unchecked warning if its argument types change under erasure.
    if (allowGenerics && (sym.flags() & STATIC) == 0 && (site.hasTag(CLASS) || site.hasTag(TYPEVAR))) {
        Type s = types.asOuterSuper(site, sym.owner);
        if (s != null && s.isRaw() && !types.isSameTypes(sym.type.getParameterTypes(), sym.erasure(types).getParameterTypes())) {
            chk.warnUnchecked(env.tree.pos(), "unchecked.call.mbr.of.raw.type", sym, s);
        }
    }
    if (env.info.defaultSuperCallSite != null) {
        for (Type sup : types.interfaces(env.enclClass.type).prepend(types.supertype((env.enclClass.type)))) {
            if (!sup.tsym.isSubClass(sym.enclClass(), types) || types.isSameType(sup, env.info.defaultSuperCallSite))
                continue;
            List<MethodSymbol> icand_sup = types.interfaceCandidates(sup, (MethodSymbol) sym);
            if (icand_sup.nonEmpty() && icand_sup.head != sym && icand_sup.head.overrides(sym, icand_sup.head.enclClass(), types, true)) {
                log.error(env.tree.pos(), "illegal.default.super.call", env.info.defaultSuperCallSite, diags.fragment("overridden.default", sym, sup));
                break;
            }
        }
        env.info.defaultSuperCallSite = null;
    }
    if (sym.isStatic() && site.isInterface() && env.tree.hasTag(APPLY)) {
        JCMethodInvocation app = (JCMethodInvocation) env.tree;
        if (app.meth.hasTag(SELECT) && !TreeInfo.isStaticSelector(((JCFieldAccess) app.meth).selected, names)) {
            log.error(env.tree.pos(), "illegal.static.intf.meth.call", site);
        }
    }
    // Compute the identifier's instantiated type.
    // For methods, we need to compute the instance type by
    // Resolve.instantiate from the symbol's type as well as
    // any type arguments and value arguments.
    noteWarner.clear();
    try {
        Type owntype = rs.checkMethod(env, site, sym, resultInfo, argtypes, typeargtypes, noteWarner);
        DeferredAttr.DeferredTypeMap checkDeferredMap = deferredAttr.new DeferredTypeMap(DeferredAttr.AttrMode.CHECK, sym, env.info.pendingResolutionPhase);
        argtypes = Type.map(argtypes, checkDeferredMap);
        if (noteWarner.hasNonSilentLint(LintCategory.UNCHECKED)) {
            chk.warnUnchecked(env.tree.pos(), "unchecked.meth.invocation.applied", kindName(sym), sym.name, rs.methodArguments(sym.type.getParameterTypes()), rs.methodArguments(Type.map(argtypes, checkDeferredMap)), kindName(sym.location()), sym.location());
            // Don't erase the return type of the instantiated method type
            // for Ceylon #1095
            owntype = new MethodType(owntype.getParameterTypes(), sourceLanguage.isCeylon() && typeargtypes != null && !typeargtypes.isEmpty() ? owntype.getReturnType() : types.erasure(owntype.getReturnType()), types.erasure(owntype.getThrownTypes()), syms.methodClass);
        }
        return chk.checkMethod(owntype, sym, env, argtrees, argtypes, env.info.lastResolveVarargs(), resultInfo.checkContext.inferenceContext());
    } catch (Infer.InferenceException ex) {
        // invalid target type - propagate exception outwards or report error
        // depending on the current check context
        resultInfo.checkContext.report(env.tree.pos(), ex.getDiagnostic());
        return types.createErrorType(site);
    } catch (Resolve.InapplicableMethodException ex) {
        final JCDiagnostic diag = ex.getDiagnostic();
        Resolve.InapplicableSymbolError errSym = rs.new InapplicableSymbolError(null) {

            @Override
            protected Pair<Symbol, JCDiagnostic> errCandidate() {
                return new Pair<Symbol, JCDiagnostic>(sym, diag);
            }
        };
        List<Type> argtypes2 = Type.map(argtypes, rs.new ResolveDeferredRecoveryMap(AttrMode.CHECK, sym, env.info.pendingResolutionPhase));
        JCDiagnostic errDiag = errSym.getDiagnostic(JCDiagnostic.DiagnosticType.ERROR, env.tree, sym, site, sym.name, argtypes2, typeargtypes);
        log.report(errDiag);
        return types.createErrorType(site);
    }
}
Also used : Symbol(org.eclipse.ceylon.langtools.tools.javac.code.Symbol) Type(org.eclipse.ceylon.langtools.tools.javac.code.Type) List(org.eclipse.ceylon.langtools.tools.javac.util.List)

Example 7 with List

use of org.eclipse.ceylon.langtools.tools.javac.util.List in project ceylon by eclipse.

the class JavacParser method term3.

/**
 *  Expression3    = PrefixOp Expression3
 *                 | "(" Expr | TypeNoParams ")" Expression3
 *                 | Primary {Selector} {PostfixOp}
 *
 *  {@literal
 *  Primary        = "(" Expression ")"
 *                 | Literal
 *                 | [TypeArguments] THIS [Arguments]
 *                 | [TypeArguments] SUPER SuperSuffix
 *                 | NEW [TypeArguments] Creator
 *                 | "(" Arguments ")" "->" ( Expression | Block )
 *                 | Ident "->" ( Expression | Block )
 *                 | [Annotations] Ident { "." [Annotations] Ident }
 *                 | Expression3 MemberReferenceSuffix
 *                   [ [Annotations] "[" ( "]" BracketsOpt "." CLASS | Expression "]" )
 *                   | Arguments
 *                   | "." ( CLASS | THIS | [TypeArguments] SUPER Arguments | NEW [TypeArguments] InnerCreator )
 *                   ]
 *                 | BasicType BracketsOpt "." CLASS
 *  }
 *
 *  PrefixOp       = "++" | "--" | "!" | "~" | "+" | "-"
 *  PostfixOp      = "++" | "--"
 *  Type3          = Ident { "." Ident } [TypeArguments] {TypeSelector} BracketsOpt
 *                 | BasicType
 *  TypeNoParams3  = Ident { "." Ident } BracketsOpt
 *  Selector       = "." [TypeArguments] Ident [Arguments]
 *                 | "." THIS
 *                 | "." [TypeArguments] SUPER SuperSuffix
 *                 | "." NEW [TypeArguments] InnerCreator
 *                 | "[" Expression "]"
 *  TypeSelector   = "." Ident [TypeArguments]
 *  SuperSuffix    = Arguments | "." Ident [Arguments]
 */
protected JCExpression term3() {
    int pos = token.pos;
    JCExpression t;
    List<JCExpression> typeArgs = typeArgumentsOpt(EXPR);
    switch(token.kind) {
        case QUES:
            if ((mode & TYPE) != 0 && (mode & (TYPEARG | NOPARAMS)) == TYPEARG) {
                mode = TYPE;
                return typeArgument();
            } else
                return illegal();
        case PLUSPLUS:
        case SUBSUB:
        case BANG:
        case TILDE:
        case PLUS:
        case SUB:
            if (typeArgs == null && (mode & EXPR) != 0) {
                TokenKind tk = token.kind;
                nextToken();
                mode = EXPR;
                if (tk == SUB && (token.kind == INTLITERAL || token.kind == LONGLITERAL) && token.radix() == 10) {
                    mode = EXPR;
                    t = literal(names.hyphen, pos);
                } else {
                    t = term3();
                    return F.at(pos).Unary(unoptag(tk), t);
                }
            } else
                return illegal();
            break;
        case LPAREN:
            if (typeArgs == null && (mode & EXPR) != 0) {
                ParensResult pres = analyzeParens();
                switch(pres) {
                    case CAST:
                        accept(LPAREN);
                        mode = TYPE;
                        int pos1 = pos;
                        List<JCExpression> targets = List.of(t = term3());
                        while (token.kind == AMP) {
                            checkIntersectionTypesInCast();
                            accept(AMP);
                            targets = targets.prepend(term3());
                        }
                        if (targets.length() > 1) {
                            t = toP(F.at(pos1).TypeIntersection(targets.reverse()));
                        }
                        accept(RPAREN);
                        mode = EXPR;
                        JCExpression t1 = term3();
                        return F.at(pos).TypeCast(t, t1);
                    case IMPLICIT_LAMBDA:
                    case EXPLICIT_LAMBDA:
                        t = lambdaExpressionOrStatement(true, pres == ParensResult.EXPLICIT_LAMBDA, pos);
                        break;
                    default:
                        // PARENS
                        accept(LPAREN);
                        mode = EXPR;
                        t = termRest(term1Rest(term2Rest(term3(), TreeInfo.orPrec)));
                        accept(RPAREN);
                        t = toP(F.at(pos).Parens(t));
                        break;
                }
            } else {
                return illegal();
            }
            break;
        case THIS:
            if ((mode & EXPR) != 0) {
                mode = EXPR;
                t = to(F.at(pos).Ident(names._this));
                nextToken();
                if (typeArgs == null)
                    t = argumentsOpt(null, t);
                else
                    t = arguments(typeArgs, t);
                typeArgs = null;
            } else
                return illegal();
            break;
        case SUPER:
            if ((mode & EXPR) != 0) {
                mode = EXPR;
                t = to(F.at(pos).Ident(names._super));
                t = superSuffix(typeArgs, t);
                typeArgs = null;
            } else
                return illegal();
            break;
        case INTLITERAL:
        case LONGLITERAL:
        case FLOATLITERAL:
        case DOUBLELITERAL:
        case CHARLITERAL:
        case STRINGLITERAL:
        case TRUE:
        case FALSE:
        case NULL:
            if (typeArgs == null && (mode & EXPR) != 0) {
                mode = EXPR;
                t = literal(names.empty);
            } else
                return illegal();
            break;
        case NEW:
            if (typeArgs != null)
                return illegal();
            if ((mode & EXPR) != 0) {
                mode = EXPR;
                nextToken();
                if (token.kind == LT)
                    typeArgs = typeArguments(false);
                t = creator(pos, typeArgs);
                typeArgs = null;
            } else
                return illegal();
            break;
        case MONKEYS_AT:
            // Only annotated cast types and method references are valid
            List<JCAnnotation> typeAnnos = typeAnnotationsOpt();
            if (typeAnnos.isEmpty()) {
                // else there would be no '@'
                throw new AssertionError("Expected type annotations, but found none!");
            }
            JCExpression expr = term3();
            if ((mode & TYPE) == 0) {
                // Type annotations on class literals no longer legal
                switch(expr.getTag()) {
                    case REFERENCE:
                        {
                            JCMemberReference mref = (JCMemberReference) expr;
                            mref.expr = toP(F.at(pos).AnnotatedType(typeAnnos, mref.expr));
                            t = mref;
                            break;
                        }
                    case SELECT:
                        {
                            JCFieldAccess sel = (JCFieldAccess) expr;
                            if (sel.name != names._class) {
                                return illegal();
                            } else {
                                log.error(token.pos, "no.annotations.on.dot.class");
                                return expr;
                            }
                        }
                    default:
                        return illegal(typeAnnos.head.pos);
                }
            } else {
                // Type annotations targeting a cast
                t = insertAnnotationsToMostInner(expr, typeAnnos, false);
            }
            break;
        case UNDERSCORE:
        case IDENTIFIER:
        case ASSERT:
        case ENUM:
            if (typeArgs != null)
                return illegal();
            if ((mode & EXPR) != 0 && peekToken(ARROW)) {
                t = lambdaExpressionOrStatement(false, false, pos);
            } else {
                t = toP(F.at(token.pos).Ident(ident()));
                loop: while (true) {
                    pos = token.pos;
                    final List<JCAnnotation> annos = typeAnnotationsOpt();
                    // index access rather than array creation level
                    if (!annos.isEmpty() && token.kind != LBRACKET && token.kind != ELLIPSIS)
                        return illegal(annos.head.pos);
                    switch(token.kind) {
                        case LBRACKET:
                            nextToken();
                            if (token.kind == RBRACKET) {
                                nextToken();
                                t = bracketsOpt(t);
                                t = toP(F.at(pos).TypeArray(t));
                                if (annos.nonEmpty()) {
                                    t = toP(F.at(pos).AnnotatedType(annos, t));
                                }
                                // .class is only allowed if there were no annotations
                                JCExpression nt = bracketsSuffix(t);
                                if (nt != t && (annos.nonEmpty() || TreeInfo.containsTypeAnnotation(t))) {
                                    // t and nt are different if bracketsSuffix parsed a .class.
                                    // The check for nonEmpty covers the case when the whole array is annotated.
                                    // Helper method isAnnotated looks for annos deeply within t.
                                    syntaxError("no.annotations.on.dot.class");
                                }
                                t = nt;
                            } else {
                                if ((mode & EXPR) != 0) {
                                    mode = EXPR;
                                    JCExpression t1 = term();
                                    if (!annos.isEmpty())
                                        t = illegal(annos.head.pos);
                                    t = to(F.at(pos).Indexed(t, t1));
                                }
                                accept(RBRACKET);
                            }
                            break loop;
                        case LPAREN:
                            if ((mode & EXPR) != 0) {
                                mode = EXPR;
                                t = arguments(typeArgs, t);
                                if (!annos.isEmpty())
                                    t = illegal(annos.head.pos);
                                typeArgs = null;
                            }
                            break loop;
                        case DOT:
                            nextToken();
                            int oldmode = mode;
                            mode &= ~NOPARAMS;
                            typeArgs = typeArgumentsOpt(EXPR);
                            mode = oldmode;
                            if ((mode & EXPR) != 0) {
                                switch(token.kind) {
                                    case CLASS:
                                        if (typeArgs != null)
                                            return illegal();
                                        mode = EXPR;
                                        t = to(F.at(pos).Select(t, names._class));
                                        nextToken();
                                        break loop;
                                    case THIS:
                                        if (typeArgs != null)
                                            return illegal();
                                        mode = EXPR;
                                        t = to(F.at(pos).Select(t, names._this));
                                        nextToken();
                                        break loop;
                                    case SUPER:
                                        mode = EXPR;
                                        t = to(F.at(pos).Select(t, names._super));
                                        t = superSuffix(typeArgs, t);
                                        typeArgs = null;
                                        break loop;
                                    case NEW:
                                        if (typeArgs != null)
                                            return illegal();
                                        mode = EXPR;
                                        int pos1 = token.pos;
                                        nextToken();
                                        if (token.kind == LT)
                                            typeArgs = typeArguments(false);
                                        t = innerCreator(pos1, typeArgs, t);
                                        typeArgs = null;
                                        break loop;
                                }
                            }
                            List<JCAnnotation> tyannos = null;
                            if ((mode & TYPE) != 0 && token.kind == MONKEYS_AT) {
                                tyannos = typeAnnotationsOpt();
                            }
                            // typeArgs saved for next loop iteration.
                            t = toP(F.at(pos).Select(t, ident()));
                            if (tyannos != null && tyannos.nonEmpty()) {
                                t = toP(F.at(tyannos.head.pos).AnnotatedType(tyannos, t));
                            }
                            break;
                        case ELLIPSIS:
                            if (this.permitTypeAnnotationsPushBack) {
                                this.typeAnnotationsPushedBack = annos;
                            } else if (annos.nonEmpty()) {
                                // Don't return here -- error recovery attempt
                                illegal(annos.head.pos);
                            }
                            break loop;
                        case LT:
                            if ((mode & TYPE) == 0 && isUnboundMemberRef()) {
                                // this is an unbound method reference whose qualifier
                                // is a generic type i.e. A<S>::m
                                int pos1 = token.pos;
                                accept(LT);
                                ListBuffer<JCExpression> args = new ListBuffer<JCExpression>();
                                args.append(typeArgument());
                                while (token.kind == COMMA) {
                                    nextToken();
                                    args.append(typeArgument());
                                }
                                accept(GT);
                                t = toP(F.at(pos1).TypeApply(t, args.toList()));
                                checkGenerics();
                                while (token.kind == DOT) {
                                    nextToken();
                                    mode = TYPE;
                                    t = toP(F.at(token.pos).Select(t, ident()));
                                    t = typeArgumentsOpt(t);
                                }
                                t = bracketsOpt(t);
                                if (token.kind != COLCOL) {
                                    // method reference expected here
                                    t = illegal();
                                }
                                mode = EXPR;
                                return term3Rest(t, typeArgs);
                            }
                            break loop;
                        default:
                            break loop;
                    }
                }
            }
            if (typeArgs != null)
                illegal();
            t = typeArgumentsOpt(t);
            break;
        case BYTE:
        case SHORT:
        case CHAR:
        case INT:
        case LONG:
        case FLOAT:
        case DOUBLE:
        case BOOLEAN:
            if (typeArgs != null)
                illegal();
            t = bracketsSuffix(bracketsOpt(basicType()));
            break;
        case VOID:
            if (typeArgs != null)
                illegal();
            if ((mode & EXPR) != 0) {
                nextToken();
                if (token.kind == DOT) {
                    JCPrimitiveTypeTree ti = toP(F.at(pos).TypeIdent(TypeTag.VOID));
                    t = bracketsSuffix(ti);
                } else {
                    return illegal(pos);
                }
            } else {
                // Support the corner case of myMethodHandle.<void>invoke() by passing
                // a void type (like other primitive types) to the next phase.
                // The error will be reported in Attr.attribTypes or Attr.visitApply.
                JCPrimitiveTypeTree ti = to(F.at(pos).TypeIdent(TypeTag.VOID));
                nextToken();
                return ti;
            // return illegal();
            }
            break;
        default:
            return illegal();
    }
    return term3Rest(t, typeArgs);
}
Also used : TokenKind(org.eclipse.ceylon.langtools.tools.javac.parser.Tokens.TokenKind) List(org.eclipse.ceylon.langtools.tools.javac.util.List)

Example 8 with List

use of org.eclipse.ceylon.langtools.tools.javac.util.List in project ceylon by eclipse.

the class ExpressionTransformer method transformQualifiedInstantiation.

private JCExpression transformQualifiedInstantiation(Invocation invocation, CallBuilder callBuilder, TransformedInvocationPrimary transformedPrimary) {
    Tree.QualifiedTypeExpression qte = (Tree.QualifiedTypeExpression) invocation.getPrimary();
    Declaration declaration = qte.getDeclaration();
    invocation.location(callBuilder);
    if (Decl.isJavaStaticOrInterfacePrimary(invocation.getPrimary())) {
        callBuilder.instantiate(transformedPrimary.expr);
    } else if (!Strategy.generateInstantiator(declaration)) {
        if (Decl.isConstructorPrimary(invocation.getPrimary())) {
            if (ModelUtil.getConstructedClass(invocation.getPrimaryDeclaration()).isMember()) /*&& invocation.getPrimary() instanceof Tree.QualifiedTypeExpression
                        && !(((Tree.QualifiedTypeExpression)invocation.getPrimary()).getPrimary() instanceof Tree.BaseTypeExpression)*/
            {
                callBuilder.instantiate(new ExpressionAndType(transformedPrimary.expr, null), makeJavaType(invocation.getReturnType(), JT_CLASS_NEW | (transformedPrimary.expr == null ? 0 : JT_NON_QUALIFIED)));
            } else {
                callBuilder.instantiate(makeJavaType(invocation.getReturnType(), JT_CLASS_NEW));
            }
        } else {
            JCExpression qualifier;
            JCExpression qualifierType;
            if (declaration.getContainer() instanceof Interface) {
                // When doing qualified invocation through an interface we need
                // to get the companion.
                Interface qualifyingInterface = (Interface) declaration.getContainer();
                qualifier = transformedPrimary.expr;
                qualifierType = makeJavaType(qualifyingInterface.getType(), JT_COMPANION);
            } else {
                qualifier = transformedPrimary.expr;
                if (declaration.getContainer() instanceof TypeDeclaration) {
                    qualifierType = makeJavaType(((TypeDeclaration) declaration.getContainer()).getType());
                } else {
                    qualifierType = null;
                }
            }
            Type classType = (Type) qte.getTarget();
            JCExpression type;
            // special case for package-qualified things that are not really qualified
            if (qualifier == null) {
                type = makeJavaType(classType, AbstractTransformer.JT_CLASS_NEW);
            } else {
                // Note: here we're not fully qualifying the class name because the JLS says that if "new" is qualified the class name
                // is qualified relative to it
                type = makeJavaType(classType, AbstractTransformer.JT_CLASS_NEW | AbstractTransformer.JT_NON_QUALIFIED);
            }
            callBuilder.instantiate(new ExpressionAndType(qualifier, qualifierType), type);
        }
    } else {
        // instantiator
        callBuilder.typeArguments(List.<JCExpression>nil());
        java.util.List<Type> typeModels = qte.getTypeArguments().getTypeModels();
        if (typeModels != null) {
            for (Type tm : typeModels) {
                callBuilder.typeArgument(makeJavaType(tm, AbstractTransformer.JT_TYPE_ARGUMENT));
            }
        }
        callBuilder.invoke(naming.makeInstantiatorMethodName(transformedPrimary.expr, ModelUtil.getConstructedClass(declaration)));
    }
    JCExpression result = callBuilder.build();
    if (Strategy.isInstantiatorUntyped(declaration)) {
        result = make().TypeCast(makeJavaType(invocation.getReturnType()), result);
    }
    return result;
}
Also used : UnionType(org.eclipse.ceylon.model.typechecker.model.UnionType) Type(org.eclipse.ceylon.model.typechecker.model.Type) JCExpression(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree) Tree(org.eclipse.ceylon.compiler.typechecker.tree.Tree) CondList(org.eclipse.ceylon.compiler.java.codegen.StatementTransformer.CondList) List(org.eclipse.ceylon.langtools.tools.javac.util.List) ParameterList(org.eclipse.ceylon.model.typechecker.model.ParameterList) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) Interface(org.eclipse.ceylon.model.typechecker.model.Interface) ClassOrInterface(org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) LazyInterface(org.eclipse.ceylon.model.loader.model.LazyInterface)

Example 9 with List

use of org.eclipse.ceylon.langtools.tools.javac.util.List in project ceylon by eclipse.

the class CeylonTransformer method makeDefs.

private List<JCTree> makeDefs(CompilationUnit t) {
    final ListBuffer<JCTree> defs = new ListBuffer<JCTree>();
    t.visit(new SourceDeclarationVisitor() {

        @Override
        public void loadFromSource(Declaration decl) {
            if (!checkNative(decl))
                return;
            Stack<Tree.Declaration> ancestors = new Stack<>();
            long flags = decl instanceof Tree.AnyInterface ? Flags.INTERFACE : 0;
            String name = Naming.toplevelClassName("", decl);
            defs.add(makeClassDef(decl, flags, name, WantedDeclaration.Normal, defs, ancestors));
            if (decl instanceof Tree.AnyInterface) {
                String implName = Naming.getImplClassName(name);
                defs.add(makeClassDef(decl, 0, implName, WantedDeclaration.InterfaceImpl, defs, ancestors));
            }
            if (Decl.isAnnotationClassNoModel(decl)) {
                String annotationName = Naming.suffixName(Suffix.$annotation$, name);
                defs.add(makeClassDef(decl, Flags.ANNOTATION | Flags.INTERFACE, annotationName, WantedDeclaration.Annotation, defs, ancestors));
                if (Decl.isSequencedAnnotationClassNoModel((Tree.AnyClass) decl)) {
                    String annotationsName = Naming.suffixName(Suffix.$annotations$, name);
                    defs.add(makeClassDef(decl, Flags.ANNOTATION | Flags.INTERFACE, annotationsName, WantedDeclaration.AnnotationSequence, defs, ancestors));
                }
            }
        }

        private JCTree makeClassDef(Tree.Declaration decl, long flags, String name, WantedDeclaration wantedDeclaration, ListBuffer<JCTree> toplevelDeclarations, Stack<Tree.Declaration> ancestors) {
            if (decl instanceof Tree.AnyInterface == false && TreeUtil.hasAnnotation(decl.getAnnotationList(), "static", null)) {
                flags |= Flags.STATIC;
            }
            ListBuffer<JCTree.JCTypeParameter> typarams = new ListBuffer<JCTree.JCTypeParameter>();
            if (decl instanceof Tree.ClassOrInterface) {
                Tree.ClassOrInterface classDecl = (ClassOrInterface) decl;
                if (decl instanceof Tree.AnyInterface) {
                    // interfaces are pulled up and catch container type params
                    for (Tree.Declaration ancestor : ancestors) {
                        if (ancestor instanceof Tree.ClassOrInterface) {
                            addTypeParameters(typarams, (Tree.ClassOrInterface) ancestor);
                        }
                    }
                }
                addTypeParameters(typarams, classDecl);
            }
            ancestors.push(decl);
            JCTree ret = make().ClassDef(make().Modifiers(flags | Flags.PUBLIC), names().fromString(name), typarams.toList(), null, List.<JCExpression>nil(), makeClassBody(decl, wantedDeclaration, toplevelDeclarations, ancestors));
            ancestors.pop();
            return ret;
        }

        private void addTypeParameters(ListBuffer<JCTypeParameter> typarams, Tree.ClassOrInterface classDecl) {
            if (classDecl.getTypeParameterList() != null) {
                for (Tree.TypeParameterDeclaration typeParamDecl : classDecl.getTypeParameterList().getTypeParameterDeclarations()) {
                    // we don't need a valid name, just a name, and making it BOGUS helps us find it later if it turns out
                    // we failed to reset everything properly
                    typarams.add(make().TypeParameter(names().fromString("BOGUS-" + typeParamDecl.getIdentifier().getText()), List.<JCExpression>nil()));
                }
            }
        }

        private List<JCTree> makeClassBody(Declaration decl, WantedDeclaration wantedDeclaration, ListBuffer<JCTree> toplevelDeclarations, Stack<Tree.Declaration> ancestors) {
            // only do it for Bootstrap where we control the annotations, because it's so dodgy ATM
            if (wantedDeclaration == WantedDeclaration.Annotation) {
                ListBuffer<JCTree> body = new ListBuffer<JCTree>();
                for (Tree.Parameter param : ((Tree.ClassDefinition) decl).getParameterList().getParameters()) {
                    String name;
                    JCExpression type = make().TypeArray(make().Type(syms().stringType));
                    if (param instanceof Tree.InitializerParameter)
                        name = ((Tree.InitializerParameter) param).getIdentifier().getText();
                    else if (param instanceof Tree.ParameterDeclaration) {
                        Tree.TypedDeclaration typedDeclaration = ((Tree.ParameterDeclaration) param).getTypedDeclaration();
                        name = typedDeclaration.getIdentifier().getText();
                        type = getAnnotationTypeFor(typedDeclaration.getType());
                    } else
                        name = "ERROR";
                    JCMethodDecl method = make().MethodDef(make().Modifiers(Flags.PUBLIC), names().fromString(name), type, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), null, null);
                    body.append(method);
                }
                return body.toList();
            }
            if (wantedDeclaration == WantedDeclaration.AnnotationSequence) {
                String name = Naming.toplevelClassName("", decl);
                String annotationName = Naming.suffixName(Suffix.$annotation$, name);
                JCExpression type = make().TypeArray(make().Ident(names().fromString(annotationName)));
                JCMethodDecl method = make().MethodDef(make().Modifiers(Flags.PUBLIC), names().fromString("value"), type, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), null, null);
                return List.<JCTree>of(method);
            }
            ListBuffer<JCTree> defs = new ListBuffer<>();
            java.util.List<Statement> statements = null;
            if (decl instanceof Tree.ClassDefinition)
                statements = ((Tree.ClassDefinition) decl).getClassBody().getStatements();
            else if (decl instanceof Tree.InterfaceDefinition) {
                // only walk interface members if we're generating the impl class
                if (wantedDeclaration == WantedDeclaration.InterfaceImpl)
                    statements = ((Tree.InterfaceDefinition) decl).getInterfaceBody().getStatements();
            }
            if (statements != null) {
                for (Tree.Statement member : statements) {
                    if (member instanceof Tree.ClassOrInterface && checkNative((Tree.Declaration) member)) {
                        long flags = member instanceof Tree.AnyInterface ? Flags.INTERFACE : 0;
                        String initialName = Naming.toplevelClassName("", (Tree.Declaration) member);
                        String name;
                        if (member instanceof Tree.AnyInterface) {
                            // interfaces are pulled to the toplevel
                            StringBuffer strbuf = new StringBuffer();
                            for (Tree.Declaration part : ancestors) strbuf.append(part.getIdentifier().getText()).append("$");
                            name = strbuf.append(initialName).toString();
                        } else {
                            name = initialName;
                        }
                        JCTree def = makeClassDef((Tree.Declaration) member, flags, name, WantedDeclaration.Normal, toplevelDeclarations, ancestors);
                        if (member instanceof Tree.AnyInterface) {
                            toplevelDeclarations.add(def);
                            String implName = Naming.getImplClassName(initialName);
                            defs.add(makeClassDef((Tree.Declaration) member, 0, implName, WantedDeclaration.InterfaceImpl, defs, ancestors));
                        } else
                            defs.add(def);
                    // FIXME: interfaces impl?
                    }
                }
            }
            return defs.toList();
        }

        private JCExpression getAnnotationTypeFor(Tree.Type type) {
            if (type instanceof Tree.BaseType) {
                String name = ((Tree.BaseType) type).getIdentifier().getText();
                if (name.equals("String") || name.equals("Declaration"))
                    return make().Type(syms().stringType);
                if (name.equals("Boolean"))
                    return make().Type(syms().booleanType);
                if (name.equals("Integer"))
                    return make().Type(syms().longType);
                if (name.equals("Float"))
                    return make().Type(syms().doubleType);
                if (name.equals("Byte"))
                    return make().Type(syms().byteType);
                if (name.equals("Character"))
                    return make().Type(syms().charType);
                if (name.equals("Declaration") || name.equals("ClassDeclaration") || name.equals("InterfaceDeclaration") || name.equals("ClassOrInterfaceDeclaration"))
                    return make().Type(syms().stringType);
                // probably an enum value then
                return make().TypeArray(make().Type(syms().stringType));
            }
            if (type instanceof Tree.SequencedType) {
                return make().TypeArray(getAnnotationTypeFor(((Tree.SequencedType) type).getType()));
            }
            if (type instanceof Tree.SequenceType) {
                return make().TypeArray(getAnnotationTypeFor(((Tree.SequenceType) type).getElementType()));
            }
            if (type instanceof Tree.IterableType) {
                return make().TypeArray(getAnnotationTypeFor(((Tree.IterableType) type).getElementType()));
            }
            if (type instanceof Tree.TupleType) {
                // can only be one, must be a SequencedType
                Tree.Type sequencedType = ((Tree.TupleType) type).getElementTypes().get(0);
                return getAnnotationTypeFor(sequencedType);
            }
            System.err.println("Unknown Annotation type: " + type);
            return make().TypeArray(make().Type(syms().stringType));
        }

        @Override
        public void loadFromSource(ModuleDescriptor that) {
        // don't think we care about these
        }

        @Override
        public void loadFromSource(PackageDescriptor that) {
        // don't think we care about these
        }
    });
    return defs.toList();
}
Also used : ClassOrInterface(org.eclipse.ceylon.compiler.typechecker.tree.Tree.ClassOrInterface) ListBuffer(org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree) Tree(org.eclipse.ceylon.compiler.typechecker.tree.Tree) SourceDeclarationVisitor(org.eclipse.ceylon.compiler.java.loader.SourceDeclarationVisitor) List(org.eclipse.ceylon.langtools.tools.javac.util.List) Declaration(org.eclipse.ceylon.compiler.typechecker.tree.Tree.Declaration) JCMethodDecl(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCMethodDecl) Stack(java.util.Stack) JCTypeParameter(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCTypeParameter) JCExpression(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression) PackageDescriptor(org.eclipse.ceylon.compiler.typechecker.tree.Tree.PackageDescriptor) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) Declaration(org.eclipse.ceylon.compiler.typechecker.tree.Tree.Declaration) ClassOrInterface(org.eclipse.ceylon.compiler.typechecker.tree.Tree.ClassOrInterface) Statement(org.eclipse.ceylon.compiler.typechecker.tree.Tree.Statement) JCStatement(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree) JCVariableDecl(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCVariableDecl) ModuleDescriptor(org.eclipse.ceylon.compiler.typechecker.tree.Tree.ModuleDescriptor) Parameter(org.eclipse.ceylon.model.typechecker.model.Parameter) JCTypeParameter(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCTypeParameter)

Aggregations

List (org.eclipse.ceylon.langtools.tools.javac.util.List)9 JCExpression (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression)6 ArrayList (java.util.ArrayList)5 ParameterList (org.eclipse.ceylon.model.typechecker.model.ParameterList)5 TypeDeclaration (org.eclipse.ceylon.model.typechecker.model.TypeDeclaration)5 TypedDeclaration (org.eclipse.ceylon.model.typechecker.model.TypedDeclaration)5 Tree (org.eclipse.ceylon.compiler.typechecker.tree.Tree)4 JCTree (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree)4 Declaration (org.eclipse.ceylon.model.typechecker.model.Declaration)4 LinkedList (java.util.LinkedList)3 JCNewClass (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCNewClass)3 Class (org.eclipse.ceylon.model.typechecker.model.Class)3 FunctionOrValue (org.eclipse.ceylon.model.typechecker.model.FunctionOrValue)3 Parameter (org.eclipse.ceylon.model.typechecker.model.Parameter)3 Type (org.eclipse.ceylon.model.typechecker.model.Type)3 TypeParameter (org.eclipse.ceylon.model.typechecker.model.TypeParameter)3 Value (org.eclipse.ceylon.model.typechecker.model.Value)3 CondList (org.eclipse.ceylon.compiler.java.codegen.StatementTransformer.CondList)2 AnnotationList (org.eclipse.ceylon.compiler.typechecker.tree.Tree.AnnotationList)2 JCPrimitiveTypeTree (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCPrimitiveTypeTree)2