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