8145239: JShell: throws AssertionError when replace classes with some methods which depends on these classes
Reviewed-by: rfield
This commit is contained in:
parent
47dafa22a0
commit
b592106de3
@ -190,7 +190,7 @@ class Eval {
|
|||||||
|
|
||||||
private List<SnippetEvent> processVariables(String userSource, List<? extends Tree> units, String compileSource, ParseTask pt) {
|
private List<SnippetEvent> processVariables(String userSource, List<? extends Tree> units, String compileSource, ParseTask pt) {
|
||||||
List<SnippetEvent> allEvents = new ArrayList<>();
|
List<SnippetEvent> allEvents = new ArrayList<>();
|
||||||
TreeDissector dis = new TreeDissector(pt);
|
TreeDissector dis = TreeDissector.createByFirstClass(pt);
|
||||||
for (Tree unitTree : units) {
|
for (Tree unitTree : units) {
|
||||||
VariableTree vt = (VariableTree) unitTree;
|
VariableTree vt = (VariableTree) unitTree;
|
||||||
String name = vt.getName().toString();
|
String name = vt.getName().toString();
|
||||||
@ -295,7 +295,7 @@ class Eval {
|
|||||||
TreeDependencyScanner tds = new TreeDependencyScanner();
|
TreeDependencyScanner tds = new TreeDependencyScanner();
|
||||||
tds.scan(unitTree);
|
tds.scan(unitTree);
|
||||||
|
|
||||||
TreeDissector dis = new TreeDissector(pt);
|
TreeDissector dis = TreeDissector.createByFirstClass(pt);
|
||||||
|
|
||||||
ClassTree klassTree = (ClassTree) unitTree;
|
ClassTree klassTree = (ClassTree) unitTree;
|
||||||
String name = klassTree.getSimpleName().toString();
|
String name = klassTree.getSimpleName().toString();
|
||||||
@ -354,7 +354,7 @@ class Eval {
|
|||||||
tds.scan(unitTree);
|
tds.scan(unitTree);
|
||||||
|
|
||||||
MethodTree mt = (MethodTree) unitTree;
|
MethodTree mt = (MethodTree) unitTree;
|
||||||
TreeDissector dis = new TreeDissector(pt);
|
TreeDissector dis = TreeDissector.createByFirstClass(pt);
|
||||||
DiagList modDiag = modifierDiagnostics(mt.getModifiers(), dis, true);
|
DiagList modDiag = modifierDiagnostics(mt.getModifiers(), dis, true);
|
||||||
if (modDiag.hasErrors()) {
|
if (modDiag.hasErrors()) {
|
||||||
return compileFailResult(modDiag, userSource);
|
return compileFailResult(modDiag, userSource);
|
||||||
@ -418,8 +418,8 @@ class Eval {
|
|||||||
private ExpressionInfo typeOfExpression(String expression) {
|
private ExpressionInfo typeOfExpression(String expression) {
|
||||||
Wrap guts = Wrap.methodReturnWrap(expression);
|
Wrap guts = Wrap.methodReturnWrap(expression);
|
||||||
TaskFactory.AnalyzeTask at = trialCompile(guts);
|
TaskFactory.AnalyzeTask at = trialCompile(guts);
|
||||||
if (!at.hasErrors() && at.cuTree() != null) {
|
if (!at.hasErrors() && at.firstCuTree() != null) {
|
||||||
return new TreeDissector(at)
|
return TreeDissector.createByFirstClass(at)
|
||||||
.typeOfReturnStatement(at.messages(), state.maps::fullClassNameAndPackageToClass);
|
.typeOfReturnStatement(at.messages(), state.maps::fullClassNameAndPackageToClass);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@ -513,13 +513,17 @@ class Eval {
|
|||||||
ins.stream().forEach(u -> u.initialize(ins));
|
ins.stream().forEach(u -> u.initialize(ins));
|
||||||
AnalyzeTask at = state.taskFactory.new AnalyzeTask(ins);
|
AnalyzeTask at = state.taskFactory.new AnalyzeTask(ins);
|
||||||
ins.stream().forEach(u -> u.setDiagnostics(at));
|
ins.stream().forEach(u -> u.setDiagnostics(at));
|
||||||
|
|
||||||
// corral any Snippets that need it
|
// corral any Snippets that need it
|
||||||
if (ins.stream().filter(u -> u.corralIfNeeded(ins)).count() > 0) {
|
AnalyzeTask cat;
|
||||||
|
if (ins.stream().anyMatch(u -> u.corralIfNeeded(ins))) {
|
||||||
// if any were corralled, re-analyze everything
|
// if any were corralled, re-analyze everything
|
||||||
AnalyzeTask cat = state.taskFactory.new AnalyzeTask(ins);
|
cat = state.taskFactory.new AnalyzeTask(ins);
|
||||||
ins.stream().forEach(u -> u.setCorralledDiagnostics(cat));
|
ins.stream().forEach(u -> u.setCorralledDiagnostics(cat));
|
||||||
|
} else {
|
||||||
|
cat = at;
|
||||||
}
|
}
|
||||||
ins.stream().forEach(u -> u.setStatus());
|
ins.stream().forEach(u -> u.setStatus(cat));
|
||||||
// compile and load the legit snippets
|
// compile and load the legit snippets
|
||||||
boolean success;
|
boolean success;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -239,7 +239,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis {
|
|||||||
private List<Suggestion> computeSuggestions(OuterWrap code, int cursor, int[] anchor) {
|
private List<Suggestion> computeSuggestions(OuterWrap code, int cursor, int[] anchor) {
|
||||||
AnalyzeTask at = proc.taskFactory.new AnalyzeTask(code);
|
AnalyzeTask at = proc.taskFactory.new AnalyzeTask(code);
|
||||||
SourcePositions sp = at.trees().getSourcePositions();
|
SourcePositions sp = at.trees().getSourcePositions();
|
||||||
CompilationUnitTree topLevel = at.cuTree();
|
CompilationUnitTree topLevel = at.firstCuTree();
|
||||||
List<Suggestion> result = new ArrayList<>();
|
List<Suggestion> result = new ArrayList<>();
|
||||||
TreePath tp = pathFor(topLevel, sp, code.snippetIndexToWrapIndex(cursor));
|
TreePath tp = pathFor(topLevel, sp, code.snippetIndexToWrapIndex(cursor));
|
||||||
if (tp != null) {
|
if (tp != null) {
|
||||||
@ -976,7 +976,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis {
|
|||||||
OuterWrap codeWrap = wrapInClass(Wrap.methodWrap(code));
|
OuterWrap codeWrap = wrapInClass(Wrap.methodWrap(code));
|
||||||
AnalyzeTask at = proc.taskFactory.new AnalyzeTask(codeWrap);
|
AnalyzeTask at = proc.taskFactory.new AnalyzeTask(codeWrap);
|
||||||
SourcePositions sp = at.trees().getSourcePositions();
|
SourcePositions sp = at.trees().getSourcePositions();
|
||||||
CompilationUnitTree topLevel = at.cuTree();
|
CompilationUnitTree topLevel = at.firstCuTree();
|
||||||
TreePath tp = pathFor(topLevel, sp, codeWrap.snippetIndexToWrapIndex(cursor));
|
TreePath tp = pathFor(topLevel, sp, codeWrap.snippetIndexToWrapIndex(cursor));
|
||||||
|
|
||||||
if (tp == null)
|
if (tp == null)
|
||||||
|
@ -56,6 +56,7 @@ import java.util.HashMap;
|
|||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import static java.util.stream.Collectors.toList;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import javax.lang.model.util.Elements;
|
import javax.lang.model.util.Elements;
|
||||||
import javax.tools.FileObject;
|
import javax.tools.FileObject;
|
||||||
@ -196,7 +197,7 @@ class TaskFactory {
|
|||||||
*/
|
*/
|
||||||
class ParseTask extends BaseTask {
|
class ParseTask extends BaseTask {
|
||||||
|
|
||||||
private final CompilationUnitTree cut;
|
private final Iterable<? extends CompilationUnitTree> cuts;
|
||||||
private final List<? extends Tree> units;
|
private final List<? extends Tree> units;
|
||||||
|
|
||||||
ParseTask(final String source) {
|
ParseTask(final String source) {
|
||||||
@ -204,16 +205,13 @@ class TaskFactory {
|
|||||||
new StringSourceHandler(),
|
new StringSourceHandler(),
|
||||||
"-XDallowStringFolding=false", "-proc:none");
|
"-XDallowStringFolding=false", "-proc:none");
|
||||||
ReplParserFactory.instance(getContext());
|
ReplParserFactory.instance(getContext());
|
||||||
Iterable<? extends CompilationUnitTree> asts = parse();
|
cuts = parse();
|
||||||
Iterator<? extends CompilationUnitTree> it = asts.iterator();
|
units = Util.stream(cuts)
|
||||||
if (it.hasNext()) {
|
.flatMap(cut -> {
|
||||||
this.cut = it.next();
|
|
||||||
List<? extends ImportTree> imps = cut.getImports();
|
List<? extends ImportTree> imps = cut.getImports();
|
||||||
this.units = !imps.isEmpty() ? imps : cut.getTypeDecls();
|
return (!imps.isEmpty() ? imps : cut.getTypeDecls()).stream();
|
||||||
} else {
|
})
|
||||||
this.cut = null;
|
.collect(toList());
|
||||||
this.units = Collections.emptyList();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Iterable<? extends CompilationUnitTree> parse() {
|
private Iterable<? extends CompilationUnitTree> parse() {
|
||||||
@ -229,8 +227,8 @@ class TaskFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
CompilationUnitTree cuTree() {
|
Iterable<? extends CompilationUnitTree> cuTrees() {
|
||||||
return cut;
|
return cuts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,7 +237,7 @@ class TaskFactory {
|
|||||||
*/
|
*/
|
||||||
class AnalyzeTask extends BaseTask {
|
class AnalyzeTask extends BaseTask {
|
||||||
|
|
||||||
private final CompilationUnitTree cut;
|
private final Iterable<? extends CompilationUnitTree> cuts;
|
||||||
|
|
||||||
AnalyzeTask(final OuterWrap wrap) {
|
AnalyzeTask(final OuterWrap wrap) {
|
||||||
this(Stream.of(wrap),
|
this(Stream.of(wrap),
|
||||||
@ -255,14 +253,7 @@ class TaskFactory {
|
|||||||
<T>AnalyzeTask(final Stream<T> stream, SourceHandler<T> sourceHandler,
|
<T>AnalyzeTask(final Stream<T> stream, SourceHandler<T> sourceHandler,
|
||||||
String... extraOptions) {
|
String... extraOptions) {
|
||||||
super(stream, sourceHandler, extraOptions);
|
super(stream, sourceHandler, extraOptions);
|
||||||
Iterator<? extends CompilationUnitTree> cuts = analyze().iterator();
|
cuts = analyze();
|
||||||
if (cuts.hasNext()) {
|
|
||||||
this.cut = cuts.next();
|
|
||||||
//proc.debug("AnalyzeTask element=%s cutp=%s cut=%s\n", e, cutp, cut);
|
|
||||||
} else {
|
|
||||||
this.cut = null;
|
|
||||||
//proc.debug("AnalyzeTask -- no elements -- %s\n", getDiagnostics());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Iterable<? extends CompilationUnitTree> analyze() {
|
private Iterable<? extends CompilationUnitTree> analyze() {
|
||||||
@ -276,8 +267,8 @@ class TaskFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
CompilationUnitTree cuTree() {
|
Iterable<? extends CompilationUnitTree> cuTrees() {
|
||||||
return cut;
|
return cuts;
|
||||||
}
|
}
|
||||||
|
|
||||||
Elements getElements() {
|
Elements getElements() {
|
||||||
@ -332,7 +323,7 @@ class TaskFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
CompilationUnitTree cuTree() {
|
Iterable<? extends CompilationUnitTree> cuTrees() {
|
||||||
throw new UnsupportedOperationException("Not supported.");
|
throw new UnsupportedOperationException("Not supported.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -362,7 +353,11 @@ class TaskFactory {
|
|||||||
compilationUnits, context);
|
compilationUnits, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract CompilationUnitTree cuTree();
|
abstract Iterable<? extends CompilationUnitTree> cuTrees();
|
||||||
|
|
||||||
|
CompilationUnitTree firstCuTree() {
|
||||||
|
return cuTrees().iterator().next();
|
||||||
|
}
|
||||||
|
|
||||||
Diag diag(Diagnostic<? extends JavaFileObject> diag) {
|
Diag diag(Diagnostic<? extends JavaFileObject> diag) {
|
||||||
return sourceHandler.diag(diag);
|
return sourceHandler.diag(diag);
|
||||||
|
@ -48,7 +48,10 @@ import jdk.jshell.Wrap.Range;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.function.BinaryOperator;
|
import java.util.function.BinaryOperator;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Stream;
|
||||||
import javax.lang.model.type.TypeMirror;
|
import javax.lang.model.type.TypeMirror;
|
||||||
|
import jdk.jshell.Util.Pair;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utilities for analyzing compiler API parse trees.
|
* Utilities for analyzing compiler API parse trees.
|
||||||
@ -68,23 +71,48 @@ class TreeDissector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final TaskFactory.BaseTask bt;
|
private final TaskFactory.BaseTask bt;
|
||||||
private ClassTree firstClass;
|
private final ClassTree targetClass;
|
||||||
|
private final CompilationUnitTree targetCompilationUnit;
|
||||||
private SourcePositions theSourcePositions = null;
|
private SourcePositions theSourcePositions = null;
|
||||||
|
|
||||||
TreeDissector(TaskFactory.BaseTask bt) {
|
private TreeDissector(TaskFactory.BaseTask bt, CompilationUnitTree targetCompilationUnit, ClassTree targetClass) {
|
||||||
this.bt = bt;
|
this.bt = bt;
|
||||||
|
this.targetCompilationUnit = targetCompilationUnit;
|
||||||
|
this.targetClass = targetClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static TreeDissector createByFirstClass(TaskFactory.BaseTask bt) {
|
||||||
|
Pair<CompilationUnitTree, ClassTree> pair = classes(bt.firstCuTree())
|
||||||
|
.findFirst().orElseGet(() -> new Pair<>(bt.firstCuTree(), null));
|
||||||
|
|
||||||
ClassTree firstClass() {
|
return new TreeDissector(bt, pair.first, pair.second);
|
||||||
if (firstClass == null) {
|
|
||||||
firstClass = computeFirstClass();
|
|
||||||
}
|
|
||||||
return firstClass;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CompilationUnitTree cuTree() {
|
private static final Predicate<? super Tree> isClassOrInterface =
|
||||||
return bt.cuTree();
|
t -> t.getKind() == Tree.Kind.CLASS || t.getKind() == Tree.Kind.INTERFACE;
|
||||||
|
|
||||||
|
private static Stream<Pair<CompilationUnitTree, ClassTree>> classes(CompilationUnitTree cut) {
|
||||||
|
return cut == null
|
||||||
|
? Stream.empty()
|
||||||
|
: cut.getTypeDecls().stream()
|
||||||
|
.filter(isClassOrInterface)
|
||||||
|
.map(decl -> new Pair<>(cut, (ClassTree)decl));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Stream<Pair<CompilationUnitTree, ClassTree>> classes(Iterable<? extends CompilationUnitTree> cuts) {
|
||||||
|
return Util.stream(cuts)
|
||||||
|
.flatMap(TreeDissector::classes);
|
||||||
|
}
|
||||||
|
|
||||||
|
static TreeDissector createBySnippet(TaskFactory.BaseTask bt, Snippet si) {
|
||||||
|
String name = si.className();
|
||||||
|
|
||||||
|
Pair<CompilationUnitTree, ClassTree> pair = classes(bt.cuTrees())
|
||||||
|
.filter(p -> p.second.getSimpleName().contentEquals(name))
|
||||||
|
.findFirst().orElseThrow(() ->
|
||||||
|
new IllegalArgumentException("Class " + name + " is not found."));
|
||||||
|
|
||||||
|
return new TreeDissector(bt, pair.first, pair.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
Types types() {
|
Types types() {
|
||||||
@ -103,11 +131,11 @@ class TreeDissector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int getStartPosition(Tree tree) {
|
int getStartPosition(Tree tree) {
|
||||||
return (int) getSourcePositions().getStartPosition(cuTree(), tree);
|
return (int) getSourcePositions().getStartPosition(targetCompilationUnit, tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
int getEndPosition(Tree tree) {
|
int getEndPosition(Tree tree) {
|
||||||
return (int) getSourcePositions().getEndPosition(cuTree(), tree);
|
return (int) getSourcePositions().getEndPosition(targetCompilationUnit, tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
Range treeToRange(Tree tree) {
|
Range treeToRange(Tree tree) {
|
||||||
@ -134,9 +162,9 @@ class TreeDissector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Tree firstClassMember() {
|
Tree firstClassMember() {
|
||||||
if (firstClass() != null) {
|
if (targetClass != null) {
|
||||||
//TODO: missing classes
|
//TODO: missing classes
|
||||||
for (Tree mem : firstClass().getMembers()) {
|
for (Tree mem : targetClass.getMembers()) {
|
||||||
if (mem.getKind() == Tree.Kind.VARIABLE) {
|
if (mem.getKind() == Tree.Kind.VARIABLE) {
|
||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
@ -152,8 +180,8 @@ class TreeDissector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StatementTree firstStatement() {
|
StatementTree firstStatement() {
|
||||||
if (firstClass() != null) {
|
if (targetClass != null) {
|
||||||
for (Tree mem : firstClass().getMembers()) {
|
for (Tree mem : targetClass.getMembers()) {
|
||||||
if (mem.getKind() == Tree.Kind.METHOD) {
|
if (mem.getKind() == Tree.Kind.METHOD) {
|
||||||
MethodTree mt = (MethodTree) mem;
|
MethodTree mt = (MethodTree) mem;
|
||||||
if (isDoIt(mt.getName())) {
|
if (isDoIt(mt.getName())) {
|
||||||
@ -169,8 +197,8 @@ class TreeDissector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
VariableTree firstVariable() {
|
VariableTree firstVariable() {
|
||||||
if (firstClass() != null) {
|
if (targetClass != null) {
|
||||||
for (Tree mem : firstClass().getMembers()) {
|
for (Tree mem : targetClass.getMembers()) {
|
||||||
if (mem.getKind() == Tree.Kind.VARIABLE) {
|
if (mem.getKind() == Tree.Kind.VARIABLE) {
|
||||||
VariableTree vt = (VariableTree) mem;
|
VariableTree vt = (VariableTree) mem;
|
||||||
return vt;
|
return vt;
|
||||||
@ -180,17 +208,6 @@ class TreeDissector {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ClassTree computeFirstClass() {
|
|
||||||
if (cuTree() == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
for (Tree decl : cuTree().getTypeDecls()) {
|
|
||||||
if (decl.getKind() == Tree.Kind.CLASS || decl.getKind() == Tree.Kind.INTERFACE) {
|
|
||||||
return (ClassTree) decl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExpressionInfo typeOfReturnStatement(JavacMessages messages, BinaryOperator<String> fullClassNameAndPackageToClass) {
|
ExpressionInfo typeOfReturnStatement(JavacMessages messages, BinaryOperator<String> fullClassNameAndPackageToClass) {
|
||||||
ExpressionInfo ei = new ExpressionInfo();
|
ExpressionInfo ei = new ExpressionInfo();
|
||||||
@ -198,7 +215,7 @@ class TreeDissector {
|
|||||||
if (unitTree instanceof ReturnTree) {
|
if (unitTree instanceof ReturnTree) {
|
||||||
ei.tree = ((ReturnTree) unitTree).getExpression();
|
ei.tree = ((ReturnTree) unitTree).getExpression();
|
||||||
if (ei.tree != null) {
|
if (ei.tree != null) {
|
||||||
TreePath viPath = trees().getPath(cuTree(), ei.tree);
|
TreePath viPath = trees().getPath(targetCompilationUnit, ei.tree);
|
||||||
if (viPath != null) {
|
if (viPath != null) {
|
||||||
TypeMirror tm = trees().getTypeMirror(viPath);
|
TypeMirror tm = trees().getTypeMirror(viPath);
|
||||||
if (tm != null) {
|
if (tm != null) {
|
||||||
|
@ -225,7 +225,7 @@ final class Unit {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setStatus() {
|
void setStatus(AnalyzeTask at) {
|
||||||
if (!compilationDiagnostics.hasErrors()) {
|
if (!compilationDiagnostics.hasErrors()) {
|
||||||
status = VALID;
|
status = VALID;
|
||||||
} else if (isRecoverable()) {
|
} else if (isRecoverable()) {
|
||||||
@ -237,7 +237,7 @@ final class Unit {
|
|||||||
} else {
|
} else {
|
||||||
status = REJECTED;
|
status = REJECTED;
|
||||||
}
|
}
|
||||||
checkForOverwrite();
|
checkForOverwrite(at);
|
||||||
|
|
||||||
state.debug(DBG_GEN, "setStatus() %s - status: %s\n",
|
state.debug(DBG_GEN, "setStatus() %s - status: %s\n",
|
||||||
si, status);
|
si, status);
|
||||||
@ -361,17 +361,18 @@ final class Unit {
|
|||||||
si, status, unresolved);
|
si, status, unresolved);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkForOverwrite() {
|
private void checkForOverwrite(AnalyzeTask at) {
|
||||||
secondaryEvents = new ArrayList<>();
|
secondaryEvents = new ArrayList<>();
|
||||||
if (replaceOldEvent != null) secondaryEvents.add(replaceOldEvent);
|
if (replaceOldEvent != null) secondaryEvents.add(replaceOldEvent);
|
||||||
|
|
||||||
// Defined methods can overwrite methods of other (equivalent) snippets
|
// Defined methods can overwrite methods of other (equivalent) snippets
|
||||||
if (si.kind() == Kind.METHOD && status.isDefined) {
|
if (si.kind() == Kind.METHOD && status.isDefined) {
|
||||||
String oqpt = ((MethodSnippet) si).qualifiedParameterTypes();
|
MethodSnippet msi = (MethodSnippet)si;
|
||||||
String nqpt = computeQualifiedParameterTypes(si);
|
String oqpt = msi.qualifiedParameterTypes();
|
||||||
|
String nqpt = computeQualifiedParameterTypes(at, msi);
|
||||||
if (!nqpt.equals(oqpt)) {
|
if (!nqpt.equals(oqpt)) {
|
||||||
((MethodSnippet) si).setQualifiedParamaterTypes(nqpt);
|
msi.setQualifiedParamaterTypes(nqpt);
|
||||||
Status overwrittenStatus = overwriteMatchingMethod(si);
|
Status overwrittenStatus = overwriteMatchingMethod(msi);
|
||||||
if (overwrittenStatus != null) {
|
if (overwrittenStatus != null) {
|
||||||
prevStatus = overwrittenStatus;
|
prevStatus = overwrittenStatus;
|
||||||
signatureChanged = true;
|
signatureChanged = true;
|
||||||
@ -383,19 +384,19 @@ final class Unit {
|
|||||||
// Check if there is a method whose user-declared parameter types are
|
// Check if there is a method whose user-declared parameter types are
|
||||||
// different (and thus has a different snippet) but whose compiled parameter
|
// different (and thus has a different snippet) but whose compiled parameter
|
||||||
// types are the same. if so, consider it an overwrite replacement.
|
// types are the same. if so, consider it an overwrite replacement.
|
||||||
private Status overwriteMatchingMethod(Snippet si) {
|
private Status overwriteMatchingMethod(MethodSnippet msi) {
|
||||||
String qpt = ((MethodSnippet) si).qualifiedParameterTypes();
|
String qpt = msi.qualifiedParameterTypes();
|
||||||
|
|
||||||
// Look through all methods for a method of the same name, with the
|
// Look through all methods for a method of the same name, with the
|
||||||
// same computed qualified parameter types
|
// same computed qualified parameter types
|
||||||
Status overwrittenStatus = null;
|
Status overwrittenStatus = null;
|
||||||
for (MethodSnippet sn : state.methods()) {
|
for (MethodSnippet sn : state.methods()) {
|
||||||
if (sn != null && sn != si && sn.status().isActive && sn.name().equals(si.name())) {
|
if (sn != null && sn != msi && sn.status().isActive && sn.name().equals(msi.name())) {
|
||||||
if (qpt.equals(sn.qualifiedParameterTypes())) {
|
if (qpt.equals(sn.qualifiedParameterTypes())) {
|
||||||
overwrittenStatus = sn.status();
|
overwrittenStatus = sn.status();
|
||||||
SnippetEvent se = new SnippetEvent(
|
SnippetEvent se = new SnippetEvent(
|
||||||
sn, overwrittenStatus, OVERWRITTEN,
|
sn, overwrittenStatus, OVERWRITTEN,
|
||||||
false, si, null, null);
|
false, msi, null, null);
|
||||||
sn.setOverwritten();
|
sn.setOverwritten();
|
||||||
secondaryEvents.add(se);
|
secondaryEvents.add(se);
|
||||||
state.debug(DBG_EVNT,
|
state.debug(DBG_EVNT,
|
||||||
@ -408,20 +409,16 @@ final class Unit {
|
|||||||
return overwrittenStatus;
|
return overwrittenStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String computeQualifiedParameterTypes(Snippet si) {
|
private String computeQualifiedParameterTypes(AnalyzeTask at, MethodSnippet msi) {
|
||||||
MethodSnippet msi = (MethodSnippet) si;
|
String rawSig = TreeDissector.createBySnippet(at, msi).typeOfMethod();
|
||||||
String qpt;
|
|
||||||
AnalyzeTask at = state.taskFactory.new AnalyzeTask(msi.outerWrap());
|
|
||||||
String rawSig = new TreeDissector(at).typeOfMethod();
|
|
||||||
String signature = expunge(rawSig);
|
String signature = expunge(rawSig);
|
||||||
int paren = signature.lastIndexOf(')');
|
int paren = signature.lastIndexOf(')');
|
||||||
if (paren < 0) {
|
|
||||||
// Uncompilable snippet, punt with user parameter types
|
// Extract the parameter type string from the method signature,
|
||||||
qpt = msi.parameterTypes();
|
// if method did not compile use the user-supplied parameter types
|
||||||
} else {
|
return paren >= 0
|
||||||
qpt = signature.substring(0, paren + 1);
|
? signature.substring(0, paren + 1)
|
||||||
}
|
: msi.parameterTypes();
|
||||||
return qpt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SnippetEvent event(String value, Exception exception) {
|
SnippetEvent event(String value, Exception exception) {
|
||||||
|
@ -91,4 +91,14 @@ class Util {
|
|||||||
static <T> Stream<T> stream(Iterable<T> iterable) {
|
static <T> Stream<T> stream(Iterable<T> iterable) {
|
||||||
return StreamSupport.stream(iterable.spliterator(), false);
|
return StreamSupport.stream(iterable.spliterator(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class Pair<T, U> {
|
||||||
|
final T first;
|
||||||
|
final U second;
|
||||||
|
|
||||||
|
Pair(T first, U second) {
|
||||||
|
this.first = first;
|
||||||
|
this.second = second;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* @test
|
* @test
|
||||||
|
* @bug 8145239
|
||||||
* @summary Tests for EvaluationState.classes
|
* @summary Tests for EvaluationState.classes
|
||||||
* @build KullaTesting TestingInputStream ExpectedDiagnostic
|
* @build KullaTesting TestingInputStream ExpectedDiagnostic
|
||||||
* @run testng ClassesTest
|
* @run testng ClassesTest
|
||||||
@ -174,6 +175,27 @@ public class ClassesTest extends KullaTesting {
|
|||||||
assertActiveKeys();
|
assertActiveKeys();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void classesRedeclaration3() {
|
||||||
|
Snippet a = classKey(assertEval("class A { }"));
|
||||||
|
assertClasses(clazz(KullaTesting.ClassType.CLASS, "A"));
|
||||||
|
assertActiveKeys();
|
||||||
|
|
||||||
|
Snippet test1 = methodKey(assertEval("A test() { return null; }"));
|
||||||
|
Snippet test2 = methodKey(assertEval("void test(A a) { }"));
|
||||||
|
Snippet test3 = methodKey(assertEval("void test(int n) {A a;}"));
|
||||||
|
assertActiveKeys();
|
||||||
|
|
||||||
|
assertEval("interface A { }",
|
||||||
|
ste(MAIN_SNIPPET, VALID, VALID, true, null),
|
||||||
|
ste(test1, VALID, VALID, true, MAIN_SNIPPET),
|
||||||
|
ste(test2, VALID, VALID, true, MAIN_SNIPPET),
|
||||||
|
ste(test3, VALID, VALID, false, MAIN_SNIPPET),
|
||||||
|
ste(a, VALID, OVERWRITTEN, false, MAIN_SNIPPET));
|
||||||
|
assertClasses(clazz(KullaTesting.ClassType.INTERFACE, "A"));
|
||||||
|
assertMethods(method("()A", "test"), method("(A)void", "test"), method("(int)void", "test"));
|
||||||
|
assertActiveKeys();
|
||||||
|
}
|
||||||
|
|
||||||
public void classesCyclic1() {
|
public void classesCyclic1() {
|
||||||
Snippet b = classKey(assertEval("class B extends A { }",
|
Snippet b = classKey(assertEval("class B extends A { }",
|
||||||
added(RECOVERABLE_NOT_DEFINED)));
|
added(RECOVERABLE_NOT_DEFINED)));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user