@Override public boolean handle( AnnotationValues<Synchronized> annotation, JCAnnotation ast, Node annotationNode) { Node methodNode = annotationNode.up(); if (methodNode == null || methodNode.getKind() != Kind.METHOD || !(methodNode.get() instanceof JCMethodDecl)) { annotationNode.addError("@Synchronized is legal only on methods."); return true; } JCMethodDecl method = (JCMethodDecl) methodNode.get(); if ((method.mods.flags & Flags.ABSTRACT) != 0) { annotationNode.addError("@Synchronized is legal only on concrete methods."); return true; } 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; } TreeMaker maker = methodNode.getTreeMaker(); if (fieldExists(lockName, methodNode) == MemberExistsResult.NOT_EXISTS) { if (!autoMake) { annotationNode.addError("The field " + new String(lockName) + " does not exist."); return true; } JCExpression objectType = chainDots(maker, methodNode, "java", "lang", "Object"); // We use 'new Object[0];' because quite unlike 'new Object();', empty arrays *ARE* // serializable! JCNewArray newObjectArray = maker.NewArray( chainDots(maker, methodNode, "java", "lang", "Object"), List.<JCExpression>of(maker.Literal(TypeTags.INT, 0)), null); JCVariableDecl fieldDecl = maker.VarDef( maker.Modifiers(Flags.FINAL | (isStatic ? Flags.STATIC : 0)), methodNode.toName(lockName), objectType, newObjectArray); injectField(methodNode.up(), fieldDecl); } if (method.body == null) return false; JCExpression lockNode = maker.Ident(methodNode.toName(lockName)); method.body = maker.Block(0, List.<JCStatement>of(maker.Synchronized(lockNode, method.body))); methodNode.rebuild(); return true; }
public void run() { Context ctx = new Context(); Options options = Options.instance(ctx); outputKind.init(options); multiPolicy.init(options); xdiagsSource.init(options); xdiagsCompact.init(options); caretKind.init(options); sourceLineKind.init(options); String indentString = ""; indentString = (summaryIndent == IndentKind.CUSTOM) ? "3" : "0"; indentString += (detailsIndent == IndentKind.CUSTOM) ? "|3" : "|0"; indentString += (sourceIndent == IndentKind.CUSTOM) ? "|3" : "|0"; indentString += (subdiagsIndent == IndentKind.CUSTOM) ? "|3" : "|0"; options.put("diagsIndentation", indentString); MyLog log = new MyLog(ctx); JavacMessages messages = JavacMessages.instance(ctx); messages.add("tester"); JCDiagnostic.Factory diags = JCDiagnostic.Factory.instance(ctx); log.useSource(new MyFileObject("This is a source line")); JCDiagnostic d = diags.error(null, log.currentSource(), posKind.pos(), errorKind.key(), "Hello!"); if (multiKind != MultilineKind.NONE) { JCDiagnostic sub = diags.fragment(errorKind.key(), "Hello!"); if (multiKind.isNested()) sub = new JCDiagnostic.MultilineDiagnostic(sub, List.of(sub)); List<JCDiagnostic> subdiags = multiKind.isDouble() ? List.of(sub, sub) : List.of(sub); d = new JCDiagnostic.MultilineDiagnostic(d, subdiags); } String diag = log.getDiagnosticFormatter().format(d, messages.getCurrentLocale()); checkOutput(diag); }
private JCTree generateFieldInit() { long flags = (modifiers & Flags.STATIC); JCTree.JCExpression varInit = variableInit; if (toplevel) { varInit = owner .make() .NewArray( attrTypeRaw, List.<JCTree.JCExpression>nil(), List.<JCTree.JCExpression>of(varInit)); } JCTree.JCAssign init = owner.make().Assign(owner.makeUnquotedIdent(fieldName), varInit); return owner.make().Block(flags, List.<JCTree.JCStatement>of(owner.make().Exec(init))); }
public JCMethodDecl generateBuilderMethod( String builderMethodName, String builderClassName, JavacNode type, List<JCTypeParameter> typeParams) { JavacTreeMaker maker = type.getTreeMaker(); ListBuffer<JCExpression> typeArgs = new ListBuffer<JCExpression>(); for (JCTypeParameter typeParam : typeParams) { typeArgs.append(maker.Ident(typeParam.name)); } JCExpression call = maker.NewClass( null, List.<JCExpression>nil(), namePlusTypeParamsToTypeReference(maker, type.toName(builderClassName), typeParams), List.<JCExpression>nil(), null); JCStatement statement = maker.Return(call); JCBlock body = maker.Block(0, List.<JCStatement>of(statement)); return maker.MethodDef( maker.Modifiers(Flags.STATIC | Flags.PUBLIC), type.toName(builderMethodName), namePlusTypeParamsToTypeReference(maker, type.toName(builderClassName), typeParams), copyTypeParams(maker, typeParams), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); }
private static void injectField( JavacNode typeNode, JCVariableDecl field, boolean addSuppressWarnings) { JCClassDecl type = (JCClassDecl) typeNode.get(); if (addSuppressWarnings) addSuppressWarningsAll(field.mods, typeNode, field.pos, getGeneratedBy(field)); List<JCTree> insertAfter = null; List<JCTree> insertBefore = type.defs; while (insertBefore.tail != null) { if (insertBefore.head instanceof JCVariableDecl) { JCVariableDecl f = (JCVariableDecl) insertBefore.head; if (isEnumConstant(f) || isGenerated(f)) { insertAfter = insertBefore; insertBefore = insertBefore.tail; continue; } } break; } List<JCTree> fieldEntry = List.<JCTree>of(field); fieldEntry.tail = insertBefore; if (insertAfter == null) { type.defs = fieldEntry; } else { insertAfter.tail = fieldEntry; } typeNode.add(field, Kind.FIELD); }
private JCCompilationUnit ceylonParse(JavaFileObject filename, CharSequence readSource) { if (ceylonEnter.hasRun()) throw new RuntimeException( "Trying to load new source file after CeylonEnter has been called: " + filename); try { String source = readSource.toString(); ANTLRStringStream input = new ANTLRStringStream(source); CeylonLexer lexer = new CeylonLexer(input); CommonTokenStream tokens = new CommonTokenStream(lexer); CeylonParser parser = new CeylonParser(tokens); CompilationUnit cu = parser.compilationUnit(); char[] chars = source.toCharArray(); LineMap map = Position.makeLineMap(chars, chars.length, false); java.util.List<LexError> lexerErrors = lexer.getErrors(); for (LexError le : lexerErrors) { printError(le, le.getMessage(), "ceylon.lexer", map); } java.util.List<ParseError> parserErrors = parser.getErrors(); for (ParseError pe : parserErrors) { printError(pe, pe.getMessage(), "ceylon.parser", map); } if (lexer.getNumberOfSyntaxErrors() != 0) { log.error("ceylon.lexer.failed"); } else if (parser.getNumberOfSyntaxErrors() != 0) { log.error("ceylon.parser.failed"); } else { ModuleManager moduleManager = phasedUnits.getModuleManager(); File sourceFile = new File(filename.toString()); // FIXME: temporary solution VirtualFile file = vfs.getFromFile(sourceFile); VirtualFile srcDir = vfs.getFromFile(getSrcDir(sourceFile)); // FIXME: this is bad in many ways String pkgName = getPackage(filename); // make a Package with no module yet, we will resolve them later com.redhat.ceylon.compiler.typechecker.model.Package p = modelLoader.findOrCreatePackage(null, pkgName == null ? "" : pkgName); PhasedUnit phasedUnit = new CeylonPhasedUnit(file, srcDir, cu, p, moduleManager, ceylonContext, filename, map); phasedUnits.addPhasedUnit(file, phasedUnit); gen.setMap(map); return gen.makeJCCompilationUnitPlaceholder(cu, filename, pkgName, phasedUnit); } } catch (Exception e) { log.error("ceylon", e.getMessage()); } JCCompilationUnit result = make.TopLevel(List.<JCAnnotation>nil(), null, List.<JCTree>of(make.Erroneous())); result.sourcefile = filename; return result; }
public JCNewClass build() { // Generate a subclass of Callable ListBuffer<JCTree> classBody = new ListBuffer<JCTree>(); int numParams = paramLists.getParameters().size(); int minimumParams = 0; for (Parameter p : paramLists.getParameters()) { if (p.isDefaulted() || p.isSequenced()) break; minimumParams++; } boolean isVariadic = minimumParams != numParams; if (parameterListTree != null) { // generate a method for each defaulted param for (Tree.Parameter p : parameterListTree.getParameters()) { if (p.getDefaultArgument() != null || p.getDeclarationModel().isSequenced()) { MethodDefinitionBuilder methodBuilder = gen.classGen().makeParamDefaultValueMethod(false, null, parameterListTree, p); classBody.append(methodBuilder.build()); } } } // collect each parameter type from the callable type model rather than the declarations to get // them all bound java.util.List<ProducedType> parameterTypes = new ArrayList<ProducedType>(numParams); if (forwardCallTo != null) { for (int i = 0; i < numParams; i++) parameterTypes.add(gen.getParameterTypeOfCallable(typeModel, i)); } else { // get them from our declaration for (Parameter p : paramLists.getParameters()) parameterTypes.add(p.getType()); } // now generate a method for each supported minimum number of parameters below 4 // which delegates to the $call$typed method if required for (int i = minimumParams, max = Math.min(numParams, 4); i < max; i++) { classBody.append(makeDefaultedCall(i, isVariadic, parameterTypes)); } // generate the $call method for the max number of parameters, // which delegates to the $call$typed method if required classBody.append(makeDefaultedCall(numParams, isVariadic, parameterTypes)); // generate the $call$typed method if required if (isVariadic && forwardCallTo == null) classBody.append(makeCallTypedMethod(body, parameterTypes)); JCClassDecl classDef = gen.make().AnonymousClassDef(gen.make().Modifiers(0), classBody.toList()); JCNewClass instance = gen.make() .NewClass( null, null, gen.makeJavaType(typeModel, JT_EXTENDS | JT_CLASS_NEW), List.<JCExpression>of(gen.make().Literal(typeModel.getProducedTypeName(true))), classDef); return instance; }
/** * Constructs an {@code AbstractCallable} suitable for an anonymous function. * * @param parameterList2 */ public static CallableBuilder anonymous( CeylonTransformer gen, Tree.Expression expr, ParameterList parameterList, Tree.ParameterList parameterListTree, ProducedType callableTypeModel) { JCExpression transformedExpr = gen.expressionGen().transformExpression(expr); final List<JCStatement> stmts = List.<JCStatement>of(gen.make().Return(transformedExpr)); return methodArgument(gen, callableTypeModel, parameterList, parameterListTree, stmts); }
@Test public void inline() { ImportPolicy.bind(context, ImportPolicy.IMPORT_TOP_LEVEL); Symtab symtab = Symtab.instance(context); Type listType = symtab.listType; bind( new UTypeVar.Key("E"), TypeWithExpression.create( new ClassType(listType, List.<Type>of(symtab.stringType), listType.tsym))); assertInlines("List<String>", UTypeVarIdent.create("E")); assertEquals(ImmutableSet.of("java.util.List"), inliner.getImportsToAdd()); }
private static void addSuppressWarningsAll( JCModifiers mods, JavacNode node, int pos, JCTree source) { TreeMaker maker = node.getTreeMaker(); JCExpression suppressWarningsType = chainDots(node, "java", "lang", "SuppressWarnings"); JCLiteral allLiteral = maker.Literal("all"); suppressWarningsType.pos = pos; allLiteral.pos = pos; JCAnnotation annotation = recursiveSetGeneratedBy( maker.Annotation(suppressWarningsType, List.<JCExpression>of(allLiteral)), source); annotation.pos = pos; mods.annotations = mods.annotations.append(annotation); }
private JCStatement buildTryCatchBlock( JavacNode node, List<JCStatement> contents, String exception) { TreeMaker maker = node.getTreeMaker(); JCBlock tryBlock = maker.Block(0, contents); JCExpression varType = chainDots(maker, node, exception.split("\\.")); JCVariableDecl catchParam = maker.VarDef(maker.Modifiers(Flags.FINAL), node.toName("$ex"), varType, null); JCExpression lombokLombokSneakyThrowNameRef = chainDots(maker, node, "lombok", "Lombok", "sneakyThrow"); JCBlock catchBody = maker.Block( 0, List.<JCStatement>of( maker.Throw( maker.Apply( List.<JCExpression>nil(), lombokLombokSneakyThrowNameRef, List.<JCExpression>of(maker.Ident(node.toName("$ex"))))))); return maker.Try(tryBlock, List.of(maker.Catch(catchParam, catchBody)), null); }
private JCTree.JCBlock generateDefaultGetterBlock() { JCTree.JCExpression returnExpr = owner.makeUnquotedIdent(fieldName); if (toplevel) { returnExpr = owner.make().Indexed(returnExpr, owner.make().Literal(0)); } JCTree.JCBlock block = owner.make().Block(0L, List.<JCTree.JCStatement>of(owner.make().Return(returnExpr))); if (toplevel) { JCTree.JCThrow throwStmt = owner .make() .Throw( owner.makeNewClass( owner.makeIdent(owner.syms().ceylonRecursiveInitializationExceptionType), null)); JCTree.JCBlock catchBlock = owner.make().Block(0, List.<JCTree.JCStatement>of(throwStmt)); JCVariableDecl excepType = owner.makeVar("ex", owner.make().Type(owner.syms().nullPointerExceptionType), null); JCTree.JCCatch catcher = owner.make().Catch(excepType, catchBlock); JCTree.JCTry tryExpr = owner.make().Try(block, List.<JCTree.JCCatch>of(catcher), null); block = owner.make().Block(0L, List.<JCTree.JCStatement>of(tryExpr)); } return block; }
public JCMethodDecl createCanEqual(JavacNode typeNode, JCTree source) { /* public boolean canEqual(final java.lang.Object other) { * return other instanceof Outer.Inner.MyType; * } */ JavacTreeMaker maker = typeNode.getTreeMaker(); JCModifiers mods = maker.Modifiers(Flags.PUBLIC, List.<JCAnnotation>nil()); JCExpression returnType = maker.TypeIdent(CTC_BOOLEAN); Name canEqualName = typeNode.toName("canEqual"); JCExpression objectType = genJavaLangTypeRef(typeNode, "Object"); Name otherName = typeNode.toName("other"); long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, typeNode.getContext()); List<JCVariableDecl> params = List.of(maker.VarDef(maker.Modifiers(flags), otherName, objectType, null)); JCBlock body = maker.Block( 0, List.<JCStatement>of( maker.Return( maker.TypeTest(maker.Ident(otherName), createTypeReference(typeNode))))); return recursiveSetGeneratedBy( maker.MethodDef( mods, canEqualName, returnType, List.<JCTypeParameter>nil(), params, List.<JCExpression>nil(), body, null), source, typeNode.getContext()); }
private void initProcessorIterator(Context context, Iterable<? extends Processor> processors) { Log log = Log.instance(context); Iterator<? extends Processor> processorIterator; if (options.isSet(XPRINT)) { try { Processor processor = PrintingProcessor.class.newInstance(); processorIterator = List.of(processor).iterator(); } catch (Throwable t) { AssertionError assertError = new AssertionError("Problem instantiating PrintingProcessor."); assertError.initCause(t); throw assertError; } } else if (processors != null) { processorIterator = processors.iterator(); } else { String processorNames = options.get(PROCESSOR); JavaFileManager fileManager = context.get(JavaFileManager.class); try { // If processorpath is not explicitly set, use the classpath. processorClassLoader = fileManager.hasLocation(ANNOTATION_PROCESSOR_PATH) ? fileManager.getClassLoader(ANNOTATION_PROCESSOR_PATH) : fileManager.getClassLoader(CLASS_PATH); /* * If the "-processor" option is used, search the appropriate * path for the named class. Otherwise, use a service * provider mechanism to create the processor iterator. */ if (processorNames != null) { processorIterator = new NameProcessIterator(processorNames, processorClassLoader, log); } else { processorIterator = new ServiceIterator(processorClassLoader, log); } } catch (SecurityException e) { /* * A security exception will occur if we can't create a classloader. * Ignore the exception if, with hindsight, we didn't need it anyway * (i.e. no processor was specified either explicitly, or implicitly, * in service configuration file.) Otherwise, we cannot continue. */ processorIterator = handleServiceLoaderUnavailability("proc.cant.create.loader", e); } } discoveredProcs = new DiscoveredProcessors(processorIterator); }
public JCMethodDecl generateBuildMethod( String name, Name staticName, JCExpression returnType, java.util.List<Name> fieldNames, JavacNode type, List<JCExpression> thrownExceptions) { JavacTreeMaker maker = type.getTreeMaker(); JCExpression call; JCStatement statement; ListBuffer<JCExpression> args = new ListBuffer<JCExpression>(); for (Name n : fieldNames) { args.append(maker.Ident(n)); } if (staticName == null) { call = maker.NewClass(null, List.<JCExpression>nil(), returnType, args.toList(), null); statement = maker.Return(call); } else { ListBuffer<JCExpression> typeParams = new ListBuffer<JCExpression>(); for (JCTypeParameter tp : ((JCClassDecl) type.get()).typarams) { typeParams.append(maker.Ident(tp.name)); } JCExpression fn = maker.Select(maker.Ident(((JCClassDecl) type.up().get()).name), staticName); call = maker.Apply(typeParams.toList(), fn, args.toList()); if (returnType instanceof JCPrimitiveTypeTree && CTC_VOID.equals(typeTag(returnType))) { statement = maker.Exec(call); } else { statement = maker.Return(call); } } JCBlock body = maker.Block(0, List.<JCStatement>of(statement)); return maker.MethodDef( maker.Modifiers(Flags.PUBLIC), type.toName(name), returnType, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), thrownExceptions, body, null); }
public JCStatement generateCompareFloatOrDouble( JCExpression thisDotField, JCExpression otherDotField, JavacTreeMaker maker, JavacNode node, boolean isDouble) { /* if (Float.compare(fieldName, other.fieldName) != 0) return false; */ JCExpression clazz = genJavaLangTypeRef(node, isDouble ? "Double" : "Float"); List<JCExpression> args = List.of(thisDotField, otherDotField); JCBinary compareCallEquals0 = maker.Binary( CTC_NOT_EQUAL, maker.Apply( List.<JCExpression>nil(), maker.Select(clazz, node.toName("compare")), args), maker.Literal(0)); return maker.If(compareCallEquals0, returnBool(maker, false), null); }
public JCTree.JCBlock generateDefaultSetterBlock() { JCTree.JCExpression fld; if (fieldName.equals(attrName)) { fld = owner.makeSelect("this", fieldName); } else { fld = owner.makeUnquotedIdent(fieldName); } if (toplevel) { fld = owner.make().Indexed(fld, owner.make().Literal(0)); } return owner .make() .Block( 0L, List.<JCTree.JCStatement>of( owner.make().Exec(owner.make().Assign(fld, owner.makeUnquotedIdent(attrName))))); }
/** * Generates a new statement that checks if the given variable is null, and if so, throws a {@code * NullPointerException} with the variable name as message. */ public static JCStatement generateNullCheck(TreeMaker treeMaker, JavacNode variable) { JCVariableDecl varDecl = (JCVariableDecl) variable.get(); if (isPrimitive(varDecl.vartype)) return null; Name fieldName = varDecl.name; JCExpression npe = chainDots(variable, "java", "lang", "NullPointerException"); JCTree exception = treeMaker.NewClass( null, List.<JCExpression>nil(), npe, List.<JCExpression>of(treeMaker.Literal(fieldName.toString())), null); JCStatement throwStatement = treeMaker.Throw(exception); return treeMaker.If( treeMaker.Binary(CTC_EQUAL, treeMaker.Ident(fieldName), treeMaker.Literal(CTC_BOT, null)), throwStatement, null); }
public void visitAnnotation(JCAnnotation tree) { try { print("@"); printExpr(tree.annotationType); if (tree.args.nonEmpty()) { print("("); if (tree.args.length() == 1 && tree.args.get(0) instanceof JCAssign) { JCExpression lhs = ((JCAssign) tree.args.get(0)).lhs; if (lhs instanceof JCIdent && ((JCIdent) lhs).name.toString().equals("value")) tree.args = List.of(((JCAssign) tree.args.get(0)).rhs); } printExprs(tree.args); print(")"); } } catch (IOException e) { throw new UncheckedIOException(e); } }
private boolean handleMethod( JavacNode annotation, JCMethodDecl method, Collection<String> exceptions) { JavacNode methodNode = annotation.up(); if ((method.mods.flags & Flags.ABSTRACT) != 0) { annotation.addError("@SneakyThrows can only be used on concrete methods."); return true; } if (method.body == null) return false; List<JCStatement> contents = method.body.stats; for (String exception : exceptions) { contents = List.of(buildTryCatchBlock(methodNode, contents, exception)); } method.body.stats = contents; methodNode.rebuild(); return true; }
public JCMethodDecl createEquals( JavacNode typeNode, List<JavacNode> fields, boolean callSuper, FieldAccess fieldAccess, boolean needsCanEqual, JCTree source) { JavacTreeMaker maker = typeNode.getTreeMaker(); JCClassDecl type = (JCClassDecl) typeNode.get(); Name oName = typeNode.toName("o"); Name otherName = typeNode.toName("other"); Name thisName = typeNode.toName("this"); JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(typeNode, "Override"), List.<JCExpression>nil()); JCModifiers mods = maker.Modifiers(Flags.PUBLIC, List.of(overrideAnnotation)); JCExpression objectType = genJavaLangTypeRef(typeNode, "Object"); JCExpression returnType = maker.TypeIdent(CTC_BOOLEAN); long finalFlag = JavacHandlerUtil.addFinalIfNeeded(0L, typeNode.getContext()); ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); final List<JCVariableDecl> params = List.of( maker.VarDef(maker.Modifiers(finalFlag | Flags.PARAMETER), oName, objectType, null)); /* if (o == this) return true; */ { statements.append( maker.If( maker.Binary(CTC_EQUAL, maker.Ident(oName), maker.Ident(thisName)), returnBool(maker, true), null)); } /* if (!(o instanceof Outer.Inner.MyType) return false; */ { JCUnary notInstanceOf = maker.Unary(CTC_NOT, maker.TypeTest(maker.Ident(oName), createTypeReference(typeNode))); statements.append(maker.If(notInstanceOf, returnBool(maker, false), null)); } /* MyType<?> other = (MyType<?>) o; */ { if (!fields.isEmpty() || needsCanEqual) { final JCExpression selfType1, selfType2; ListBuffer<JCExpression> wildcards1 = new ListBuffer<JCExpression>(); ListBuffer<JCExpression> wildcards2 = new ListBuffer<JCExpression>(); for (int i = 0; i < type.typarams.length(); i++) { wildcards1.append(maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null)); wildcards2.append(maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null)); } if (type.typarams.isEmpty()) { selfType1 = maker.Ident(type.name); selfType2 = maker.Ident(type.name); } else { selfType1 = maker.TypeApply(maker.Ident(type.name), wildcards1.toList()); selfType2 = maker.TypeApply(maker.Ident(type.name), wildcards2.toList()); } statements.append( maker.VarDef( maker.Modifiers(finalFlag), otherName, selfType1, maker.TypeCast(selfType2, maker.Ident(oName)))); } } /* if (!other.canEqual((java.lang.Object) this)) return false; */ { if (needsCanEqual) { List<JCExpression> exprNil = List.nil(); JCExpression thisRef = maker.Ident(thisName); JCExpression castThisRef = maker.TypeCast(genJavaLangTypeRef(typeNode, "Object"), thisRef); JCExpression equalityCheck = maker.Apply( exprNil, maker.Select(maker.Ident(otherName), typeNode.toName("canEqual")), List.of(castThisRef)); statements.append( maker.If(maker.Unary(CTC_NOT, equalityCheck), returnBool(maker, false), null)); } } /* if (!super.equals(o)) return false; */ if (callSuper) { JCMethodInvocation callToSuper = maker.Apply( List.<JCExpression>nil(), maker.Select(maker.Ident(typeNode.toName("super")), typeNode.toName("equals")), List.<JCExpression>of(maker.Ident(oName))); JCUnary superNotEqual = maker.Unary(CTC_NOT, callToSuper); statements.append(maker.If(superNotEqual, returnBool(maker, false), null)); } Name thisDollar = typeNode.toName("this$"); Name otherDollar = typeNode.toName("other$"); for (JavacNode fieldNode : fields) { JCExpression fType = getFieldType(fieldNode, fieldAccess); JCExpression thisFieldAccessor = createFieldAccessor(maker, fieldNode, fieldAccess); JCExpression otherFieldAccessor = createFieldAccessor(maker, fieldNode, fieldAccess, maker.Ident(otherName)); if (fType instanceof JCPrimitiveTypeTree) { switch (((JCPrimitiveTypeTree) fType).getPrimitiveTypeKind()) { case FLOAT: /* if (Float.compare(this.fieldName, other.fieldName) != 0) return false; */ statements.append( generateCompareFloatOrDouble( thisFieldAccessor, otherFieldAccessor, maker, typeNode, false)); break; case DOUBLE: /* if (Double.compare(this.fieldName, other.fieldName) != 0) return false; */ statements.append( generateCompareFloatOrDouble( thisFieldAccessor, otherFieldAccessor, maker, typeNode, true)); break; default: /* if (this.fieldName != other.fieldName) return false; */ statements.append( maker.If( maker.Binary(CTC_NOT_EQUAL, thisFieldAccessor, otherFieldAccessor), returnBool(maker, false), null)); break; } } else if (fType instanceof JCArrayTypeTree) { /* if (!java.util.Arrays.deepEquals(this.fieldName, other.fieldName)) return false; //use equals for primitive arrays. */ boolean multiDim = ((JCArrayTypeTree) fType).elemtype instanceof JCArrayTypeTree; boolean primitiveArray = ((JCArrayTypeTree) fType).elemtype instanceof JCPrimitiveTypeTree; boolean useDeepEquals = multiDim || !primitiveArray; JCExpression eqMethod = chainDots(typeNode, "java", "util", "Arrays", useDeepEquals ? "deepEquals" : "equals"); List<JCExpression> args = List.of(thisFieldAccessor, otherFieldAccessor); statements.append( maker.If( maker.Unary(CTC_NOT, maker.Apply(List.<JCExpression>nil(), eqMethod, args)), returnBool(maker, false), null)); } else /* objects */ { /* final java.lang.Object this$fieldName = this.fieldName; */ /* final java.lang.Object other$fieldName = other.fieldName; */ /* if (this$fieldName == null ? other$fieldName != null : !this$fieldName.equals(other$fieldName)) return false;; */ Name fieldName = ((JCVariableDecl) fieldNode.get()).name; Name thisDollarFieldName = thisDollar.append(fieldName); Name otherDollarFieldName = otherDollar.append(fieldName); statements.append( maker.VarDef( maker.Modifiers(finalFlag), thisDollarFieldName, genJavaLangTypeRef(typeNode, "Object"), thisFieldAccessor)); statements.append( maker.VarDef( maker.Modifiers(finalFlag), otherDollarFieldName, genJavaLangTypeRef(typeNode, "Object"), otherFieldAccessor)); JCExpression thisEqualsNull = maker.Binary(CTC_EQUAL, maker.Ident(thisDollarFieldName), maker.Literal(CTC_BOT, null)); JCExpression otherNotEqualsNull = maker.Binary( CTC_NOT_EQUAL, maker.Ident(otherDollarFieldName), maker.Literal(CTC_BOT, null)); JCExpression thisEqualsThat = maker.Apply( List.<JCExpression>nil(), maker.Select(maker.Ident(thisDollarFieldName), typeNode.toName("equals")), List.<JCExpression>of(maker.Ident(otherDollarFieldName))); JCExpression fieldsAreNotEqual = maker.Conditional( thisEqualsNull, otherNotEqualsNull, maker.Unary(CTC_NOT, thisEqualsThat)); statements.append(maker.If(fieldsAreNotEqual, returnBool(maker, false), null)); } } /* return true; */ { statements.append(returnBool(maker, true)); } JCBlock body = maker.Block(0, statements.toList()); return recursiveSetGeneratedBy( maker.MethodDef( mods, typeNode.toName("equals"), returnType, List.<JCTypeParameter>nil(), params, List.<JCExpression>nil(), body, null), source, typeNode.getContext()); }
public JCMethodDecl createHashCode( JavacNode typeNode, List<JavacNode> fields, boolean callSuper, FieldAccess fieldAccess, JCTree source) { JavacTreeMaker maker = typeNode.getTreeMaker(); JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(typeNode, "Override"), List.<JCExpression>nil()); JCModifiers mods = maker.Modifiers(Flags.PUBLIC, List.of(overrideAnnotation)); JCExpression returnType = maker.TypeIdent(CTC_INT); ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); Name primeName = typeNode.toName(PRIME_NAME); Name resultName = typeNode.toName(RESULT_NAME); long finalFlag = JavacHandlerUtil.addFinalIfNeeded(0L, typeNode.getContext()); /* final int PRIME = X; */ { if (!fields.isEmpty() || callSuper) { statements.append( maker.VarDef( maker.Modifiers(finalFlag), primeName, maker.TypeIdent(CTC_INT), maker.Literal(HandlerUtil.primeForHashcode()))); } } /* int result = 1; */ { statements.append( maker.VarDef(maker.Modifiers(0), resultName, maker.TypeIdent(CTC_INT), maker.Literal(1))); } if (callSuper) { JCMethodInvocation callToSuper = maker.Apply( List.<JCExpression>nil(), maker.Select(maker.Ident(typeNode.toName("super")), typeNode.toName("hashCode")), List.<JCExpression>nil()); statements.append(createResultCalculation(typeNode, callToSuper)); } Name dollar = typeNode.toName("$"); for (JavacNode fieldNode : fields) { JCExpression fType = getFieldType(fieldNode, fieldAccess); JCExpression fieldAccessor = createFieldAccessor(maker, fieldNode, fieldAccess); if (fType instanceof JCPrimitiveTypeTree) { switch (((JCPrimitiveTypeTree) fType).getPrimitiveTypeKind()) { case BOOLEAN: /* this.fieldName ? X : Y */ statements.append( createResultCalculation( typeNode, maker.Conditional( fieldAccessor, maker.Literal(HandlerUtil.primeForTrue()), maker.Literal(HandlerUtil.primeForFalse())))); break; case LONG: { Name dollarFieldName = dollar.append(((JCVariableDecl) fieldNode.get()).name); statements.append( maker.VarDef( maker.Modifiers(finalFlag), dollarFieldName, maker.TypeIdent(CTC_LONG), fieldAccessor)); statements.append( createResultCalculation( typeNode, longToIntForHashCode( maker, maker.Ident(dollarFieldName), maker.Ident(dollarFieldName)))); } break; case FLOAT: /* Float.floatToIntBits(this.fieldName) */ statements.append( createResultCalculation( typeNode, maker.Apply( List.<JCExpression>nil(), genJavaLangTypeRef(typeNode, "Float", "floatToIntBits"), List.of(fieldAccessor)))); break; case DOUBLE: { /* longToIntForHashCode(Double.doubleToLongBits(this.fieldName)) */ Name dollarFieldName = dollar.append(((JCVariableDecl) fieldNode.get()).name); JCExpression init = maker.Apply( List.<JCExpression>nil(), genJavaLangTypeRef(typeNode, "Double", "doubleToLongBits"), List.of(fieldAccessor)); statements.append( maker.VarDef( maker.Modifiers(finalFlag), dollarFieldName, maker.TypeIdent(CTC_LONG), init)); statements.append( createResultCalculation( typeNode, longToIntForHashCode( maker, maker.Ident(dollarFieldName), maker.Ident(dollarFieldName)))); } break; default: case BYTE: case SHORT: case INT: case CHAR: /* just the field */ statements.append(createResultCalculation(typeNode, fieldAccessor)); break; } } else if (fType instanceof JCArrayTypeTree) { /* java.util.Arrays.deepHashCode(this.fieldName) //use just hashCode() for primitive arrays. */ boolean multiDim = ((JCArrayTypeTree) fType).elemtype instanceof JCArrayTypeTree; boolean primitiveArray = ((JCArrayTypeTree) fType).elemtype instanceof JCPrimitiveTypeTree; boolean useDeepHC = multiDim || !primitiveArray; JCExpression hcMethod = chainDots(typeNode, "java", "util", "Arrays", useDeepHC ? "deepHashCode" : "hashCode"); statements.append( createResultCalculation( typeNode, maker.Apply(List.<JCExpression>nil(), hcMethod, List.of(fieldAccessor)))); } else /* objects */ { /* final java.lang.Object $fieldName = this.fieldName; */ /* $fieldName == null ? 0 : $fieldName.hashCode() */ Name dollarFieldName = dollar.append(((JCVariableDecl) fieldNode.get()).name); statements.append( maker.VarDef( maker.Modifiers(finalFlag), dollarFieldName, genJavaLangTypeRef(typeNode, "Object"), fieldAccessor)); JCExpression hcCall = maker.Apply( List.<JCExpression>nil(), maker.Select(maker.Ident(dollarFieldName), typeNode.toName("hashCode")), List.<JCExpression>nil()); JCExpression thisEqualsNull = maker.Binary(CTC_EQUAL, maker.Ident(dollarFieldName), maker.Literal(CTC_BOT, null)); statements.append( createResultCalculation( typeNode, maker.Conditional(thisEqualsNull, maker.Literal(0), hcCall))); } } /* return result; */ { statements.append(maker.Return(maker.Ident(resultName))); } JCBlock body = maker.Block(0, statements.toList()); return recursiveSetGeneratedBy( maker.MethodDef( mods, typeNode.toName("hashCode"), returnType, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null), source, typeNode.getContext()); }
/** * Container for all annotations (attributes in javac) on a Symbol. * * <p>This class is explicitly mutable. Its contents will change when attributes are annotated onto * the Symbol. However this class depends on the facts that List (in javac) is immutable. * * <p>An instance of this class can be in one of three states: * * <p>NOT_STARTED indicates that the Symbol this instance belongs to has not been annotated (yet). * Specifically if the declaration is not annotated this instance will never move past NOT_STARTED. * You can never go back to NOT_STARTED. * * <p>IN_PROGRESS annotations have been found on the declaration. Will be processed later. You can * reset to IN_PROGRESS. While IN_PROGRESS you can set the list of attributes (and this moves out of * the IN_PROGRESS state). * * <p>"unnamed" this Annotations contains some attributes, possibly the final set. While in this * state you can only prepend or append to the attributes not set it directly. You can also move * back to the IN_PROGRESS state using reset(). * * <p><b>This is NOT part of any supported API. If you write code that depends on this, you do so at * your own risk. This code and its internal interfaces are subject to change or deletion without * notice.</b> */ public class Annotations { private static final List<Attribute.Compound> DECL_NOT_STARTED = List.of(null); private static final List<Attribute.Compound> DECL_IN_PROGRESS = List.of(null); /* * This field should never be null */ private List<Attribute.Compound> attributes = DECL_NOT_STARTED; /* * This field should never be null */ private List<Attribute.TypeCompound> type_attributes = List.<Attribute.TypeCompound>nil(); /* * The Symbol this Annotations instance belongs to */ private final Symbol sym; public Annotations(Symbol sym) { this.sym = sym; } public List<Attribute.Compound> getDeclarationAttributes() { return filterDeclSentinels(attributes); } public List<Attribute.TypeCompound> getTypeAttributes() { return type_attributes; } public void setDeclarationAttributes(List<Attribute.Compound> a) { Assert.check(pendingCompletion() || !isStarted()); if (a == null) { throw new NullPointerException(); } attributes = a; } public void setTypeAttributes(List<Attribute.TypeCompound> a) { if (a == null) { throw new NullPointerException(); } type_attributes = a; } public void setAttributes(Annotations other) { if (other == null) { throw new NullPointerException(); } setDeclarationAttributes(other.getDeclarationAttributes()); setTypeAttributes(other.getTypeAttributes()); } public void setDeclarationAttributesWithCompletion( final Annotate.AnnotateRepeatedContext<Attribute.Compound> ctx) { Assert.check(pendingCompletion() || (!isStarted() && sym.kind == PCK)); this.setDeclarationAttributes(getAttributesForCompletion(ctx)); } public void appendTypeAttributesWithCompletion( final Annotate.AnnotateRepeatedContext<Attribute.TypeCompound> ctx) { this.appendUniqueTypes(getAttributesForCompletion(ctx)); } private <T extends Attribute.Compound> List<T> getAttributesForCompletion( final Annotate.AnnotateRepeatedContext<T> ctx) { Map<Symbol.TypeSymbol, ListBuffer<T>> annotated = ctx.annotated; boolean atLeastOneRepeated = false; List<T> buf = List.<T>nil(); for (ListBuffer<T> lb : annotated.values()) { if (lb.size() == 1) { buf = buf.prepend(lb.first()); } else { // repeated // This will break when other subtypes of Attributs.Compound // are introduced, because PlaceHolder is a subtype of TypeCompound. T res; @SuppressWarnings("unchecked") T ph = (T) new Placeholder<T>(ctx, lb.toList(), sym); res = ph; buf = buf.prepend(res); atLeastOneRepeated = true; } } if (atLeastOneRepeated) { // The Symbol s is now annotated with a combination of // finished non-repeating annotations and placeholders for // repeating annotations. // // We need to do this in two passes because when creating // a container for a repeating annotation we must // guarantee that the @Repeatable on the // contained annotation is fully annotated // // The way we force this order is to do all repeating // annotations in a pass after all non-repeating are // finished. This will work because @Repeatable // is non-repeating and therefore will be annotated in the // fist pass. // Queue a pass that will replace Attribute.Placeholders // with Attribute.Compound (made from synthesized containers). ctx.annotateRepeated( new Annotate.Annotator() { @Override public String toString() { return "repeated annotation pass of: " + sym + " in: " + sym.owner; } @Override public void enterAnnotation() { complete(ctx); } }); } // Add non-repeating attributes return buf.reverse(); } public Annotations reset() { attributes = DECL_IN_PROGRESS; return this; } public boolean isEmpty() { return !isStarted() || pendingCompletion() || attributes.isEmpty(); } public boolean isTypesEmpty() { return type_attributes.isEmpty(); } public boolean pendingCompletion() { return attributes == DECL_IN_PROGRESS; } public Annotations append(List<Attribute.Compound> l) { attributes = filterDeclSentinels(attributes); if (l.isEmpty()) {; // no-op } else if (attributes.isEmpty()) { attributes = l; } else { attributes = attributes.appendList(l); } return this; } public Annotations appendUniqueTypes(List<Attribute.TypeCompound> l) { if (l.isEmpty()) {; // no-op } else if (type_attributes.isEmpty()) { type_attributes = l; } else { // TODO: in case we expect a large number of annotations, this // might be inefficient. for (Attribute.TypeCompound tc : l) { if (!type_attributes.contains(tc)) type_attributes = type_attributes.append(tc); } } return this; } public Annotations prepend(List<Attribute.Compound> l) { attributes = filterDeclSentinels(attributes); if (l.isEmpty()) {; // no-op } else if (attributes.isEmpty()) { attributes = l; } else { attributes = attributes.prependList(l); } return this; } private List<Attribute.Compound> filterDeclSentinels(List<Attribute.Compound> a) { return (a == DECL_IN_PROGRESS || a == DECL_NOT_STARTED) ? List.<Attribute.Compound>nil() : a; } private boolean isStarted() { return attributes != DECL_NOT_STARTED; } private List<Attribute.Compound> getPlaceholders() { List<Attribute.Compound> res = List.<Attribute.Compound>nil(); for (Attribute.Compound a : filterDeclSentinels(attributes)) { if (a instanceof Placeholder) { res = res.prepend(a); } } return res.reverse(); } private List<Attribute.TypeCompound> getTypePlaceholders() { List<Attribute.TypeCompound> res = List.<Attribute.TypeCompound>nil(); for (Attribute.TypeCompound a : type_attributes) { if (a instanceof Placeholder) { res = res.prepend(a); } } return res.reverse(); } /* * Replace Placeholders for repeating annotations with their containers */ private <T extends Attribute.Compound> void complete(Annotate.AnnotateRepeatedContext<T> ctx) { Log log = ctx.log; Env<AttrContext> env = ctx.env; JavaFileObject oldSource = log.useSource(env.toplevel.sourcefile); try { // TODO: can we reduce duplication in the following branches? if (ctx.isTypeCompound) { Assert.check(!isTypesEmpty()); if (isTypesEmpty()) { return; } List<Attribute.TypeCompound> result = List.nil(); for (Attribute.TypeCompound a : getTypeAttributes()) { if (a instanceof Placeholder) { @SuppressWarnings("unchecked") Placeholder<Attribute.TypeCompound> ph = (Placeholder<Attribute.TypeCompound>) a; Attribute.TypeCompound replacement = replaceOne(ph, ph.getRepeatedContext()); if (null != replacement) { result = result.prepend(replacement); } } else { result = result.prepend(a); } } type_attributes = result.reverse(); Assert.check(Annotations.this.getTypePlaceholders().isEmpty()); } else { Assert.check(!pendingCompletion()); if (isEmpty()) { return; } List<Attribute.Compound> result = List.nil(); for (Attribute.Compound a : getDeclarationAttributes()) { if (a instanceof Placeholder) { @SuppressWarnings("unchecked") Attribute.Compound replacement = replaceOne((Placeholder<T>) a, ctx); if (null != replacement) { result = result.prepend(replacement); } } else { result = result.prepend(a); } } attributes = result.reverse(); Assert.check(Annotations.this.getPlaceholders().isEmpty()); } } finally { log.useSource(oldSource); } } private <T extends Attribute.Compound> T replaceOne( Placeholder<T> placeholder, Annotate.AnnotateRepeatedContext<T> ctx) { Log log = ctx.log; // Process repeated annotations T validRepeated = ctx.processRepeatedAnnotations(placeholder.getPlaceholderFor(), sym); if (validRepeated != null) { // Check that the container isn't manually // present along with repeated instances of // its contained annotation. ListBuffer<T> manualContainer = ctx.annotated.get(validRepeated.type.tsym); if (manualContainer != null) { log.error( ctx.pos.get(manualContainer.first()), "invalid.repeatable.annotation.repeated.and.container.present", manualContainer.first().type.tsym); } } // A null return will delete the Placeholder return validRepeated; } private static class Placeholder<T extends Attribute.Compound> extends Attribute.TypeCompound { private final Annotate.AnnotateRepeatedContext<T> ctx; private final List<T> placeholderFor; private final Symbol on; public Placeholder(Annotate.AnnotateRepeatedContext<T> ctx, List<T> placeholderFor, Symbol on) { super( on.type, List.<Pair<Symbol.MethodSymbol, Attribute>>nil(), ctx.isTypeCompound ? ((Attribute.TypeCompound) placeholderFor.head).position : null); this.ctx = ctx; this.placeholderFor = placeholderFor; this.on = on; } @Override public String toString() { return "<placeholder: " + placeholderFor + " on: " + on + ">"; } public List<T> getPlaceholderFor() { return placeholderFor; } public Annotate.AnnotateRepeatedContext<T> getRepeatedContext() { return ctx; } } }
/** * Main method: compile a list of files, return all compiled classes * * @param filenames The names of all files to be compiled. */ public List<ClassSymbol> compile( List<String> filenames, Map<String, String> origOptions, ClassLoader aptCL, AnnotationProcessorFactory providedFactory, java.util.Set<Class<? extends AnnotationProcessorFactory>> productiveFactories, java.util.Set<java.io.File> aggregateGenFiles) throws Throwable { // as a JavaCompiler can only be used once, throw an exception if // it has been used before. assert !hasBeenUsed : "attempt to reuse JavaCompiler"; hasBeenUsed = true; this.aggregateGenFiles = aggregateGenFiles; long msec = System.currentTimeMillis(); ListBuffer<ClassSymbol> classes = new ListBuffer<ClassSymbol>(); try { JavacFileManager fm = (JavacFileManager) fileManager; // parse all files ListBuffer<JCCompilationUnit> trees = new ListBuffer<JCCompilationUnit>(); for (List<String> l = filenames; l.nonEmpty(); l = l.tail) { if (classesAsDecls) { if (!l.head.endsWith(".java")) { // process as class file ClassSymbol cs = reader.enterClass(names.fromString(l.head)); try { cs.complete(); } catch (Symbol.CompletionFailure cf) { bark.aptError("CantFindClass", l); continue; } classes.append(cs); // add to list of classes continue; } } JavaFileObject fo = fm.getJavaFileObjectsFromStrings(List.of(l.head)).iterator().next(); trees.append(parse(fo)); } // enter symbols for all files List<JCCompilationUnit> roots = trees.toList(); if (errorCount() == 0) { boolean prev = bark.setDiagnosticsIgnored(true); try { enter.main(roots); } finally { bark.setDiagnosticsIgnored(prev); } } if (errorCount() == 0) { apt.main(roots, classes, origOptions, aptCL, providedFactory, productiveFactories); genSourceFileNames.addAll(apt.getSourceFileNames()); genClassFileNames.addAll(apt.getClassFileNames()); } } catch (Abort ex) { } if (verbose) log.printVerbose("total", Long.toString(System.currentTimeMillis() - msec)); chk.reportDeferredDiagnostics(); printCount("error", errorCount()); printCount("warn", warningCount()); return classes.toList(); }
/** Adds a binary operator symbol. */ final BinaryOperatorHelper addBinaryOperator( OperatorType arg1, OperatorType arg2, OperatorType res, int... opcode) { operatorSuppliers = operatorSuppliers.prepend(() -> makeOperator(name, List.of(arg1, arg2), res, opcode)); return this; }
Attribute enterAttributeValue(Type expected, JCExpression tree, Env<AttrContext> env) { // first, try completing the attribution value sym - if a completion // error is thrown, we should recover gracefully, and display an // ordinary resolution diagnostic. try { expected.tsym.complete(); } catch (CompletionFailure e) { log.error(tree.pos(), "cant.resolve", Kinds.kindName(e.sym), e.sym); return new Attribute.Error(expected); } if (expected.isPrimitive() || types.isSameType(expected, syms.stringType)) { Type result = attr.attribExpr(tree, env, expected); if (result.isErroneous()) return new Attribute.Error(expected); if (result.constValue() == null) { log.error(tree.pos(), "attribute.value.must.be.constant"); return new Attribute.Error(expected); } result = cfolder.coerce(result, expected); return new Attribute.Constant(expected, result.constValue()); } if (expected.tsym == syms.classType.tsym) { Type result = attr.attribExpr(tree, env, expected); if (result.isErroneous()) return new Attribute.Error(expected); if (TreeInfo.name(tree) != names._class) { log.error(tree.pos(), "annotation.value.must.be.class.literal"); return new Attribute.Error(expected); } return new Attribute.Class(types, (((JCFieldAccess) tree).selected).type); } if ((expected.tsym.flags() & Flags.ANNOTATION) != 0 || types.isSameType(expected, syms.annotationType)) { if (tree.getTag() != JCTree.ANNOTATION) { log.error(tree.pos(), "annotation.value.must.be.annotation"); expected = syms.errorType; } return enterAnnotation((JCAnnotation) tree, expected, env); } if (expected.tag == TypeTags.ARRAY) { // should really be isArray() if (tree.getTag() != JCTree.NEWARRAY) { tree = make.at(tree.pos).NewArray(null, List.<JCExpression>nil(), List.of(tree)); } JCNewArray na = (JCNewArray) tree; if (na.elemtype != null) { log.error(na.elemtype.pos(), "new.not.allowed.in.annotation"); return new Attribute.Error(expected); } ListBuffer<Attribute> buf = new ListBuffer<Attribute>(); for (List<JCExpression> l = na.elems; l.nonEmpty(); l = l.tail) { buf.append(enterAttributeValue(types.elemtype(expected), l.head, env)); } na.type = expected; return new Attribute.Array(expected, buf.toArray(new Attribute[buf.length()])); } if (expected.tag == TypeTags.CLASS && (expected.tsym.flags() & Flags.ENUM) != 0) { attr.attribExpr(tree, env, expected); Symbol sym = TreeInfo.symbol(tree); if (sym == null || TreeInfo.nonstaticSelect(tree) || sym.kind != Kinds.VAR || (sym.flags() & Flags.ENUM) == 0) { log.error(tree.pos(), "enum.annotation.must.be.enum.constant"); return new Attribute.Error(expected); } VarSymbol enumerator = (VarSymbol) sym; return new Attribute.Enum(expected, enumerator); } if (!expected.isErroneous()) log.error(tree.pos(), "annotation.value.not.allowable.type"); return new Attribute.Error(attr.attribExpr(tree, env, expected)); }
private JCCompilationUnit ceylonParse(JavaFileObject filename, CharSequence readSource) { if (ceylonEnter.hasRun()) throw new RuntimeException( "Trying to load new source file after CeylonEnter has been called: " + filename); try { ModuleManager moduleManager = phasedUnits.getModuleManager(); File sourceFile = new File(filename.getName()); // FIXME: temporary solution VirtualFile file = vfs.getFromFile(sourceFile); VirtualFile srcDir = vfs.getFromFile(getSrcDir(sourceFile)); String source = readSource.toString(); char[] chars = source.toCharArray(); LineMap map = Position.makeLineMap(chars, chars.length, false); PhasedUnit phasedUnit = null; PhasedUnit externalPhasedUnit = compilerDelegate.getExternalSourcePhasedUnit(srcDir, file); if (externalPhasedUnit != null) { phasedUnit = new CeylonPhasedUnit(externalPhasedUnit, filename, map); phasedUnits.addPhasedUnit(externalPhasedUnit.getUnitFile(), phasedUnit); gen.setMap(map); String pkgName = phasedUnit.getPackage().getQualifiedNameString(); if ("".equals(pkgName)) { pkgName = null; } return gen.makeJCCompilationUnitPlaceholder( phasedUnit.getCompilationUnit(), filename, pkgName, phasedUnit); } if (phasedUnit == null) { ANTLRStringStream input = new ANTLRStringStream(source); CeylonLexer lexer = new CeylonLexer(input); CommonTokenStream tokens = new CommonTokenStream(lexer); CeylonParser parser = new CeylonParser(tokens); CompilationUnit cu = parser.compilationUnit(); java.util.List<LexError> lexerErrors = lexer.getErrors(); for (LexError le : lexerErrors) { printError(le, le.getMessage(), "ceylon.lexer", map); } java.util.List<ParseError> parserErrors = parser.getErrors(); for (ParseError pe : parserErrors) { printError(pe, pe.getMessage(), "ceylon.parser", map); } if (lexerErrors.size() == 0 && parserErrors.size() == 0) { // FIXME: this is bad in many ways String pkgName = getPackage(filename); // make a Package with no module yet, we will resolve them later /* * Stef: see javadoc for findOrCreateModulelessPackage() for why this is here. */ com.redhat.ceylon.compiler.typechecker.model.Package p = modelLoader.findOrCreateModulelessPackage(pkgName == null ? "" : pkgName); phasedUnit = new CeylonPhasedUnit( file, srcDir, cu, p, moduleManager, ceylonContext, filename, map); phasedUnits.addPhasedUnit(file, phasedUnit); gen.setMap(map); return gen.makeJCCompilationUnitPlaceholder(cu, filename, pkgName, phasedUnit); } } } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } JCCompilationUnit result = make.TopLevel(List.<JCAnnotation>nil(), null, List.<JCTree>of(make.Erroneous())); result.sourcefile = filename; return result; }
void createSymbols() throws IOException { Set<String> legacy = getLegacyPackages(); Set<String> legacyProprietary = getLegacyPackages(); Set<String> documented = new HashSet<String>(); Set<PackageSymbol> packages = ((JavacProcessingEnvironment) processingEnv).getSpecifiedPackages(); String jarName = processingEnv.getOptions().get("com.sun.tools.javac.sym.Jar"); if (jarName == null) throw new RuntimeException("Must use -Acom.sun.tools.javac.sym.Jar=LOCATION_OF_JAR"); String destName = processingEnv.getOptions().get("com.sun.tools.javac.sym.Dest"); if (destName == null) throw new RuntimeException("Must use -Acom.sun.tools.javac.sym.Dest=LOCATION_OF_JAR"); for (PackageSymbol psym : packages) { String name = psym.getQualifiedName().toString(); legacyProprietary.remove(name); documented.add(name); } JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager fm = tool.getStandardFileManager(null, null, null); Location jarLocation = StandardLocation.locationFor(jarName); File jarFile = new File(jarName); fm.setLocation(jarLocation, List.of(jarFile)); fm.setLocation(StandardLocation.CLASS_PATH, List.<File>nil()); fm.setLocation(StandardLocation.SOURCE_PATH, List.<File>nil()); { ArrayList<File> bootClassPath = new ArrayList<File>(); bootClassPath.add(jarFile); for (File path : fm.getLocation(StandardLocation.PLATFORM_CLASS_PATH)) { if (!new File(path.getName()).equals(new File("rt.jar"))) bootClassPath.add(path); } System.err.println("Using boot class path = " + bootClassPath); fm.setLocation(StandardLocation.PLATFORM_CLASS_PATH, bootClassPath); } // System.out.println(fm.getLocation(StandardLocation.PLATFORM_CLASS_PATH)); File destDir = new File(destName); if (!destDir.exists()) if (!destDir.mkdirs()) throw new RuntimeException("Could not create " + destDir); fm.setLocation(StandardLocation.CLASS_OUTPUT, List.of(destDir)); Set<String> hiddenPackages = new HashSet<String>(); Set<String> crisp = new HashSet<String>(); List<String> options = List.of("-XDdev"); // options = options.prepend("-doe"); // options = options.prepend("-verbose"); JavacTaskImpl task = (JavacTaskImpl) tool.getTask(null, fm, null, options, null, null); com.sun.tools.javac.main.JavaCompiler compiler = com.sun.tools.javac.main.JavaCompiler.instance(task.getContext()); ClassReader reader = ClassReader.instance(task.getContext()); ClassWriter writer = ClassWriter.instance(task.getContext()); Symtab syms = Symtab.instance(task.getContext()); Attribute.Compound proprietary = new Attribute.Compound( syms.proprietaryType, List.<Pair<Symbol.MethodSymbol, Attribute>>nil()); Type.moreInfo = true; Pool pool = new Pool(); for (JavaFileObject file : fm.list(jarLocation, "", EnumSet.of(CLASS), true)) { String className = fm.inferBinaryName(jarLocation, file); int index = className.lastIndexOf('.'); String pckName = index == -1 ? "" : className.substring(0, index); boolean addLegacyAnnotation = false; if (documented.contains(pckName)) { if (!legacy.contains(pckName)) crisp.add(pckName); // System.out.println("Documented: " + className); } else if (legacyProprietary.contains(pckName)) { addLegacyAnnotation = true; // System.out.println("Legacy proprietary: " + className); } else { // System.out.println("Hidden " + className); hiddenPackages.add(pckName); continue; } TypeSymbol sym = (TypeSymbol) compiler.resolveIdent(className); if (sym.kind != Kinds.TYP) { if (className.indexOf('$') < 0) { System.err.println("Ignoring (other) " + className + " : " + sym); System.err.println(" " + sym.getClass().getSimpleName() + " " + sym.type); } continue; } sym.complete(); if (sym.getEnclosingElement().getKind() != ElementKind.PACKAGE) { System.err.println("Ignoring (bad) " + sym.getQualifiedName()); continue; } ClassSymbol cs = (ClassSymbol) sym; if (addLegacyAnnotation) { cs.attributes_field = (cs.attributes_field == null) ? List.of(proprietary) : cs.attributes_field.prepend(proprietary); } writeClass(pool, cs, writer); } if (false) { for (String pckName : crisp) System.out.println("Crisp: " + pckName); for (String pckName : hiddenPackages) System.out.println("Hidden: " + pckName); for (String pckName : legacyProprietary) System.out.println("Legacy proprietary: " + pckName); for (String pckName : documented) System.out.println("Documented: " + pckName); } }