8272135: jshell: Method cannot use its overloaded version
Reviewed-by: vromero
This commit is contained in:
parent
5caa77b043
commit
70157c78a8
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -34,14 +34,17 @@ import javax.lang.model.element.Name;
|
||||
import com.sun.source.tree.ArrayTypeTree;
|
||||
import com.sun.source.tree.AssignmentTree;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import com.sun.source.tree.CompilationUnitTree;
|
||||
import com.sun.source.tree.ExpressionStatementTree;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.IdentifierTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.tree.ModifiersTree;
|
||||
import com.sun.source.tree.NewClassTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.source.tree.VariableTree;
|
||||
import com.sun.source.util.TreePathScanner;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.Pretty;
|
||||
import java.io.IOException;
|
||||
@ -829,7 +832,7 @@ class Eval {
|
||||
* @param userSource the incoming bad user source
|
||||
* @return a rejected snippet
|
||||
*/
|
||||
private List<Snippet> compileFailResult(BaseTask xt, String userSource, Kind probableKind) {
|
||||
private List<Snippet> compileFailResult(BaseTask<?> xt, String userSource, Kind probableKind) {
|
||||
return compileFailResult(xt.getDiagnostics(), userSource, probableKind);
|
||||
}
|
||||
|
||||
@ -1007,6 +1010,53 @@ class Eval {
|
||||
|
||||
ins.stream().forEach(Unit::initialize);
|
||||
ins.stream().forEach(u -> u.setWrap(ins, ins));
|
||||
|
||||
if (ins.stream().anyMatch(u -> u.snippet().kind() == Kind.METHOD)) {
|
||||
//if there is any method declaration, check the body of the method for
|
||||
//invocations of a method of the same name. It may be an invocation of
|
||||
//an overloaded method, in which case we need to add all the overloads to
|
||||
//ins, so that they are processed together and can refer to each other:
|
||||
Set<Unit> overloads = new LinkedHashSet<>();
|
||||
Map<OuterWrap, Unit> outter2Unit = new LinkedHashMap<>();
|
||||
ins.forEach(u -> outter2Unit.put(u.snippet().outerWrap(), u));
|
||||
|
||||
state.taskFactory.analyze(outter2Unit.keySet(), at -> {
|
||||
Set<Unit> suspiciousMethodInvocation = new LinkedHashSet<>();
|
||||
for (CompilationUnitTree cut : at.cuTrees()) {
|
||||
Unit unit = outter2Unit.get(at.sourceForFile(cut.getSourceFile()));
|
||||
String name = unit.snippet().name();
|
||||
|
||||
new TreePathScanner<Void, Void>() {
|
||||
@Override
|
||||
public Void visitMethodInvocation(MethodInvocationTree node, Void p) {
|
||||
if (node.getMethodSelect().getKind() == Tree.Kind.IDENTIFIER &&
|
||||
((IdentifierTree) node.getMethodSelect()).getName().contentEquals(name)) {
|
||||
suspiciousMethodInvocation.add(unit);
|
||||
}
|
||||
return super.visitMethodInvocation(node, p);
|
||||
}
|
||||
|
||||
}.scan(cut, null);
|
||||
}
|
||||
for (Unit source : suspiciousMethodInvocation) {
|
||||
for (Snippet dep : state.maps.snippetList()) {
|
||||
if (dep != source.snippet() && dep.status().isActive() &&
|
||||
dep.kind() == Kind.METHOD &&
|
||||
source.snippet().kind() == Kind.METHOD &&
|
||||
dep.name().equals(source.snippet().name())) {
|
||||
overloads.add(new Unit(state, dep, source.snippet(), new DiagList()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
if (ins.addAll(overloads)) {
|
||||
ins.stream().forEach(Unit::initialize);
|
||||
ins.stream().forEach(u -> u.setWrap(ins, ins));
|
||||
}
|
||||
}
|
||||
|
||||
state.taskFactory.analyze(outerWrapSet(ins), at -> {
|
||||
ins.stream().forEach(u -> u.setDiagnostics(at));
|
||||
|
||||
|
@ -30,6 +30,7 @@ import com.sun.source.tree.Tree;
|
||||
import com.sun.source.util.Trees;
|
||||
import com.sun.tools.javac.api.JavacTaskImpl;
|
||||
import com.sun.tools.javac.util.Context;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.tools.Diagnostic;
|
||||
@ -189,7 +190,7 @@ class TaskFactory {
|
||||
worker);
|
||||
}
|
||||
|
||||
private <S, T extends BaseTask, Z> Z runTask(Stream<S> inputs,
|
||||
private <S, T extends BaseTask<S>, Z> Z runTask(Stream<S> inputs,
|
||||
SourceHandler<S> sh,
|
||||
List<String> options,
|
||||
BiFunction<JavacTaskImpl, DiagnosticCollector<JavaFileObject>, T> creator,
|
||||
@ -230,7 +231,7 @@ class TaskFactory {
|
||||
});
|
||||
}
|
||||
|
||||
interface Worker<T extends BaseTask, Z> {
|
||||
interface Worker<T extends BaseTask<?>, Z> {
|
||||
public Z withTask(T task);
|
||||
}
|
||||
|
||||
@ -258,15 +259,26 @@ class TaskFactory {
|
||||
private interface SourceHandler<T> {
|
||||
|
||||
JavaFileObject sourceToFileObject(MemoryFileManager fm, T t);
|
||||
T sourceForFileObject(JavaFileObject file);
|
||||
|
||||
Diag diag(Diagnostic<? extends JavaFileObject> d);
|
||||
}
|
||||
|
||||
private class StringSourceHandler implements SourceHandler<String> {
|
||||
|
||||
private final Map<URI, String> file2Snippet = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public JavaFileObject sourceToFileObject(MemoryFileManager fm, String src) {
|
||||
return fm.createSourceFileObject(src, "$NeverUsedName$", src);
|
||||
JavaFileObject result = fm.createSourceFileObject(src, "$NeverUsedName$", src);
|
||||
|
||||
file2Snippet.put(result.toUri(), src);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String sourceForFileObject(JavaFileObject file) {
|
||||
return file2Snippet.get(file.toUri());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -308,9 +320,19 @@ class TaskFactory {
|
||||
|
||||
private class WrapSourceHandler implements SourceHandler<OuterWrap> {
|
||||
|
||||
private final Map<URI, OuterWrap> file2Snippet = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public JavaFileObject sourceToFileObject(MemoryFileManager fm, OuterWrap w) {
|
||||
return fm.createSourceFileObject(w, w.classFullName(), w.wrapped());
|
||||
JavaFileObject result = fm.createSourceFileObject(w, w.classFullName(), w.wrapped());
|
||||
|
||||
file2Snippet.put(result.toUri(), w);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OuterWrap sourceForFileObject(JavaFileObject file) {
|
||||
return file2Snippet.get(file.toUri());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -332,7 +354,7 @@ class TaskFactory {
|
||||
* Parse a snippet of code (as a String) using the parser subclass. Return
|
||||
* the parse tree (and errors).
|
||||
*/
|
||||
class ParseTask extends BaseTask {
|
||||
class ParseTask extends BaseTask<String> {
|
||||
|
||||
private final Iterable<? extends CompilationUnitTree> cuts;
|
||||
private final List<? extends Tree> units;
|
||||
@ -373,7 +395,7 @@ class TaskFactory {
|
||||
/**
|
||||
* Run the normal "analyze()" pass of the compiler over the wrapped snippet.
|
||||
*/
|
||||
class AnalyzeTask extends BaseTask {
|
||||
class AnalyzeTask extends BaseTask<OuterWrap> {
|
||||
|
||||
private final Iterable<? extends CompilationUnitTree> cuts;
|
||||
|
||||
@ -411,7 +433,7 @@ class TaskFactory {
|
||||
/**
|
||||
* Unit the wrapped snippet to class files.
|
||||
*/
|
||||
class CompileTask extends BaseTask {
|
||||
class CompileTask extends BaseTask<OuterWrap> {
|
||||
|
||||
private final Map<OuterWrap, List<OutputMemoryJavaFileObject>> classObjs = new HashMap<>();
|
||||
|
||||
@ -469,18 +491,18 @@ class TaskFactory {
|
||||
javacTaskPool = new JavacTaskPool(5);
|
||||
}
|
||||
|
||||
abstract class BaseTask {
|
||||
abstract class BaseTask<S> {
|
||||
|
||||
final DiagnosticCollector<JavaFileObject> diagnostics;
|
||||
final JavacTaskImpl task;
|
||||
private DiagList diags = null;
|
||||
private final SourceHandler<?> sourceHandler;
|
||||
private final SourceHandler<S> sourceHandler;
|
||||
final Context context;
|
||||
private Types types;
|
||||
private JavacMessages messages;
|
||||
private Trees trees;
|
||||
|
||||
private <T>BaseTask(SourceHandler<T> sh,
|
||||
private BaseTask(SourceHandler<S> sh,
|
||||
JavacTaskImpl task,
|
||||
DiagnosticCollector<JavaFileObject> diagnostics) {
|
||||
this.sourceHandler = sh;
|
||||
@ -591,6 +613,10 @@ class TaskFactory {
|
||||
diag.getStartPosition(), diag.getEndPosition(), diag.getMessage(null));
|
||||
}
|
||||
}
|
||||
|
||||
S sourceForFile(JavaFileObject sourceFile) {
|
||||
return sourceHandler.sourceForFileObject(sourceFile);
|
||||
}
|
||||
}
|
||||
|
||||
/**The variable types inferred for "var"s may be non-denotable.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -58,18 +58,18 @@ import jdk.jshell.Util.Pair;
|
||||
|
||||
class TreeDissector {
|
||||
|
||||
private final TaskFactory.BaseTask bt;
|
||||
private final TaskFactory.BaseTask<?> bt;
|
||||
private final ClassTree targetClass;
|
||||
private final CompilationUnitTree targetCompilationUnit;
|
||||
private SourcePositions theSourcePositions = null;
|
||||
|
||||
private TreeDissector(TaskFactory.BaseTask bt, CompilationUnitTree targetCompilationUnit, ClassTree targetClass) {
|
||||
private TreeDissector(TaskFactory.BaseTask<?> bt, CompilationUnitTree targetCompilationUnit, ClassTree targetClass) {
|
||||
this.bt = bt;
|
||||
this.targetCompilationUnit = targetCompilationUnit;
|
||||
this.targetClass = targetClass;
|
||||
}
|
||||
|
||||
static TreeDissector createByFirstClass(TaskFactory.BaseTask bt) {
|
||||
static TreeDissector createByFirstClass(TaskFactory.BaseTask<?> bt) {
|
||||
Pair<CompilationUnitTree, ClassTree> pair = classes(bt.firstCuTree())
|
||||
.findFirst().orElseGet(() -> new Pair<>(bt.firstCuTree(), null));
|
||||
|
||||
@ -92,7 +92,7 @@ class TreeDissector {
|
||||
.flatMap(TreeDissector::classes);
|
||||
}
|
||||
|
||||
static TreeDissector createBySnippet(TaskFactory.BaseTask bt, Snippet si) {
|
||||
static TreeDissector createBySnippet(TaskFactory.BaseTask<?> bt, Snippet si) {
|
||||
String name = si.className();
|
||||
|
||||
Pair<CompilationUnitTree, ClassTree> pair = classes(bt.cuTrees())
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8080357 8167643 8187359 8199762 8080353 8246353 8247456 8267221
|
||||
* @bug 8080357 8167643 8187359 8199762 8080353 8246353 8247456 8267221 8272135
|
||||
* @summary Tests for EvaluationState.methods
|
||||
* @build KullaTesting TestingInputStream ExpectedDiagnostic
|
||||
* @run testng MethodsTest
|
||||
@ -384,4 +384,17 @@ public class MethodsTest extends KullaTesting {
|
||||
MethodSnippet m3 = methodKey(assertEval("void m3(int[][] p) { }", added(VALID)));
|
||||
assertEquals(m3.parameterTypes(), "int[][]");
|
||||
}
|
||||
|
||||
public void testOverloadCalls() {
|
||||
MethodSnippet orig = methodKey(assertEval("int m(String s) { return 0; }"));
|
||||
MethodSnippet overload = methodKey(assertEval("int m(int i) { return 1; }"));
|
||||
assertEval("m(\"\")", "0");
|
||||
assertEval("m(0)", "1");
|
||||
assertEval("int m(String s) { return m(0); }",
|
||||
ste(MAIN_SNIPPET, VALID, VALID, true, null),
|
||||
ste(overload, VALID, VALID, true, MAIN_SNIPPET),
|
||||
ste(orig, VALID, OVERWRITTEN, false, MAIN_SNIPPET));
|
||||
assertEval("m(\"\")", "1");
|
||||
assertEval("m(0)", "1");
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user