SSR: javadoc matching fix and tests
[idea/community.git] / platform / structuralsearch / testSource / com / intellij / structuralsearch / StructuralSearchTest.java
1 /*
2  * Copyright 2000-2016 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.structuralsearch;
17
18 import com.intellij.openapi.fileTypes.StdFileTypes;
19 import com.intellij.psi.*;
20 import com.intellij.structuralsearch.impl.matcher.MatcherImplUtil;
21 import com.intellij.testFramework.PlatformTestUtil;
22 import org.jetbrains.annotations.NotNull;
23
24 import java.io.IOException;
25 import java.util.ArrayList;
26 import java.util.List;
27
28 /**
29  * @author Maxim.Mossienko
30  */
31 @SuppressWarnings({"HardCodedStringLiteral"})
32 public class StructuralSearchTest extends StructuralSearchTestCase {
33   private static final String s1 = "debug(\"In action performed:\"+event);"+
34                                    "project = (Project)event.getDataContext().getData(DataConstants.PROJECT);" +
35                                    "CodeEditorManager.getInstance(project).commitAllToPsiFile();" +
36                                    "file = (PsiFile) event.getDataContext().getData(\"psi.File\"); " +
37                                    "((dialog==null)?" +
38                                    "  (dialog = new SearchDialog()):" +
39                                    "  dialog" +
40                                    ").show();";
41
42   private static final String s2 = "((dialog==null)? (dialog = new SearchDialog()): dialog).show();";
43
44   private static final String s4 = " do { " +
45                                    "  pattern = pattern.getNextSibling(); " +
46                                    " } " +
47                                    " while (pattern!=null && filterLexicalNodes(pattern));";
48
49   private static final String s5 = "{ System.out.println();" +
50                                    "  while(false) { " +
51                                    "    do { " +
52                                    "       pattern = pattern.getNextSibling(); " +
53                                    "    } " +
54                                    "      while (pattern!=null && filterLexicalNodes(pattern)); " +
55                                    "  } " +
56                                    " do { " +
57                                    "  pattern = pattern.getNextSibling(); " +
58                                    " } while (pattern!=null && filterLexicalNodes(pattern));" +
59                                    " { { " +
60                                    "   do { " +
61                                    "     pattern = pattern.getNextSibling(); " +
62                                    "   } while (pattern!=null && filterLexicalNodes(pattern));" +
63                                    " } }" +
64                                    "}";
65
66   private static final String s6 = " do { " +
67                                    "  pattern.getNextSibling(); " +
68                                    " } " +
69                                    " while (pattern!=null && filterLexicalNodes(pattern));";
70
71   private static final String s7 = " if (true) throw new UnsupportedPatternException(statement.toString());" +
72                                    " if (true) { " +
73                                    "   throw new UnsupportedPatternException(statement.toString());" +
74                                    " } ";
75
76   private static final String s8 = " if (true) { " +
77                                    "   throw new UnsupportedPatternException(statement.toString());" +
78                                    " } ";
79
80   private static final String s9 = " if (true) throw new UnsupportedPatternException(statement.toString());";
81
82   private static final String s10 = "listener.add(new Runnable() { public void run() {} });";
83
84   private static final String s12 = "new Runnable() {" +
85                                     "  public void run() {" +
86                                     "   matchContext.getSink().matchingFinished();" +
87                                     "   } " +
88                                     " }";
89
90   private static final String s14_1 = "if (true) { aaa(var); }";
91   private static final String s14_2 = "if (true) { aaa(var); bbb(var2); }\n if(1==1) { system.out.println('o'); }";
92   private static final String s17 = "token.getText().equals(token2.getText());" +
93                                     "token.getText().equals(token2.getText2());" +
94                                     "token.a.equals(token2.b);" +
95                                     "token.a.equals(token2.a);";
96   private static final String s19 = "Aaa a = (Aaa)b; Aaa c = (Bbb)d;";
97
98   private static final String s22 = "Aaa a = (Aaa)b; Bbb c = (Bbb)d;";
99
100   private static final String s23 = "a[i] = 1; b[a[i]] = f(); if (a[i]==1) return b[c[i]];";
101   private static final String s25  = "class MatcherImpl {  void doMatch(int a) {} }\n" +
102                                      "class Matcher { abstract void doMatch(int a);}\n " +
103                                      "class Matcher2Impl { void doMatch(int a, int b) {} } ";
104   private static final String s27 = "class A {} interface B {}";
105
106   private static final String s29 = "class A { void B(int C) {} } class D { void E(double e) {} }";
107
108   private static final String s31 = "class A extends B { } class D extends B { } class C extends C {}";
109
110   private static final String s33 = "class A implements B,C { } class D implements B,D { } class C2 implements C,B {}";
111
112   private static final String s35 = "class A { int b; double c; void d() {} int e() {} } " +
113                                     "class A2 { int b; void d() {} }";
114
115   private static final String s37 = "class A { void d() throws B,C,D {} } class A2 { void d() throws B,C {} }";
116
117   private static final String s39 = "class A extends B { } class A2 {  }";
118
119   private static final String s41 = "class A extends B { int a = 1; } class B { int[] c= new int[2]; } " +
120                                     "class D { double e; } class E { int d; } ";
121
122   private static final String s43 = "interface A extends B { int B = 1; } " +
123                                     "interface D { public final static double e = 1; } " +
124                                     "interface E { final static ind d = 2; } " +
125                                     "interface F {  } ";
126   private static final String s45 = "class A extends B { private static final int B = 1; } " +
127                                     "class C extends D { int B = 1; }" +
128                                     "class E { }";
129
130   private static final String s47 = "class C { java.lang.String t; } class B { BufferedString t2;} class A { String p;} ";
131
132   private static final String s49 = "class C { void a() throws java.lang.RuntimeException {} } class B { BufferedString t2;}";
133
134   private static final String s51 = "class C extends B { } class B extends A { } class E {}";
135
136   private static final String s53 = "class C { " +
137                                     "   String a = System.getProperty(\"abcd\"); " +
138                                     "  static { String s = System.getProperty(a); }" +
139                                     "  static void b() { String s = System.getProperty(a); }" +
140                                     " }";
141
142   private static final String s55 = " a = b.class; ";
143
144   private static final String s57 = "/** @author Maxim */ class C {" +
145                                     "  private int value; " +
146                                     "} " +
147                                     "class D {" +
148                                     "  /** @serializable */ private int value;" +
149                                     "private int value2; " +
150                                     "  /** @since 1.4 */ void a() {} "+
151                                     "}" +
152                                     "class F { " +
153                                     "  /** @since 1.4 */ void a() {} "+
154                                     "  /** @serializable */ private int value2; " +
155                                     "}" +
156                                     "class G { /** @param a*/ void a() {} }";
157
158   private static final String s59 = "interface A { void B(); }";
159
160   private static final String s61 = "{ a=b; c=d; return; } { e=f; } {}";
161
162   private static final String s63 = " class A { A() {} } class B { public void run() {} }";
163   private static final String s63_2 = " class A { A() {} " +
164                                       "class B { public void run() {} } " +
165                                       "class D { public void run() {} } " +
166                                       "} " +
167                                       "class C {}";
168
169   private static final String s65 = " if (A instanceof B) {} else if (B instanceof C) {}";
170
171   private static final String s67 = " buf.append((VirtualFile)a);";
172
173   private static final String s69 = " System.getProperties(); System.out.println(); java.lang.System.out.println(); some.other.System.out.println();";
174
175   private static final String s71 = " class A { " +
176                                     "class D { D() { c(); } }" +
177                                     "void a() { c(); new MouseListener() { void b() { c(); } } }" +
178                                     " }";
179
180   private static final String s73 = " class A { int A; static int B=5; public abstract void a(int c); void q() { ind d=7; } }";
181   private static final String s75 = "/** @class aClass\n @author the author */ class A {}\n" +
182                                     "/** */ class B {}\n" +
183                                     "/** @class aClass */ class C {}";
184
185   private static final String s77 = " new ActionListener() {} ";
186
187   private static final String s79 = " class A { static { int c; } void a() { int b; b=1; }} ";
188
189   private static final String s81 = "class Pair<First,Second> {" +
190                                     "  <C,F> void a(B<C> b, D<F> e) throws C {" +
191                                     "    P<Q> r = (S<T>)null;"+
192                                     "    Q q = null; "+
193                                     "    if (r instanceof S<T>) {}"+
194                                     "  } " +
195                                     "} class Q { void b() {} } ";
196
197   private static final String s81_2 = "class Double<T> {} class T {} class Single<First extends A & B> {}";
198
199
200   private static final String s83 = "/**\n" +
201                                     " * @hibernate.class\n" +
202                                     " *  table=\"CATS\"\n" +
203                                     " */\n" +
204                                     "public class Cat {\n" +
205                                     "    private Long id; // identifier\n" +
206                                     "    private Date birthdate;\n" +
207                                     "    /**\n" +
208                                     "     * @hibernate.id\n" +
209                                     "     *  generator-class=\"native\"\n" +
210                                     "     *  column=\"CAT_ID\"\n" +
211                                     "     */\n" +
212                                     "    public Long getId() {\n" +
213                                     "        return id;\n" +
214                                     "    }\n" +
215                                     "    private void setId(Long id) {\n" +
216                                     "        this.id=id;\n" +
217                                     "    }\n" +
218                                     "\n" +
219                                     "    /**\n" +
220                                     "     * @hibernate.property\n" +
221                                     "     *  column=\"BIRTH_DATE\"\n" +
222                                     "     */\n" +
223                                     "    public Date getBirthdate() {\n" +
224                                     "        return birthdate;\n" +
225                                     "    }\n" +
226                                     "    void setBirthdate(Date date) {\n" +
227                                     "        birthdate = date;\n" +
228                                     "    }\n" +
229                                     "    /**\n" +
230                                     "     * @hibernate.property\n" +
231                                     "     *  column=\"SEX\"\n" +
232                                     "     *  not-null=\"true\"\n" +
233                                     "     *  update=\"false\"\n" +
234                                     "     */\n" +
235                                     "    public char getSex() {\n" +
236                                     "        return sex;\n" +
237                                     "    }\n" +
238                                     "    void setSex(char sex) {\n" +
239                                     "        this.sex=sex;\n" +
240                                     "    }\n" +
241                                     "}";
242
243
244
245
246   private static final String s85 = "{ int a; a=1; a=1; return a; }";
247   private static final String s86 = "'T; 'T;";
248
249   private static final String s87 = " getSomething(\"1\"); a.call(); ";
250   private static final String s88 = " '_Instance.'Call('_*); ";
251   private static final String s88_2 = " 'Call('_*); ";
252   private static final String s88_3 = " '_Instance?.'Call('_*); ";
253   private static final String s89 = "{ a = 1; b = 2; c=3; }";
254
255   private static final String s91 = "class a {\n" +
256                                     "  void b() {\n" +
257                                     "    int c;\n" +
258                                     "\n" +
259                                     "    c = 1;\n" +
260                                     "    b();\n" +
261                                     "    a a1;\n" +
262                                     "  }\n" +
263                                     "}";
264
265   private static final String s93 = " class A {" +
266                                     "private int field;" +
267                                     "public void b() {}" +
268                                     "}";
269
270   private static final String s95 = " class Clazz {" +
271                                     "private int field;" +
272                                     "private int field2;" +
273                                     "private int fiel-d2;" +
274                                     "}";
275
276   public void testSearchExpressions() {
277     assertFalse("subexpr match", findMatchesCount(s2, "dialog = new SearchDialog()") == 0);
278     assertEquals("search for new ", 0, findMatchesCount(s10, " new XXX()"));
279     assertEquals("search for anonymous classes", 1, findMatchesCount(s12, "new Runnable() {}"));
280     assertEquals("expr in def initializer", 3, findMatchesCount(s53, "System.getProperty('T)"));
281
282     assertEquals("a.class expression", 1, findMatchesCount(s55, "'T.class"));
283
284     String complexCode = "interface I { void b(); } interface I2 extends I {} class I3 extends I {} " +
285                          "class A implements I2 {  void b() {} } class B implements I3 { void b() {}} " +
286                          "I2 a; I3 b; a.b(); b.b(); b.b(); A c; B d; c.b(); d.b(); d.b(); ";
287
288     assertEquals("expr type condition", 1, findMatchesCount(complexCode, "'t:[exprtype( I2 )].b();"));
289     assertEquals("expr type condition 2", 5, findMatchesCount(complexCode, "'t:[!exprtype( I2 )].b();"));
290     assertEquals("expr type condition 3", 2, findMatchesCount(complexCode, "'t:[exprtype( *I2 )].b();"));
291     assertEquals("expr type condition 4", 4, findMatchesCount(complexCode, "'t:[!exprtype( *I2 )].b();"));
292
293     String complexCode2 = "enum X { XXX, YYY }\n class C { static void ordinal() {} void test() { C c; c.ordinal(); c.ordinal(); X.XXX.ordinal(); } }";
294     assertEquals("expr type condition with enums", 1,
295                  findMatchesCount(complexCode2, "'t:[exprtype( *java\\.lang\\.Enum )].ordinal()"));
296
297     final String in = "processInheritors(1,2,3,4); " +
298                       "processInheritors(1,2,3); " +
299                       "processInheritors(1,2,3,4,5,6);";
300     assertEquals("no smart detection of search target", 3,
301                  findMatchesCount(in, "'instance?.processInheritors('_param1{1,6});"));
302
303     String arrays = "int[] a = new int[20];\n" +
304                     "byte[] b = new byte[30]";
305     assertEquals("Improper array search", 1, findMatchesCount(arrays, "new int['_a]"));
306
307     String someCode = "a *= 2; a+=2;";
308     assertEquals("Improper *= 2 search", 1, findMatchesCount(someCode, "a *= 2;"));
309
310     String s1 = "Thread t = new Thread(\"my thread\",\"my another thread\") {\n" +
311                 "    public void run() {\n" +
312                 "        // do stuff\n" +
313                 "    }\n" +
314                 "}";
315     assertEquals("Find inner class parameters", 2, findMatchesCount(s1, "new Thread('args*) { '_Other* }"));
316
317     String s3 = "Thread t = new Thread(\"my thread\") {\n" +
318                 "    public void run() {\n" +
319                 "        // do stuff\n" +
320                 "    }\n" +
321                 "};";
322     assertEquals("Find inner class by new", 1, findMatchesCount(s3, "new Thread('_args)"));
323
324     String s5 = "class A {\n" +
325                 "public static <T> T[] copy(T[] array, Class<T> aClass) {\n" +
326                 "    int i = (int)0;\n" +
327                 "    int b = (int)0;\n" +
328                 "    return (T[])array.clone();\n" +
329                 "  }\n" +
330                 "}";
331     assertEquals("Find cast to array", 1, findMatchesCount(s5, "('_T[])'_expr"));
332
333     String s7 = "import java.math.BigDecimal;\n" +
334                 "\n" +
335                 "public class Prorator {\n" +
336                 "        public void prorate(BigDecimal[] array) {\n" +
337                 "                // do nothing\n" +
338                 "        }\n" +
339                 "        public void prorate2(java.math.BigDecimal[] array) {\n" +
340                 "                // do nothing\n" +
341                 "        }\n" +
342                 "        public void prorate(BigDecimal bd) {\n" +
343                 "                // do nothing\n" +
344                 "        }\n" +
345                 "\n" +
346                 "        public static void main(String[] args) {\n" +
347                 "                BigDecimal[] something = new BigDecimal[2];\n" +
348                 "                java.math.BigDecimal[] something2 = new BigDecimal[2];\n" +
349                 "                something[0] = new BigDecimal(1.0);\n" +
350                 "                something[1] = new BigDecimal(1.0);\n" +
351                 "\n" +
352                 "                Prorator prorator = new Prorator();\n" +
353                 "\n" +
354                 "// ---------------------------------------------------\n" +
355                 "// the line below should've been found, in my opinion.\n" +
356                 "// --------------------------------------------------\n" +
357                 "                prorator.prorate(something);\n" +
358                 "                prorator.prorate(something2);\n" +
359
360                 "                prorator.prorate(something[0]);\n" +
361                 "                prorator.prorate(something[1]);\n" +
362                 "                prorator.prorate(something[0]);\n" +
363                 "        }\n" +
364                 "}";
365     assertEquals("Find method call with array for parameter expr type", 2,
366                  findMatchesCount(s7, "'_Instance.'_MethodCall:[regex( prorate )]('_Param:[exprtype( BigDecimal\\[\\] )]) ", true));
367
368     String s13 = "try { } catch(Exception e) { e.printStackTrace(); }";
369     assertEquals("Find statement in catch", 1, findMatchesCount(s13, "'_Instance.'_MethodCall('_Parameter*)"));
370
371     String s9 = "int a[] = new int[] { 1,2,3,4};\n" +
372                 "int b[] = { 2,3,4,5 };\n" +
373                 "Object[] c = new Object[] { \"\", null};\n" +
374                 "Object[] d = {null, null};\n" +
375                 "Object[] e = {};\n" +
376                 "Object[] f = new Object[]{}\n" +
377                 "String[] g = new String[]{}\n" +
378                 "String[] h = new String[]{new String()}";
379
380     assertEquals("Find new array expressions, but no array initializer expressions", 5,
381                  findMatchesCount(s9, "new '_ []{ '_* }"));
382
383     assertEquals("Find new int array expressions, including array initializer expressions", 2,
384                  findMatchesCount(s9, "new int []{ '_* }"));
385
386     assertEquals("Find new int array expressions, including array initializer expressions using variable ", 2,
387                  findMatchesCount(s9, "new 'a?:int [] { '_* }"));
388
389     assertEquals("Find all new array expressions, including array initializers", 8,
390                  findMatchesCount(s9, "new '_? []{ '_* }"));
391
392     assertEquals("Find new Object array expressions, including array initializer expressions", 4,
393                  findMatchesCount(s9, "new Object[] { '_* }"));
394
395     assertEquals("Find only array initializer expressions", 3,
396                  findMatchesCount(s9, "new '_{0,0}[] { '_* }"));
397
398     assertEquals("Find only int array initializer expressions", 1,
399                  findMatchesCount(s9, "new '_{0,0}:int [] { '_* }"));
400
401     assertEquals("Try to find String array initializer expressions", 0,
402                  findMatchesCount(s9, "new '_{0,0}:String [] { '_* }"));
403
404     String s10 = "int time = 99;\n" +
405                  "String str = time < 0 ? \"\" : \"\";" +
406                  "String str2 = time < time ? \"\" : \"\";";
407
408     assertEquals("Find expressions mistaken for declarations by parser in block mode", 1,
409                  findMatchesCount(s10, "time < time"));
410
411     assertEquals("Find expressions mistaken for declarations by parser in block mode 2", 1,
412                  findMatchesCount(s10, "time < 0"));
413
414     assertEquals("Find expressions mistaken for declarations by parser in block mode 3", 1,
415                  findMatchesCount(s10, "time < 0 ? '_a : '_b"));
416
417     assertEquals("Find expressions mistaken for declarations by parser in block mode 4", 2,
418                  findMatchesCount(s10, "'_a < '_b"));
419   }
420
421   public void testLiteral() {
422     String s = "class A {\n" +
423                "  static String a = 1;\n" +
424                "  static String s = \"aaa\";\n" +
425                "  static String s2;\n" +
426                "}";
427     assertEquals("Literal", 2, findMatchesCount(s, "static String '_FieldName = '_Init?:[!regex( \".*\" )];"));
428     assertEquals("Literal, 2", 1, findMatchesCount(s, "static String '_FieldName = '_Init:[!regex( \".*\" )];"));
429     assertEquals("String literal", 1, findMatchesCount(s, "\"'String\""));
430
431     String source = "@SuppressWarnings(\"test\") class A {" +
432                     "  @SuppressWarnings({\"other\", \"test\"}) String field;" +
433                     "}";
434     assertEquals("String literal in annotation", 2, findMatchesCount(source, "\"test\""));
435   }
436
437   public void testCovariantArraySearch() {
438     String s1 = "String[] argv;";
439     String s2 = "String argv;";
440     assertEquals("Find array types", 0, findMatchesCount(s1, s2));
441     assertEquals("Find array types, 2", 0, findMatchesCount(s2, s1));
442     assertEquals("Find array types, 3", 0, findMatchesCount(s2, "'T[] argv;"));
443     assertEquals("Find array types, 3", 1, findMatchesCount(s1, "'T:*Object [] argv;"));
444
445     String s11 = "class A {\n" +
446                  "  void main(String[] argv);" +
447                  "  void main(String argv[]);" +
448                  "  void main(String argv);" +
449                  "}";
450     assertEquals("Find array covariant types", 2, findMatchesCount(s11, "'_t:[regex( *Object\\[\\] ) ] '_t2;"));
451     assertEquals("Find array covariant types, 2", 2, findMatchesCount(s11, "'_t:[regex( *Object ) ] '_t2 [];"));
452     assertEquals("Find array covariant types, 3", 1, findMatchesCount(s11, "'_t:[regex( *Object ) ] '_t2;"));
453   }
454
455   public void testFindArrayDeclarations() {
456     String source = "class A {" +
457                     "  String ss[][];" +
458                     "  int f()[] {" +
459                     "    return null;" +
460                     "  }" +
461                     "}";
462
463     String target = "String[][] '_s;";
464     assertEquals("should find multi-dimensional c-style array declarations", 1, findMatchesCount(source, target));
465
466     String target2 = "class '_A { int[] 'f(); }";
467     assertEquals("should find c-style method return type declarations", 1, findMatchesCount(source, target2));
468
469     String target3 = "class '_A { int 'f(); }";
470     assertEquals("should not find methods with array return types",0, findMatchesCount(source, target3));
471
472     String source2 = "class A {" +
473                      "  void y(int... i) {}" +
474                      "  void y(String... ss) {}" +
475                      "  void y(boolean b) {}" +
476                      "}";
477     assertEquals("find ellipsis type 1", 1, findMatchesCount(source2, "String[] '_a;"));
478     assertEquals("find ellipsis type 2", 1, findMatchesCount(source2, "int[] '_a;"));
479     assertEquals("find ellipsis type 3", 1, findMatchesCount(source2, "class '_X { void '_m(int... '_a); }"));
480     assertEquals("find ellipsis type 4", 2, findMatchesCount(source2, "'_T[] '_a;"));
481
482     String source3 = "class A {" +
483                      "  private int[] is;" +
484                      "}";
485     assertEquals("find primitive array 1", 1, findMatchesCount(source3, "int[] '_a;"));
486     assertEquals("find primitive array 2", 1, findMatchesCount(source3, "'_T[] '_a;"));
487     assertEquals("find primitive array 3", 1, findMatchesCount(source3, "'_T:[regex( int )][] '_a;"));
488     assertEquals("find primitive array 4", 1, findMatchesCount(source3, "'_T:[regex( int\\[\\] )] '_a;"));
489   }
490
491   // @todo support back references (\1 in another reg exp or as field member)
492   //private static final String s1002 = " setSSS( instance.getSSS() ); " +
493   //                                    " setSSS( instance.SSS ); ";
494   //private static final String s1003 = " 't:set(.+) ( '_.get't_1() ); ";
495   //private static final String s1003_2 = " 't:set(.+) ( '_.'t_1 ); ";
496
497   public void testSearchStatements() {
498     assertEquals("statement search", 1, findMatchesCount(s1, s2));
499     assertEquals("several constructions match", 3, findMatchesCount(s5, s4));
500     assertFalse("several constructions 2",(findMatchesCount(s5,s6))!=0);
501
502     assertEquals("several constructions 3", 2, findMatchesCount(s7, s8));
503     assertEquals("several constructions 4", 2, findMatchesCount(s7, s9));
504
505     final String s1000 = "{ lastTest = \"search for parameterized pattern\";\n" +
506                          "      matches = testMatcher.findMatches(s14_1,s15, options);\n" +
507                          "      if (matches.size()!=2 ) return false;\n" +
508                          "lastTest = \"search for parameterized pattern\";\n" +
509                          "      matches = testMatcher.findMatches(s14_1,s15, options);\n" +
510                          "      if (matches.size()!=2 ) return false; }";
511     final String s1001 = "lastTest = '_Descr; " +
512                          "      matches = testMatcher.findMatches('_In,'_Pattern, options);\n" +
513                          "      if (matches.size()!='_Number ) return false;";
514
515     assertEquals("several operators 5", 2, findMatchesCount(s1000, s1001));
516     assertEquals("two the same statements search", 1, findMatchesCount(s85,s86));
517     assertEquals("search for simple call", 1, findMatchesCount(s87,s88));
518     assertEquals("search for simple call 2", 1, findMatchesCount(s87,s88_2));
519     assertEquals("search for simple call 3", 2, findMatchesCount(s87,s88_3));
520
521     String s10015 = "DocumentListener[] listeners = getCachedListeners();";
522     assertEquals("search for definition with init", 1, findMatchesCount(s10015, "'_Type 'Var = '_Call();"));
523
524     String s10017 = "a = b; b = c; a=a; c=c;";
525     assertEquals("search silly assignments", 2, findMatchesCount(s10017, "'_a = '_a;"));
526
527     String s10019 = "a.b(); a.b(null); a.b(null, 1);";
528     assertEquals("search parameter", 1, findMatchesCount(s10019, "a.b(null);"));
529
530     String s1008 = "int a, b, c, d; int a,b,c; int c,d; int e;";
531     assertEquals("search many declarations", 2, findMatchesCount(s1008, "int '_a{3,4};"));
532
533     String s1 = "super(1,1);  call(1,1); call(2,2);";
534     assertEquals("search super", 1, findMatchesCount(s1, "super('_t*);"));
535
536     String s10021 = "short a = 1;\n" +
537                     "short b = 2;\n" +
538                     "short c = a.b();";
539
540     assertEquals("search def init bug", 1, findMatchesCount(s10021, "short '_a = '_b.b();"));
541
542     String s10023 = "abstract class A { public abstract short getType(); }\n" +
543                     "A a;\n" +
544                     "switch(a.getType()) {\n" +
545                     "  default:\n" +
546                     "  return 0;\n" +
547                     "}\n" +
548                     "switch(a.getType()) {\n" +
549                     "  case 1:\n" +
550                     "  { return 0; }\n" +
551                     "}";
552     assertEquals("finding switch", 2,
553                  findMatchesCount(s10023, "switch('_a:[exprtype( short )]) { '_statement*; }"));
554
555     String s10025 = "A[] a;\n" +
556                     "A b[];\n" +
557                     "A c;";
558     assertEquals("array types in dcl", 2, findMatchesCount(s10025, "A[] 'a;"));
559     assertEquals("array types in dcl 2", 2, findMatchesCount(s10025, "A 'a[];"));
560
561     String s10027 = "try { a(); } catch(Exception ex) {}\n" +
562                     "try { a(); } finally {}\n" +
563                     "try { a(); } catch(Exception ex) {} finally {} \n";
564     assertEquals("finally matching", 2, findMatchesCount(s10027, "try { a(); } finally {}\n"));
565
566     String s10029 = "for(String a:b) { System.out.println(a); }";
567     assertEquals("for each matching", 1, findMatchesCount(s10029, "for(String a:b) { '_a; }"));
568
569     String s10031 = "try { a(); } catch(Exception ex) {} catch(Error error) { 1=1; }\n" +
570                     "try { a(); } catch(Exception ex) {}";
571     assertEquals("finally matching", 2,
572                  findMatchesCount(s10031, "try { a(); } catch('_Type+ 'Arg+) { '_Statements*; }\n"));
573
574     String s10033 = "return x;\n" +
575                     "return !x;\n" +
576                     "return (x);\n" +
577                     "return (x);\n" +
578                     "return !(x);";
579     assertEquals("Find statement with parenthesized expr",2,findMatchesCount(s10033, "return ('a);"));
580
581     String in = "if (true) {" +
582                 "  System.out.println();" +
583                 "} else {" +
584                 "  System.out.println();" +
585                 "}" +
586                 "if (true) System.out.println();";
587     assertEquals("Find if statement with else", 2, findMatchesCount(in, "if ('_exp) { '_statement*; }"));
588     assertEquals("Find if statement without else", 1,
589                  findMatchesCount(in, "if ('_exp) { '_statement*; } else { '_statement2{0,0}; }"));
590   }
591
592   public void testSearchClass() {
593     assertEquals("no modifier for interface vars", 3, findMatchesCount(s43, "interface '_ { '_T 'T2 = '_T3; } "));
594     assertEquals("different order of access modifiers", 1,
595                  findMatchesCount(s45, "class '_ { final static private '_T 'T2 = '_T3; } "));
596     assertEquals("no access modifier", 2, findMatchesCount(s45, "class '_ { '_T 'T2 = '_T3; } "));
597     assertEquals("type differs with package", 2, findMatchesCount(s47, "class '_ { String '_; }"));
598     assertEquals("reference could differ in package", 1,
599                  findMatchesCount(s49, "class '_ { '_ '_() throws RuntimeException; }"));
600
601     String s51 = "class C extends java.awt.List {} class A extends java.util.List {} class B extends java.awt.List {} ";
602     assertEquals("reference could differ in package 2", 2,
603                  findMatchesCount(s51, "class 'B extends '_C:java\\.awt\\.List {}"));
604     assertEquals("method access modifier", 0, findMatchesCount(s93, " class '_ {private void b() {}}"));
605     assertEquals("method access modifier 2", 1, findMatchesCount(s93, " class '_ {public void b() {}}"));
606     assertEquals("field access modifier", 0, findMatchesCount(s93, " class '_ {protected int field;}"));
607     assertEquals("field access modifier 2", 1, findMatchesCount(s93, " class '_ {private int field;}"));
608
609     final String s127 = "class a { void b() { new c() {}; } }";
610     assertEquals("class finds anonymous class", 2, findMatchesCount(s127, "class 't {}"));
611
612     final String s129 = "class a { public void run() {} }\n" +
613                         "class a2 { public void run() { run(); } }\n" +
614                         "class a3 { public void run() { run(); } }\n" +
615                         "class a4 { public void run(); }";
616
617     assertEquals("empty method finds empty method only", 1,
618                  findMatchesCount(s129, "class 'a { public void run() {} }"));
619     assertEquals("nonempty method finds nonempty method", 2,
620                  findMatchesCount(s129, "class 'a { public void run() { '_statement; } }"));
621     assertEquals("nonempty method finds nonempty method", 4,
622                  findMatchesCount(s129, "class 'a { public void run(); }"));
623
624     final String s133 = "class S {\n" +
625                         "void cc() {\n" +
626                         "        new Runnable() {\n" +
627                         "            public void run() {\n" +
628                         "                f();\n" +
629                         "            }\n" +
630                         "            private void f() {\n" +
631                         "                //To change body of created methods use File | Settings | File Templates.\n" +
632                         "            }\n" +
633                         "        };\n" +
634                         "        new Runnable() {\n" +
635                         "            public void run() {\n" +
636                         "                f();\n" +
637                         "            }\n" +
638                         "            private void g() {\n" +
639                         "                //To change body of created methods use File | Settings | File Templates.\n" +
640                         "            }\n" +
641                         "        };\n" +
642                         "        new Runnable() {\n" +
643                         "            public void run() {\n" +
644                         "                f();\n" +
645                         "            }\n" +
646                         "        };\n" +
647                         "    }\n" +
648                         "    private void f() {\n" +
649                         "        //To change body of created methods use File | Settings | File Templates.\n" +
650                         "    }\n" +
651                         "} ";
652     final String s134 = "new Runnable() {\n" +
653                         "            public void run() {\n" +
654                         "                '_f ();\n" +
655                         "            }\n" +
656                         "            private void '_f ();\n" +
657                         "        }";
658     assertEquals(
659       "complex expr matching",
660       1,
661       findMatchesCount(s133,s134)
662     );
663
664     final String s135 = "abstract class My {\n" +
665                         "    abstract void f();\n" +
666                         "}\n" +
667                         "abstract class My2 {\n" +
668                         "    abstract void f();\n" +
669                         "    void fg() {}\n" +
670                         "}";
671     final String s136 = "class 'm {\n" +
672                         "    void f();\n" +
673                         "    '_type '_method{0,0} ('_paramtype* '_paramname* );\n" +
674                         "}";
675     assertEquals("reject method with 0 max occurence", 1, findMatchesCount(s135,s136));
676
677     final String s137 = "abstract class My {\n" +
678                         "  int a;\n" +
679                         "}\n" +
680                         "abstract class My2 {\n" +
681                         "    Project b;\n" +
682                         "}" +
683                         "abstract class My3 {\n" +
684                         "    Class clazz;"+
685                         "    Project b = null;\n" +
686                         "}" +
687                         "abstract class My {\n" +
688                         "  int a = 1;\n" +
689                         "}\n";
690     assertEquals("reject field with 0 max occurence", 2,
691                  findMatchesCount(s137, "class 'm { Project '_f{0,0} = '_t?; }"));
692
693     final String s139 = "class My { boolean equals(Object o); int hashCode(); }";
694     final String s140 = "class 'A { boolean equals(Object '_o ); int '_hashCode{0,0}:hashCode (); }";
695     assertEquals("reject method with constraint", 0, findMatchesCount(s139,s140));
696
697     final String s139_2 = "class My { boolean equals(Object o); }";
698     assertEquals("reject field with 0 max occurence", 1, findMatchesCount(s139_2,s140));
699
700     final String s141 = "class A { static { a = 10 } }\n" +
701                         "class B { { a = 10; } }\n" +
702                         "class C { { a = 10; } }";
703     assertEquals("static block search", 1, findMatchesCount(s141, "class '_ { static { a = 10; } } "));
704   }
705
706   public void testParameterlessConstructorSearch() {
707     final String s143 = "class A { A() {} };\n" +
708                         "class B { B(int a) {} };\n" +
709                         "class C { C() {} C(int a) {} };\n" +
710                         "class D {}\n" +
711                         "class E {}";
712     assertEquals("parameterless constructor search", 3,
713                  findMatchesCount(s143, "class '_a { '_d{0,0}:[ script( \"__context__.constructor\" ) ]('_b+ '_c+); }"));
714   }
715
716   public void testScriptSearch() {
717     final String source = "package a;" +
718                           "class BX extends java.util.List {" +
719                           "  private static final java.util.List VALUE = new BX();" +
720                           "}" +
721                           "class CX extends java.util.List {" +
722                           "  private static final String S = \"\";" +
723                           "}";
724     // find static final fields whose type is a proper ancestor of the class declaring their fields
725     assertEquals("all variables accessible from script", 1,
726                  findMatchesCount(source,
727                                   "[script(\""                                                         +
728                                   "import com.intellij.psi.util.InheritanceUtil\n"                     +
729                                   "import com.intellij.psi.util.PsiTreeUtil\n"                         +
730                                   "import com.intellij.psi.PsiClass\n"                                 +
731                                   "init != null &&"                                                    + // redundant reference to '_init
732                                   "InheritanceUtil.isInheritor(\n"                                     +
733                                   "        PsiTreeUtil.getParentOfType(variable, PsiClass.class),\n"   + // reference to 'variable
734                                   "        true, \n"                                                   +
735                                   "        Type.type.canonicalText\n"                                  + // reference to '_Type
736                                   ")\n\")]"                                                            +
737                                   "static final '_Type 'variable = '_init;"));
738
739     final String source2 = "class A {" +
740                            "  String s = new String();" +
741                            "  @SuppressWarnings(\"\") int m() {" +
742                            "    n();" +
743                            "    int i = 2+1;" +
744                            "    return i;" +
745                            "  }" +
746                            "  void n() {}" +
747                            "}";
748     assertEquals("type of variables in script are as expected", 1,
749                  findMatchesCount(source2,
750                                   "[script(\"" +
751                                   "import com.intellij.psi.*\n" +
752                                   "__context__ instanceof PsiElement &&" +
753                                   "a instanceof PsiClass &&" +
754                                   "b instanceof PsiTypeElement &&" +
755                                   "c instanceof PsiField &&" +
756                                   "d instanceof PsiNewExpression &&" +
757                                   "e instanceof PsiTypeElement &&" +
758                                   "f instanceof PsiMethod &&" +
759                                   "g instanceof PsiTypeElement &&" +
760                                   "h instanceof PsiLocalVariable &&" +
761                                   "i instanceof PsiPolyadicExpression &&" +
762                                   "j instanceof PsiReferenceExpression &&" +
763                                   "k instanceof PsiMethodCallExpression &&" +
764                                   "l instanceof PsiAnnotation\n" +
765                                   "\")]" +
766                                   "class '_a {" +
767                                   "  '_b '_c = new '_d();" +
768                                   "  @'_l '_e '_f() {" +
769                                   "    '_k();" +
770                                   "    '_g '_h = '_i;" +
771                                   "    return '_j;" +
772                                   "  }" +
773                                   "}"));
774
775     assertEquals("Current variable should be available under own name", 1,
776                  findMatchesCount(source2, "'_a + '_b:[script(\"__log__.info(b)\n__log__.info(__context__)\ntrue\")]"));
777   }
778
779   public void testCheckScriptValidation() {
780     try {
781       findMatchesCount("", "'_b:[script( \"^^^\" )]");
782       fail("Validation does not work");
783     } catch (MalformedPatternException ignored) {}
784   }
785
786   //public void testRelationBetweenVars() {
787   //  final String s1 = "public class Foo {\n" +
788   //                      "    public static final Logger log = Logger.getInstance(Foo.class);\n" +
789   //                      "    public static final Logger log2 = Logger.getInstance(Foo2.class);\n" +
790   //                      "    public static final Logger log3 = Logger.getInstance(Foo2.class);\n" +
791   //                      "}";
792   //  final String s2 = "class '_a { static Logger 'log+ = Logger.getInstance('_b:[script( \"_a != _b\" )].class); }";
793   //  assertEquals(
794   //    "relation between vars in script",
795   //    2,
796   //    findMatchesCount(s1,s2)
797   //  );
798   //}
799
800   public void testExprTypeWithObject() {
801     String s1 = "import java.util.*;\n" +
802                 "class A {\n" +
803                 "  void b() {\n" +
804                 "    Map map = new HashMap();" +
805                 "    class AppPreferences {}\n" +
806                 "    String key = \"key\";\n" +
807                 "    AppPreferences value = new AppPreferences();\n" +
808                 "    map.put(key, value );\n" +
809                 "    map.put(value, value );\n" +
810                 "    map.put(\"key\", value );\n" +
811                 "    map.put(\"key\", new AppPreferences());\n" +
812                 "  }\n" +
813                 "}";
814     String s2 = "'_map:[exprtype( *java\\.util\\.Map )].put('_key:[ exprtype( *Object ) ], '_value:[ exprtype( *AppPreferences ) ]);";
815     assertEquals("expr type with object", 4, findMatchesCount(s1,s2,true));
816   }
817
818   public void testInterfaceImplementationsSearch() {
819     String in = "class A implements Cloneable {\n" +
820                 "    \n" +
821                 "  }\n" +
822                 "  \n" +
823                 "  class B implements Serializable {\n" +
824                 "    \n" +
825                 "  }\n" +
826                 "  \n" +
827                 "  class C implements Cloneable,Serializable {\n" +
828                 "    \n" +
829                 "  }\n" +
830                 "  class C2 implements Serializable,Cloneable {\n" +
831                 "    \n" +
832                 "  }\n" +
833                 "  \n" +
834                 "  class E extends B implements Cloneable {\n" +
835                 "    \n" +
836                 "  }\n" +
837                 "  \n" +
838                 "  class F extends A implements Serializable {\n" +
839                 "    \n" +
840                 "  }\n" +
841                 "  \n" +
842                 "  class D extends C {\n" +
843                 "    \n" +
844                 "  }";
845     assertEquals("search interface within hierarchy", 5,
846                  findMatchesCount(in, "class 'A implements '_B:*Serializable , '_C:*Cloneable {}"));
847   }
848
849   public void testSearchBacktracking() {
850     assertEquals("backtracking greedy regexp", 1, findMatchesCount(s89, "{ '_T*; '_T2*; }"));
851     assertEquals("backtracking greedy regexp 2", 1, findMatchesCount(s89, " { '_T*; '_T2*; '_T3+; } "));
852     assertEquals("backtracking greedy regexp 3", 0, findMatchesCount(s89, " { '_T+; '_T2+; '_T3+; '_T4+; } "));
853     assertEquals("counted regexp (with back tracking)", 1, findMatchesCount(s89, " { '_T{1,3}; '_T2{2}; } "));
854     assertEquals("nongreedy regexp (counted, with back tracking)", 1,
855                  findMatchesCount(s89, " { '_T{1}?; '_T2*?; '_T3+?; } "));
856     assertEquals("nongreedy regexp (counted, with back tracking) 2", 0,
857                  findMatchesCount(s89, " { '_T{1}?; '_T2{1,2}?; '_T3+?; '_T4+?; } "));
858
859     String s1000 = "class A {\n" +
860                    "      void _() {}\n" +
861                    "      void a(String in, String pattern) {}\n" +
862                    "    }";
863     String s1001 = "class '_Class { \n" +
864                    "  '_ReturnType+ 'MethodName+ ('_ParameterType* '_Parameter* );\n" +
865                    "}";
866     assertEquals("handling of no match", 2, findMatchesCount(s1000,s1001));
867   }
868
869   public void testSearchSymbol() {
870     final String s131 = "a.b(); c.d = 1; ";
871     assertEquals("symbol match", 2, findMatchesCount(s131, "'T:b|d"));
872
873     options.setCaseSensitiveMatch(true);
874     final String s129 = "A a = new A();";
875     assertEquals("case sensitive match", 2, findMatchesCount(s129, "'Sym:A"));
876
877     final String s133 = "class C { int a; int A() { a = 1; }} void c(int a) { a = 2; }";
878     final String s134 = "a";
879     assertEquals("find sym finds declaration", 4, findMatchesCount(s133, s134, true, StdFileTypes.JAVA));
880
881     final String s133_2 = "class C { int a() {} int A() { a(1); }}";
882     assertEquals("find sym finds declaration", 2, findMatchesCount(s133_2, s134, true));
883
884     final String in = "class C {" +
885                       "  {" +
886                       "    int i = 0;" +
887                       "    i += 1;" +
888                       "    (i) = 3;" +
889                       "    int j = i;" +
890                       "    i();" +
891                       "  }" +
892                       "  void i() {}" +
893                       "}";
894     assertEquals("Find reads of symbol (including operator assignment)", 2, findMatchesCount(in, "'_:[read]"));
895     assertEquals("Find writes of symbol", 3, findMatchesCount(in, "'_:[write && regex( i )]"));
896
897     final String source = "class A {" +
898                           "  static A a() {};" +
899                           "  void m() {" +
900                           "    A a = A.a();" +
901                           "  }" +
902                           "}";
903     assertEquals("No duplicate results", 4, findMatchesCount(source, "A"));
904   }
905
906   public void testSearchGenerics() {
907     assertEquals("parameterized class match", 2, findMatchesCount(s81, "class '_<'T+> {}"));
908     assertEquals("parameterized instanceof match", 1, findMatchesCount(s81, "'_Expr instanceof '_Type<'_Parameter+>"));
909     assertEquals("parameterized cast match", 1, findMatchesCount(s81, "( '_Type<'_Parameter+> ) '_Expr"));
910     assertEquals("parameterized symbol without variables matching", 2, findMatchesCount(s81, "S<T>"));
911     assertEquals("parameterized definition match", 3, findMatchesCount(s81, "'_Type<'_Parameter+> 'a = '_Init?;"));
912     assertEquals("parameterized method match", 1, findMatchesCount(s81, "class '_ { <'_+> '_Type 'Method('_* '_*); }"));
913     assertEquals("parameterized constraint match", 2, findMatchesCount(s81_2, "class '_<'_+ extends 'res+> {}"));
914
915     String s82_7 = "'Type";
916     assertEquals("symbol matches parameterization", 29, findMatchesCount(s81,s82_7));
917     assertEquals("symbol matches parameterization 2", 7, findMatchesCount(s81_2,s82_7));
918
919     String s81_3 = " class A {\n" +
920                    "  public static <T> Collection<T> unmodifiableCollection(int c) {\n" +
921                    "    return new d<T>(c);\n" +
922                    "  }\n" +
923                    "  static class d<E> implements Collection<E>, Serializable {\n" +
924                    "    public <T> T[] toArray(T[] a)       {return c.toArray(a);}\n" +
925                    "  }\n" +
926                    "}";
927     assertEquals("typed symbol symbol", 2, findMatchesCount(s81_3, "class '_ { <'_+> '_Type 'Method('_* '_*); }"));
928
929     String s81_4="class A<B> { \n" +
930                  "  static <C> void c(D<E> f) throws R<S> {\n" +
931                  "    if ( f instanceof G<H>) {\n" +
932                  "      ((I<G<K>>)l).a();\n" +
933                  "      throw new P<Q>();" +
934                  "    }\n" +
935                  "  }\n" +
936                  "} " +
937                  "class C {\n" +
938                  "  void d(E f) throws Q {\n" +
939                  "    if (g instanceof H) { a.c(); b.d(new A() {}); throw new Exception(((I)k)); }"+
940                  "  }\n" +
941                  "}";
942     assertEquals("typed symbol", 8, findMatchesCount(s81_4, "'T<'_Subst+>"));
943
944     String s81_5 = "class A { HashMap<String, Integer> variable = new HashMap<String, Integer>(\"aaa\");}";
945     String s82_9 = "'_Type<'_GType, '_GType2> '_instance = new '_Type<'_GType, '_GType2>('_Param);";
946     assertEquals("generic vars in new", 1, findMatchesCount(s81_5,s82_9));
947     assertEquals("no exception on searching for diamond operator", 0, findMatchesCount(s81_5, "new 'Type<>('_Param)"));
948     assertEquals("order of parameters matters", 0, findMatchesCount(s81_5, "HashMap<Integer, String>"));
949     assertEquals("order of parameters matters 2", 2, findMatchesCount(s81_5, "HashMap<String, Integer>"));
950
951     String source1 = "class Comparator<T> { private Comparator<String> c; private Comparator d; private Comparator e; }";
952     assertEquals("qualified type should not match 1", 0, findMatchesCount(source1, "java.util.Comparator 'a;"));
953     assertEquals("qualified type should not match 2", 0, findMatchesCount(source1, "java.util.Comparator<String> 'a;"));
954
955     assertEquals("unparameterized type query should match", 3, findMatchesCount(source1, "Comparator 'a;"));
956     assertEquals("parameterized type query should only match parameterized", 1,
957                  findMatchesCount(source1, "Comparator<'_a> 'b;"));
958
959     assertEquals("should find unparameterized only", 2, findMatchesCount(source1, "Comparator<'_a{0,0}> 'b;"));
960
961     String source2 = "class A<@Q T> {}\n" +
962                      "class B<T> {}";
963     assertEquals("find annotated type parameter", 1, findMatchesCount(source2, "class '_A<@Q '_T> {}"));
964
965     // @todo typed vars constrains (super),
966     // @todo generic method invocation
967
968     //String s83 = "class A {} List<A> a; List b;";
969     //String s84 = "'a:List 'c;";
970     //String s84_2 = "'a:List\\<'_\\> 'c;";
971     //String s84_3 = "'a:List(?>\\<'_\\>) 'c;";
972     //
973     //assertEquals(
974     //  "finding list",
975     //  findMatchesCount(s83,s84),
976     //  2
977     //);
978     //
979     //assertEquals(
980     //  "finding list 2",
981     //  findMatchesCount(s83,s84_2),
982     //  1
983     //);
984     //
985     //assertEquals(
986     //  "finding list 3",
987     //  findMatchesCount(s83,s84_3),
988     //  1
989     //);
990   }
991
992   public void testSearchSubstitutions() {
993     final String s15 = "'T;";
994
995     assertEquals("search for parameterized pattern", 2, findMatchesCount(s14_1, s15));
996     assertEquals("search for parameterized pattern 2", 5, findMatchesCount(s14_2, s15));
997
998     options.setRecursiveSearch(false);
999
1000     assertEquals("search for parameterized pattern-non-recursive", 1, findMatchesCount(s14_1, s15));
1001     assertEquals("search for parameterized pattern 2-non-recursive", 2, findMatchesCount(s14_2, s15));
1002
1003     final String s24_2  = "'T['_T2:.*i.* ]";
1004     // typed vars with arrays
1005     assertEquals("typed pattern with array 2-non-recursive", 4, findMatchesCount(s23, s24_2));
1006
1007     options.setRecursiveSearch(true);
1008
1009     assertEquals("search for parameterized pattern 3", 1, findMatchesCount(s14_2, "if('_T) { '_T2; }"));
1010
1011     assertEquals("search for parameterized pattern in field selection", 1,
1012                  findMatchesCount(s17, "'_T1.'_T2.equals('_T3.'_T2);"));
1013
1014     assertEquals("search for parameterized pattern with method call", 1,
1015                  findMatchesCount(s17, "'_T1.'_T2().equals('_T3.'_T2());"));
1016
1017     assertEquals("search for parameterized pattern with method call ep.2", 4,
1018                  findMatchesCount(s17, "'_T1.'_T2"));
1019
1020     assertEquals("search for same var constraint", 1, findMatchesCount(s19, "'_T1 'T2 = ('_T1)'_T3;"));
1021
1022     assertEquals("search for same var constraint for semi anonymous typed vars", 1,
1023                  findMatchesCount(s19, "'_T1 '_T2 = ('_T1)'_T3;"));
1024
1025     assertEquals("search for typed var constraint", 1, findMatchesCount(s22, "'_T1:Aa* 'T2 = ('_T1)'_T3;"));
1026
1027     try {
1028       findMatchesCount(s22, "'_T1:A* 'T2 = ( '_T1:A+ )'_T3;");
1029       fail("search for noncompatible typed var constraint");
1030     } catch(MalformedPatternException ignored) {}
1031
1032     assertEquals("search for same typed var constraint", 1, findMatchesCount(s22, "'_T1:Aa* 'T2 = ( '_T1 )'_T3;"));
1033     assertEquals("typed instanceof", 1, findMatchesCount(s65, " '_T instanceof '_T2:B"));
1034
1035     try {
1036       findMatchesCount(s65, "'_T instanceof");
1037       fail("warn on incomplete instanceof");
1038     } catch (MalformedPatternException e) {
1039       assertEquals("Type expected", e.getMessage());
1040     }
1041
1042     assertEquals("typed pattern with array", 2, findMatchesCount(s23, "'T['_T2:.*i.* ] = '_T3;"));
1043     assertEquals("typed pattern with array 2", 6, findMatchesCount(s23, s24_2));
1044     assertEquals("typed pattern in class name, method name, return type, parameter type and name", 1,
1045                  findMatchesCount(s25, "class 'T:.*Impl { '_T2 '_T3('_T4 '_T5) {\n\n} } "));
1046     assertEquals("finding interface", 1, findMatchesCount(s27, "interface 'T {}"));
1047     assertEquals("anonymous typed vars", 1, findMatchesCount(s29, "class '_ { void '_('_:int '_); } "));
1048     assertEquals("finding class descendants", 2, findMatchesCount(s31, "class '_ extends B {  } "));
1049     assertEquals("interface implementation", 2, findMatchesCount(s33, "class '_ implements B,C {  } "));
1050     assertEquals("different order of fields and methods", 1,
1051                  findMatchesCount(s35, "class '_ { double '_; int '_; int '_() {} void '_() {} } "));
1052     assertEquals("different order in throws", 1, findMatchesCount(s37, "class 'T { '_ '_() throws D,C {} } "));
1053     assertEquals("match of class without extends to class with it", 2, findMatchesCount(s39, "class 'T { } "));
1054     assertEquals("match of class without extends to class with it, ep. 2", 2,
1055                  findMatchesCount(s41, "class '_ { '_T '_T2 = '_T3; } "));
1056     assertEquals("match of class without extends to class with it, ep 3", 4,
1057                  findMatchesCount(s41, "class '_ { '_T '_T2; } "));
1058     assertEquals("match class with fields without initializers", 2,
1059                  findMatchesCount(s41, "class '_ { '_T '_T2 = '_T3{0,0}; } "));
1060     assertEquals("typed reference element", 2, findMatchesCount(s51, "class '_ extends '_ {  }"));
1061     assertEquals("empty name for typed var", 1, findMatchesCount(s59, "interface '_ { void '_(); }"));
1062
1063     final String s64 = " class 'T { public void '_T2:run () {} }";
1064     assertEquals("comparing method with constructor", 1, findMatchesCount(s63,s64));
1065     assertEquals("finding nested class", 2, findMatchesCount(s63_2,s64));
1066     assertEquals("find nested class by special pattern", 1,
1067                  findMatchesCount(s63_2, "class '_ { class 'T { public void '_T2:run () {} } }"));
1068
1069     assertEquals("* regexp for typed var", 5, findMatchesCount(s61, "{ 'T*; }"));
1070     assertEquals("+ regexp for typed var", 4, findMatchesCount(s61, "{ 'T+; }"));
1071     assertEquals("? regexp for typed var", 2, findMatchesCount(s61, "{ 'T?; }"));
1072     assertEquals("cast in method arguments", 1, findMatchesCount(s67, " (VirtualFile)'T"));
1073     assertEquals("searching for static field in static call", 2, findMatchesCount(s69, " System.out "));
1074     assertEquals("searching for static field in static call, 2", 2, findMatchesCount(s69, " java.lang.System.out "));
1075     assertEquals("* regexp for anonymous typed var", 3, findMatchesCount(s61, "{ '_*; }"));
1076     assertEquals("+ regexp for anonymous typed var", 2, findMatchesCount(s61, "{ '_+; }"));
1077     assertEquals("? regexp for anonymous typed var", 2, findMatchesCount(s61, "{ '_?; }"));
1078     assertEquals("statement inside anonymous class", 3, findMatchesCount(s71, " c(); "));
1079     assertEquals("clever regexp match", 2, findMatchesCount(s91, "'T:a"));
1080     assertEquals("clever regexp match 2", 2, findMatchesCount(s91, "'T:b"));
1081     assertEquals("clever regexp match 3", 2, findMatchesCount(s91, "'T:c"));
1082   }
1083
1084   public void testSearchJavaDoc() {
1085     final String s58 = "/** @'T '_T2 */ class '_ { }";
1086     assertEquals("java doc comment in class in file", 1, findMatchesCount(s57,s58,true));
1087
1088     assertEquals("javadoc comment for field", 2, findMatchesCount(s57, "class '_ { /** @serializable '_* */ '_ '_; }"));
1089     assertEquals("javadoc comment for method", 2, findMatchesCount(s57, "class '_ { /** @'T 1.4 */ '_ '_() {} }"));
1090     assertEquals("javadoc comment for method 2", 2, findMatchesCount(s57, "/** @'T 1.4 */ '_t '_m();"));
1091     assertEquals("just javadoc comment search", 4, findMatchesCount(s57, "/** @'T '_T2 */"));
1092
1093     final String s84 = "    /**\n" +
1094                        "     * @hibernate.property\n" +
1095                        "     *  'Property+\n" +
1096                        "     */\n";
1097     assertEquals("XDoclet metadata", 2, findMatchesCount(s83,s84));
1098
1099     final String s84_2 = "    /**\n" +
1100                          "     * @hibernate.property\n" +
1101                          "     *  update=\"fa.se\"\n" +
1102                          "     */\n";
1103     assertEquals("XDoclet metadata 2", 1, findMatchesCount(s83,s84_2));
1104
1105     assertEquals("optional tag value match", 6, findMatchesCount(s57, "/** @'T '_T2? */"));
1106     assertEquals("multiple tags match +", 2, findMatchesCount(s75, " /** @'_tag+ '_value+ */"));
1107     assertEquals("multiple tags match *", 3, findMatchesCount(s75, " /** @'_tag* '_value* */"));
1108     assertEquals("multiple tags match ?", 3, findMatchesCount(s75, " /** @'_tag? '_value? */ class 't {}", true));
1109     assertEquals("no infinite loop on javadoc matching", 1, findMatchesCount(s57, "/** 'Text */ class '_ { }", true));
1110
1111     final String source = "class outer {\n" +
1112                           "  /** bla */\n" +
1113                           "  class One {}\n" +
1114                           "  class Two {}\n" +
1115                           "}";
1116     final String pattern = "class '_A { /** '_Text */class 'B {}}";
1117     assertEquals("match inner class with javadoc", 1, findMatchesCount(source, pattern));
1118   }
1119
1120   public void testNamedPatterns() {
1121     String s133 = "class String1 implements java.io.Serializable { " +
1122                   "private static final long serialVersionUID = -6849794470754667710L;" +
1123                   "private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0];" +
1124                   "}" +
1125                   "class StringBuilder1 implements java.io.Serializable {" +
1126                   "    private void writeObject(java.io.ObjectOutputStream s)\n" +
1127                   "        throws java.io.IOException {\n" +
1128                   "        s.defaultWriteObject();\n" +
1129                   "    }" +
1130                   "private void readObject(java.io.ObjectInputStream s)\n" +
1131                   "        throws java.io.IOException, ClassNotFoundException {\n" +
1132                   "        s.defaultReadObject();\n" +
1133                   "    }" +
1134                   "    static final long serialVersionUID = 4383685877147921099L;" +
1135                   "}";
1136     String s134 = "class '_ implements '_:*Serializable {\n" +
1137                   "  static final long 'VersionField?:serialVersionUID = '_?;\n" +
1138                   "  private static final ObjectStreamField[] '_?:serialPersistentFields = '_?; \n" +
1139                   "  private void '_SerializationWriteHandler?:writeObject (ObjectOutputStream s) throws IOException;\n" +
1140                   "  private void '_SerializationReadHandler?:readObject (ObjectInputStream s) throws IOException, ClassNotFoundException;\n" +
1141                   "  Object '_SpecialSerializationReadHandler?:readResolve () throws ObjectStreamException;" +
1142                   "  Object '_SpecialSerializationWriteHandler?:writeReplace () throws ObjectStreamException;" +
1143                   "}";
1144     assertEquals("serialization match", 2, findMatchesCount(s133,s134));
1145
1146     String s135 = "class SimpleStudentEventActionImpl extends Action { " +
1147                   "  public ActionForward execute(ActionMapping mapping,\n" +
1148                   "         ActionForm _form,\n" +
1149                   "         HttpServletRequest _request,\n" +
1150                   "         HttpServletResponse _response)" +
1151                   "  throws Exception {}" +
1152                   "} " +
1153                   "public class DoEnrollStudent extends SimpleStudentEventActionImpl { }" +
1154                   "public class DoCancelStudent extends SimpleStudentEventActionImpl { }";
1155     String s136 = "public class 'StrutsActionClass extends '_*:Action {" +
1156                   "  public ActionForward '_AnActionMethod:*execute (ActionMapping '_,\n" +
1157                   "                                 ActionForm '_,\n" +
1158                   "                                 HttpServletRequest '_,\n" +
1159                   "                                 HttpServletResponse '_);" +
1160                   "}";
1161     assertEquals("Struts actions", 2, findMatchesCount(s135, s136));
1162
1163     final String s123 = "class NodeFilter {} public class MethodFilter extends NodeFilter {\n" +
1164                         "  private MethodFilter() {}\n" +
1165                         "\n" +
1166                         "  public static NodeFilter getInstance() {\n" +
1167                         "    if (instance==null) instance = new MethodFilter();\n" +
1168                         "    return instance;\n" +
1169                         "  }\n" +
1170                         "  private static NodeFilter instance;\n" +
1171                         "}";
1172     final String s124 = "class 'Class {\n" +
1173                         "  private 'Class('_* '_*) {\n" +
1174                         "   '_*;\n" +
1175                         "  }\n" +
1176                         "  private static '_Class2:* '_Instance;\n" +
1177                         "  static '_Class2 '_GetInstance() {\n" +
1178                         "    '_*;\n" +
1179                         "    return '_Instance;\n" +
1180                         "  }\n" +
1181                         "}";
1182     assertEquals("singleton search", 1, findMatchesCount(s123,s124));
1183
1184     String s1111 = "if (true) { a=1; b=1; } else { a=1; }\n" +
1185                    "if(true) { a=1; } else { a=1; b=1; }\n" +
1186                    "if(true) { a=1; b=2; } else { a = 1; b=2; }";
1187     assertEquals("same multiple name pattern", 1, findMatchesCount(s1111, "if (true) { '_a{1,2}; } else { '_a; }"));
1188   }
1189
1190   public void testHierarchy() {
1191     final String s105 = "class B {} class A extends B { }";
1192     assertEquals("extends match", 1, findMatchesCount(s105, "class '_ extends '_:[ref('T)] {}"));
1193
1194     final String s107 = "interface IA {} interface IB extends IA { } interface IC extends IB {} interface ID extends IC {}" +
1195                         "class A implements IA {} class B extends A { } class C extends B implements IC {} class D extends C {}";
1196     assertEquals("extends navigation match", 2, findMatchesCount(s107, "class '_ extends 'Type:+A {}"));
1197     assertEquals("implements navigation match", 3, findMatchesCount(s107, "class '_ implements 'Type:+IA {}"));
1198
1199     final String s109 = "interface I {} interface I2 extends I {} class A implements I2 {} class B extends A { } class C extends B {} class D { void e() { C c; B b; A a;} }";
1200     assertEquals("extends navigation match in definition", 3, findMatchesCount(s109, "'_:*A '_;"));
1201     assertEquals("implements navigation match in definition 2", 3, findMatchesCount(s109, "'_:*I '_;"));
1202     assertEquals("implements navigation match in definition 2 with nested conditions", 1,
1203                  findMatchesCount(s109, "'_:*[regex( I ) && ref('T)] '_;"));
1204     try {
1205       findMatchesCount(s109, "'_:*[regex( I ) && ref2('T)] '_;");
1206       fail("implements navigation match in definition 2 with nested conditions - incorrect cond");
1207     } catch(UnsupportedPatternException ignored) {}
1208
1209     final String s111 = "interface E {} class A implements E {} class B extends A { int f = 0; } class C extends B {} class D { void e() { C c; B b; A a;} }";
1210     final String s112 = "'_";
1211     assertEquals("symbol match", 17, findMatchesCount(s111,s112));
1212
1213     final String s113 = "class B {int c; void d() {} } int a; B b; a = 1; b.d(); ++a; int c=a; System.out.println(a); " +
1214                         "b.c = 1; System.out.println(b.c); b.c++;";
1215     assertEquals("read symbol match", 11, findMatchesCount(s113, "'_:[read]"));
1216     assertEquals("write symbol match", 5, findMatchesCount(s113, "'_:[write]"));
1217
1218     final String s115 = "class B {} public class C {}";
1219     assertEquals("public modifier for class", 1, findMatchesCount(s115, "public class '_ {}"));
1220
1221     final String s117 = "class A { int b; void c() { int e; b=1; this.b=1; e=5; " +
1222                         "System.out.println(e); " +
1223                         "System.out.println(b); System.out.println(this.b);} }";
1224     assertEquals("fields of class", 4, findMatchesCount(s117, "this.'Field"));
1225     assertEquals("fields of class read", 2, findMatchesCount(s117, "this.'Field:[read]"));
1226     assertEquals("fields of class written", 2, findMatchesCount(s117, "this.'Field:[write]"));
1227
1228     final String s119 = "try { a.b(); } catch(IOException e) { c(); } catch(Exception ex) { d(); }";
1229     assertEquals("catches loose matching", 1, findMatchesCount(s119, "try { '_; } catch('_ '_) { '_; }"));
1230     assertEquals("catches loose matching 2", 0, findMatchesCount(s119, "try { '_; } catch(Throwable '_) { '_; }"));
1231
1232     final String s121 = "class A { private int a; class Inner {} } " +
1233                         "class B extends A { private int a; class Inner2 {} }";
1234     assertEquals("hierarchical matching", 2, findMatchesCount(s121, "class '_ { int '_:* ; }"));
1235     assertEquals("hierarchical matching 2", 4, findMatchesCount(s121, "class '_ { int '_:+hashCode (); }"));
1236     assertEquals("hierarchical matching 3", 2, findMatchesCount(s121, "class '_ { class '_:* {} }"));
1237   }
1238
1239   public void testSearchInCommentsAndLiterals() {
1240     String s1 = "{" +
1241                 "// This is some comment\n" +
1242                 "/* This is another\n comment*/\n" +
1243                 "// Some garbage\n"+
1244                 "/** And now third comment*/\n" +
1245                 "/** Some garbage*/ }";
1246     assertEquals("Comment matching", 3, findMatchesCount(s1, "// 'Comment:[regex( .*(?:comment).* )]"));
1247     assertEquals("Comment matching, 2", 3, findMatchesCount(s1, "/* 'Comment:[regex( .*(?:comment).* )] */"));
1248     assertEquals("Java doc matching", 1, findMatchesCount(s1, "/** 'Comment:[regex( .*(?:comment).* )] */"));
1249
1250     String s4 = "\"'test\", \"another test\", \"garbage\"";
1251     assertEquals("Literal content", 2, findMatchesCount(s4, "\"'test:[regex( .*test.* )]\""));
1252     assertEquals("Literal content with escaping", 1, findMatchesCount(s4, "\"''test\""));
1253
1254     String s7 = "\"aaa\"";
1255     assertEquals("Simple literal content", 1, findMatchesCount(s7, "\"'test:[regex( aaa )]\""));
1256
1257     String s9 = "\" aaa \" \" bbb \" \" ccc ccc aaa\"";
1258     assertEquals("Whole word literal content with alternations", 2,
1259                  findMatchesCount(s9, "\"'test:[regexw( aaa|ccc )]\""));
1260     assertEquals("Whole word literal content", 1, findMatchesCount(s9, "\"'test:[regexw( bbb )]\""));
1261
1262     String s12 = "assert agentInfo != null : \"agentInfo is null\";\n" +
1263                  "assert addresses != null : \"addresses is null\";";
1264     assertEquals("reference to substitution in comment", 2,
1265                  findMatchesCount(s12, "assert '_exp != null : \"'_exp is null\";"));
1266
1267     String s14 = "\"(some text with special chars)\"," +
1268                  "\" some\"," +
1269                  "\"(some)\"";
1270     assertEquals("meta char in literal", 2, findMatchesCount(s14, "\"('a:[regexw( some )])\""));
1271
1272     String s16 = "/**\n" +
1273                  "* Created by IntelliJ IDEA.\n" +
1274                  "* User: cdr\n" +
1275                  "* Date: Nov 15, 2005\n" +
1276                  "* Time: 4:23:29 PM\n" +
1277                  "* To change this template use File | Settings | File Templates.\n" +
1278                  "*/\n" +
1279                  "public class Y {\n" +
1280                  "}";
1281     String s17 = "/**\n" +
1282                  "* Created by IntelliJ IDEA.\n" +
1283                  "* User: '_USER\n" +
1284                  "* Date: '_DATE\n" +
1285                  "* Time: '_TIME\n" +
1286                  "* To change this template use File | Settings | File Templates.\n" +
1287                  "*/\n" +
1288                  "class 'c {\n" +
1289                  "}";
1290     assertEquals("complete comment match", 1, findMatchesCount(s16,s17,true));
1291
1292     String s18 = "public class A {\n" +
1293                  "   private void f(int i) {\n" +
1294                  "       int g=0; //sss\n" +
1295                  "   }\n" +
1296                  "}";
1297     String s19 = "class '_c {\n" +
1298                  "   '_type '_f('_t '_p){\n" +
1299                  "       '_s; // sss\n" +
1300                  "   }\n" +
1301                  "}";
1302     assertEquals("statement match with comment", 1, findMatchesCount(s18,s19));
1303   }
1304
1305   public void testOther() {
1306     assertEquals("optional init match in definition", 4, findMatchesCount(s73, " '_Type 'Var = '_Init?; "));
1307     assertEquals("null match", 0, findMatchesCount(s77, " class 'T:.*aaa {} "));
1308     assertEquals("body of method by block search", 2, findMatchesCount(s79, " { '_T 'T3 = '_T2?; '_*; } "));
1309     assertEquals("first matches, next not", 2, findMatchesCount(s95, " class '_ {private int 'T+:field.* ;}"));
1310
1311     final String s97 = "class A { int c; void b() { C d; } } class C { C() { A a; a.b(); a.c=1; } }";
1312     assertEquals("method predicate match", 1, findMatchesCount(s97, "'_.'_:[ref('T)] ()"));
1313     assertEquals("field predicate match", 1, findMatchesCount(s97, "'_.'_:[ref('T)]"));
1314     assertEquals("dcl predicate match", 1, findMatchesCount(s97, "'_:[ref('T)].'_ ();"));
1315
1316     final String s99 = " char s = '\\u1111';  char s1 = '\\n'; ";
1317     assertEquals("char constants in pattern", 1, findMatchesCount(s99, " char 'var = '\\u1111'; "));
1318     assertEquals("char constants in pattern 2", 1, findMatchesCount(s99, " char 'var = '\\n'; "));
1319
1320     assertEquals("class predicate match (from definition)", 3, findMatchesCount(s97, "'_:[ref('T)] '_;"));
1321
1322     final String s101 = "class A { void b() { String d; String e; String[] f; f.length=1; f.length=1; } }";
1323     assertEquals("distinct match", 1, findMatchesCount(s101, "'_:[ref('T)] '_;"));
1324
1325     String s107 = "class A {\n" +
1326                   "  /* */\n" +
1327                   "  void a() {\n" +
1328                   "  }" +
1329                   "  /* */\n" +
1330                   "  int b = 1;\n" +
1331                   "  /*" +
1332                   "   *" +
1333                   "   */\n" +
1334                   "   class C {}" +
1335                   "}";
1336     String s108 = "  /*" +
1337                   "   *" +
1338                   "   */";
1339     assertEquals("finding comments without typed var", 1, findMatchesCount(s107,s108));
1340
1341     String s109 = "class A { void b(); int b(int c); char d(char e); }\n" +
1342                   "A a; a.b(1); a.b(2); a.b(); a.d('e'); a.d('f'); a.d('g');";
1343     assertEquals("caring about method return type", 2, findMatchesCount(s109, "'_a.'_b:[exprtype( int ) ]('_c*);"));
1344
1345     String s111 = "class A { void getManager() { getManager(); } };\n" +
1346                   "class B { void getManager() { getManager(); getManager(); } };";
1347     assertEquals("caring about missing qualifier type", 2, findMatchesCount(s111, "'Instance?:[exprtype( B )].getManager()"));
1348     assertEquals("static query should not match instance method", 0, findMatchesCount(s111, "'Instance?:[regex( B )].getManager()"));
1349     assertEquals("static query should not match instance method 2", 0, findMatchesCount(s111, "B.getManager()"));
1350
1351     String s113 = "class A { static void a() { a(); }}\n" +
1352                   "class B { static void a() { a(); a(); }}\n";
1353     assertEquals("should care about implicit class qualifier", 2, findMatchesCount(s113, "'_Q?:[regex( B )].a()"));
1354     assertEquals("should match simple implicit class qualifier query", 2, findMatchesCount(s113, "B.a()"));
1355     assertEquals("instance query should not match static method", 0, findMatchesCount(s113, "'_Q?:[exprtype( B )].a()"));
1356
1357     String s115 = "class A { int a; int f() { return a; }}\n" +
1358                   "class B { int a; int g() { return a + a; }}\n";
1359     assertEquals("should care about implicit instance qualifier", 2, findMatchesCount(s115, "'_Instance?:[exprtype( B )].a"));
1360     assertEquals("should not match instance method", 0, findMatchesCount(s115, "A.a"));
1361
1362     String s117 = "class A { static int a; static int f() { return a; }}\n" +
1363                   "class B { static int a; static int g() { return a + a; }}\n";
1364     assertEquals("should care about implicit class qualifier for field", 2, findMatchesCount(s117, "'_Q?:[regex( B )].a"));
1365
1366     // b) hierarchy navigation support
1367     // c) or search support
1368
1369     // e) xml search (down-up, nested query), navigation from xml representation <-> java code
1370     // f) impl data conversion (jdk 1.5 style) <-> other from (replace support)
1371
1372     // Directions:
1373     // @todo different navigation on sub/supertyping relation (fixed depth), methods implementing interface,
1374     // g.  like predicates
1375     // i. performance
1376     // more context for top level classes, difference with interface, etc
1377
1378     // global issues:
1379     // @todo matches out of context
1380     // @todo proper regexp support
1381
1382     // @todo define strict equality of the matches
1383     // @todo search for field selection retrieves packages also
1384   }
1385
1386   public void testFQNInPatternAndVariableConstraints() {
1387     String s1 = "import java.awt.List;\n" +
1388                 "class A { List l; }";
1389     String s2 = "class '_ { 'Type:java\\.util\\.List '_Field; }";
1390     assertEquals("No matches for qualified class", 0, findMatchesCount(s1, s2, true));
1391
1392     String s1_2 = "import java.util.List;\n" +
1393                   "class A { List l; }";
1394     assertEquals("Matches for qualified class", 1, findMatchesCount(s1_2, s2, true));
1395
1396     String s3 = "import java.util.ArrayList;\n" +
1397                 "class A { ArrayList l; }";
1398     assertEquals("Matches for qualified class in hierarchy", 1,
1399                  findMatchesCount(s3, "class '_ { 'Type:*java\\.util\\.Collection '_Field; }", true));
1400
1401     String s5 = "import java.util.List;\n" +
1402                 "class A { { List l = new List(); l.add(\"1\"); }  }";
1403     assertEquals("Matches for qualified expr type in hierarchy", 2,
1404                  findMatchesCount(s5, "'a:[exprtype( *java\\.util\\.Collection )]", true));
1405
1406     String s6 = "'a:[exprtype( java\\.util\\.List )]";
1407     assertEquals("Matches for qualified expr type", 2, findMatchesCount(s5, s6, true));
1408
1409     String s5_2 = "import java.awt.List;\n" +
1410                   "class A { { List l = new List(); l.add(\"1\"); } }";
1411     assertEquals("No matches for qualified expr type", 0, findMatchesCount(s5_2, s6, true));
1412
1413     String s6_3 = "java.util.List '_a = '_b?;";
1414     assertEquals("Matches for qualified var type in pattern", 1, findMatchesCount(s5, s6_3, true));
1415     assertEquals("No matches for qualified var type in pattern", 0, findMatchesCount(s5_2, s6_3, true));
1416
1417     String s7 = "import java.util.List;\n" +
1418                 "class A extends List { }";
1419
1420     String s8 = "class 'a extends java.util.List {}";
1421     assertEquals("Matches for qualified type in pattern", 1, findMatchesCount(s7, s8, true));
1422
1423     String s7_2 = "import java.awt.List;\n" +
1424                   "class A extends List {}";
1425     assertEquals("No matches for qualified type in pattern", 0, findMatchesCount(s7_2, s8, true));
1426
1427     String s9 = "String.intern(\"1\");\n" +
1428                 "java.util.Collections.sort(null);" +
1429                 "java.util.Collections.sort(null);";
1430     assertEquals("FQN in class name",1,
1431                  findMatchesCount(s9, "java.lang.String.'_method ( '_params* )", false));
1432   }
1433
1434   public void testAnnotations() throws Exception {
1435     String s1 = "@MyBean(\"\")\n" +
1436                 "@MyBean2(\"\")\n" +
1437                 "public class TestBean {}\n" +
1438                 "@MyBean2(\"\")\n" +
1439                 "@MyBean(value=\"\")\n" +
1440                 "public class TestBean2 {}\n" +
1441                 "public class TestBean3 {}\n" +
1442                 "@MyBean(\"a\")\n" +
1443                 "@MyBean2(\"a\")\n" +
1444                 "public class TestBean4";
1445     String s2 = "@MyBean(\"\")\n" +
1446                 "@MyBean2(\"\")\n" +
1447                 "public class '_a {}\n";
1448
1449     assertEquals("Simple find annotated class",2,findMatchesCount(s1,s2,false));
1450     assertEquals("Match value of anonymous name value pair 1", 1, findMatchesCount(s1, "@MyBean(\"a\") class '_a {}"));
1451     assertEquals("Match value of anonymous name value pair 2", 2, findMatchesCount(s1, "@MyBean(\"\") class '_a {}"));
1452
1453     String s3 = "@VisualBean(\"????????? ?????????? ? ??\")\n" +
1454                 "public class TestBean\n" +
1455                 "{\n" +
1456                 "    @VisualBeanField(\n" +
1457                 "            name = \"??? ????????????\",\n" +
1458                 "            initialValue = \"?????????????\"\n" +
1459                 "            )\n" +
1460                 "    public String user;\n" +
1461                 "\n" +
1462                 "    @VisualBeanField(\n" +
1463                 "            name = \"??????\",\n" +
1464                 "            initialValue = \"\",\n" +
1465                 "            fieldType = FieldTypeEnum.PASSWORD_FIELD\n" +
1466                 "            )\n" +
1467                 "    public String password;\n" +
1468                 "\n" +
1469                 "    @VisualBeanField(\n" +
1470                 "            initialValue = \"User\",\n" +
1471                 "            name = \"????? ???????\",\n" +
1472                 "            name = \"Second name\",\n" +
1473                 "            fieldType = FieldTypeEnum.COMBOBOX_FIELD,\n" +
1474                 "            comboValues = {\n" +
1475                 "               @ComboFieldValue(\"Administrator\"),\n" +
1476                 "               @ComboFieldValue(\"User\"),\n" +
1477                 "               @ComboFieldValue(\"Guest\")}\n" +
1478                 "            )    \n" +
1479                 "    public String accessRights;\n" +
1480                 "    \n" +
1481                 "    public String otherField;\n" +
1482                 "}";
1483     String s4 = "class '_a {\n" +
1484                 "  @'_Annotation+ ( 'AnnotationMember*:name = '_AnnotationValue* )\n" +
1485                 "  String '_field* ;\n" +
1486                 "}";
1487     assertEquals("Find annotation members of annotated field class",4,findMatchesCount(s3,s4,false));
1488
1489     String s4_2 = "class '_a {\n" +
1490                   "  @'_Annotation+ ()\n" +
1491                   "  String 'field* ;\n" +
1492                   "}";
1493     assertEquals("Find annotation fields",3,findMatchesCount(s3,s4_2,false));
1494
1495     String s5 = "class A {" +
1496                 "  @NotNull private static Collection<PsiElement> resolveElements(final PsiReference reference, final Project project) {}\n" +
1497                 "  @NotNull private static Collection resolveElements2(final PsiReference reference, final Project project) {}\n" +
1498                 "}";
1499
1500     assertEquals("Find annotated methods",2,
1501                  findMatchesCount(s5, "class '_c {@NotNull '_rt 'method* ('_pt* '_p*){ '_inst*; } }"));
1502     assertEquals("Find annotated methods, 2",2,
1503                  findMatchesCount(s5, "class '_c {@'_:NotNull '_rt 'method* ('_pt* '_p*){ '_inst*; } }"));
1504
1505     String s7 = "class A { void message(@NonNls String msg); }\n" +
1506                 "class B { void message2(String msg); }\n" +
1507                 "class C { void message2(String msg); }";
1508     assertEquals("Find not annotated methods",2,findMatchesCount(s7, "class '_A { void 'b( @'_Ann{0,0}:NonNls String  '_); }"));
1509
1510     String s9 = "class A {\n" +
1511                 "  Object[] method1() {}\n" +
1512                 "  Object method1_2() {}\n" +
1513                 "  Object method1_3() {}\n" +
1514                 "  Object method1_4() {}\n" +
1515                 "  @MyAnnotation Object[] method2(int a) {}\n" +
1516                 "  @NonNls Object[] method3() {}\n" +
1517                 "}";
1518     assertEquals("Find not annotated methods, 2",2,
1519                  findMatchesCount(s9, "class '_A { @'_Ann{0,0}:NonNls '_Type:Object\\[\\] 'b+( '_pt* '_p* ); }"));
1520     assertEquals("Find not annotated methods, 2",2,
1521                  findMatchesCount(s9, "class '_A { @'_Ann{0,0}:NonNls '_Type [] 'b+( '_pt* '_p* ); }"));
1522     assertEquals("Find not annotated methods, 2",2,
1523                  findMatchesCount(s9, "class '_A { @'_Ann{0,0}:NonNls '_Type:Object [] 'b+( '_pt* '_p* ); }"));
1524
1525     String s11 = "class A {\n" +
1526                  "@Foo(value=baz) int a;\n" +
1527                  "@Foo(value=baz2) int a2;\n" +
1528                  "@Foo(value=baz2) int a3;\n" +
1529                  "@Foo(value2=baz3) int a3;\n" +
1530                  "@Foo(value2=baz3) int a3;\n" +
1531                  "@Foo(value2=baz3) int a3;\n" +
1532                  "@Foo(value2=baz4) int a3;\n" +
1533                  "}";
1534     assertEquals("Find anno parameter value",1,findMatchesCount(s11, "@Foo(value=baz) int 'a;"));
1535     assertEquals("Find anno parameter value",2,findMatchesCount(s11, "@Foo(value='baz:baz2 ) int '_a;"));
1536     assertEquals("Find anno parameter value",3,findMatchesCount(s11, "@Foo('value:value2 = baz3 ) int '_a;"));
1537     assertEquals("Find anno parameter value",3,findMatchesCount(s11, "@Foo('value:value2 = '_baz3:baz3 ) int '_a;"));
1538     assertEquals("Find anno parameter value",0,findMatchesCount(s11, "@Foo('value:value2 = '_baz3:baz ) int '_a;"));
1539     assertEquals("Find anno parameter value",4,findMatchesCount(s11, "@Foo('value:value2 = '_baz3 ) int '_a;"));
1540     assertEquals("Find anno parameter value",4,findMatchesCount(s11, "@Foo('value:value2 = ) int '_a;"));
1541
1542     String source1 = "class A {" +
1543                      "  void m() {" +
1544                      "    new @B Object();" +
1545                      "  }" +
1546                      "}";
1547     assertEquals("Find annotated new expression", 1, findMatchesCount(source1, "new Object()"));
1548     assertEquals("Find annotated new expression", 1, findMatchesCount(source1, "new @B Object()"));
1549     assertEquals("Find annotated new expression", 0, findMatchesCount(source1, "new @C Object()"));
1550
1551     String source2 = "@X\n" +
1552                      "class A {\n" +
1553                      "  @Y int value;" +
1554                      "  @Y int void m(@Z int i) {\n" +
1555                      "    return 1;\n" +
1556                      "  }\n" +
1557                      "}\n";
1558     assertEquals("Find all annotations", 4, findMatchesCount(source2, "@'_Annotation"));
1559
1560     String source3 = "class A<@HH T> extends @HH Object {\n" +
1561                      "  @HH final String s = (@HH String) new @HH Object();\n" +
1562                      "  final String t = (String) new Object();\n" +
1563                      "  Map<@HH String, @HH List<@HH String>> map;\n" +
1564                      "}\n";
1565     assertEquals("Find annotated casts", 1, findMatchesCount(source3, "(@'_A 'Cast) '_Expression"));
1566     assertEquals("Find annotated new expressions", 1, findMatchesCount(source3, "new @'_A 'Type()"));
1567     assertEquals("Find all annotations 2", 8, findMatchesCount(source3, "@'_Annotation"));
1568
1569     // package-info.java
1570     final String source4 = "/**\n" +
1571                            " * documentation\n" +
1572                            " */\n" +
1573                            "@Deprecated\n" +
1574                            "package one.two;";
1575     assertEquals("Find annotation on package statement", 1, findMatchesCount(source4, "@'_Annotation", true));
1576
1577     final String source5 ="class A {" +
1578                           "  boolean a(Object o) {" +
1579                           "    return o instanceof @HH String;" +
1580                           "  }" +
1581                           "}";
1582     assertEquals("Find annotation on instanceof expression", 1, findMatchesCount(source5, "'_a instanceof @HH String"));
1583     assertEquals("Match annotation correctly on instanceof expression", 0, findMatchesCount(source5, "'_a instanceof @GG String"));
1584   }
1585
1586   public void testBoxingAndUnboxing() {
1587     String s1 = " class A { void b(Integer i); void b2(int i); void c(int d); void c2(Integer d); }\n" +
1588                 "A a;\n" +
1589                 "a.b2(1)\n;" +
1590                 "a.b2(1)\n;" +
1591                 "a.b(1)\n;" +
1592                 "a.b( new Integer(0) )\n;" +
1593                 "a.b( new Integer(0) )\n;" +
1594                 "a.c(new Integer(2));\n" +
1595                 "a.c(new Integer(3));\n" +
1596                 "a.c2(new Integer(3));\n" +
1597                 "a.c(3);\n" +
1598                 "Integer i = 4;\n" +
1599                 "int j = Integer.valueOf(4);\n";
1600
1601     assertEquals("Find boxing in method call",1,
1602                  findMatchesCount(s1, "a.'b('_Params:[formal( Integer ) && exprtype( int ) ])", false));
1603     assertEquals("Find unboxing in method call",2,
1604                  findMatchesCount(s1, "a.c('_Params:[formal( int ) && exprtype( Integer ) ])", false));
1605     assertEquals("Find any boxing", 2, findMatchesCount(s1, "'_a:[formal( Integer ) && exprtype( int ) ]"));
1606     assertEquals("Find any unboxing", 3, findMatchesCount(s1, "'_a:[formal( int ) && exprtype( Integer ) ]"));
1607   }
1608
1609   public void testCommentsInDclSearch() {
1610     String s1 = "class A {\n" +
1611                 "  int a; // comment\n" +
1612                 "  char b;\n" +
1613                 "  int c; // comment2\n" +
1614                 "}";
1615     assertEquals("Find field by dcl with comment",2,findMatchesCount(s1, "'_Type '_Variable = '_Value?; //'Comment"));
1616
1617     String s1_2 = "class A {\n" +
1618                   "  // comment\n" +
1619                   "  int a;\n" +
1620                   "  char b;\n" +
1621                   "  // comment2\n" +
1622                   "  int c;\n" +
1623                   "}";
1624     String s2_2 = "//'Comment\n" +
1625                   "'_Type '_Variable = '_Value?;";
1626     assertEquals("Find field by dcl with comment 2",2,findMatchesCount(s1_2,s2_2));
1627   }
1628
1629   public void testSearchingEmptyModifiers() {
1630     String s1 = "class A {\n" +
1631                 "  int a;\n" +
1632                 "  private char b;\n" +
1633                 "  private char b2;\n" +
1634                 "  public int c;\n" +
1635                 "  public int c2;\n" +
1636                 "}";
1637     assertEquals("Finding package-private dcls",1,
1638                  findMatchesCount(s1, "@Modifier(\"packageLocal\") '_Type '_Variable = '_Value?;"));
1639     assertEquals("Finding package-private dcls",3,
1640                  findMatchesCount(s1, "@Modifier({\"packageLocal\",\"private\"}) '_Type '_Variable = '_Value?;"));
1641     try {
1642       findMatchesCount(s1, "@Modifier({\"PackageLocal\",\"private\"}) '_Type '_Variable = '_Value?;");
1643       fail("Finding package-private dcls");
1644     } catch(MalformedPatternException ignored) {}
1645
1646     String s3 = "class A {\n" +
1647                 "  int a;\n" +
1648                 "  static char b;\n" +
1649                 "  static char b2;\n" +
1650                 "}";
1651     assertEquals("Finding instance fields",1,
1652                  findMatchesCount(s3, "@Modifier(\"Instance\") '_Type '_Variable = '_Value?;"));
1653     assertEquals("Finding all fields",3,
1654                  findMatchesCount(s3, "@Modifier({\"static\",\"Instance\"}) '_Type '_Variable = '_Value?;"));
1655
1656     String s5 = "class A {}\n" +
1657                 "abstract class B {}\n" +
1658                 "final class C {}\n" +
1659                 "class D {}";
1660     assertEquals("Finding instance classes",3,findMatchesCount(s5, "@Modifier(\"Instance\") class 'Type {}"));
1661     assertEquals("Finding all classes",4,
1662                  findMatchesCount(s5, "@Modifier({\"abstract\",\"final\",\"Instance\"}) class 'Type {}"));
1663   }
1664
1665   public void testSearchTransientFieldsWithModifier() {
1666     String source =
1667       "public class TestClass {\n" +
1668       "  transient private String field1;\n" +
1669       "  transient String field2;\n" +
1670       "  String field3;\n" +
1671       "}";
1672     assertEquals("Finding package-private transient fields", 1,
1673                  findMatchesCount(source, "transient @Modifier(\"packageLocal\") '_Type '_Variable = '_Value?;"));
1674   }
1675
1676   public void test() {
1677     String s1 = "if (LOG.isDebugEnabled()) {\n" +
1678                 "  int a = 1;\n" +
1679                 "  int a = 1;\n" +
1680                 "}";
1681     String s2 = "if ('_Log.isDebugEnabled()) {\n" +
1682                 "  '_ThenStatement;\n" +
1683                 "  '_ThenStatement;\n" +
1684                 "}";
1685     assertEquals("Comparing declarations",1,findMatchesCount(s1,s2));
1686   }
1687
1688   public void testFindStaticMethodsWithinHierarchy() {
1689     String s1 = "class A {}\n" +
1690                 "class B extends A { static void foo(); }\n" +
1691                 "class B2 extends A { static void foo(int a); }\n" +
1692                 "class B3 extends A { static void foo(int a, int b); }\n" +
1693                 "class C { static void foo(); }\n" +
1694                 "B.foo();\n" +
1695                 "B2.foo(1);\n" +
1696                 "B3.foo(2,3);\n" +
1697                 "C.foo();";
1698     assertEquals("Find static methods within expr type hierarchy", 3,
1699                  findMatchesCount(s1, "'_Instance:[regex( *A )].'_Method:[regex( foo )] ( '_Params* )"));
1700   }
1701
1702   public void testFindClassesWithinHierarchy() {
1703     String s1 = "class A implements I {}\n" +
1704                 "interface I {}\n" +
1705                 "class B extends A implements I { }\n" +
1706                 "class B2 implements I  { }\n" +
1707                 "class B3 extends A { }\n" +
1708                 "class C extends B2 { static void foo(); }\n";
1709     assertEquals("Find class within type hierarchy with not", 1,
1710                  findMatchesCount(s1, "class '_ extends '_Extends:[!regex( *A )] implements '_Implements:[regex( I )] {}"));
1711     assertEquals("Find class within type hierarchy with not, 2", 1,
1712                  findMatchesCount(s1, "class '_ extends '_Extends:[!regex( *A )]{}"));
1713   }
1714
1715   public void testFindTryWithoutProperFinally() {
1716     String s1 = "try {\n" +
1717                 "  conn = 1;\n" +
1718                 "} finally {\n" +
1719                 "  conn.close();\n" +
1720                 "}\n" +
1721                 "try {\n" +
1722                 "  conn = 1;\n" +
1723                 "} finally {\n" +
1724                 "  int a = 1;\n" +
1725                 "}\n" +
1726                 "try {\n" +
1727                 "  conn = 1;\n" +
1728                 "} finally {\n" +
1729                 "  int a = 1;\n" +
1730                 "}";
1731     String s2 = "try { '_StatementBefore*; '_Dcl:[regex( conn = 1 )]; '_StatementAfter*; } finally { '_Finally*:[!regex( .*conn.* ) ]; }";
1732     assertEquals("FindTryWithoutProperFinally", 2, findMatchesCount(s1,s2));
1733   }
1734
1735   public void testBug() {
1736     String s1 = "public class DiallingNumber extends DataGroup\n" + "{\n" + "    protected static byte [] CLEAR = { };\n" + "\n" +
1737                 "    private static DataItemTemplate template;\n" + "\n" + "\tprotected DataTemplate createDefaultTemplate()\n" + "\t{\n" +
1738                 "        return null;\n" + "    }\n" + "}";
1739     String s2 = "class '_Class {\n" + "    static '_FieldType '_FieldName:.*template.* = '_FieldInitial?;\n" +
1740                 "    '_RetType createDefaultTemplate() { '_Statements*; }\n" + "\t'_Content*\n" + "}";
1741     assertEquals("Bug in class matching", 1, findMatchesCount(s1,s2));
1742   }
1743
1744   //public void testFindFieldUsageByQName() {
1745   //  String s1 = "{ class A { int b; { b = 1; } } class B extends A { { this.b = 2} } { B i; i.b = 3; } }";
1746   //  String s2 = "A.b";
1747   //  assertEquals( 3, findMatchesCount(s1,s2));
1748   //}
1749   //
1750   //public void testFindMethodUsageByQName() {
1751   //  String s1 = "{ class A { void b(int a) {} { b(1); } } class B extends A { { this.b(2); } } { B i; i.b(3); } }";
1752   //  String s2 = "A.b";
1753   //  assertEquals( 3, findMatchesCount(s1,s2));
1754   //}
1755
1756   @SuppressWarnings("unused")
1757   public void _testStaticInstanceInitializers() {
1758     String s1 = "public class DiallingNumber {\n static { int a = 1; } static { int b = 1; } { int c = 2; }}";
1759     assertEquals("Static / instance initializers", 2, findMatchesCount(s1, "class '_Class { static { 't*; } }"));
1760     assertEquals("Static / instance initializers", 1,
1761                  findMatchesCount(s1, "class '_Class { @Modifier(\"Instance\") { 't*; } }"));
1762     assertEquals("Static / instance initializers", 3, findMatchesCount(s1, "class '_Class { { 't*; } }"));
1763   }
1764
1765   @NotNull
1766   @Override
1767   protected String getTestDataPath() {
1768     return PlatformTestUtil.getCommunityPath() + "/platform/structuralsearch/testData/java/";
1769   }
1770
1771   public void testDoNotFindReturn() throws IOException {
1772     String s1 = loadFile(getTestName(false) + ".java");
1773     String s2 = "ApplicationManager.getApplication().runReadAction(new Runnable() {\n" +
1774                 "      public void run() {\n" +
1775                 "        't*:[ !regex( .*return.* ) ];\n" +
1776                 "    }});";
1777     assertEquals(0, findMatchesCount(s1,s2));
1778   }
1779
1780   public void testDownUpMatch() {
1781     String s1 = "class A {\n" +
1782                 "  int bbb(int c, int ddd, int eee) {\n" +
1783                 "    int a = 1;\n" +
1784                 "    try { int b = 1; } catch(Type t) { a = 2; } catch(Type2 t2) { a = 3; }\n" +
1785                 "  }\n" +
1786                 "}";
1787
1788     final List<PsiVariable> vars = new ArrayList<>();
1789     @SuppressWarnings("deprecation") final PsiFile file = PsiFileFactory.getInstance(getProject()).createFileFromText("_.java", s1);
1790
1791     //noinspection AnonymousInnerClassMayBeStatic
1792     file.acceptChildren(new JavaRecursiveElementWalkingVisitor() {
1793       @Override public void visitVariable(final PsiVariable variable) {
1794         super.visitVariable(variable);
1795         vars.add(variable);
1796       }
1797     });
1798
1799     assertEquals(7, vars.size());
1800
1801     Matcher testMatcher = new Matcher(getProject());
1802     MatchOptions options = new MatchOptions();
1803     options.setSearchPattern("try  { '_st*; } catch('_Type 't+) { '_st2*; }");
1804     MatcherImplUtil.transform(options);
1805     options.setFileType(StdFileTypes.JAVA);
1806
1807     List<MatchResult> results = new ArrayList<>();
1808     for(PsiVariable var:vars) {
1809       final List<MatchResult> matchResult = testMatcher.matchByDownUp(var, options);
1810       results.addAll(matchResult);
1811       assertTrue((var instanceof PsiParameter && var.getParent() instanceof PsiCatchSection && !matchResult.isEmpty()) ||
1812                  matchResult.isEmpty());
1813     }
1814
1815     assertEquals(2, results.size());
1816     MatchResult result = results.get(0);
1817     assertEquals("t", result.getMatchImage());
1818
1819     result = results.get(1);
1820     assertEquals("t2", result.getMatchImage());
1821
1822     results.clear();
1823
1824     options.clearVariableConstraints();
1825     options.setSearchPattern("try  { '_st*; } catch('Type:Type2 '_t) { '_st2*; }");
1826     MatcherImplUtil.transform(options);
1827
1828     for(PsiVariable var:vars) {
1829       final PsiTypeElement typeElement = var.getTypeElement();
1830       final List<MatchResult> matchResult = testMatcher.matchByDownUp(typeElement, options);
1831       results.addAll(matchResult);
1832       assertTrue((var instanceof PsiParameter && var.getParent() instanceof PsiCatchSection && !matchResult.isEmpty()) ||
1833                  matchResult.isEmpty());
1834     }
1835
1836     assertEquals(1, results.size());
1837
1838     result = results.get(0);
1839     assertEquals("Type2", result.getMatchImage());
1840   }
1841
1842   @SuppressWarnings("unused")
1843   public void _testContainsPredicate() {
1844     String s1 = "{{\n" +
1845                 "  int a;\n" +
1846                 "  a = 1;\n" +
1847                 "}\n" +
1848                 "{\n" +
1849                 "  int b = 1;\n" +
1850                 "  b = 1;\n" +
1851                 "}\n" +
1852                 "{\n" +
1853                 "  int c = 2;\n" +
1854                 "  c = 2;\n" +
1855                 "}}";
1856     assertEquals(2, findMatchesCount(s1, "{ '_a*:[contains( \"'type '_a = '_b;\" )]; }"));
1857     assertEquals(1, findMatchesCount(s1, "{ '_a*:[!contains( \"'_type '_a = '_b;\" )]; }"));
1858   }
1859
1860   public void testWithinPredicate() {
1861     String s1 = "if (true) {\n" +
1862                 "  int a = 1;\n" +
1863                 "}\n" +
1864                 "if (true) {\n" +
1865                 "  int b = 1;\n" +
1866                 "}\n" +
1867                 "while(true) {\n" +
1868                 "  int c = 2;\n" +
1869                 "}";
1870     String s2 = "[within( \"if ('_a) { '_st*; }\" )]'_type 'a = '_b;";
1871     assertEquals(2,findMatchesCount(s1, s2));
1872
1873     String s2_2 = "[!within( \"if ('_a) { '_st*; }\" )]'_type 'a = '_b;";
1874     assertEquals(1,findMatchesCount(s1, s2_2));
1875
1876     String s3 = "if (true) {\n" +
1877                 "  if (true) return;\n" +
1878                 "  int a = 1;\n" +
1879                 "}\n" +
1880                 "else if (true) {\n" +
1881                 "  int b = 2;\n" +
1882                 "  return;\n" +
1883                 "}\n" +
1884                 "int c = 3;\n";
1885     assertEquals(2,findMatchesCount(s3, s2));
1886     assertEquals(1,findMatchesCount(s3, s2_2));
1887   }
1888
1889   public void testWithinPredicate2() {
1890     String s3 = "class C {\n" +
1891                 "  void aaa() {\n" +
1892                 "        LOG.debug(1);\n" +
1893                 "        LOG.debug(2);\n" +
1894                 "        LOG.debug(3);\n" +
1895                 "        LOG.debug(4);\n" +
1896                 "        LOG.debug(5);\n" +
1897                 "        if (true) {\n" +
1898                 "            LOG.debug(6);\n" +
1899                 "        }\n" +
1900                 "        if (true) LOG.debug(7);\n" +
1901                 "        if (true) { int 1 = 1; } else { LOG.debug(8); }\n" +
1902                 "        if (true) {\n" +
1903                 "          if (true) {}\n" +
1904                 "          if (true) {}\n" +
1905                 "        } else{\n" +
1906                 "          LOG.debug(9);\n" +
1907                 "        }" +
1908                 "    }" +
1909                 "}";
1910     String s4 = "[!within( \"if('_a) { 'st*; }\" )]LOG.debug('_params*);";
1911
1912     assertEquals(7,findMatchesCount(s3, s4));
1913   }
1914
1915   public void testMultiStatementPatternWithTypedVariable() throws Exception {
1916     String s = "Integer i;\ni.valueOf();";
1917     assertEquals(1, findMatchesCount(s, "Integer '_i;\n'_i.valueOf();"));
1918
1919     String s_2 = "Integer i;\nint a = 1;\ni.valueOf();";
1920     assertEquals(1, findMatchesCount(s_2, "Integer '_i;\n'_st; '_i.valueOf();"));
1921
1922     String s2_3 = "Integer '_i;\n'_st*; '_i.valueOf();";
1923     assertEquals(1, findMatchesCount(s_2, s2_3));
1924     assertEquals(1, findMatchesCount(s, s2_3));
1925   }
1926
1927   public void testFindAnnotationDeclarations() throws Exception {
1928     String s = "interface Foo {} interface Bar {} @interface X {}";
1929     String s2 = "@interface 'x {}";
1930
1931     assertEquals(1, findMatchesCount(s,s2));
1932   }
1933
1934   public void testFindEnums() throws Exception {
1935     String s = "class Foo {} class Bar {} enum X {}";
1936     String s2 = "enum 'x {}";
1937
1938     assertEquals(1, findMatchesCount(s,s2));
1939   }
1940
1941   public void testFindDeclaration() throws Exception {
1942     String s = "public class F {\n" +
1943                "  static Category cat = Category.getInstance(F.class.getName());\n" +
1944                "  Category cat2 = Category.getInstance(F.class.getName());\n" +
1945                "  Category cat3 = Category.getInstance(F.class.getName());\n" +
1946                "}";
1947     String s2 = "static '_Category '_cat = '_Category.getInstance('_Arg);";
1948
1949     assertEquals(1, findMatchesCount(s,s2));
1950   }
1951
1952   public void testFindMethodCallWithTwoOrThreeParameters() {
1953     String source = "{ String.format(\"\"); String.format(\"\", 1); String.format(\"\", 1, 2); String.format(\"\", 1, 2, 3); }";
1954     String pattern = "'_Instance.'_MethodCall('_Parameter{2,3})";
1955
1956     assertEquals(2, findMatchesCount(source, pattern));
1957   }
1958
1959   public void testFindMethodWithCountedExceptionsInThrows() {
1960     String source = "class A {" +
1961                     "  void a() {}" +
1962                     "  void b() throws E1 {}" +
1963                     "  void c() throws E1, E2{}" +
1964                     "  void d() throws E1, E2, E3 {}" +
1965                     "}";
1966
1967     String pattern1 = "class '_A {" +
1968                       "  '_type+ 'method+ () throws '_E{0,0};" +
1969                       "}";
1970     assertEquals(1, findMatchesCount(source, pattern1));
1971
1972     String pattern2 = "class '_A {" +
1973                       "  '_type+ 'method+ () throws '_E{1,2};" +
1974                       "}";
1975     assertEquals(2, findMatchesCount(source, pattern2));
1976
1977     String pattern3 = "class '_A {" +
1978                       "  '_type+ 'method+ () throws '_E{2,2};" +
1979                       "}";
1980     assertEquals(1, findMatchesCount(source, pattern3));
1981
1982     String pattern4 = "class '_A {" +
1983                       "  '_type+ 'method+ () throws '_E{0,0}:[ regex( E2 )];" +
1984                       "}";
1985     assertEquals(2, findMatchesCount(source, pattern4));
1986   }
1987
1988   public void testFindMethodsCalledWithinClass() {
1989     String source = "class A {" +
1990                     "  void a() {}" +
1991                     "  static void b() {}" +
1992                     "  void c() {" +
1993                     "    a();" +
1994                     "    b();" +
1995                     "  }" +
1996                     "}" +
1997                     "class B extends A {" +
1998                     "  void d() {" +
1999                     "    a();" +
2000                     "    b();" +
2001                     "  }" +
2002                     "}";
2003     String pattern1 = "this.a()";
2004     assertEquals(2, findMatchesCount(source, pattern1));
2005   }
2006
2007   public void testFindReferenceWithParentheses() {
2008     String source = "class A {" +
2009                     "  String value;" +
2010                     "  A(String v) {" +
2011                     "    value = (value);" +
2012                     "    System.out.println(((2)));" +
2013                     "    System.out.println(2);" +
2014                     "  }" +
2015                     "}";
2016
2017     String pattern1 = "'_value='_value";
2018     assertEquals(1, findMatchesCount(source, pattern1));
2019
2020     String pattern2 = "System.out.println('_v);" +
2021                       "System.out.println('_v);";
2022     assertEquals(1, findMatchesCount(source, pattern2));
2023   }
2024
2025   public void testFindSelfAssignment() {
2026     String source = "class A {" +
2027                     "  protected String s;" +
2028                     "  A(String t) {" +
2029                     "    this.s = s;" +
2030                     "    t = t;" +
2031                     "    s = this.s;" +
2032                     "  }" +
2033                     "}" +
2034                     "class B extends A {" +
2035                     "  B(String t) {" +
2036                     "    super.s = s;" +
2037                     "  }" +
2038                     "}";
2039
2040     String pattern = "'_var='_var";
2041     assertEquals(4, findMatchesCount(source, pattern));
2042   }
2043
2044   public void testFindLambdas() {
2045     String source = "public interface IntFunction<R> {" +
2046                     "    R apply(int value);" +
2047                     "}" +
2048                     "public interface Function<T, R> {" +
2049                     "    R apply(T t);" +
2050                     "}" +
2051                     "class A {" +
2052                     "  void m() {" +
2053                     "    Runnable q = () -> { /*comment*/ };" +
2054                     "    Runnable r = () -> { System.out.println(); };" +
2055                     "    IntFunction<String> f = a -> \"hello\";" +
2056                     "    Function<String, String> g = a -> \"world\";" +
2057                     "  }" +
2058                     "}";
2059
2060     String pattern1 = "() -> {}";
2061     assertEquals("should find lambdas", 4, findMatchesCount(source, pattern1));
2062
2063     String pattern2 = "(int '_a) -> {}";
2064     assertEquals("should find lambdas with specific parameter type", 1, findMatchesCount(source, pattern2));
2065
2066     String pattern3 = "('_a{0,0})->{}";
2067     assertEquals("should find lambdas without any parameters", 2, findMatchesCount(source, pattern3));
2068
2069     String pattern4 = "()->System.out.println()";
2070     assertEquals("should find lambdas with matching body", 1, findMatchesCount(source, pattern4));
2071
2072     String pattern5 = "()->{/*comment*/}";
2073     assertEquals("should find lambdas with comment body", 1, findMatchesCount(source, pattern5));
2074
2075     String pattern6 = "('_Parameter+) -> System.out.println()";
2076     assertEquals("should find lambdas with at least one parameter and matching body", 0, findMatchesCount(source, pattern6));
2077   }
2078
2079   public void testFindDefaultMethods() {
2080     String source = "interface XYZ {" +
2081                     "  default void m() {" +
2082                     "    System.out.println();" +
2083                     "  }" +
2084                     "  void f();" +
2085                     "  void g();" +
2086                     "}" +
2087                     "interface ABC {" +
2088                     "  void m();" +
2089                     "}";
2090
2091     String pattern1 = "interface '_Class {  default '_ReturnType+ 'MethodName+('_ParameterType* '_Parameter*);}";
2092     assertEquals("should find default method", 1, findMatchesCount(source, pattern1));
2093
2094     String pattern2 = "interface 'Class {  default '_ReturnType+ '_MethodName{0,0}('_ParameterType* '_Parameter*);}";
2095     assertEquals("should find interface without default methods", 1, findMatchesCount(source, pattern2));
2096   }
2097
2098   public void testFindMethodReferences() {
2099     String source = "class A {" +
2100                     "  Runnable r = System.out::println;" +
2101                     "  Runnable s = this::hashCode;" +
2102                     "  Runnable t = this::new;" +
2103                     "  Runnable u = @AA A::new;" +
2104                     "  static {" +
2105                     "    System.out.println();" +
2106                     "  }" +
2107                     "}";
2108
2109     String pattern1 = "System . out :: println";
2110     assertEquals("should find method reference", 1, findMatchesCount(source, pattern1));
2111
2112     String pattern2 = "this::'_a";
2113     assertEquals("should find method reference 2", 2, findMatchesCount(source, pattern2));
2114
2115     String pattern3 = "'_a::'_b";
2116     assertEquals("should find all method references", 4, findMatchesCount(source, pattern3));
2117
2118     String pattern4 = "@AA A::new";
2119     assertEquals("should find annotated method references", 1, findMatchesCount(source, pattern4));
2120   }
2121
2122   public void testNoUnexpectedException() {
2123     String source = "{}";
2124
2125     try {
2126       findMatchesCount(source, "/*$A$a*/");
2127       fail("malformed pattern warning expected");
2128     } catch (MalformedPatternException ignored) {}
2129
2130     try {
2131       findMatchesCount(source, "class $A$Visitor {}");
2132       fail("malformed pattern warning expected");
2133     } catch (MalformedPatternException ignored) {
2134     }
2135
2136     try {
2137       String pattern3 = "class $Class$ { \n" +
2138                         "  class $n$$FieldType$ $FieldName$ = $Init$;\n" +
2139                         "}";
2140       findMatchesCount(source, pattern3);
2141       fail("malformed pattern warning expected");
2142     } catch (MalformedPatternException ignored) {}
2143
2144     try {
2145       findMatchesCount(source, "import java.util.ArrayList;");
2146       fail("malformed pattern warning expected");
2147     } catch (MalformedPatternException ignored) {}
2148   }
2149
2150   public void testFindInnerClass() {
2151     String source = "class Foo {\n" +
2152                     "  static class Bar {}\n" +
2153                     "}" +
2154                     "class A {{" +
2155                     "  new Foo.Bar();" +
2156                     "}}";
2157     String pattern = "new Foo.Bar();";
2158     assertEquals("should find qualified with outer class", 1, findMatchesCount(source, pattern));
2159   }
2160
2161   public void testFindCommentsEverywhere() {
2162     String source = "abstract class A<T/*1*/> implements java.util.List<T/*2*/>, /*3*/java.io.Serializable {" +
2163                     "  @SuppressWarnings({\"one\",/*10*/ \"two\"})" +
2164                     "  public /*11*/ static void m(/*12*/) {" +
2165                     "    System./*4*/out.println(/*5*/);" +
2166                     "    A<String/*6*/> a1 = new A(){};" +
2167                     "    int i = 1 + /*7*/ + 2;" +
2168                     "    try (java.io.FileInputStream /*8*/in = new java.io.FileInputStream(\"name\")) {" +
2169                     "    } catch (java.lang./*9*/Exception e) {" +
2170                     "    }" +
2171                     "  }" +
2172                     "}";
2173     String pattern = "/*$Text$*/";
2174     assertEquals("should find comments in all the right places", 12, findMatchesCount(source, pattern));
2175   }
2176
2177   public void testCaseInsensitive() {
2178     String source = "/* HELLO */\n" +
2179                     "class A<T> {\n" +
2180                     "  private char b = 'C';\n" +
2181                     "  void m() {\n" +
2182                     "    @X String s = \"\";\n" +
2183                     "    s.equals(\"\");\n" +
2184                     "    s = s;\n" +
2185                     "    this.b = 'D';\n" +
2186                     "  }\n" +
2187                     "}";
2188     String pattern1 = "a";
2189     assertEquals("should find symbol case insensitively", 1, findMatchesCount(source, pattern1));
2190     String pattern2 = "class a {}";
2191     assertEquals("should find class case insensitively", 1, findMatchesCount(source, pattern2));
2192     String pattern3 = "/* hello */";
2193     assertEquals("should find comment case insensitively", 1, findMatchesCount(source, pattern3));
2194     String pattern4 = "'c'";
2195     assertEquals("should find character literal case insensitively", 1, findMatchesCount(source, pattern4));
2196     String pattern5 = "char B = '_initializer;";
2197     assertEquals("should find variable case insensitively", 1, findMatchesCount(source, pattern5));
2198     String pattern6 = "class '_a<t> {}";
2199     assertEquals("should find type parameter case insensitively", 1, findMatchesCount(source, pattern6));
2200     String pattern7 = "class '_A {" +
2201                       "  void M();" +
2202                       "}";
2203     assertEquals("should find class with method case insensitively", 1, findMatchesCount(source, pattern7));
2204     String pattern8 = "'_a.EQUALS('_b)";
2205     assertEquals("should find method call case insensitively", 1, findMatchesCount(source, pattern8));
2206     String pattern9 = "S.'_call('_e)";
2207     assertEquals("should find qualifier case insensitively", 1, findMatchesCount(source, pattern9));
2208     String pattern10 = "S = S";
2209     assertEquals("should find reference case insensitively", 1, findMatchesCount(source, pattern10));
2210     String pattern11 = "this.B";
2211     assertEquals("should find qualified reference case insensitively", 1, findMatchesCount(source, pattern11));
2212     String pattern12 = "@x";
2213     assertEquals("should find annotation case insensitively", 1, findMatchesCount(source, pattern12));
2214   }
2215
2216   public void testFindTry() {
2217     String source = "class A {{\n" +
2218                     "  try (InputStream in = new FileInputStream(\"tmp\")) {\n" +
2219                     "  }\n" +
2220                     "  try {\n" +
2221                     "  } catch (FileNotFoundException e) {\n" +
2222                     "  } finally {}\n" +
2223                     "  try {\n" +
2224                     "  } catch(NullPointerException  | UnsupportedOperationException e) {\n" +
2225                     "    throw e;\n" +
2226                     "  } catch(Exception e) {\n" +
2227                     "     throw new RuntimeException(e);\n" +
2228                     "  } finally {}\n" +
2229                     "  try {\n" +
2230                     "    throw new NoRouteToHostException();\n" +
2231                     "  } catch (NoRouteToHostException e) {\n" +
2232                     "    System.out.println();\n" +
2233                     "  } catch (SocketException e) {\n" +
2234                     "    System.out.println();\n" +
2235                     "  } catch (IOException e) {\n" +
2236                     "  } catch (RuntimeException e) {\n" +
2237                     "    System.out.println();\n" +
2238                     "  } finally {}\n" +
2239                     "}}";
2240
2241     String pattern1 = "try ('_ResourceType '_Var = '_exp) { '_Statement*; }";
2242     assertEquals("Find try-with-resources", 1, findMatchesCount(source, pattern1));
2243
2244     String pattern2 = "try { '_St1*; } catch ('_ExceptionType1 '_e1) { '_St2*; } catch ('_ExceptionType2 '_e2) { '_St3*; }";
2245     assertEquals("Find try with two or more catch blocks", 2, findMatchesCount(source, pattern2));
2246
2247     String pattern3 = "try { '_St1*; } finally { '_St2*; }";
2248     assertEquals("Find try with finally block", 3, findMatchesCount(source, pattern3));
2249
2250     String pattern4 = "try { '_St1*; } catch (NullPointerException | IllegalArgumentException '_e) { '_St2*; }";
2251     assertEquals("Match multi catch correctly", 0, findMatchesCount(source, pattern4));
2252
2253     String pattern5 = "try { '_St1*; } catch (UnsupportedOperationException | NullPointerException '_e) { '_St2*; }";
2254     assertEquals("Find multi catch", 1, findMatchesCount(source, pattern5));
2255
2256     String pattern6 = "try { '_St1*; } catch ('_E1 | '_E2 '_e) { '_St2*; }";
2257     assertEquals("Find multi catch with variables", 1, findMatchesCount(source, pattern6));
2258   }
2259
2260   public void testFindAsserts() {
2261     String source = "class A {" +
2262                     "  void f(int i) {" +
2263                     "    assert i > 0;" +
2264                     "    assert i < 10 : \"i: \" + i;" +
2265                     "    assert i == 5;" +
2266                     "  }" +
2267                     "}";
2268     assertEquals("find assert statements", 3, findMatchesCount(source, "assert '_a;"));
2269     assertEquals("find assert statements 2", 3, findMatchesCount(source, "assert '_a : 'b*;"));
2270     assertEquals("find assert statement with messages", 1, findMatchesCount(source, "assert '_a : '_b;"));
2271     assertEquals("find assert statement without messages", 2, findMatchesCount(source, "assert 'a : '_b{0,0};"));
2272   }
2273
2274   public void testPolyadicExpression() {
2275     String source = "class A {" +
2276                     "  void f() {" +
2277                     "    int i = 1 + 2;" +
2278                     "    int j = 1 + 2 + 3;" +
2279                     "    int k = 1 + 2 + 3 + 4;" +
2280                     "  }" +
2281                     "}";
2282     assertEquals("find polyadic expression", 3, findMatchesCount(source, "'_a + '_b+"));
2283     assertEquals("find polyadic expression of 3 operands", 1, findMatchesCount(source, "'_a + '_b{2,2}"));
2284     assertEquals("find polyadic expression of >3 operands", 2, findMatchesCount(source, "'_a + '_b{2,100}"));
2285   }
2286
2287   public void testMultipleFieldsInOneDeclaration() {
2288     String source = "class A {" +
2289                     "  int i;" +
2290                     "  int j, k;" +
2291                     "  int l, m, n;" +
2292                     "  int o, p, q;" +
2293                     "}";
2294     assertEquals("find multiple fields in one declaration 1", 3, findMatchesCount(source, "'_a '_b{2,100};"));
2295     assertEquals("find multiple fields in one declaration 2", 3, findMatchesCount(source, "int '_b{2,100};"));
2296     assertEquals("find multiple fields in one declaration 2", 2, findMatchesCount(source, "int '_b{3,3};"));
2297     assertEquals("find declarations with only one field", 1, findMatchesCount(source, "int '_a;"));
2298     assertEquals("find all declarations", 4, findMatchesCount(source, "int '_a+;"));
2299     assertEquals("find all fields", 9, findMatchesCount(source, "int 'a+;"));
2300
2301     String source2 = "class ABC {" +
2302                      "    String u;" +
2303                      "    String s,t," +
2304                      "    void m() {}" +
2305                      "}";
2306     assertEquals("find incomplete code", 1, findMatchesCount(source2, "'_a '_b{2,100};"));
2307   }
2308
2309   public void testFindWithSimpleMemberPattern() {
2310     String source  = "class X {" +
2311                      "  static {}" +
2312                      "  static {}" +