Skip to content

Commit 70157c7

Browse files
committed
8272135: jshell: Method cannot use its overloaded version
Reviewed-by: vromero
1 parent 5caa77b commit 70157c7

File tree

4 files changed

+108
-19
lines changed

4 files changed

+108
-19
lines changed

src/jdk.jshell/share/classes/jdk/jshell/Eval.java

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -34,14 +34,17 @@
3434
import com.sun.source.tree.ArrayTypeTree;
3535
import com.sun.source.tree.AssignmentTree;
3636
import com.sun.source.tree.ClassTree;
37+
import com.sun.source.tree.CompilationUnitTree;
3738
import com.sun.source.tree.ExpressionStatementTree;
3839
import com.sun.source.tree.ExpressionTree;
3940
import com.sun.source.tree.IdentifierTree;
41+
import com.sun.source.tree.MethodInvocationTree;
4042
import com.sun.source.tree.MethodTree;
4143
import com.sun.source.tree.ModifiersTree;
4244
import com.sun.source.tree.NewClassTree;
4345
import com.sun.source.tree.Tree;
4446
import com.sun.source.tree.VariableTree;
47+
import com.sun.source.util.TreePathScanner;
4548
import com.sun.tools.javac.tree.JCTree;
4649
import com.sun.tools.javac.tree.Pretty;
4750
import java.io.IOException;
@@ -829,7 +832,7 @@ private Kind kindOfTree(Tree tree) {
829832
* @param userSource the incoming bad user source
830833
* @return a rejected snippet
831834
*/
832-
private List<Snippet> compileFailResult(BaseTask xt, String userSource, Kind probableKind) {
835+
private List<Snippet> compileFailResult(BaseTask<?> xt, String userSource, Kind probableKind) {
833836
return compileFailResult(xt.getDiagnostics(), userSource, probableKind);
834837
}
835838

@@ -1007,6 +1010,53 @@ private Set<Unit> compileAndLoad(Set<Unit> ins) {
10071010

10081011
ins.stream().forEach(Unit::initialize);
10091012
ins.stream().forEach(u -> u.setWrap(ins, ins));
1013+
1014+
if (ins.stream().anyMatch(u -> u.snippet().kind() == Kind.METHOD)) {
1015+
//if there is any method declaration, check the body of the method for
1016+
//invocations of a method of the same name. It may be an invocation of
1017+
//an overloaded method, in which case we need to add all the overloads to
1018+
//ins, so that they are processed together and can refer to each other:
1019+
Set<Unit> overloads = new LinkedHashSet<>();
1020+
Map<OuterWrap, Unit> outter2Unit = new LinkedHashMap<>();
1021+
ins.forEach(u -> outter2Unit.put(u.snippet().outerWrap(), u));
1022+
1023+
state.taskFactory.analyze(outter2Unit.keySet(), at -> {
1024+
Set<Unit> suspiciousMethodInvocation = new LinkedHashSet<>();
1025+
for (CompilationUnitTree cut : at.cuTrees()) {
1026+
Unit unit = outter2Unit.get(at.sourceForFile(cut.getSourceFile()));
1027+
String name = unit.snippet().name();
1028+
1029+
new TreePathScanner<Void, Void>() {
1030+
@Override
1031+
public Void visitMethodInvocation(MethodInvocationTree node, Void p) {
1032+
if (node.getMethodSelect().getKind() == Tree.Kind.IDENTIFIER &&
1033+
((IdentifierTree) node.getMethodSelect()).getName().contentEquals(name)) {
1034+
suspiciousMethodInvocation.add(unit);
1035+
}
1036+
return super.visitMethodInvocation(node, p);
1037+
}
1038+
1039+
}.scan(cut, null);
1040+
}
1041+
for (Unit source : suspiciousMethodInvocation) {
1042+
for (Snippet dep : state.maps.snippetList()) {
1043+
if (dep != source.snippet() && dep.status().isActive() &&
1044+
dep.kind() == Kind.METHOD &&
1045+
source.snippet().kind() == Kind.METHOD &&
1046+
dep.name().equals(source.snippet().name())) {
1047+
overloads.add(new Unit(state, dep, source.snippet(), new DiagList()));
1048+
}
1049+
}
1050+
}
1051+
return null;
1052+
});
1053+
1054+
if (ins.addAll(overloads)) {
1055+
ins.stream().forEach(Unit::initialize);
1056+
ins.stream().forEach(u -> u.setWrap(ins, ins));
1057+
}
1058+
}
1059+
10101060
state.taskFactory.analyze(outerWrapSet(ins), at -> {
10111061
ins.stream().forEach(u -> u.setDiagnostics(at));
10121062

src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import com.sun.source.util.Trees;
3131
import com.sun.tools.javac.api.JavacTaskImpl;
3232
import com.sun.tools.javac.util.Context;
33+
import java.net.URI;
3334
import java.util.ArrayList;
3435
import java.util.List;
3536
import javax.tools.Diagnostic;
@@ -189,7 +190,7 @@ public <Z> Z compile(Collection<OuterWrap> wraps,
189190
worker);
190191
}
191192

192-
private <S, T extends BaseTask, Z> Z runTask(Stream<S> inputs,
193+
private <S, T extends BaseTask<S>, Z> Z runTask(Stream<S> inputs,
193194
SourceHandler<S> sh,
194195
List<String> options,
195196
BiFunction<JavacTaskImpl, DiagnosticCollector<JavaFileObject>, T> creator,
@@ -230,7 +231,7 @@ private <S, T extends BaseTask, Z> Z runTask(Stream<S> inputs,
230231
});
231232
}
232233

233-
interface Worker<T extends BaseTask, Z> {
234+
interface Worker<T extends BaseTask<?>, Z> {
234235
public Z withTask(T task);
235236
}
236237

@@ -258,15 +259,26 @@ <Z> Z parse(final String source, Worker<ParseTask, Z> worker) {
258259
private interface SourceHandler<T> {
259260

260261
JavaFileObject sourceToFileObject(MemoryFileManager fm, T t);
262+
T sourceForFileObject(JavaFileObject file);
261263

262264
Diag diag(Diagnostic<? extends JavaFileObject> d);
263265
}
264266

265267
private class StringSourceHandler implements SourceHandler<String> {
266268

269+
private final Map<URI, String> file2Snippet = new HashMap<>();
270+
267271
@Override
268272
public JavaFileObject sourceToFileObject(MemoryFileManager fm, String src) {
269-
return fm.createSourceFileObject(src, "$NeverUsedName$", src);
273+
JavaFileObject result = fm.createSourceFileObject(src, "$NeverUsedName$", src);
274+
275+
file2Snippet.put(result.toUri(), src);
276+
return result;
277+
}
278+
279+
@Override
280+
public String sourceForFileObject(JavaFileObject file) {
281+
return file2Snippet.get(file.toUri());
270282
}
271283

272284
@Override
@@ -308,9 +320,19 @@ public String getMessage(Locale locale) {
308320

309321
private class WrapSourceHandler implements SourceHandler<OuterWrap> {
310322

323+
private final Map<URI, OuterWrap> file2Snippet = new HashMap<>();
324+
311325
@Override
312326
public JavaFileObject sourceToFileObject(MemoryFileManager fm, OuterWrap w) {
313-
return fm.createSourceFileObject(w, w.classFullName(), w.wrapped());
327+
JavaFileObject result = fm.createSourceFileObject(w, w.classFullName(), w.wrapped());
328+
329+
file2Snippet.put(result.toUri(), w);
330+
return result;
331+
}
332+
333+
@Override
334+
public OuterWrap sourceForFileObject(JavaFileObject file) {
335+
return file2Snippet.get(file.toUri());
314336
}
315337

316338
/**
@@ -332,7 +354,7 @@ public Diag diag(Diagnostic<? extends JavaFileObject> d) {
332354
* Parse a snippet of code (as a String) using the parser subclass. Return
333355
* the parse tree (and errors).
334356
*/
335-
class ParseTask extends BaseTask {
357+
class ParseTask extends BaseTask<String> {
336358

337359
private final Iterable<? extends CompilationUnitTree> cuts;
338360
private final List<? extends Tree> units;
@@ -373,7 +395,7 @@ Iterable<? extends CompilationUnitTree> cuTrees() {
373395
/**
374396
* Run the normal "analyze()" pass of the compiler over the wrapped snippet.
375397
*/
376-
class AnalyzeTask extends BaseTask {
398+
class AnalyzeTask extends BaseTask<OuterWrap> {
377399

378400
private final Iterable<? extends CompilationUnitTree> cuts;
379401

@@ -411,7 +433,7 @@ javax.lang.model.util.Types getTypes() {
411433
/**
412434
* Unit the wrapped snippet to class files.
413435
*/
414-
class CompileTask extends BaseTask {
436+
class CompileTask extends BaseTask<OuterWrap> {
415437

416438
private final Map<OuterWrap, List<OutputMemoryJavaFileObject>> classObjs = new HashMap<>();
417439

@@ -469,18 +491,18 @@ private void initTaskPool() {
469491
javacTaskPool = new JavacTaskPool(5);
470492
}
471493

472-
abstract class BaseTask {
494+
abstract class BaseTask<S> {
473495

474496
final DiagnosticCollector<JavaFileObject> diagnostics;
475497
final JavacTaskImpl task;
476498
private DiagList diags = null;
477-
private final SourceHandler<?> sourceHandler;
499+
private final SourceHandler<S> sourceHandler;
478500
final Context context;
479501
private Types types;
480502
private JavacMessages messages;
481503
private Trees trees;
482504

483-
private <T>BaseTask(SourceHandler<T> sh,
505+
private BaseTask(SourceHandler<S> sh,
484506
JavacTaskImpl task,
485507
DiagnosticCollector<JavaFileObject> diagnostics) {
486508
this.sourceHandler = sh;
@@ -591,6 +613,10 @@ void debugPrintDiagnostics(String src) {
591613
diag.getStartPosition(), diag.getEndPosition(), diag.getMessage(null));
592614
}
593615
}
616+
617+
S sourceForFile(JavaFileObject sourceFile) {
618+
return sourceHandler.sourceForFileObject(sourceFile);
619+
}
594620
}
595621

596622
/**The variable types inferred for "var"s may be non-denotable.

src/jdk.jshell/share/classes/jdk/jshell/TreeDissector.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -58,18 +58,18 @@
5858

5959
class TreeDissector {
6060

61-
private final TaskFactory.BaseTask bt;
61+
private final TaskFactory.BaseTask<?> bt;
6262
private final ClassTree targetClass;
6363
private final CompilationUnitTree targetCompilationUnit;
6464
private SourcePositions theSourcePositions = null;
6565

66-
private TreeDissector(TaskFactory.BaseTask bt, CompilationUnitTree targetCompilationUnit, ClassTree targetClass) {
66+
private TreeDissector(TaskFactory.BaseTask<?> bt, CompilationUnitTree targetCompilationUnit, ClassTree targetClass) {
6767
this.bt = bt;
6868
this.targetCompilationUnit = targetCompilationUnit;
6969
this.targetClass = targetClass;
7070
}
7171

72-
static TreeDissector createByFirstClass(TaskFactory.BaseTask bt) {
72+
static TreeDissector createByFirstClass(TaskFactory.BaseTask<?> bt) {
7373
Pair<CompilationUnitTree, ClassTree> pair = classes(bt.firstCuTree())
7474
.findFirst().orElseGet(() -> new Pair<>(bt.firstCuTree(), null));
7575

@@ -92,7 +92,7 @@ private static Stream<Pair<CompilationUnitTree, ClassTree>> classes(Iterable<? e
9292
.flatMap(TreeDissector::classes);
9393
}
9494

95-
static TreeDissector createBySnippet(TaskFactory.BaseTask bt, Snippet si) {
95+
static TreeDissector createBySnippet(TaskFactory.BaseTask<?> bt, Snippet si) {
9696
String name = si.className();
9797

9898
Pair<CompilationUnitTree, ClassTree> pair = classes(bt.cuTrees())

test/langtools/jdk/jshell/MethodsTest.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
2323

2424
/*
2525
* @test
26-
* @bug 8080357 8167643 8187359 8199762 8080353 8246353 8247456 8267221
26+
* @bug 8080357 8167643 8187359 8199762 8080353 8246353 8247456 8267221 8272135
2727
* @summary Tests for EvaluationState.methods
2828
* @build KullaTesting TestingInputStream ExpectedDiagnostic
2929
* @run testng MethodsTest
@@ -384,4 +384,17 @@ public void testMethodArrayParameters() {
384384
MethodSnippet m3 = methodKey(assertEval("void m3(int[][] p) { }", added(VALID)));
385385
assertEquals(m3.parameterTypes(), "int[][]");
386386
}
387+
388+
public void testOverloadCalls() {
389+
MethodSnippet orig = methodKey(assertEval("int m(String s) { return 0; }"));
390+
MethodSnippet overload = methodKey(assertEval("int m(int i) { return 1; }"));
391+
assertEval("m(\"\")", "0");
392+
assertEval("m(0)", "1");
393+
assertEval("int m(String s) { return m(0); }",
394+
ste(MAIN_SNIPPET, VALID, VALID, true, null),
395+
ste(overload, VALID, VALID, true, MAIN_SNIPPET),
396+
ste(orig, VALID, OVERWRITTEN, false, MAIN_SNIPPET));
397+
assertEval("m(\"\")", "1");
398+
assertEval("m(0)", "1");
399+
}
387400
}

0 commit comments

Comments
 (0)