Adding recent spi.java.hints changes from NetBeans proper - NB tip b26b3e83daa5
authorJan Lahoda <jlahoda@netbeans.org>
Sun, 23 Jun 2013 21:19:45 +0200
changeset 965cec9f7dfcd43
parent 964 7ad2db2a7ba7
child 966 b39f71ac1a49
Adding recent spi.java.hints changes from NetBeans proper - NB tip b26b3e83daa5
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/providers/spi/PositionRefresherHelper.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/JavaHintsPositionRefresher.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/Utilities.java
java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/batch/BatchUtilities.java
java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/JavaFix.java
java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/JavaFixUtilities.java
java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/UtilitiesTest.java
java.hints/spi.java.hints/test/unit/src/org/netbeans/spi/java/hints/JavaFixUtilitiesTest.java
java.hints/spi.java.hints/test/unit/src/org/netbeans/spi/java/hints/matching/CopyFinderTest.java
     1.1 --- a/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/providers/spi/PositionRefresherHelper.java	Sun Jun 23 13:20:03 2013 +0200
     1.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/providers/spi/PositionRefresherHelper.java	Sun Jun 23 21:19:45 2013 +0200
     1.3 @@ -64,7 +64,7 @@
     1.4      }
     1.5  
     1.6      protected abstract boolean isUpToDate(Context context, Document doc, V oldVersion);
     1.7 -    /**XXX: should be protected*/public abstract List<ErrorDescription> getErrorDescriptionsAt(CompilationInfo info, Context context, Document doc) throws Exception;
     1.8 +    /**XXX: should be protected*/public abstract @CheckForNull List<ErrorDescription> getErrorDescriptionsAt(CompilationInfo info, Context context, Document doc) throws Exception;
     1.9  
    1.10      protected final void setVersion(Document doc, V version) {
    1.11          if (doc != null) {
     2.1 --- a/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/JavaHintsPositionRefresher.java	Sun Jun 23 13:20:03 2013 +0200
     2.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/JavaHintsPositionRefresher.java	Sun Jun 23 21:19:45 2013 +0200
     2.3 @@ -148,7 +148,11 @@
     2.4                      return;
     2.5                  }
     2.6                  
     2.7 -                eds.put(h.getKey(), h.getErrorDescriptionsAt(controller, ctx, doc));
     2.8 +                List errors = h.getErrorDescriptionsAt(controller, ctx, doc);
     2.9 +                
    2.10 +                if (errors == null) continue;
    2.11 +                
    2.12 +                eds.put(h.getKey(), errors);
    2.13              }
    2.14          }
    2.15          
     3.1 --- a/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/Utilities.java	Sun Jun 23 13:20:03 2013 +0200
     3.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/Utilities.java	Sun Jun 23 21:19:45 2013 +0200
     3.3 @@ -160,6 +160,7 @@
     3.4  import org.netbeans.lib.nbjavac.services.CancelService;
     3.5  import org.netbeans.lib.nbjavac.services.NBParserFactory.NBJavacParser;
     3.6  import org.netbeans.lib.nbjavac.services.NBParserFactory;
     3.7 +import org.netbeans.lib.nbjavac.services.NBResolve;
     3.8  import org.netbeans.modules.java.hints.spiimpl.JackpotTrees.AnnotationWildcard;
     3.9  import org.netbeans.modules.java.hints.spiimpl.JackpotTrees.FakeBlock;
    3.10  import org.netbeans.modules.java.source.parsing.FileObjects;
    3.11 @@ -354,7 +355,8 @@
    3.12          Context c = jti.getContext();
    3.13          TreeFactory make = TreeFactory.instance(c);
    3.14          List<Diagnostic<? extends JavaFileObject>> patternTreeErrors = new LinkedList<Diagnostic<? extends JavaFileObject>>();
    3.15 -        Tree patternTree = !isStatement(pattern) ? parseExpression(c, pattern, true, sourcePositions, patternTreeErrors) : null;
    3.16 +        Tree toAttribute;
    3.17 +        Tree patternTree = toAttribute = !isStatement(pattern) ? parseExpression(c, pattern, true, sourcePositions, patternTreeErrors) : null;
    3.18          int offset = 0;
    3.19          boolean expression = true;
    3.20          boolean classMember = false;
    3.21 @@ -365,7 +367,7 @@
    3.22  
    3.23              offset = "switch ($$foo) {".length();
    3.24              patternTreeErrors = currentPatternTreeErrors;
    3.25 -            patternTree = ((SwitchTree) switchTree).getCases().get(0);
    3.26 +            patternTree = toAttribute = ((SwitchTree) switchTree).getCases().get(0);
    3.27          }
    3.28  
    3.29          if (patternTree == null || isErrorTree(patternTree)) {
    3.30 @@ -403,26 +405,34 @@
    3.31                      sourcePositions[0] = classPatternTreePositions[0];
    3.32                      offset = "new Object() {".length();
    3.33                      patternTreeErrors = classPatternTreeErrors;
    3.34 -                    patternTree = classPatternTree;
    3.35 +                    patternTree = toAttribute = classPatternTree;
    3.36                      classMember = true;
    3.37                  } else {
    3.38 +                    offset = 1;
    3.39                      sourcePositions[0] = currentPatternTreePositions[0];
    3.40 -                    offset = 1;
    3.41 -                    patternTreeErrors = currentPatternTreeErrors;
    3.42 -                    patternTree = currentPatternTree;
    3.43 +                    VariableTree var;
    3.44 +                    Names names = Names.instance(jti.getContext());
    3.45 +                    if (currentPatternTree.getKind() == Kind.VARIABLE && (var = ((VariableTree) currentPatternTree)).getType().getKind() == Kind.ERRONEOUS && var.getName() == names.error && var.getInitializer() == null && var.getModifiers().getAnnotations().size() == 1 && !containsError(var.getModifiers().getAnnotations().get(0))) {
    3.46 +                        patternTreeErrors = currentPatternTreeErrors; //TODO: the errors are incorrect
    3.47 +                        toAttribute = currentPatternTree;
    3.48 +                        patternTree = var.getModifiers().getAnnotations().get(0);
    3.49 +                    } else {
    3.50 +                        patternTreeErrors = currentPatternTreeErrors;
    3.51 +                        patternTree = toAttribute = currentPatternTree;
    3.52 +                    }
    3.53                  }
    3.54              } else {
    3.55                  sourcePositions[0] = currentPatternTreePositions[0];
    3.56                  offset = 1;
    3.57                  patternTreeErrors = currentPatternTreeErrors;
    3.58 -                patternTree = currentPatternTree;
    3.59 +                patternTree = toAttribute = currentPatternTree;
    3.60              }
    3.61  
    3.62              expression = false;
    3.63          }
    3.64  
    3.65          if (scope != null) {
    3.66 -            TypeMirror type = attributeTree(jti, patternTree, scope, patternTreeErrors);
    3.67 +            TypeMirror type = attributeTree(jti, toAttribute, scope, patternTreeErrors);
    3.68  
    3.69              if (isError(type) && expression) {
    3.70                  //maybe type?
    3.71 @@ -616,6 +626,8 @@
    3.72                  errors.add(diag);
    3.73              }            
    3.74          };
    3.75 +        NBResolve resolve = NBResolve.instance(jti.getContext());
    3.76 +        resolve.disableAccessibilityChecks();
    3.77          try {
    3.78              Attr attr = Attr.instance(jti.getContext());
    3.79              Env<AttrContext> env = ((JavacScope) scope).getEnv();
    3.80 @@ -625,6 +637,7 @@
    3.81          } finally {
    3.82              log.useSource(prev);
    3.83              log.popDiagnosticHandler(discardHandler);
    3.84 +            resolve.restoreAccessbilityChecks();
    3.85          }
    3.86      }
    3.87  
    3.88 @@ -707,6 +720,7 @@
    3.89          Context context = jti.getContext();
    3.90          JavaCompiler compiler = JavaCompiler.instance(context);
    3.91          Log log = Log.instance(context);
    3.92 +        NBResolve resolve = NBResolve.instance(context);
    3.93          Log.DiagnosticHandler discardHandler = new Log.DiscardDiagnosticHandler(compiler.log);
    3.94  
    3.95          JavaFileObject jfo = FileObjects.memoryFileObject("$", "$", new File("/tmp/$" + count + ".java").toURI(), System.currentTimeMillis(), clazz.toString());
    3.96 @@ -715,6 +729,7 @@
    3.97  
    3.98          try {
    3.99              compiler.skipAnnotationProcessing = true;
   3.100 +            resolve.disableAccessibilityChecks();
   3.101              
   3.102              JCCompilationUnit cut = compiler.parse(jfo);
   3.103  
   3.104 @@ -740,6 +755,7 @@
   3.105  
   3.106              return res;
   3.107          } finally {
   3.108 +            resolve.restoreAccessbilityChecks();
   3.109              log.popDiagnosticHandler(discardHandler);
   3.110              compiler.skipAnnotationProcessing = oldSkipAPs;
   3.111          }
     4.1 --- a/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/batch/BatchUtilities.java	Sun Jun 23 13:20:03 2013 +0200
     4.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/batch/BatchUtilities.java	Sun Jun 23 21:19:45 2013 +0200
     4.3 @@ -67,6 +67,8 @@
     4.4  import java.util.logging.Level;
     4.5  import java.util.logging.Logger;
     4.6  import javax.swing.text.BadLocationException;
     4.7 +import javax.swing.text.Document;
     4.8 +import org.netbeans.api.annotations.common.CheckForNull;
     4.9  import org.netbeans.api.annotations.common.NonNull;
    4.10  import org.netbeans.api.java.classpath.ClassPath;
    4.11  import org.netbeans.api.java.classpath.ClassPath.PathConversionMode;
    4.12 @@ -104,8 +106,11 @@
    4.13  import org.netbeans.spi.editor.hints.Fix;
    4.14  import org.netbeans.spi.java.hints.HintContext.MessageKind;
    4.15  import org.netbeans.spi.java.hints.JavaFix;
    4.16 +import org.openide.cookies.EditorCookie;
    4.17  import org.openide.filesystems.FileObject;
    4.18  import org.openide.filesystems.FileUtil;
    4.19 +import org.openide.loaders.DataObject;
    4.20 +import org.openide.loaders.DataObjectNotFoundException;
    4.21  import org.openide.util.Exceptions;
    4.22  import org.openide.util.Lookup;
    4.23  
    4.24 @@ -193,12 +198,28 @@
    4.25      public static void addResourceContentChanges(final Map<FileObject, byte[]> resourceContentChanges, final Map<FileObject, List<Difference>> result) {
    4.26          for (Entry<FileObject, byte[]> e : resourceContentChanges.entrySet()) {
    4.27              try {
    4.28 -                byte[] origBytes = e.getKey().asBytes();
    4.29                  Charset encoding = FileEncodingQuery.getEncoding(e.getKey());
    4.30 -                String origContent = encoding.newDecoder().decode(ByteBuffer.wrap(origBytes)).toString();
    4.31 +                final Document originalDocument = getDocument(e.getKey());
    4.32 +                final String[] origContent = new String[1];
    4.33 +                if (originalDocument != null) {
    4.34 +                    originalDocument.render(new Runnable() {
    4.35 +                        @Override public void run() {
    4.36 +                            try {
    4.37 +                                origContent[0] = originalDocument.getText(0, originalDocument.getLength());
    4.38 +                            } catch (BadLocationException ex) {
    4.39 +                                Exceptions.printStackTrace(ex);
    4.40 +                            }
    4.41 +                        }
    4.42 +                    });
    4.43 +                }
    4.44 +                
    4.45 +                if (origContent[0] == null) {
    4.46 +                    byte[] origBytes = e.getKey().asBytes();
    4.47 +                    origContent[0] = encoding.newDecoder().decode(ByteBuffer.wrap(origBytes)).toString();
    4.48 +                }
    4.49                  String newContent  = encoding.newDecoder().decode(ByteBuffer.wrap(e.getValue())).toString();
    4.50  
    4.51 -                result.put(e.getKey(), DiffUtilities.diff2ModificationResultDifference(e.getKey(), null, Collections.<Integer, String>emptyMap(), origContent, newContent));
    4.52 +                result.put(e.getKey(), DiffUtilities.diff2ModificationResultDifference(e.getKey(), null, Collections.<Integer, String>emptyMap(), origContent[0], newContent));
    4.53              } catch (BadLocationException ex) {
    4.54                  Exceptions.printStackTrace(ex);
    4.55              } catch (IOException ex) {
    4.56 @@ -206,6 +227,20 @@
    4.57              }
    4.58          }
    4.59      }
    4.60 +    
    4.61 +    public static @CheckForNull Document getDocument(@NonNull FileObject file) {
    4.62 +        try {
    4.63 +            DataObject od = DataObject.find(file);
    4.64 +            EditorCookie ec = od.getLookup().lookup(EditorCookie.class);
    4.65 +
    4.66 +            if (ec == null) return null;
    4.67 +
    4.68 +            return ec.getDocument();
    4.69 +        } catch (DataObjectNotFoundException ex) {
    4.70 +            LOG.log(Level.FINE, null, ex);
    4.71 +            return null;
    4.72 +        }
    4.73 +    }
    4.74  
    4.75      private static String positionToString(ErrorDescription ed) {
    4.76          try {
     5.1 --- a/java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/JavaFix.java	Sun Jun 23 13:20:03 2013 +0200
     5.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/JavaFix.java	Sun Jun 23 21:19:45 2013 +0200
     5.3 @@ -59,20 +59,17 @@
     5.4  import javax.lang.model.type.TypeMirror;
     5.5  import javax.swing.text.BadLocationException;
     5.6  import javax.swing.text.Document;
     5.7 -import org.netbeans.api.annotations.common.CheckForNull;
     5.8  import org.netbeans.api.annotations.common.NonNull;
     5.9  import org.netbeans.api.java.source.CompilationInfo;
    5.10  import org.netbeans.api.java.source.TreePathHandle;
    5.11  import org.netbeans.api.java.source.WorkingCopy;
    5.12  import org.netbeans.api.queries.FileEncodingQuery;
    5.13  import org.netbeans.modules.java.hints.spiimpl.JavaFixImpl;
    5.14 +import org.netbeans.modules.java.hints.spiimpl.batch.BatchUtilities;
    5.15  import org.netbeans.modules.refactoring.spi.RefactoringElementImplementation;
    5.16  import org.netbeans.spi.editor.hints.ChangeInfo;
    5.17  import org.netbeans.spi.editor.hints.Fix;
    5.18 -import org.openide.cookies.EditorCookie;
    5.19  import org.openide.filesystems.FileObject;
    5.20 -import org.openide.loaders.DataObject;
    5.21 -import org.openide.loaders.DataObjectNotFoundException;
    5.22  import org.openide.util.Exceptions;
    5.23  import org.openide.util.Parameters;
    5.24  
    5.25 @@ -248,7 +245,7 @@
    5.26              byte[] newContent = resourceContentChanges != null ? resourceContentChanges.get(file) : null;
    5.27  
    5.28              if (newContent == null) {
    5.29 -                final Document doc = getDocument(file);
    5.30 +                final Document doc = BatchUtilities.getDocument(file);
    5.31  
    5.32                  if (doc != null) {
    5.33                      final String[] result = new String[1];
    5.34 @@ -307,22 +304,6 @@
    5.35              return fileChanges;
    5.36          }
    5.37  
    5.38 -        private @CheckForNull Document getDocument(@NonNull FileObject file) {
    5.39 -            try {
    5.40 -                DataObject od = DataObject.find(file);
    5.41 -                EditorCookie ec = od.getLookup().lookup(EditorCookie.class);
    5.42 -
    5.43 -                if (ec == null) return null;
    5.44 -
    5.45 -                return ec.getDocument();
    5.46 -            } catch (DataObjectNotFoundException ex) {
    5.47 -                LOG.log(Level.FINE, null, ex);
    5.48 -                return null;
    5.49 -            }
    5.50 -        }
    5.51 -
    5.52      }
    5.53  
    5.54 -    private static final Logger LOG = Logger.getLogger(JavaFix.class.getName());
    5.55 -
    5.56  }
     6.1 --- a/java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/JavaFixUtilities.java	Sun Jun 23 13:20:03 2013 +0200
     6.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/spi/java/hints/JavaFixUtilities.java	Sun Jun 23 21:19:45 2013 +0200
     6.3 @@ -1145,6 +1145,16 @@
     6.4              return super.visitLambdaExpression(node, p);
     6.5          }
     6.6  
     6.7 +        @Override
     6.8 +        public Number visitAnnotation(AnnotationTree node, Void p) {
     6.9 +            List<? extends ExpressionTree> args = resolveMultiParameters(node.getArguments());
    6.10 +            AnnotationTree nue = make.Annotation(node.getAnnotationType(), args);
    6.11 +
    6.12 +            rewrite(node, nue);
    6.13 +
    6.14 +            return super.visitAnnotation(node, p);
    6.15 +        }
    6.16 +
    6.17          private <T extends Tree> List<T> resolveMultiParameters(List<T> list) {
    6.18              if (list == null) return null;
    6.19              if (!Utilities.containsMultistatementTrees(list)) return list;
    6.20 @@ -1183,7 +1193,7 @@
    6.21              switch (original.getKind()) {
    6.22                  case PARENTHESIZED:
    6.23                      ExpressionTree expr = ((ParenthesizedTree) original).getExpression();
    6.24 -                    return negate(expr, original, nullOnPlainNeg);
    6.25 +                    return make.Parenthesized(negate(expr, original, nullOnPlainNeg));
    6.26                  case LOGICAL_COMPLEMENT:
    6.27                      newTree = ((UnaryTree) original).getExpression();
    6.28                      while (newTree.getKind() == Kind.PARENTHESIZED && !JavaFixUtilities.requiresParenthesis(((ParenthesizedTree) newTree).getExpression(), original, parent)) {
    6.29 @@ -1232,16 +1242,17 @@
    6.30          
    6.31          private ExpressionTree negateBinaryOperator(Tree original, Kind newKind, boolean negateOperands) {
    6.32              BinaryTree bt = (BinaryTree) original;
    6.33 +            BinaryTree nonNegated = make.Binary(newKind,
    6.34 +                                                bt.getLeftOperand(),
    6.35 +                                                bt.getRightOperand());
    6.36              if (negateOperands) {
    6.37 -                ExpressionTree lo = negate(bt.getLeftOperand(), original, false);
    6.38 -                ExpressionTree ro = negate(bt.getRightOperand(), original, false);
    6.39 +                ExpressionTree lo = negate(bt.getLeftOperand(), nonNegated, false);
    6.40 +                ExpressionTree ro = negate(bt.getRightOperand(), nonNegated, false);
    6.41                  return make.Binary(newKind,
    6.42                                     lo != null ? lo : bt.getLeftOperand(),
    6.43                                     ro != null ? ro : bt.getRightOperand());
    6.44              }
    6.45 -            return make.Binary(newKind,
    6.46 -                               bt.getLeftOperand(),
    6.47 -                               bt.getRightOperand());
    6.48 +            return nonNegated;
    6.49          }
    6.50          
    6.51          private void rewrite(Tree from, Tree to) {
     7.1 --- a/java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/UtilitiesTest.java	Sun Jun 23 13:20:03 2013 +0200
     7.2 +++ b/java.hints/spi.java.hints/test/unit/src/org/netbeans/modules/java/hints/spiimpl/UtilitiesTest.java	Sun Jun 23 21:19:45 2013 +0200
     7.3 @@ -451,6 +451,18 @@
     7.4          String golden = "{ $$1$; $mods$$type $name; $name = $init; $$2$; }";
     7.5          assertEquals(golden.replaceAll("[ \n\r]+", " "), result.toString().replaceAll("[ \n\r]+", " "));
     7.6      }
     7.7 +    
     7.8 +    public void testAnnotation() throws Exception {
     7.9 +        prepareTest("test/Test.java", "package test; public class Test{}");
    7.10 +
    7.11 +        Scope s = Utilities.constructScope(info, Collections.<String, TypeMirror>emptyMap());
    7.12 +        Tree result = Utilities.parseAndAttribute(info, "@$annotation($args$)", s);
    7.13 +
    7.14 +        assertTrue(result.getKind().name(), result.getKind() == Kind.ANNOTATION);
    7.15 +
    7.16 +        String golden = "@$annotation(value = $args$)";
    7.17 +        assertEquals(golden.replaceAll("[ \n\r]+", " "), result.toString().replaceAll("[ \n\r]+", " "));
    7.18 +    }
    7.19  
    7.20      public void testParseAndAttributeMultipleStatementsWithBefore() throws Exception {
    7.21          prepareTest("test/Test.java", "package test; public class Test{}");
     8.1 --- a/java.hints/spi.java.hints/test/unit/src/org/netbeans/spi/java/hints/JavaFixUtilitiesTest.java	Sun Jun 23 13:20:03 2013 +0200
     8.2 +++ b/java.hints/spi.java.hints/test/unit/src/org/netbeans/spi/java/hints/JavaFixUtilitiesTest.java	Sun Jun 23 21:19:45 2013 +0200
     8.3 @@ -977,7 +977,7 @@
     8.4      }
     8.5      
     8.6      public void testOptimizeNegExpressionParens() throws Exception {
     8.7 -        performOptimizeNegExpressionTest("(!(a.length == 0))", "a.length == 0");
     8.8 +        performOptimizeNegExpressionTest("!(a.length == 0)", "a.length == 0");
     8.9      }
    8.10      
    8.11      public void testOptimizeNegExpressionEquals() throws Exception {
    8.12 @@ -1024,6 +1024,14 @@
    8.13          performOptimizeNegExpressionTest("b1 && b2", "!b1 || !b2");
    8.14      }
    8.15      
    8.16 +    public void test229785a() throws Exception {
    8.17 +        performOptimizeNegExpressionTest("(a[0] == null && a[1] != null) || (a[0] != null && !a[0].equals(a[1]))", "(a[0] != null || a[1] == null) && (a[0] == null || a[0].equals(a[1]))");
    8.18 +    }
    8.19 +    
    8.20 +    public void test229785b() throws Exception {
    8.21 +        performOptimizeNegExpressionTest("a[0] == null && a[1] != null || a[0] != null && !a[0].equals(a[1])", "(a[0] != null || a[1] == null) && (a[0] == null || a[0].equals(a[1]))");
    8.22 +    }
    8.23 +    
    8.24      private void performOptimizeNegExpressionTest(String origExpr, String newExpr) throws Exception {
    8.25          performRewriteTest("package test;\n" +
    8.26                             "public class Test {\n" +
     9.1 --- a/java.hints/spi.java.hints/test/unit/src/org/netbeans/spi/java/hints/matching/CopyFinderTest.java	Sun Jun 23 13:20:03 2013 +0200
     9.2 +++ b/java.hints/spi.java.hints/test/unit/src/org/netbeans/spi/java/hints/matching/CopyFinderTest.java	Sun Jun 23 21:19:45 2013 +0200
     9.3 @@ -1197,6 +1197,35 @@
     9.4                               false);
     9.5      }
     9.6      
     9.7 +    public void testAnnotation1() throws Exception {
     9.8 +        performVariablesTest("package test; import test.Test.A; @A(i=1) public class Test { @interface A { public int i(); } }",
     9.9 +                             "@$annotation($args$)",
    9.10 +                             new Pair[] {
    9.11 +                                 new Pair<String, int[]>("$annotation", new int[] {35, 36})
    9.12 +                             },
    9.13 +                             new Pair[] {
    9.14 +                                 new Pair<String, int[]>("$args$", new int[] {37, 40})
    9.15 +                             },
    9.16 +                             new Pair[0],
    9.17 +                             false,
    9.18 +                             true);
    9.19 +    }
    9.20 +    
    9.21 +    public void testAnnotation2() throws Exception {
    9.22 +        performVariablesTest("package test; import test.Test.A; @A(i=1,b=true,l=2) public class Test { @interface A { public int i(); public boolean b(); public long l(); } }",
    9.23 +                             "@test.Test.A($prefix$, b=$value, $suffix$)",
    9.24 +                             new Pair[] {
    9.25 +                                 new Pair<String, int[]>("$value", new int[] {43, 47})
    9.26 +                             },
    9.27 +                             new Pair[] {
    9.28 +                                 new Pair<String, int[]>("$prefix$", new int[] {37, 40}),
    9.29 +                                 new Pair<String, int[]>("$suffix$", new int[] {48, 51})
    9.30 +                             },
    9.31 +                             new Pair[0],
    9.32 +                             false,
    9.33 +                             false);
    9.34 +    }
    9.35 +    
    9.36      protected void prepareTest(String code) throws Exception {
    9.37          prepareTest(code, -1);
    9.38      }