|
1 |
| package edu.rice.cs.dynamicjava.sourcechecker; |
|
2 |
| |
|
3 |
| import static edu.rice.cs.plt.debug.DebugUtil.debug; |
|
4 |
| |
|
5 |
| import java.io.File; |
|
6 |
| import java.io.FileFilter; |
|
7 |
| import java.io.FileNotFoundException; |
|
8 |
| import java.io.FileReader; |
|
9 |
| import java.io.PrintWriter; |
|
10 |
| import java.lang.reflect.Field; |
|
11 |
| import java.util.ArrayList; |
|
12 |
| import java.util.Arrays; |
|
13 |
| import java.util.EnumSet; |
|
14 |
| import java.util.HashSet; |
|
15 |
| import java.util.LinkedHashMap; |
|
16 |
| import java.util.LinkedHashSet; |
|
17 |
| import java.util.List; |
|
18 |
| import java.util.Map; |
|
19 |
| import java.util.Set; |
|
20 |
| |
|
21 |
| import koala.dynamicjava.interpreter.NodeProperties; |
|
22 |
| import koala.dynamicjava.interpreter.error.ExecutionError; |
|
23 |
| import koala.dynamicjava.parser.wrapper.JavaCCParser; |
|
24 |
| import koala.dynamicjava.parser.wrapper.ParseError; |
|
25 |
| import koala.dynamicjava.tree.*; |
|
26 |
| import koala.dynamicjava.tree.tiger.HookTypeName; |
|
27 |
| import koala.dynamicjava.tree.visitor.DepthFirstVisitor; |
|
28 |
| import edu.rice.cs.dynamicjava.Options; |
|
29 |
| import edu.rice.cs.dynamicjava.interpreter.*; |
|
30 |
| import edu.rice.cs.dynamicjava.symbol.*; |
|
31 |
| import edu.rice.cs.dynamicjava.symbol.type.*; |
|
32 |
| import edu.rice.cs.plt.collect.CollectUtil; |
|
33 |
| import edu.rice.cs.plt.collect.IndexedRelation; |
|
34 |
| import edu.rice.cs.plt.collect.PredicateSet; |
|
35 |
| import edu.rice.cs.plt.collect.UnindexedRelation; |
|
36 |
| import edu.rice.cs.plt.collect.Relation; |
|
37 |
| import edu.rice.cs.plt.io.IOUtil; |
|
38 |
| import edu.rice.cs.plt.iter.IterUtil; |
|
39 |
| import edu.rice.cs.plt.lambda.Box; |
|
40 |
| import edu.rice.cs.plt.lambda.Lambda; |
|
41 |
| import edu.rice.cs.plt.lambda.Lambda2; |
|
42 |
| import edu.rice.cs.plt.lambda.LambdaUtil; |
|
43 |
| import edu.rice.cs.plt.lambda.Predicate2; |
|
44 |
| import edu.rice.cs.plt.lambda.SimpleBox; |
|
45 |
| import edu.rice.cs.plt.lambda.Thunk; |
|
46 |
| import edu.rice.cs.plt.recur.RecursionStack2; |
|
47 |
| import edu.rice.cs.plt.reflect.PathClassLoader; |
|
48 |
| import edu.rice.cs.plt.text.ArgumentParser; |
|
49 |
| import edu.rice.cs.plt.text.TextUtil; |
|
50 |
| import edu.rice.cs.plt.tuple.Option; |
|
51 |
| import edu.rice.cs.plt.tuple.Pair; |
|
52 |
| |
|
53 |
| public class SourceChecker { |
|
54 |
| |
|
55 |
| private final Options _opt; |
|
56 |
| private final boolean _quiet; |
|
57 |
| private int _statusCount; |
|
58 |
| private Iterable<CompilationUnit> _processed; |
|
59 |
| |
|
60 |
0
| public SourceChecker(Options opt, boolean quiet) {
|
|
61 |
0
| _opt = opt;
|
|
62 |
0
| _quiet = quiet;
|
|
63 |
0
| _statusCount = 0;
|
|
64 |
0
| _processed = IterUtil.empty();
|
|
65 |
| } |
|
66 |
| |
|
67 |
0
| public Iterable<CompilationUnit> processed() { return _processed; }
|
|
68 |
| |
|
69 |
0
| public void check(File... sources) throws InterpreterException {
|
|
70 |
0
| check(IterUtil.asIterable(sources), IterUtil.<File>empty());
|
|
71 |
| } |
|
72 |
| |
|
73 |
0
| public void check(Iterable<? extends File> sources) throws InterpreterException {
|
|
74 |
0
| check(sources, IterUtil.<File>empty());
|
|
75 |
| } |
|
76 |
| |
|
77 |
0
| public void check(Iterable<? extends File> sources, Iterable<? extends File> classPath)
|
|
78 |
| throws InterpreterException { |
|
79 |
0
| Iterable<CompilationUnit> tree = parse(sources);
|
|
80 |
0
| _processed = IterUtil.compose(_processed, tree);
|
|
81 |
0
| TypeContext context = makeContext(tree, classPath);
|
|
82 |
0
| Relation<TypeDeclaration, ClassChecker> decls = extractDeclarations(tree, context);
|
|
83 |
0
| initializeClassSignatures(decls);
|
|
84 |
0
| checkSignatures(decls);
|
|
85 |
0
| checkBodies(decls);
|
|
86 |
| } |
|
87 |
| |
|
88 |
0
| private Iterable<CompilationUnit> parse(Iterable<? extends File> sources) throws InterpreterException {
|
|
89 |
0
| final List<CompilationUnit> result = new ArrayList<CompilationUnit>();
|
|
90 |
0
| Iterable<File> files = IterUtil.collapse(IterUtil.map(sources, new Lambda<File, Iterable<File>>() {
|
|
91 |
| private final FileFilter _filter = IOUtil.extensionFilePredicate("java"); |
|
92 |
0
| public Iterable<File> value(File f) { return IOUtil.listFilesRecursively(f, _filter); }
|
|
93 |
| })); |
|
94 |
0
| new Phase<File>("Parsing") {
|
|
95 |
0
| protected void step(File source) throws InterpreterException {
|
|
96 |
0
| try {
|
|
97 |
0
| JavaCCParser parser = new JavaCCParser(new FileReader(source), source, _opt);
|
|
98 |
0
| result.add(parser.parseCompilationUnit());
|
|
99 |
| } |
|
100 |
0
| catch (ParseError e) { throw new ParserException(e); }
|
|
101 |
0
| catch (FileNotFoundException e) { throw new SourceException(e); }
|
|
102 |
| } |
|
103 |
0
| protected SourceInfo location(File f) { return SourceInfo.point(f, 0, 0); }
|
|
104 |
| }.run(files); |
|
105 |
0
| return result;
|
|
106 |
| } |
|
107 |
| |
|
108 |
0
| private TypeContext makeContext(Iterable<CompilationUnit> sources, Iterable<? extends File> cp) {
|
|
109 |
0
| Library classLib = SymbolUtil.classLibrary(new PathClassLoader(null, cp));
|
|
110 |
0
| debug.logStart("creating TreeLibrary");
|
|
111 |
0
| Library sourceLib = new TreeLibrary(sources, classLib.classLoader(), _opt);
|
|
112 |
0
| debug.logEnd("creating TreeLibrary");
|
|
113 |
0
| return new ImportContext(new LibraryContext(new LibraryContext(classLib), sourceLib), _opt);
|
|
114 |
| } |
|
115 |
| |
|
116 |
0
| private Relation<TypeDeclaration, ClassChecker> extractDeclarations(Iterable<CompilationUnit> sources,
|
|
117 |
| TypeContext context) |
|
118 |
| throws InterpreterException { |
|
119 |
0
| final CompilationUnitChecker unitChecker = new CompilationUnitChecker(context, _opt);
|
|
120 |
0
| final Relation<TypeDeclaration, ClassChecker> checkers = UnindexedRelation.makeLinkedHashBased();
|
|
121 |
0
| new Phase<CompilationUnit>("Resolving imports") {
|
|
122 |
0
| protected void step(CompilationUnit u) throws InterpreterException {
|
|
123 |
0
| checkers.addAll(unitChecker.extractDeclarations(u));
|
|
124 |
| } |
|
125 |
0
| protected SourceInfo location(CompilationUnit arg) { return arg.getSourceInfo(); }
|
|
126 |
| }.run(sources); |
|
127 |
0
| return checkers;
|
|
128 |
| } |
|
129 |
| |
|
130 |
0
| private void initializeClassSignatures(Relation<TypeDeclaration, ClassChecker> decls) throws InterpreterException {
|
|
131 |
0
| new ClassCheckerPhase("Checking class signatures") {
|
|
132 |
0
| protected void step(TypeDeclaration ast, ClassChecker checker) { checker.initializeClassSignatures(ast); }
|
|
133 |
| }.run(decls); |
|
134 |
| } |
|
135 |
| |
|
136 |
0
| private void checkSignatures(Relation<TypeDeclaration, ClassChecker> decls) throws InterpreterException {
|
|
137 |
0
| new ClassCheckerPhase("Checking class member signatures") {
|
|
138 |
0
| protected void step(TypeDeclaration ast, ClassChecker checker) { checker.checkSignatures(ast); }
|
|
139 |
| }.run(decls); |
|
140 |
| } |
|
141 |
| |
|
142 |
0
| private void checkBodies(Relation<TypeDeclaration, ClassChecker> decls) throws InterpreterException {
|
|
143 |
0
| new ClassCheckerPhase("Checking class member bodies") {
|
|
144 |
0
| protected void step(TypeDeclaration ast, ClassChecker checker) { checker.checkBodies(ast); }
|
|
145 |
| }.run(decls); |
|
146 |
| } |
|
147 |
| |
|
148 |
| |
|
149 |
0
| private void startStatus(String description) {
|
|
150 |
0
| _statusCount = 0;
|
|
151 |
0
| if (!_quiet) {
|
|
152 |
0
| String fullDesc = TextUtil.padRight(description + "...", ' ', 36);
|
|
153 |
0
| System.out.print(fullDesc);
|
|
154 |
0
| System.out.flush();
|
|
155 |
| } |
|
156 |
| } |
|
157 |
| |
|
158 |
0
| private void incrementStatus() {
|
|
159 |
0
| _statusCount++;
|
|
160 |
| |
|
161 |
0
| if (!_quiet && (_statusCount % 10 == 0)) { System.out.print('*'); System.out.flush(); }
|
|
162 |
| } |
|
163 |
| |
|
164 |
0
| private void endStatus() {
|
|
165 |
0
| if (!_quiet) { System.out.println(); }
|
|
166 |
| } |
|
167 |
| |
|
168 |
| |
|
169 |
| private abstract class Phase<T> { |
|
170 |
| private final String _description; |
|
171 |
0
| protected Phase(String description) { _description = description; }
|
|
172 |
| |
|
173 |
| protected abstract void step(T arg) throws InterpreterException; |
|
174 |
| protected abstract SourceInfo location(T arg); |
|
175 |
| |
|
176 |
0
| public void run(Iterable<? extends T> args) throws InterpreterException {
|
|
177 |
0
| List<InterpreterException> errors = new ArrayList<InterpreterException>();
|
|
178 |
0
| debug.logStart(_description);
|
|
179 |
0
| startStatus(_description);
|
|
180 |
0
| for (T arg : args) {
|
|
181 |
0
| debug.logStart("location", location(arg));
|
|
182 |
0
| try { step(arg); }
|
|
183 |
0
| catch (InterpreterException e) { errors.add(e); }
|
|
184 |
0
| catch (RuntimeException e) { errors.add(new InternalException(e, location(arg))); }
|
|
185 |
0
| incrementStatus();
|
|
186 |
0
| debug.logEnd();
|
|
187 |
| } |
|
188 |
0
| endStatus();
|
|
189 |
0
| debug.logEnd(_description);
|
|
190 |
0
| if (!errors.isEmpty()) { throw CompositeException.make(errors); }
|
|
191 |
| } |
|
192 |
| } |
|
193 |
| |
|
194 |
| private abstract class ClassCheckerPhase extends Phase<Pair<TypeDeclaration, ClassChecker>> { |
|
195 |
0
| protected ClassCheckerPhase(String description) { super(description); }
|
|
196 |
0
| protected final void step(Pair<TypeDeclaration, ClassChecker> arg) throws InterpreterException {
|
|
197 |
0
| try { step(arg.first(), arg.second()); }
|
|
198 |
0
| catch (ExecutionError e) { throw extractErrors(arg.first()); }
|
|
199 |
| } |
|
200 |
0
| protected final SourceInfo location(Pair<TypeDeclaration, ClassChecker> arg) {
|
|
201 |
0
| return arg.first().getSourceInfo();
|
|
202 |
| } |
|
203 |
| protected abstract void step(TypeDeclaration ast, ClassChecker checker); |
|
204 |
| } |
|
205 |
| |
|
206 |
| |
|
207 |
| |
|
208 |
0
| private static InterpreterException extractErrors(Node ast) {
|
|
209 |
| |
|
210 |
0
| final Set<ExecutionError> result = new LinkedHashSet<ExecutionError>();
|
|
211 |
0
| new PropertiesDepthFirstVisitor() {
|
|
212 |
0
| public void run(Node node) {
|
|
213 |
0
| if (NodeProperties.hasError(node)) { result.add(NodeProperties.getError(node)); }
|
|
214 |
0
| super.run(node);
|
|
215 |
| } |
|
216 |
| }.run(ast); |
|
217 |
0
| return CompositeException.make(IterUtil.map(result, CheckerException.FACTORY));
|
|
218 |
| } |
|
219 |
| |
|
220 |
| |
|
221 |
| |
|
222 |
| |
|
223 |
| |
|
224 |
| private static class PropertiesDepthFirstVisitor extends DepthFirstVisitor { |
|
225 |
0
| public void run(Node node) {
|
|
226 |
0
| try { node.acceptVisitor(this); }
|
|
227 |
| catch (IllegalArgumentException e) { } |
|
228 |
0
| if (NodeProperties.hasLeftExpression(node)) { recur(NodeProperties.getLeftExpression(node)); }
|
|
229 |
0
| if (NodeProperties.hasTranslation(node)) { recur(NodeProperties.getTranslation(node)); }
|
|
230 |
0
| if (NodeProperties.hasStatementTranslation(node)) { recur(NodeProperties.getStatementTranslation(node)); }
|
|
231 |
| } |
|
232 |
| } |
|
233 |
| |
|
234 |
| private static final Map<String, Options> _options; |
|
235 |
| static { |
|
236 |
| abstract class SourceCheckerOptions extends Options { |
|
237 |
| protected abstract TypeSystem makeTypeSystem(); |
|
238 |
0
| @Override protected Thunk<? extends TypeSystem> typeSystemFactory() {
|
|
239 |
0
| return LambdaUtil.valueLambda(makeTypeSystem());
|
|
240 |
| } |
|
241 |
0
| @Override public boolean enforceAllAccess() { return true; }
|
|
242 |
0
| @Override public boolean prohibitUncheckedCasts() { return false; }
|
|
243 |
| } |
|
244 |
| |
|
245 |
0
| _options = new LinkedHashMap<String, Options>();
|
|
246 |
0
| _options.put("jls", new SourceCheckerOptions() {
|
|
247 |
0
| public TypeSystem makeTypeSystem() { return new JLSTypeSystem(this, true, true, true, true, true, false); }
|
|
248 |
| }); |
|
249 |
0
| _options.put("ext", new SourceCheckerOptions() {
|
|
250 |
0
| public TypeSystem makeTypeSystem() { return new ExtendedTypeSystem(this, true, true, true, false); }
|
|
251 |
| }); |
|
252 |
0
| _options.put("jls-inferred", new SourceCheckerOptions() {
|
|
253 |
0
| public TypeSystem makeTypeSystem() { return new JLSTypeSystem(this, true, true, true, true, false, false); }
|
|
254 |
| }); |
|
255 |
0
| _options.put("ext-inferred", new SourceCheckerOptions() {
|
|
256 |
0
| public TypeSystem makeTypeSystem() { return new ExtendedTypeSystem(this, true, true, false, false); }
|
|
257 |
| }); |
|
258 |
| } |
|
259 |
| |
|
260 |
0
| public static void main(String... args) {
|
|
261 |
0
| debug.logStart();
|
|
262 |
| |
|
263 |
0
| ArgumentParser argParser = new ArgumentParser();
|
|
264 |
0
| argParser.supportOption("classpath", "");
|
|
265 |
0
| argParser.supportAlias("cp", "classpath");
|
|
266 |
0
| argParser.supportOption("opt", 1);
|
|
267 |
0
| argParser.supportOption("verbose");
|
|
268 |
0
| argParser.requireParams(1);
|
|
269 |
0
| final ArgumentParser.Result parsedArgs = argParser.parse(args);
|
|
270 |
0
| Iterable<File> cp = IOUtil.parsePath(parsedArgs.getUnaryOption("classpath"));
|
|
271 |
0
| Iterable<File> sources = IterUtil.map(parsedArgs.params(), IOUtil.FILE_FACTORY);
|
|
272 |
0
| boolean verbose = parsedArgs.hasOption("verbose");
|
|
273 |
| |
|
274 |
0
| if (parsedArgs.hasOption("opt")) {
|
|
275 |
0
| Options opt = _options.get(parsedArgs.getUnaryOption("opt"));
|
|
276 |
0
| if (opt == null) { System.out.println("Unrecognized options name: " + parsedArgs.getUnaryOption("opt")); }
|
|
277 |
0
| else { processFiles(sources, cp, opt); }
|
|
278 |
| } |
|
279 |
| |
|
280 |
| else { |
|
281 |
0
| String canonical = IterUtil.first(_options.keySet());
|
|
282 |
0
| Map<String, Iterable<CompilationUnit>> results = new LinkedHashMap<String, Iterable<CompilationUnit>>();
|
|
283 |
0
| for (String n : _options.keySet()) {
|
|
284 |
0
| System.out.println("============ Checking with type system " + n + " ============");
|
|
285 |
0
| results.put(n, processFiles(sources, cp, _options.get(n)));
|
|
286 |
| } |
|
287 |
0
| for (Map.Entry<String, Iterable<CompilationUnit>> e : results.entrySet()) {
|
|
288 |
0
| if (e.getKey().equals(canonical)) continue;
|
|
289 |
0
| String compareTo;
|
|
290 |
0
| if (e.getKey().endsWith("-inferred")) {
|
|
291 |
0
| compareTo = e.getKey().substring(0, e.getKey().length() - "-inferred".length());
|
|
292 |
| } |
|
293 |
0
| else { compareTo = canonical; }
|
|
294 |
| |
|
295 |
0
| NodeDiffLog log = new NodeDiffLog(compareTo, _options.get(compareTo).typeSystem(),
|
|
296 |
| e.getKey(), _options.get(e.getKey()).typeSystem(), verbose); |
|
297 |
0
| new NodeDiff(log).compare(results.get(compareTo), e.getValue());
|
|
298 |
| |
|
299 |
0
| String firstInferred = compareTo + "-inferred";
|
|
300 |
0
| String secondInferred = e.getKey() + "-inferred";
|
|
301 |
0
| if (results.containsKey(firstInferred) && results.containsKey(secondInferred)) {
|
|
302 |
0
| NodeDiffLog log2 = new NodeDiffLog(firstInferred, _options.get(firstInferred).typeSystem(),
|
|
303 |
| secondInferred, _options.get(secondInferred).typeSystem(), verbose); |
|
304 |
0
| new NodeDiff(log2).compare(results.get(firstInferred), results.get(secondInferred));
|
|
305 |
| } |
|
306 |
| } |
|
307 |
| } |
|
308 |
| |
|
309 |
0
| debug.logEnd();
|
|
310 |
| } |
|
311 |
| |
|
312 |
| |
|
313 |
0
| private static Iterable<CompilationUnit> processFiles(Iterable<File> sources, Iterable<File> cp, Options opt) {
|
|
314 |
0
| SourceChecker checker = new SourceChecker(opt, false);
|
|
315 |
0
| try {
|
|
316 |
0
| checker.check(sources, cp);
|
|
317 |
0
| System.out.println("Completed checking successfully.");
|
|
318 |
| } |
|
319 |
| catch (InterpreterException e) { |
|
320 |
0
| debug.log(e);
|
|
321 |
0
| e.printUserMessage(new PrintWriter(System.out, true));
|
|
322 |
| } |
|
323 |
0
| return checker.processed();
|
|
324 |
| } |
|
325 |
| |
|
326 |
| static class NodeDiffLog { |
|
327 |
| |
|
328 |
| private final String _leftName; |
|
329 |
| private final TypeSystem _leftTS; |
|
330 |
| private final String _rightName; |
|
331 |
| private final TypeSystem _rightTS; |
|
332 |
| private final boolean _verbose; |
|
333 |
| |
|
334 |
| private final Relation<SourceInfo, Location> _commonErrors; |
|
335 |
| private final Relation<SourceInfo, Location> _leftErrors; |
|
336 |
| private final Relation<SourceInfo, Location> _rightErrors; |
|
337 |
| private final Relation<SourceInfo, Location> _polymorphicDeclarations; |
|
338 |
| private final Relation<SourceInfo, Location> _inferredInvocations; |
|
339 |
| private final Relation<SourceInfo, Location> _explicitInvocations; |
|
340 |
| private final Relation<SourceInfo, Location> _simpleWildcards; |
|
341 |
| private final Relation<SourceInfo, Location> _extendsWildcards; |
|
342 |
| private final Relation<SourceInfo, Location> _superWildcards; |
|
343 |
| private final Relation<SourceInfo, MismatchedType> _mismatchedTypes; |
|
344 |
| private final Relation<SourceInfo, Cast> _leftCasts; |
|
345 |
| private final Relation<SourceInfo, Cast> _rightCasts; |
|
346 |
| |
|
347 |
0
| public NodeDiffLog(String leftName, TypeSystem leftTS, String rightName, TypeSystem rightTS, boolean verbose) {
|
|
348 |
0
| _leftName = leftName;
|
|
349 |
0
| _leftTS = leftTS;
|
|
350 |
0
| _rightName = rightName;
|
|
351 |
0
| _rightTS = rightTS;
|
|
352 |
0
| _verbose = verbose;
|
|
353 |
| |
|
354 |
0
| Thunk<Map<SourceInfo, PredicateSet<MismatchedType>>> mapFactory1 = CollectUtil.treeMapFactory();
|
|
355 |
0
| Thunk<Map<SourceInfo, PredicateSet<Location>>> mapFactory2 = CollectUtil.treeMapFactory();
|
|
356 |
0
| Thunk<Map<SourceInfo, PredicateSet<Cast>>> mapFactory3 = CollectUtil.treeMapFactory();
|
|
357 |
0
| Thunk<Set<MismatchedType>> setFactory1 = CollectUtil.hashSetFactory();
|
|
358 |
0
| Thunk<Set<Location>> setFactory2 = CollectUtil.hashSetFactory();
|
|
359 |
0
| Thunk<Set<Cast>> setFactory3 = CollectUtil.hashSetFactory();
|
|
360 |
0
| _commonErrors = new IndexedRelation<SourceInfo, Location>(mapFactory2, setFactory2);
|
|
361 |
0
| _leftErrors = new IndexedRelation<SourceInfo, Location>(mapFactory2, setFactory2);
|
|
362 |
0
| _rightErrors = new IndexedRelation<SourceInfo, Location>(mapFactory2, setFactory2);
|
|
363 |
0
| _polymorphicDeclarations = new IndexedRelation<SourceInfo, Location>(mapFactory2, setFactory2);
|
|
364 |
0
| _inferredInvocations = new IndexedRelation<SourceInfo, Location>(mapFactory2, setFactory2);
|
|
365 |
0
| _explicitInvocations = new IndexedRelation<SourceInfo, Location>(mapFactory2, setFactory2);
|
|
366 |
0
| _simpleWildcards = new IndexedRelation<SourceInfo, Location>(mapFactory2, setFactory2);
|
|
367 |
0
| _extendsWildcards = new IndexedRelation<SourceInfo, Location>(mapFactory2, setFactory2);
|
|
368 |
0
| _superWildcards = new IndexedRelation<SourceInfo, Location>(mapFactory2, setFactory2);
|
|
369 |
0
| _mismatchedTypes = new IndexedRelation<SourceInfo, MismatchedType>(mapFactory1, setFactory1);
|
|
370 |
0
| _leftCasts = new IndexedRelation<SourceInfo, Cast>(mapFactory3, setFactory3);
|
|
371 |
0
| _rightCasts = new IndexedRelation<SourceInfo, Cast>(mapFactory3, setFactory3);
|
|
372 |
| } |
|
373 |
| |
|
374 |
0
| public void start() {
|
|
375 |
0
| System.out.println("\n**********************************************************");
|
|
376 |
0
| System.out.println("Comparing " + _leftName + " with " + _rightName);
|
|
377 |
0
| System.out.println("**********************************************************");
|
|
378 |
| } |
|
379 |
| |
|
380 |
0
| public void end() {
|
|
381 |
0
| System.out.println();
|
|
382 |
0
| System.out.println("Common statements with errors: " + sizeString(_commonErrors));
|
|
383 |
0
| if (_verbose) { dump(_commonErrors.secondSet()); }
|
|
384 |
0
| System.out.println("Left statements with errors: " + sizeString(_leftErrors));
|
|
385 |
0
| if (_verbose) { dump(_leftErrors.secondSet()); }
|
|
386 |
0
| System.out.println("Right statements with errors: " + sizeString(_rightErrors));
|
|
387 |
0
| if (_verbose) { dump(_rightErrors.secondSet()); }
|
|
388 |
0
| System.out.println("Polymorphic declarations: " + sizeString(_polymorphicDeclarations));
|
|
389 |
0
| if (_verbose) { dump(_polymorphicDeclarations.secondSet()); }
|
|
390 |
0
| System.out.println("Inferred polymorphic invocations: " + sizeString(_inferredInvocations));
|
|
391 |
0
| if (_verbose) { dump(_inferredInvocations.secondSet()); }
|
|
392 |
0
| System.out.println("Explicit polymorphic invocations: " + sizeString(_explicitInvocations));
|
|
393 |
0
| if (_verbose) { dump(_explicitInvocations.secondSet()); }
|
|
394 |
0
| System.out.println("Simple wildcards: " + sizeString(_simpleWildcards));
|
|
395 |
0
| if (_verbose) { dump(_simpleWildcards.secondSet()); }
|
|
396 |
0
| System.out.println("Upper-bounded wildcards: " + sizeString(_extendsWildcards));
|
|
397 |
0
| if (_verbose) { dump(_extendsWildcards.secondSet()); }
|
|
398 |
0
| System.out.println("Lower-bounded wildcards: " + sizeString(_superWildcards));
|
|
399 |
0
| if (_verbose) { dump(_superWildcards.secondSet()); }
|
|
400 |
0
| System.out.println("Mismatched types: " + sizeString(_mismatchedTypes));
|
|
401 |
0
| if (_verbose) { dump(_mismatchedTypes.secondSet()); }
|
|
402 |
0
| System.out.println("Left extra casts: " + sizeString(_leftCasts));
|
|
403 |
0
| if (_verbose) { dump(_leftCasts.secondSet()); }
|
|
404 |
0
| System.out.println("Right extra casts: " + sizeString(_rightCasts));
|
|
405 |
0
| if (_verbose) { dump(_rightCasts.secondSet()); }
|
|
406 |
0
| System.out.println();
|
|
407 |
| } |
|
408 |
| |
|
409 |
0
| private String sizeString(Relation<?,?> r) {
|
|
410 |
0
| int size = r.size();
|
|
411 |
0
| int unique = r.firstSet().size();
|
|
412 |
0
| if (size == unique) { return "" + size; }
|
|
413 |
0
| else { return size + " (" + unique + " unique)"; }
|
|
414 |
| } |
|
415 |
| |
|
416 |
0
| private void dump(Set<?> s) {
|
|
417 |
0
| int counter = 0;
|
|
418 |
0
| for (Object obj: s) {
|
|
419 |
0
| counter++;
|
|
420 |
0
| if (counter > 100) { System.out.println("..."); break; }
|
|
421 |
0
| else { System.out.println(obj.toString()); }
|
|
422 |
| } |
|
423 |
| } |
|
424 |
| |
|
425 |
0
| public void mismatchedCompilationUnits() {
|
|
426 |
0
| System.out.println("Can't compare results: mismatched CompilationUnit lists");
|
|
427 |
| } |
|
428 |
| |
|
429 |
0
| public void commonErrorStatement(String context, SourceInfo.Wrapper left, SourceInfo.Wrapper right) {
|
|
430 |
0
| _commonErrors.add(left.getSourceInfo(), new Location(context, left, right));
|
|
431 |
| } |
|
432 |
| |
|
433 |
0
| public void leftErrorStatement(String context, SourceInfo.Wrapper left, SourceInfo.Wrapper right) {
|
|
434 |
0
| _leftErrors.add(left.getSourceInfo(), new Location(context, left, right));
|
|
435 |
| } |
|
436 |
| |
|
437 |
0
| public void rightErrorStatement(String context, SourceInfo.Wrapper left, SourceInfo.Wrapper right) {
|
|
438 |
0
| _rightErrors.add(left.getSourceInfo(), new Location(context, left, right));
|
|
439 |
| } |
|
440 |
| |
|
441 |
0
| public void polymorphicDeclaration(String context, SourceInfo.Wrapper left, SourceInfo.Wrapper right) {
|
|
442 |
0
| _polymorphicDeclarations.add(left.getSourceInfo(), new Location(context, left, right));
|
|
443 |
| } |
|
444 |
| |
|
445 |
0
| public void polymorphicInvocation(String context, SourceInfo.Wrapper left, SourceInfo.Wrapper right,
|
|
446 |
| boolean inferred) { |
|
447 |
0
| if (inferred) { _inferredInvocations.add(left.getSourceInfo(), new Location(context, left, right)); }
|
|
448 |
0
| else { _explicitInvocations.add(left.getSourceInfo(), new Location(context, left, right)); }
|
|
449 |
| } |
|
450 |
| |
|
451 |
0
| public void wildcard(String context, SourceInfo.Wrapper left, SourceInfo.Wrapper right,
|
|
452 |
| boolean upper, boolean lower) { |
|
453 |
0
| if (lower) { _superWildcards.add(left.getSourceInfo(), new Location(context, left, right)); }
|
|
454 |
0
| else if (upper) { _extendsWildcards.add(left.getSourceInfo(), new Location(context, left, right)); }
|
|
455 |
0
| else { _simpleWildcards.add(left.getSourceInfo(), new Location(context, left, right)); }
|
|
456 |
| } |
|
457 |
| |
|
458 |
0
| public void extraLeftCast(String context, Class<?> target, SourceInfo.Wrapper left, SourceInfo.Wrapper right) {
|
|
459 |
0
| _leftCasts.add(left.getSourceInfo(), new Cast(context, target, left, right));
|
|
460 |
| } |
|
461 |
| |
|
462 |
0
| public void extraRightCast(String context, Class<?> target, SourceInfo.Wrapper left, SourceInfo.Wrapper right) {
|
|
463 |
0
| _rightCasts.add(left.getSourceInfo(), new Cast(context, target, left, right));
|
|
464 |
| } |
|
465 |
| |
|
466 |
0
| public void mismatchedType(String context, Type leftType, SourceInfo.Wrapper left,
|
|
467 |
| Type rightType, SourceInfo.Wrapper right) { |
|
468 |
0
| _mismatchedTypes.add(left.getSourceInfo(), new MismatchedType(context, leftType, left, rightType, right));
|
|
469 |
| } |
|
470 |
| |
|
471 |
0
| public void mismatch(String description, String context, String leftData, SourceInfo.Wrapper left,
|
|
472 |
| String rightData, SourceInfo.Wrapper right) { |
|
473 |
0
| System.out.println("*** " + description + " in " + context);
|
|
474 |
0
| System.out.println("Left (" + left.getSourceInfo() + "): " + leftData);
|
|
475 |
0
| System.out.println("Right (" + right.getSourceInfo() + "): " + rightData);
|
|
476 |
| } |
|
477 |
| |
|
478 |
| private static class Location { |
|
479 |
| private final String _context; |
|
480 |
| private final SourceInfo _left; |
|
481 |
| private final SourceInfo _right; |
|
482 |
0
| public Location(String context, SourceInfo.Wrapper left, SourceInfo.Wrapper right) {
|
|
483 |
0
| _context = context; _left = left.getSourceInfo(); _right = right.getSourceInfo();
|
|
484 |
| } |
|
485 |
0
| public String toString() {
|
|
486 |
0
| if (_left.equals(_right)) { return _left + ": " + _context; }
|
|
487 |
0
| else { return _left + "/" + _right + ": " + _context; }
|
|
488 |
| } |
|
489 |
| } |
|
490 |
| |
|
491 |
| private class MismatchedType { |
|
492 |
| private final Location _location; |
|
493 |
| private final Type _leftType; |
|
494 |
| private final Type _rightType; |
|
495 |
0
| public MismatchedType(String context, Type leftType, SourceInfo.Wrapper left,
|
|
496 |
| Type rightType, SourceInfo.Wrapper right) { |
|
497 |
0
| _location = new Location(context, left, right);
|
|
498 |
0
| _leftType = leftType;
|
|
499 |
0
| _rightType = rightType;
|
|
500 |
| } |
|
501 |
0
| public String toString() {
|
|
502 |
0
| return _location + " has types " +
|
|
503 |
| _leftTS.typePrinter().print(_leftType) + "/" + |
|
504 |
| _rightTS.typePrinter().print(_rightType); |
|
505 |
| } |
|
506 |
| } |
|
507 |
| |
|
508 |
| private class Cast { |
|
509 |
| private final Location _location; |
|
510 |
| private final Class<?> _target; |
|
511 |
0
| public Cast(String context, Class<?> target, SourceInfo.Wrapper left, SourceInfo.Wrapper right) {
|
|
512 |
0
| _location = new Location(context, left, right);
|
|
513 |
0
| _target = target;
|
|
514 |
| } |
|
515 |
0
| public String toString() {
|
|
516 |
0
| return _location + " cast to " + _target.getName();
|
|
517 |
| } |
|
518 |
| } |
|
519 |
| |
|
520 |
| } |
|
521 |
| |
|
522 |
| static class NodeDiff { |
|
523 |
| |
|
524 |
| private final NodeDiffLog _log; |
|
525 |
| |
|
526 |
0
| public NodeDiff(NodeDiffLog log) { _log = log; }
|
|
527 |
| |
|
528 |
0
| public void compare(Iterable<CompilationUnit> left, Iterable<CompilationUnit> right) {
|
|
529 |
0
| _log.start();
|
|
530 |
0
| if (IterUtil.sizeOf(left) != IterUtil.sizeOf(right)) {
|
|
531 |
0
| _log.mismatchedCompilationUnits();
|
|
532 |
| } |
|
533 |
| else { |
|
534 |
0
| for (Pair<CompilationUnit, CompilationUnit> p : IterUtil.zip(left, right)) {
|
|
535 |
0
| compare("Compilation unit", p.first(), p.second());
|
|
536 |
| } |
|
537 |
| } |
|
538 |
0
| _log.end();
|
|
539 |
| } |
|
540 |
| |
|
541 |
0
| private void compare(String context, Node left, Node right) {
|
|
542 |
0
| if (left.getClass().equals(right.getClass())) {
|
|
543 |
0
| if ((left instanceof Statement && !(left instanceof BlockStatement)) ||
|
|
544 |
| left instanceof VariableDeclaration || |
|
545 |
| left instanceof FieldDeclaration || |
|
546 |
| left instanceof Expression) { |
|
547 |
0
| if (hasNestedError(left)) {
|
|
548 |
0
| if (hasNestedError(right)) { _log.commonErrorStatement(context, left, right); }
|
|
549 |
0
| else { _log.leftErrorStatement(context, left, right); }
|
|
550 |
0
| return;
|
|
551 |
| } |
|
552 |
0
| else if (hasNestedError(right)) {
|
|
553 |
0
| _log.rightErrorStatement(context, left, right);
|
|
554 |
0
| return;
|
|
555 |
| } |
|
556 |
| } |
|
557 |
0
| if (NodeProperties.hasMethod(left)) {
|
|
558 |
0
| DJMethod m = NodeProperties.getMethod(left);
|
|
559 |
0
| if (left instanceof MethodCall && !IterUtil.isEmpty(m.typeParameters())) {
|
|
560 |
0
| _log.polymorphicInvocation(context, left, right, ((MethodCall) left).getTypeArgs().isNone());
|
|
561 |
| } |
|
562 |
0
| else if (left instanceof MethodDeclaration && !IterUtil.isEmpty(m.typeParameters())) {
|
|
563 |
0
| _log.polymorphicDeclaration(context, left, right);
|
|
564 |
| } |
|
565 |
| } |
|
566 |
0
| if (NodeProperties.hasConstructor(left)) {
|
|
567 |
0
| DJConstructor k = NodeProperties.getConstructor(left);
|
|
568 |
0
| if (!IterUtil.isEmpty(k.typeParameters())) {
|
|
569 |
0
| Boolean inferred = null;
|
|
570 |
0
| if (left instanceof ConstructorCall) { inferred = true; }
|
|
571 |
0
| else if (left instanceof SimpleAllocation) { inferred = ((SimpleAllocation) left).getTypeArgs().isNone(); }
|
|
572 |
0
| else if (left instanceof InnerAllocation) { inferred = ((InnerAllocation) left).getTypeArgs().isNone(); }
|
|
573 |
0
| if (inferred != null) { _log.polymorphicInvocation(context, left, right, inferred); }
|
|
574 |
0
| if (left instanceof ConstructorDeclaration) { _log.polymorphicDeclaration(context, left, right); }
|
|
575 |
| } |
|
576 |
| } |
|
577 |
0
| if (left instanceof HookTypeName) {
|
|
578 |
0
| HookTypeName t = (HookTypeName) left;
|
|
579 |
0
| _log.wildcard(context, left, right, t.getUpperBound().isSome(), t.getLowerBound().isSome());
|
|
580 |
| } |
|
581 |
0
| Class<?> c = left.getClass();
|
|
582 |
0
| while (!c.equals(Node.class)) {
|
|
583 |
0
| compareDeclaredFields(c, left, right);
|
|
584 |
0
| c = c.getSuperclass();
|
|
585 |
| } |
|
586 |
0
| Field props;
|
|
587 |
0
| try { props = Node.class.getDeclaredField("properties"); }
|
|
588 |
0
| catch (NoSuchFieldException e) { throw new RuntimeException(e); }
|
|
589 |
0
| compareProperties(left.getClass(), (Map<?,?>) fieldValue(props, left), left,
|
|
590 |
| (Map<?,?>) fieldValue(props, right), right); |
|
591 |
| } |
|
592 |
| else { |
|
593 |
0
| _log.mismatch("Different classes", context, left.getClass().getName(), left,
|
|
594 |
| right.getClass().getName(), right); |
|
595 |
| } |
|
596 |
| } |
|
597 |
| |
|
598 |
0
| private boolean hasNestedError(Node n) {
|
|
599 |
0
| final Box<Boolean> result = new SimpleBox<Boolean>(false);
|
|
600 |
0
| new PropertiesDepthFirstVisitor() {
|
|
601 |
0
| @Override public void run(Node n) {
|
|
602 |
0
| if (!result.value()) {
|
|
603 |
0
| if (NodeProperties.hasError(n)) { result.set(true); }
|
|
604 |
0
| else { super.run(n); }
|
|
605 |
| } |
|
606 |
| } |
|
607 |
| }.run(n); |
|
608 |
0
| return result.value();
|
|
609 |
| } |
|
610 |
| |
|
611 |
0
| private void compareDeclaredFields(Class<?> c, Node left, Node right) {
|
|
612 |
0
| if (c.equals(ArrayAllocation.class)) {
|
|
613 |
| |
|
614 |
0
| ArrayAllocation leftAlloc = (ArrayAllocation) left;
|
|
615 |
0
| ArrayAllocation rightAlloc = (ArrayAllocation) right;
|
|
616 |
0
| compareObjects("field ArrayAllocation.elementType",
|
|
617 |
| leftAlloc.getElementType(), left, rightAlloc.getElementType(), right); |
|
618 |
0
| compareObjects("field ArrayAllocation.typeDescriptor.dimension",
|
|
619 |
| leftAlloc.getDimension(), left, rightAlloc.getDimension(), right); |
|
620 |
0
| compareObjects("field ArrayAllocation.typeDescriptor.sizes",
|
|
621 |
| leftAlloc.getSizes(), left, rightAlloc.getSizes(), right); |
|
622 |
0
| compareObjects("field ArrayAllocation.typeDescriptor.initialization",
|
|
623 |
| leftAlloc.getInitialization(), left, rightAlloc.getInitialization(), right); |
|
624 |
| } |
|
625 |
| else { |
|
626 |
0
| for (Field f : c.getDeclaredFields()) {
|
|
627 |
0
| String name = "field " + c.getName() + "." + f.getName();
|
|
628 |
0
| compareObjects(name, fieldValue(f, left), left, fieldValue(f, right), right);
|
|
629 |
| } |
|
630 |
| } |
|
631 |
| } |
|
632 |
| |
|
633 |
0
| private void compareProperties(Class<?> c, Map<?,?> leftProps, SourceInfo.Wrapper left,
|
|
634 |
| Map<?,?> rightProps, SourceInfo.Wrapper right) { |
|
635 |
0
| Set<Object> keys = new HashSet<Object>(leftProps.keySet());
|
|
636 |
0
| keys.retainAll(rightProps.keySet());
|
|
637 |
0
| Set<Object> leftKeys = new HashSet<Object>(leftProps.keySet());
|
|
638 |
0
| leftKeys.removeAll(keys);
|
|
639 |
0
| Set<Object> rightKeys = new HashSet<Object>(rightProps.keySet());
|
|
640 |
0
| rightKeys.removeAll(keys);
|
|
641 |
0
| for (Object k : keys) {
|
|
642 |
0
| compareObjects("property " + k + " of " + c.getName(), leftProps.get(k), left, rightProps.get(k), right);
|
|
643 |
| } |
|
644 |
0
| if (leftKeys.contains("assertedType")) {
|
|
645 |
| |
|
646 |
0
| _log.extraRightCast(c.getName(), (Class<?>) ((Thunk<?>) leftProps.get("assertedType")).value(), left, right);
|
|
647 |
0
| leftKeys.remove("assertedType");
|
|
648 |
0
| rightKeys.remove("checkedType");
|
|
649 |
| } |
|
650 |
0
| if (rightKeys.contains("assertedType")) {
|
|
651 |
| |
|
652 |
0
| _log.extraLeftCast(c.getName(), (Class<?>) ((Thunk<?>) rightProps.get("assertedType")).value(), left, right);
|
|
653 |
0
| leftKeys.remove("checkedType");
|
|
654 |
0
| rightKeys.remove("assertedType");
|
|
655 |
| } |
|
656 |
0
| if (leftKeys.contains("checkedType")) {
|
|
657 |
| |
|
658 |
0
| leftKeys.remove("checkedType");
|
|
659 |
| } |
|
660 |
0
| if (rightKeys.contains("checkedType")) {
|
|
661 |
| |
|
662 |
0
| rightKeys.remove("checkedType");
|
|
663 |
| } |
|
664 |
0
| if (!leftKeys.isEmpty() || !rightKeys.isEmpty()) {
|
|
665 |
0
| _log.mismatch("Extra properties", c.getName(), leftKeys.toString(), left, rightKeys.toString(), right);
|
|
666 |
| } |
|
667 |
| } |
|
668 |
| |
|
669 |
0
| private void compareObjects(String context, Object leftVal, SourceInfo.Wrapper left,
|
|
670 |
| Object rightVal, SourceInfo.Wrapper right) { |
|
671 |
| |
|
672 |
0
| if (leftVal == null || rightVal == null) {
|
|
673 |
0
| if (leftVal != null || rightVal != null) {
|
|
674 |
0
| _log.mismatch("Different value", context, ""+leftVal, left, ""+rightVal, right);
|
|
675 |
| } |
|
676 |
| } |
|
677 |
| |
|
678 |
0
| else if (leftVal instanceof Object[] && rightVal instanceof Object[]) {
|
|
679 |
0
| compareObjects(context, Arrays.asList((Object[]) leftVal), left, Arrays.asList((Object[]) rightVal), right);
|
|
680 |
| } |
|
681 |
| |
|
682 |
0
| else if (leftVal instanceof Thunk<?> && rightVal instanceof Thunk<?> ||
|
|
683 |
| leftVal instanceof Lambda<?,?> && rightVal instanceof Lambda<?,?> || |
|
684 |
| leftVal instanceof Lambda2<?,?,?> && rightVal instanceof Lambda2<?,?,?>) {} |
|
685 |
| |
|
686 |
0
| else if (leftVal instanceof IdentifierToken && rightVal instanceof IdentifierToken) {
|
|
687 |
0
| String leftName = ((IdentifierToken) leftVal).image();
|
|
688 |
0
| String rightName = ((IdentifierToken) rightVal).image();
|
|
689 |
0
| if (!leftName.equals(rightName)) {
|
|
690 |
0
| _log.mismatch("Different value", context, leftName, left, rightName, right);
|
|
691 |
| } |
|
692 |
| } |
|
693 |
| |
|
694 |
0
| else if (leftVal instanceof Node && rightVal instanceof Node) {
|
|
695 |
0
| compare(context, (Node) leftVal, (Node) rightVal);
|
|
696 |
| } |
|
697 |
| |
|
698 |
0
| else if (leftVal instanceof List<?> && rightVal instanceof List<?>) {
|
|
699 |
0
| List<?> leftList = (List<?>) leftVal;
|
|
700 |
0
| List<?> rightList = (List<?>) rightVal;
|
|
701 |
0
| if (leftList.size() == rightList.size()) {
|
|
702 |
0
| for (Pair<Object, Object> p : IterUtil.zip(leftList, rightList)) {
|
|
703 |
0
| compareObjects("element of " + context, p.first(), left, p.second(), right);
|
|
704 |
| } |
|
705 |
| } |
|
706 |
| else { |
|
707 |
0
| _log.mismatch("Different lengths", context, ""+leftList.size(), left, ""+rightList.size(), right);
|
|
708 |
| } |
|
709 |
| } |
|
710 |
| |
|
711 |
0
| else if (leftVal instanceof Option<?> && rightVal instanceof Option<?>) {
|
|
712 |
0
| Option<?> leftOpt = (Option<?>) leftVal;
|
|
713 |
0
| Option<?> rightOpt = (Option<?>) rightVal;
|
|
714 |
0
| if (leftOpt.isSome() && rightOpt.isSome()) {
|
|
715 |
0
| compareObjects(context, leftOpt.unwrap(), left, rightOpt.unwrap(), right);
|
|
716 |
| } |
|
717 |
0
| else if (!leftOpt.isNone() || !rightOpt.isNone()) {
|
|
718 |
0
| _log.mismatch("Different value", context, leftVal.toString(), left, rightVal.toString(), right);
|
|
719 |
| } |
|
720 |
| } |
|
721 |
| |
|
722 |
0
| else if (leftVal instanceof Pair<?,?> && rightVal instanceof Pair<?,?>) {
|
|
723 |
0
| Pair<?,?> leftPair = (Pair<?,?>) leftVal;
|
|
724 |
0
| Pair<?,?> rightPair = (Pair<?,?>) rightVal;
|
|
725 |
0
| compareObjects(context, leftPair.first(), left, rightPair.first(), right);
|
|
726 |
0
| compareObjects(context, leftPair.second(), left, rightPair.second(), right);
|
|
727 |
| } |
|
728 |
| |
|
729 |
0
| else if (leftVal instanceof DJClass && rightVal instanceof DJClass) {
|
|
730 |
0
| if (!sameClass((DJClass) leftVal, (DJClass) rightVal)) {
|
|
731 |
0
| _log.mismatch("Different value", context, leftVal.toString(), left, rightVal.toString(), right);
|
|
732 |
| } |
|
733 |
| } |
|
734 |
| |
|
735 |
0
| else if (leftVal instanceof Variable && rightVal instanceof Variable) {
|
|
736 |
0
| if (!sameVariable((Variable) leftVal, (Variable) rightVal)) {
|
|
737 |
0
| _log.mismatch("Different value", context, leftVal.toString(), left, rightVal.toString(), right);
|
|
738 |
| } |
|
739 |
| } |
|
740 |
| |
|
741 |
0
| else if (leftVal instanceof Function && rightVal instanceof Function) {
|
|
742 |
0
| if (!sameFunction((Function) leftVal, (Function) rightVal)) {
|
|
743 |
0
| _log.mismatch("Different value", context, leftVal.toString(), left, rightVal.toString(), right);
|
|
744 |
| } |
|
745 |
| } |
|
746 |
| |
|
747 |
0
| else if (leftVal instanceof Type && rightVal instanceof Type) {
|
|
748 |
0
| if (!sameType((Type) leftVal, (Type) rightVal)) {
|
|
749 |
0
| _log.mismatchedType(context, (Type) leftVal, left, (Type) rightVal, right);
|
|
750 |
| } |
|
751 |
| } |
|
752 |
| |
|
753 |
0
| else if (supportedAtom(leftVal) && supportedAtom(rightVal)) {
|
|
754 |
0
| if (!leftVal.equals(rightVal)) {
|
|
755 |
0
| _log.mismatch("Different value", context, leftVal.toString(), left, rightVal.toString(), right);
|
|
756 |
| } |
|
757 |
| } |
|
758 |
| |
|
759 |
| else { |
|
760 |
0
| _log.mismatch("Unsupported object type", context,
|
|
761 |
| leftVal.getClass().getName(), left, rightVal.getClass().getName(), right); |
|
762 |
| } |
|
763 |
| } |
|
764 |
| |
|
765 |
0
| private boolean supportedAtom(Object val) {
|
|
766 |
0
| return val instanceof String || val instanceof Number || val instanceof Boolean ||
|
|
767 |
| val instanceof Character || val instanceof Class<?> || |
|
768 |
| val instanceof EnumSet<?> || val instanceof Enum<?>; |
|
769 |
| } |
|
770 |
| |
|
771 |
0
| private boolean sameClass(DJClass left, DJClass right) {
|
|
772 |
0
| return left.getClass().equals(right.getClass()) && left.fullName().equals(right.fullName());
|
|
773 |
| } |
|
774 |
| |
|
775 |
0
| private boolean sameVariable(Variable left, Variable right) {
|
|
776 |
0
| if (left.getClass().equals(right.getClass())) {
|
|
777 |
0
| boolean result = true;
|
|
778 |
0
| if (left instanceof DJField) {
|
|
779 |
0
| DJClass leftClass = ((DJField) left).declaringClass();
|
|
780 |
0
| DJClass rightClass = ((DJField) right).declaringClass();
|
|
781 |
0
| result &= (leftClass == rightClass) ||
|
|
782 |
| (leftClass != null && rightClass != null && sameClass(leftClass, rightClass)); |
|
783 |
| } |
|
784 |
0
| result &= left.declaredName().equals(right.declaredName());
|
|
785 |
0
| result &= sameType(left.type(), right.type());
|
|
786 |
| |
|
787 |
0
| return result;
|
|
788 |
| } |
|
789 |
0
| else { return false; }
|
|
790 |
| } |
|
791 |
| |
|
792 |
0
| private boolean sameFunction(Function left, Function right) {
|
|
793 |
0
| if (left.getClass().equals(right.getClass())) {
|
|
794 |
0
| boolean result = true;
|
|
795 |
0
| if (left instanceof DJMethod) {
|
|
796 |
| |
|
797 |
0
| left = ((DJMethod) left).declaredSignature();
|
|
798 |
0
| right = ((DJMethod) right).declaredSignature();
|
|
799 |
0
| result &= left.getClass().equals(right.getClass());
|
|
800 |
0
| DJClass leftClass = ((DJMethod) left).declaringClass();
|
|
801 |
0
| DJClass rightClass = ((DJMethod) right).declaringClass();
|
|
802 |
0
| result &= (leftClass == rightClass) ||
|
|
803 |
| (leftClass != null && rightClass != null && sameClass(leftClass, rightClass)); |
|
804 |
| } |
|
805 |
0
| result &= left.declaredName().equals(right.declaredName());
|
|
806 |
0
| result &= sameType(left.returnType(), right.returnType());
|
|
807 |
0
| result &= IterUtil.sizeOf(left.typeParameters()) == IterUtil.sizeOf(right.typeParameters());
|
|
808 |
0
| result &= IterUtil.sizeOf(left.parameters()) == IterUtil.sizeOf(right.parameters());
|
|
809 |
0
| if (result) {
|
|
810 |
0
| for (Pair<VariableType, VariableType> p : IterUtil.zip(left.typeParameters(), right.typeParameters())) {
|
|
811 |
0
| result &= sameType(p.first(), p.second());
|
|
812 |
| } |
|
813 |
0
| for (Pair<LocalVariable, LocalVariable> p : IterUtil.zip(left.parameters(), right.parameters())) {
|
|
814 |
0
| result &= sameVariable(p.first(), p.second());
|
|
815 |
| } |
|
816 |
| } |
|
817 |
0
| return result;
|
|
818 |
| } |
|
819 |
0
| else { return false; }
|
|
820 |
| } |
|
821 |
| |
|
822 |
0
| private boolean sameType(Type left, final Type right) {
|
|
823 |
0
| return new TypeStructComparer().contains(left, right);
|
|
824 |
| } |
|
825 |
| |
|
826 |
0
| private Object fieldValue(Field f, Object receiver) {
|
|
827 |
0
| try { f.setAccessible(true); }
|
|
828 |
| catch (SecurityException e) { } |
|
829 |
0
| try { return f.get(receiver); }
|
|
830 |
| catch (IllegalAccessException e) { |
|
831 |
0
| throw new RuntimeException(e);
|
|
832 |
| } |
|
833 |
| } |
|
834 |
| |
|
835 |
| private class TypeStructComparer implements Predicate2<Type, Type> { |
|
836 |
| private final RecursionStack2<Type, Type> _stack = new RecursionStack2<Type, Type>(); |
|
837 |
| |
|
838 |
0
| public boolean contains(Type left, final Type right) {
|
|
839 |
0
| if (left.getClass().equals(right.getClass())) {
|
|
840 |
0
| return left.apply(new TypeAbstractVisitor<Boolean>() {
|
|
841 |
0
| @Override public Boolean defaultCase(Type left) { return true; }
|
|
842 |
0
| @Override public Boolean forArrayType(ArrayType left) {
|
|
843 |
0
| return contains(left.ofType(), ((ArrayType) right).ofType());
|
|
844 |
| } |
|
845 |
0
| @Override public Boolean forClassType(ClassType left) {
|
|
846 |
0
| return sameClass(left.ofClass(), ((ClassType) right).ofClass());
|
|
847 |
| } |
|
848 |
0
| @Override public Boolean forParameterizedClassType(ParameterizedClassType left) {
|
|
849 |
0
| return forClassType(left) && compareList(left.typeArguments(),
|
|
850 |
| ((ParameterizedClassType) right).typeArguments()); |
|
851 |
| } |
|
852 |
0
| @Override public Boolean forBoundType(BoundType left) {
|
|
853 |
0
| return compareList(left.ofTypes(), ((BoundType) right).ofTypes());
|
|
854 |
| } |
|
855 |
0
| @Override public Boolean forVariableType(VariableType left) {
|
|
856 |
0
| return handleBoundedSymbol(left.symbol(), ((VariableType) right).symbol());
|
|
857 |
| } |
|
858 |
0
| @Override public Boolean forWildcard(Wildcard left) {
|
|
859 |
0
| return handleBoundedSymbol(left.symbol(), ((Wildcard) right).symbol());
|
|
860 |
| } |
|
861 |
| |
|
862 |
0
| private boolean handleBoundedSymbol(BoundedSymbol left, BoundedSymbol right) {
|
|
863 |
0
| boolean result = true;
|
|
864 |
0
| if (left.generated()) { result &= right.generated(); }
|
|
865 |
0
| else { result &= !right.generated() && left.name().equals(right.name()); }
|
|
866 |
0
| if (result) {
|
|
867 |
0
| Lambda2<Type, Type, Boolean> recur = LambdaUtil.asLambda(TypeStructComparer.this);
|
|
868 |
0
| result &= _stack.apply(recur, true, left.upperBound(), right.upperBound());
|
|
869 |
0
| result &= _stack.apply(recur, true, left.lowerBound(), right.lowerBound());
|
|
870 |
| } |
|
871 |
0
| return result;
|
|
872 |
| } |
|
873 |
| |
|
874 |
| }); |
|
875 |
| } |
|
876 |
0
| else { return false; }
|
|
877 |
| } |
|
878 |
| |
|
879 |
0
| private boolean compareList(Iterable<? extends Type> lefts, Iterable<? extends Type> rights) {
|
|
880 |
0
| return IterUtil.sizeOf(lefts) == IterUtil.sizeOf(rights) && IterUtil.and(lefts, rights, this);
|
|
881 |
| } |
|
882 |
| |
|
883 |
| } |
|
884 |
| |
|
885 |
| } |
|
886 |
| |
|
887 |
| } |