From f408a8b39dd0e562056ca58a38cc23002f3e7bb3 Mon Sep 17 00:00:00 2001 From: Voitech Date: Thu, 19 Sep 2019 23:48:27 +0200 Subject: [PATCH] Add null checks for tree.getParameters(), unit test for #7441 Signed-off-by: Voitech --- .../java/codegen/CeylonTransformer.java | 49 ++--- .../java/codegen/ClassTransformer.java | 184 +++++++++--------- .../test/issues/IssuesTests_7000_7499.java | 4 + .../java/test/issues/bug74xx/bug7441.ceylon | 8 + .../analyzer/AnnotationVisitor.java | 1 + 5 files changed, 133 insertions(+), 113 deletions(-) create mode 100644 compiler-java/test/src/org/eclipse/ceylon/compiler/java/test/issues/bug74xx/bug7441.ceylon diff --git a/compiler-java/src/org/eclipse/ceylon/compiler/java/codegen/CeylonTransformer.java b/compiler-java/src/org/eclipse/ceylon/compiler/java/codegen/CeylonTransformer.java index 6fc642e40a5..fcd9fd6d2f4 100644 --- a/compiler-java/src/org/eclipse/ceylon/compiler/java/codegen/CeylonTransformer.java +++ b/compiler-java/src/org/eclipse/ceylon/compiler/java/codegen/CeylonTransformer.java @@ -222,29 +222,32 @@ private List makeClassBody(Declaration decl, WantedDeclaration wantedDec // only do it for Bootstrap where we control the annotations, because it's so dodgy ATM if(wantedDeclaration == WantedDeclaration.Annotation){ ListBuffer body = new ListBuffer(); - 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.nil(), - List.nil(), - List.nil(), - null, - null); - body.append(method); - } - return body.toList(); + Tree.ClassDefinition classDefiniton=(Tree.ClassDefinition)decl; + if(classDefiniton.getParameterList()!=null) { + for(Tree.Parameter param : classDefiniton.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.nil(), + List.nil(), + List.nil(), + null, + null); + body.append(method); + } + return body.toList(); + } } if(wantedDeclaration == WantedDeclaration.AnnotationSequence){ String name = Naming.toplevelClassName("", decl); diff --git a/compiler-java/src/org/eclipse/ceylon/compiler/java/codegen/ClassTransformer.java b/compiler-java/src/org/eclipse/ceylon/compiler/java/codegen/ClassTransformer.java index fa3aea24ba6..df8055b100a 100644 --- a/compiler-java/src/org/eclipse/ceylon/compiler/java/codegen/ClassTransformer.java +++ b/compiler-java/src/org/eclipse/ceylon/compiler/java/codegen/ClassTransformer.java @@ -841,96 +841,99 @@ private void transformAnnotationClassConstructor( // annotation ListBuffer args = new ListBuffer(); - if (!klass.getUnit().getPackage().isLanguagePackage() - || !classBuilder.getClassName().equals("RestrictedAnnotation")) { //ignore argument to restricted() - for (Tree.Parameter parameter : def.getParameterList().getParameters()) { - at(parameter); - Parameter parameterModel = parameter.getParameterModel(); - JCExpression annoAttr = make().Apply(null, naming.makeQuotedQualIdent(naming.makeUnquotedIdent("anno"), - parameter.getParameterModel().getName()), - List.nil()); - Type parameterType = parameterModel.getType(); - JCExpression argExpr; - if (typeFact().isIterableType(parameterType) - && !isCeylonString(parameterType)) { - // Convert from array to Sequential - Type iteratedType = typeFact().getIteratedType(parameterType); - boolean nonEmpty = typeFact().isNonemptyIterableType(parameterType); - if (isCeylonBasicType(iteratedType)) { - argExpr = utilInvocation().sequentialWrapperBoxed(annoAttr); - } else if (Decl.isAnnotationClass(iteratedType.getDeclaration())) { - // Can't use Util.sequentialAnnotation becase we need to 'box' - // the Java annotations in their Ceylon annotation class - argExpr = make().Apply(null, naming.makeUnquotedIdent(naming.getAnnotationSequenceMethodName()), List.of(annoAttr)); - ListBuffer stmts = new ListBuffer(); - SyntheticName array = naming.synthetic(Unfix.$array$); - SyntheticName sb = naming.synthetic(Unfix.$sb$); - SyntheticName index = naming.synthetic(Unfix.$index$); - SyntheticName element = naming.synthetic(Unfix.$element$); - stmts.append(makeVar(FINAL, sb, - make().TypeArray(make().Type(syms().objectType)), - make().NewArray(make().Type(syms().objectType), List.of(naming.makeQualIdent(array.makeIdent(), "length")), null))); - stmts.append(makeVar(index, - make().Type(syms().intType), - make().Literal(0))); - stmts.append(make().ForeachLoop( - makeVar(element, makeJavaType(iteratedType, JT_ANNOTATION), null), - array.makeIdent(), - make().Exec(make().Assign( - make().Indexed(sb.makeIdent(), - make().Unary(JCTree.Tag.POSTINC, index.makeIdent())), - instantiateAnnotationClass(iteratedType, element.makeIdent()))))); - stmts.append(make().Return( - make().NewClass(null, - null, - make().QualIdent(syms().ceylonTupleType.tsym), - List.of(makeReifiedTypeArgument(iteratedType), - sb.makeIdent(), - makeEmpty(), - make().Literal(false)), - null))); - classBuilder.method( - systemMethod(this, naming.getAnnotationSequenceMethodName()) - .ignoreModelAnnotations() - .modifiers(PRIVATE | STATIC) - .resultType(new TransformedType(makeJavaType(typeFact().getSequentialType(iteratedType)), null, makeAtNonNull())) - .parameter(systemParameter(this, array.getName()) - .type(new TransformedType(make().TypeArray(makeJavaType(iteratedType, JT_ANNOTATION))))) - .body(stmts.toList())); - } else if (isCeylonMetamodelDeclaration(iteratedType)) { - argExpr = makeMetamodelInvocation("parseMetamodelReferences", - List.of(makeReifiedTypeArgument(iteratedType), annoAttr), - List.of(makeJavaType(iteratedType, JT_TYPE_ARGUMENT))); - } else if (Decl.isEnumeratedTypeWithAnonCases(iteratedType)) { - argExpr = makeMetamodelInvocation("parseEnumerationReferences", - List.of(makeReifiedTypeArgument(iteratedType), annoAttr), - List.of(makeJavaType(iteratedType, JT_TYPE_ARGUMENT))); - } else { - argExpr = makeErroneous(parameter, "compiler bug"); - } - if (nonEmpty) { - argExpr = make().TypeCast(makeJavaType(parameterType), argExpr); - } - } else if (Decl.isAnnotationClass(parameterType.getDeclaration())) { - argExpr = instantiateAnnotationClass(parameterType, annoAttr); - } else if (isCeylonMetamodelDeclaration(parameterType)) { - argExpr = makeMetamodelInvocation("parseMetamodelReference", - List.of(annoAttr), - List.of(makeJavaType(parameterType, JT_TYPE_ARGUMENT))); - } else if (Decl.isEnumeratedTypeWithAnonCases(parameterType)) { - argExpr = makeMetamodelInvocation("parseEnumerationReference", - List.of(annoAttr), - null); - } else { - argExpr = annoAttr; - argExpr = expressionGen().applyErasureAndBoxing(annoAttr, parameterType.withoutUnderlyingType(), false, BoxingStrategy.UNBOXED, parameterType); - } - - args.add(argExpr); - } + if(def.getParameterList()!=null) { + if (!klass.getUnit().getPackage().isLanguagePackage() + || !classBuilder.getClassName().equals("RestrictedAnnotation")) { //ignore argument to restricted() + for (Tree.Parameter parameter : def.getParameterList().getParameters()) { + at(parameter); + Parameter parameterModel = parameter.getParameterModel(); + JCExpression annoAttr = make().Apply(null, naming.makeQuotedQualIdent(naming.makeUnquotedIdent("anno"), + parameter.getParameterModel().getName()), + List.nil()); + Type parameterType = parameterModel.getType(); + JCExpression argExpr; + if (typeFact().isIterableType(parameterType) + && !isCeylonString(parameterType)) { + // Convert from array to Sequential + Type iteratedType = typeFact().getIteratedType(parameterType); + boolean nonEmpty = typeFact().isNonemptyIterableType(parameterType); + if (isCeylonBasicType(iteratedType)) { + argExpr = utilInvocation().sequentialWrapperBoxed(annoAttr); + } else if (Decl.isAnnotationClass(iteratedType.getDeclaration())) { + // Can't use Util.sequentialAnnotation becase we need to 'box' + // the Java annotations in their Ceylon annotation class + argExpr = make().Apply(null, naming.makeUnquotedIdent(naming.getAnnotationSequenceMethodName()), List.of(annoAttr)); + ListBuffer stmts = new ListBuffer(); + SyntheticName array = naming.synthetic(Unfix.$array$); + SyntheticName sb = naming.synthetic(Unfix.$sb$); + SyntheticName index = naming.synthetic(Unfix.$index$); + SyntheticName element = naming.synthetic(Unfix.$element$); + stmts.append(makeVar(FINAL, sb, + make().TypeArray(make().Type(syms().objectType)), + make().NewArray(make().Type(syms().objectType), List.of(naming.makeQualIdent(array.makeIdent(), "length")), null))); + stmts.append(makeVar(index, + make().Type(syms().intType), + make().Literal(0))); + stmts.append(make().ForeachLoop( + makeVar(element, makeJavaType(iteratedType, JT_ANNOTATION), null), + array.makeIdent(), + make().Exec(make().Assign( + make().Indexed(sb.makeIdent(), + make().Unary(JCTree.Tag.POSTINC, index.makeIdent())), + instantiateAnnotationClass(iteratedType, element.makeIdent()))))); + stmts.append(make().Return( + make().NewClass(null, + null, + make().QualIdent(syms().ceylonTupleType.tsym), + List.of(makeReifiedTypeArgument(iteratedType), + sb.makeIdent(), + makeEmpty(), + make().Literal(false)), + null))); + classBuilder.method( + systemMethod(this, naming.getAnnotationSequenceMethodName()) + .ignoreModelAnnotations() + .modifiers(PRIVATE | STATIC) + .resultType(new TransformedType(makeJavaType(typeFact().getSequentialType(iteratedType)), null, makeAtNonNull())) + .parameter(systemParameter(this, array.getName()) + .type(new TransformedType(make().TypeArray(makeJavaType(iteratedType, JT_ANNOTATION))))) + .body(stmts.toList())); + } else if (isCeylonMetamodelDeclaration(iteratedType)) { + argExpr = makeMetamodelInvocation("parseMetamodelReferences", + List.of(makeReifiedTypeArgument(iteratedType), annoAttr), + List.of(makeJavaType(iteratedType, JT_TYPE_ARGUMENT))); + } else if (Decl.isEnumeratedTypeWithAnonCases(iteratedType)) { + argExpr = makeMetamodelInvocation("parseEnumerationReferences", + List.of(makeReifiedTypeArgument(iteratedType), annoAttr), + List.of(makeJavaType(iteratedType, JT_TYPE_ARGUMENT))); + } else { + argExpr = makeErroneous(parameter, "compiler bug"); + } + if (nonEmpty) { + argExpr = make().TypeCast(makeJavaType(parameterType), argExpr); + } + } else if (Decl.isAnnotationClass(parameterType.getDeclaration())) { + argExpr = instantiateAnnotationClass(parameterType, annoAttr); + } else if (isCeylonMetamodelDeclaration(parameterType)) { + argExpr = makeMetamodelInvocation("parseMetamodelReference", + List.of(annoAttr), + List.of(makeJavaType(parameterType, JT_TYPE_ARGUMENT))); + } else if (Decl.isEnumeratedTypeWithAnonCases(parameterType)) { + argExpr = makeMetamodelInvocation("parseEnumerationReference", + List.of(annoAttr), + null); + } else { + argExpr = annoAttr; + argExpr = expressionGen().applyErasureAndBoxing(annoAttr, parameterType.withoutUnderlyingType(), false, BoxingStrategy.UNBOXED, parameterType); + } + + args.add(argExpr); + } + } } annoCtor.body(at(def).Exec( make().Apply(null, naming.makeThis(), args.toList()))); + } private JCNewClass instantiateAnnotationClass( @@ -983,9 +986,10 @@ private List transformAnnotationClass(Tree.AnyClass def) { } else { annoBuilder.annotations(transformAnnotationConstraints(klass)); } - - for (Tree.Parameter p : def.getParameterList().getParameters()) { - annoBuilder.method(makeAnnotationMethod(p)); + if(def.getParameterList()!=null) { + for (Tree.Parameter p : def.getParameterList().getParameters()) { + annoBuilder.method(makeAnnotationMethod(p)); + } } List result; if (isSequencedAnnotation(klass)) { diff --git a/compiler-java/test/src/org/eclipse/ceylon/compiler/java/test/issues/IssuesTests_7000_7499.java b/compiler-java/test/src/org/eclipse/ceylon/compiler/java/test/issues/IssuesTests_7000_7499.java index 03f2b5ee86c..6fa40a7db2a 100644 --- a/compiler-java/test/src/org/eclipse/ceylon/compiler/java/test/issues/IssuesTests_7000_7499.java +++ b/compiler-java/test/src/org/eclipse/ceylon/compiler/java/test/issues/IssuesTests_7000_7499.java @@ -146,4 +146,8 @@ public void bug7263() throws Throwable{ compile("bug72xx/bug7263/run.ceylon"); runInJBossModules("run", "org.eclipse.ceylon.compiler.java.test.issues.bug72xx.bug7263/1", Collections.emptyList()); } + @Test + public void bug7441() { + assertErrors("bug74xx/bug7441",Collections.emptyList(), null,new CompilerError(8, "illegal annotation parameter type: 'Anything'") ); + } } diff --git a/compiler-java/test/src/org/eclipse/ceylon/compiler/java/test/issues/bug74xx/bug7441.ceylon b/compiler-java/test/src/org/eclipse/ceylon/compiler/java/test/issues/bug74xx/bug7441.ceylon new file mode 100644 index 00000000000..b0b4110de8c --- /dev/null +++ b/compiler-java/test/src/org/eclipse/ceylon/compiler/java/test/issues/bug74xx/bug7441.ceylon @@ -0,0 +1,8 @@ +import ceylon.language.meta.declaration { + ValueDeclaration +} + +shared final annotation class TestAnnotation satisfies OptionalAnnotation { + shared new (Anything args) {} +} +shared annotation TestAnnotation testAnnotation(Anything args) => TestAnnotation(args); \ No newline at end of file diff --git a/typechecker/src/org/eclipse/ceylon/compiler/typechecker/analyzer/AnnotationVisitor.java b/typechecker/src/org/eclipse/ceylon/compiler/typechecker/analyzer/AnnotationVisitor.java index 50b7d6a4c78..2320f9ac575 100644 --- a/typechecker/src/org/eclipse/ceylon/compiler/typechecker/analyzer/AnnotationVisitor.java +++ b/typechecker/src/org/eclipse/ceylon/compiler/typechecker/analyzer/AnnotationVisitor.java @@ -429,6 +429,7 @@ private void checkAnnotationType(Tree.AnyClass that, Class c) { that.addError("annotation class must directly extend 'Basic'"); } } + if(that.getParameterList()!=null) for (Tree.Parameter pn: that.getParameterList().getParameters()) { checkAnnotationParameter(c, pn);