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
package edu.caltech.cs2.helpers;
import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.body.ConstructorDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.stmt.BlockStmt;
import com.github.javaparser.ast.stmt.Statement;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import java.io.File;
import java.io.FileNotFoundException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.fail;
public class Inspection {
private static String[] getUsageOf(List<String> regexps, List<? extends Node> codeObjects) {
for (Node d : codeObjects) {
for (String regex : regexps) {
if (d.toString().replaceAll("\\R", "").matches(".*" + regex + ".*")) {
return new String[]{d.toString().replaceAll("\\R", ""), regex};
}
}
}
return null;
}
public static void assertNoImportsOf(String filePath, List<String> regexps) {
try {
CompilationUnit cu = JavaParser.parse(new File(filePath));
String[] usage = getUsageOf(regexps, cu.getImports());
if (usage != null) {
fail(usage[0] + " is a banned import under " + usage[1] + " in " + Paths.get(filePath).getFileName()
+ ".");
}
} catch (FileNotFoundException e) {
fail("Missing Java file: " + Paths.get(filePath).getFileName());
}
}
public static void assertNoImportsOfExcept(String filePath, String bannedImport, List<String> allowedClasses) {
try {
CompilationUnit cu = JavaParser.parse(new File(filePath));
String bannedRegex = bannedImport + "\\.(?!" + String.join("|", allowedClasses) + ")";
String[] usage = getUsageOf(List.of(bannedRegex), cu.getImports());
if (usage != null) {
fail(usage[0] + " is a banned import under " + bannedImport +
" and is not an allowed import " +
allowedClasses + " in " + Paths.get(filePath).getFileName() + ".");
}
} catch (FileNotFoundException e) {
fail("Missing Java file: " + Paths.get(filePath).getFileName());
}
}
private static class ConstructorCollector extends VoidVisitorAdapter<List<ConstructorDeclaration>> {
@Override
public void visit(ConstructorDeclaration md, List<ConstructorDeclaration> collector) {
super.visit(md, collector);
collector.add(md);
}
}
private static class MethodCollector extends VoidVisitorAdapter<List<MethodDeclaration>> {
@Override
public void visit(MethodDeclaration md, List<MethodDeclaration> collector) {
super.visit(md, collector);
collector.add(md);
}
}
private static MethodCollector METHOD_COLLECTOR = new MethodCollector();
private static ConstructorCollector CONSTRUCTOR_COLLECTOR = new ConstructorCollector();
public static void assertNoUsageOf(String filePath, List<String> regexps) {
try {
CompilationUnit cu = JavaParser.parse(new File(filePath));
List<ConstructorDeclaration> constructors = new ArrayList<>();
CONSTRUCTOR_COLLECTOR.visit(cu, constructors);
String[] usage = getUsageOf(regexps, constructors);
if (usage != null) {
fail("You may not use " + usage[1] + " in " + Paths.get(filePath).getFileName() + ".");
}
List<MethodDeclaration> methods = new ArrayList<>();
METHOD_COLLECTOR.visit(cu, methods);
usage = getUsageOf(regexps, methods);
if (usage != null) {
fail("You may not use " + usage[1] + " in " + Paths.get(filePath).getFileName() + ".");
}
} catch (FileNotFoundException e) {
fail("Missing Java file: " + Paths.get(filePath).getFileName());
}
}
public static void assertConstructorHygiene(String filePath) {
try {
CompilationUnit cu = JavaParser.parse(new File(filePath));
List<ConstructorDeclaration> constructors = new ArrayList<>();
CONSTRUCTOR_COLLECTOR.visit(cu, constructors);
int nonThisConstructors = 0;
for (ConstructorDeclaration c : constructors) {
BlockStmt body = c.getBody();
List<Statement> statements = body.getStatements();
if (statements.size() != 1) {
nonThisConstructors++;
} else if (!statements.get(0).toString().startsWith("this(")) {
nonThisConstructors++;
}
if (nonThisConstructors > 1) {
fail("All but one of your constructors must use the this(...) notation.");
}
}
} catch (FileNotFoundException e) {
fail("Missing Java file: " + Paths.get(filePath).getFileName());
}
}
}