-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
/
ParserCornersTest.java
350 lines (301 loc) · 13.2 KB
/
ParserCornersTest.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.ast;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.util.List;
import java.util.Map;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import net.sourceforge.pmd.lang.ast.TokenMgrError;
import net.sourceforge.pmd.lang.java.JavaParsingHelper;
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
public class ParserCornersTest {
private static final String MULTICATCH = "public class Foo { public void bar() { "
+ "try { System.out.println(); } catch (RuntimeException | IOException e) {} } }";
private final JavaParsingHelper java = JavaParsingHelper.WITH_PROCESSING.withResourceContext(ParserCornersTest.class);
private final JavaParsingHelper java9 = java.withDefaultVersion("9");
private final JavaParsingHelper java8 = java.withDefaultVersion("1.8");
private final JavaParsingHelper java4 = java.withDefaultVersion("1.4");
private final JavaParsingHelper java5 = java.withDefaultVersion("1.5");
private final JavaParsingHelper java7 = java.withDefaultVersion("1.7");
@Rule
public ExpectedException expect = ExpectedException.none();
@Test
public void testInvalidUnicodeEscape() {
expect.expect(TokenMgrError.class); // previously Error
expect.expectMessage("Lexical error in file x/filename.java at line 1, column 2. Encountered: Invalid unicode escape");
java.parse("\\u00k0", null, "x/filename.java");
}
/**
* #1107 PMD 5.0.4 couldn't parse call of parent outer java class method
* from inner class.
*/
@Test
public void testInnerOuterClass() {
java7.parse("/**\n" + " * @author azagorulko\n" + " *\n" + " */\n"
+ "public class TestInnerClassCallsOuterParent {\n" + "\n" + " public void test() {\n"
+ " new Runnable() {\n" + " @Override\n" + " public void run() {\n"
+ " TestInnerClassCallsOuterParent.super.toString();\n" + " }\n"
+ " };\n" + " }\n" + "}\n");
}
/**
* #888 PMD 6.0.0 can't parse valid <> under 1.8.
*/
@Test
public void testDiamondUsageJava8() {
java8.parse("public class PMDExceptionTest {\n"
+ " private Component makeUI() {\n"
+ " String[] model = {\"123456\", \"7890\"};\n"
+ " JComboBox<String> comboBox = new JComboBox<>(model);\n"
+ " comboBox.setEditable(true);\n"
+ " comboBox.setEditor(new BasicComboBoxEditor() {\n"
+ " private Component editorComponent;\n"
+ " @Override public Component getEditorComponent() {\n"
+ " if (editorComponent == null) {\n"
+ " JTextField tc = (JTextField) super.getEditorComponent();\n"
+ " editorComponent = new JLayer<>(tc, new ValidationLayerUI<>());\n"
+ " }\n"
+ " return editorComponent;\n"
+ " }\n"
+ " });\n"
+ " JPanel p = new JPanel();\n"
+ " p.add(comboBox);\n"
+ " return p;\n"
+ " }\n"
+ "}");
}
@Test
public final void testGetFirstASTNameImageNull() {
java4.parse(ABSTRACT_METHOD_LEVEL_CLASS_DECL);
}
@Test
public final void testCastLookaheadProblem() {
java4.parse(CAST_LOOKAHEAD_PROBLEM);
}
@Test
public final void testTryWithResourcesConcise() {
// https://github.com/pmd/pmd/issues/3697
java9.parse("import java.io.InputStream;\n"
+ "public class Foo {\n"
+ " public InputStream in;\n"
+ " public void bar() {\n"
+ " Foo f = this;\n"
+ " try (f.in) {\n"
+ " }\n"
+ " }\n"
+ "}");
}
@Test
public final void testTryWithResourcesThis() {
// https://github.com/pmd/pmd/issues/3697
java9.parse("import java.io.InputStream;\n"
+ "public class Foo {\n"
+ " public InputStream in;\n"
+ " public void bar() {\n"
+ " try (this.in) {\n"
+ " }\n"
+ " }\n"
+ "}");
}
/**
* Tests a specific generic notation for calling methods. See:
* https://jira.codehaus.org/browse/MPMD-139
*/
@Test
public void testGenericsProblem() {
java5.parse(GENERICS_PROBLEM);
java7.parse(GENERICS_PROBLEM);
}
@Test
public void testParsersCases15() {
java5.parseResource("ParserCornerCases.java");
}
@Test
public void testParsersCases17() {
java7.parseResource("ParserCornerCases17.java");
}
@Test
public void testParsersCases18() throws Exception {
ASTCompilationUnit cu = java8.parseResource("ParserCornerCases18.java");
Assert.assertEquals(21, cu.findChildNodesWithXPath("//FormalParameter").size());
Assert.assertEquals(4,
cu.findChildNodesWithXPath("//FormalParameter[@ExplicitReceiverParameter='true']").size());
Assert.assertEquals(17,
cu.findChildNodesWithXPath("//FormalParameter[@ExplicitReceiverParameter='false']").size());
}
/**
* Test for https://sourceforge.net/p/pmd/bugs/1333/
*/
@Test
public void testLambdaBug1333() {
java8.parse("final class Bug1333 {\n"
+ " private static final Logger LOG = LoggerFactory.getLogger(Foo.class);\n" + "\n"
+ " public void deleteDirectoriesByNamePattern() {\n"
+ " delete(path -> deleteDirectory(path));\n" + " }\n" + "\n"
+ " private void delete(Consumer<? super String> consumer) {\n"
+ " LOG.debug(consumer.toString());\n" + " }\n" + "\n"
+ " private void deleteDirectory(String path) {\n" + " LOG.debug(path);\n" + " }\n"
+ "}");
}
@Test
public void testLambdaBug1470() {
java8.parseResource("LambdaBug1470.java");
}
/**
* Test for https://sourceforge.net/p/pmd/bugs/1355/
*/
@Test
public void emptyFileJustComment() {
java8.parse("// just a comment");
}
@Test
public void testMultipleExceptionCatchingJava5() {
expect.expect(ParseException.class);
expect.expectMessage("Line 1, Column 94: Cannot catch multiple exceptions when running in JDK inferior to 1.7 mode!");
java5.parse(MULTICATCH);
}
@Test
public void testMultipleExceptionCatchingJava7() {
java7.parse(MULTICATCH);
}
@Test
public void testBug1429ParseError() {
java8.parseResource("Bug1429.java");
}
@Test
public void testBug1530ParseError() {
java8.parseResource("Bug1530.java");
}
@Test
public void testGitHubBug207() {
java8.parseResource("GitHubBug207.java");
}
@Test
public void testLambda2783() {
java8.parseResource("LambdaBug2783.java");
}
@Test
public void testGitHubBug2767() {
// PMD fails to parse an initializer block.
// PMD 6.26.0 parses this code just fine.
java.withDefaultVersion("16")
.parse("class Foo {\n"
+ " {final int I;}\n"
+ "}\n");
}
@Test
public void testBug206() {
java8.parse("public @interface Foo {" + "\n"
+ "static final ThreadLocal<Interner<Integer>> interner =" + "\n"
+ " ThreadLocal.withInitial(Interners::newStrongInterner);" + "\n"
+ "}");
}
@Test
public void testGitHubBug208ParseError() {
java5.parseResource("GitHubBug208.java");
}
@Test
public void testGitHubBug257NonExistingCast() {
String code = "public class Test {" + "\n"
+ " public static void main(String[] args) {" + "\n"
+ " double a = 4.0;" + "\n"
+ " double b = 2.0;" + "\n"
+ " double result = Math.sqrt((a) - b);" + "\n"
+ " System.out.println(result);" + "\n"
+ " }" + "\n"
+ "}";
assertEquals("A cast was found when none expected",
0,
java5.parse(code).findDescendantsOfType(ASTCastExpression.class).size());
}
@Test
public void testGitHubBug309() {
java8.parseResource("GitHubBug309.java");
}
@Test(timeout = 30000)
public void testInfiniteLoopInLookahead() {
expect.expect(ParseException.class);
// https://github.com/pmd/pmd/issues/3117
java8.parseResource("InfiniteLoopInLookahead.java");
}
/**
* This triggered bug #1484 UnusedLocalVariable - false positive -
* parenthesis
*/
@Test
public void stringConcatentationShouldNotBeCast() {
String code = "public class Test {\n" + " public static void main(String[] args) {\n"
+ " System.out.println(\"X\" + (args) + \"Y\");\n" + " }\n" + "}";
Assert.assertEquals(0, java8.parse(code).findDescendantsOfType(ASTCastExpression.class).size());
}
/**
* Empty statements should be allowed.
* @throws Exception
* @see <a href="https://github.com/pmd/pmd/issues/378">github issue 378</a>
*/
@Test
public void testParseEmptyStatements() {
String code = "import a;;import b; public class Foo {}";
ASTCompilationUnit cu = java8.parse(code);
assertNotNull(cu);
Assert.assertEquals(ASTEmptyStatement.class, cu.getChild(1).getClass());
String code2 = "package c;; import a; import b; public class Foo {}";
ASTCompilationUnit cu2 = java8.parse(code2);
assertNotNull(cu2);
Assert.assertEquals(ASTEmptyStatement.class, cu2.getChild(1).getClass());
String code3 = "package c; import a; import b; public class Foo {};";
ASTCompilationUnit cu3 = java8.parse(code3);
assertNotNull(cu3);
Assert.assertEquals(ASTEmptyStatement.class, cu3.getChild(4).getClass());
}
@Test
public void testMethodReferenceConfused() {
ASTCompilationUnit compilationUnit = java.parseResource("MethodReferenceConfused.java", "10");
ASTBlock firstBlock = compilationUnit.getFirstDescendantOfType(ASTBlock.class);
Map<NameDeclaration, List<NameOccurrence>> declarations = firstBlock.getScope().getDeclarations();
boolean foundVariable = false;
for (Map.Entry<NameDeclaration, List<NameOccurrence>> declaration : declarations.entrySet()) {
String varName = declaration.getKey().getImage();
if ("someVarNameSameAsMethodReference".equals(varName)) {
foundVariable = true;
Assert.assertTrue("no usages expected", declaration.getValue().isEmpty());
} else if ("someObject".equals(varName)) {
Assert.assertEquals("1 usage expected", 1, declaration.getValue().size());
Assert.assertEquals(6, declaration.getValue().get(0).getLocation().getBeginLine());
}
}
Assert.assertTrue("Test setup wrong - variable 'someVarNameSameAsMethodReference' not found anymore!", foundVariable);
}
@Test
public void testSwitchWithFallthrough() {
ASTCompilationUnit compilationUnit = java.parseResource("SwitchWithFallthrough.java", "11");
ASTSwitchStatement switchStatement = compilationUnit.getFirstDescendantOfType(ASTSwitchStatement.class);
Assert.assertEquals(2, switchStatement.findChildrenOfType(ASTSwitchLabel.class).size());
}
@Test
public void testSwitchStatements() {
ASTCompilationUnit compilationUnit = java.parseResource("SwitchStatements.java", "11");
ASTSwitchStatement switchStatement = compilationUnit.getFirstDescendantOfType(ASTSwitchStatement.class);
Assert.assertEquals(2, switchStatement.findChildrenOfType(ASTSwitchLabel.class).size());
}
private static final String GENERICS_PROBLEM =
"public class Test {\n public void test() {\n String o = super.<String> doStuff(\"\");\n }\n}";
private static final String ABSTRACT_METHOD_LEVEL_CLASS_DECL =
"public class Test {\n"
+ " void bar() {\n"
+ " abstract class X { public abstract void f(); }\n"
+ " class Y extends X { public void f() { new Y().f(); } }\n"
+ " }\n"
+ "}";
private static final String CAST_LOOKAHEAD_PROBLEM =
"public class BadClass {\n public Class foo() {\n return (byte[].class);\n }\n}";
@Test
public void testGithubBug3101UnresolvedTypeParams() {
java.parseResource("GitHubBug3101.java");
}
}