@@ -343,7 +343,20 @@ object JavaParsers {
343343 annots.toList
344344 }
345345
346- /** Annotation ::= TypeName [`(` AnnotationArgument {`,` AnnotationArgument} `)`]
346+ /** Annotation ::= TypeName [`(` [AnnotationArgument {`,` AnnotationArgument}] `)`]
347+ * AnnotationArgument ::= ElementValuePair | ELementValue
348+ * ElementValuePair ::= Identifier `=` ElementValue
349+ * ElementValue ::= ConstExpressionSubset
350+ * | ElementValueArrayInitializer
351+ * | Annotation
352+ * ElementValueArrayInitializer ::= `{` [ElementValue {`,` ElementValue}] [`,`] `}`
353+ * ConstExpressionSubset ::= Literal
354+ * | QualifiedName
355+ * | ClassLiteral
356+ *
357+ * We support only subset of const expressions expected in this context by java.
358+ * If we encounter expression that we cannot parse, we do not raise parsing error,
359+ * but instead we skip entire annotation silently.
347360 */
348361 def annotation (): Option [Tree ] = {
349362 object LiteralT :
@@ -372,60 +385,64 @@ object JavaParsers {
372385 )
373386 else id
374387
375- def array (): Tree =
388+ def array (): Option [ Tree ] =
376389 accept(LBRACE )
377- val buffer = ListBuffer [Tree ]()
378- while ( in.token != RBRACE ) {
390+ val buffer = ListBuffer [Option [ Tree ] ]()
391+ while in.token != RBRACE do
379392 buffer += argValue()
380- if (in.token == COMMA ) in.nextToken() // using this instead of repsep allows us to handle trailing commas
381- }
382- val ok = ! buffer.contains(EmptyTree )
383- in.token match {
384- case RBRACE if ok =>
385- accept(RBRACE )
386- Apply (scalaDot(nme.Array ), buffer.toList)
387- case _ =>
388- skipTo(RBRACE )
389- EmptyTree
393+ if in.token == COMMA then
394+ in.nextToken() // using this instead of repsep allows us to handle trailing commas
395+ accept(RBRACE )
396+ Option .unless(buffer contains None ) {
397+ Apply (scalaDot(nme.Array ), buffer.flatten.toList)
390398 }
391399
392- def argValue (): Tree =
393- in.token match {
400+ def argValue (): Option [ Tree ] =
401+ val tree = in.token match {
394402 case LiteralT (c) =>
395403 val tree = atSpan(in.offset)(Literal (c))
396404 in.nextToken()
397- tree
405+ Some ( tree)
398406 case AT =>
399407 in.nextToken()
400- annotation().get
401- case IDENTIFIER => classOrId()
408+ annotation()
409+ case IDENTIFIER => Some ( classOrId() )
402410 case LBRACE => array()
403- case _ => EmptyTree
411+ case _ => None
404412 }
413+ if in.token == COMMA || in.token == RBRACE || in.token == RPAREN then
414+ tree
415+ else
416+ skipTo(COMMA , RBRACE , RPAREN )
417+ None
405418
406- def annArg (): Tree =
407- if (in.token == IDENTIFIER && in.lookaheadToken == EQUALS )
408- val name = ident()
419+ def annArg (): Option [ Tree ] =
420+ val name = if (in.token == IDENTIFIER && in.lookaheadToken == EQUALS )
421+ val n = ident()
409422 accept(EQUALS )
410- val argv = argValue()
411- NamedArg (name, argv)
412-
423+ n
413424 else
414- NamedArg (nme.value, argValue())
425+ nme.value
426+ argValue().map(NamedArg (name, _))
415427
416428
417429 val id = convertToTypeId(qualId())
418- val args = if in.token == LPAREN then
430+ val args = ListBuffer [Option [Tree ]]()
431+ if in.token == LPAREN then
419432 in.nextToken()
420- val args = repsep(annArg, COMMA )
433+ if in.token != RPAREN then
434+ args += annArg()
435+ while in.token == COMMA do
436+ in.nextToken()
437+ args += annArg()
421438 accept(RPAREN )
422- args
423- else Nil
424439
425- Some (Apply (
426- Select (New (id), nme.CONSTRUCTOR ),
427- args
428- ))
440+ Option .unless(args contains None ) {
441+ Apply (
442+ Select (New (id), nme.CONSTRUCTOR ),
443+ args.flatten.toList
444+ )
445+ }
429446 }
430447
431448 def modifiers (inInterface : Boolean ): Modifiers = {
0 commit comments