8309235: Unnamed Variables (_) can't be used in JShell
Co-authored-by: Jan Lahoda <jlahoda@openjdk.org> Co-authored-by: Aggelos Biboudis <abimpoudis@openjdk.org> Reviewed-by: asotona
This commit is contained in:
parent
9d64a9d220
commit
79a4ac791c
@ -3350,7 +3350,8 @@ public class JShellTool implements MessageHandler {
|
||||
String val = state.status(vk) == Status.VALID
|
||||
? feedback.truncateVarValue(state.varValue(vk))
|
||||
: getResourceString("jshell.msg.vars.not.active");
|
||||
hard(" %s %s = %s", vk.typeName(), vk.name(), val);
|
||||
String varName = vk.name();
|
||||
hard(" %s %s = %s", vk.typeName(), varName.isEmpty() ? "_" : varName, val);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
@ -385,21 +385,28 @@ class Eval {
|
||||
subkind = SubKind.VAR_DECLARATION_SUBKIND;
|
||||
}
|
||||
Wrap wname;
|
||||
int nameStart = compileSource.lastIndexOf(name, nameMax);
|
||||
if (nameStart < 0) {
|
||||
// the name has been transformed (e.g. unicode).
|
||||
// Use it directly
|
||||
wname = Wrap.identityWrap(name);
|
||||
String fieldName;
|
||||
if (name.isEmpty()) {
|
||||
fieldName = "$UNNAMED";
|
||||
wname = Wrap.simpleWrap(fieldName);
|
||||
} else {
|
||||
int nameEnd = nameStart + name.length();
|
||||
Range rname = new Range(nameStart, nameEnd);
|
||||
wname = new Wrap.RangeWrap(compileSource, rname);
|
||||
fieldName = name;
|
||||
int nameStart = compileSource.lastIndexOf(name, nameMax);
|
||||
if (nameStart < 0) {
|
||||
// the name has been transformed (e.g. unicode).
|
||||
// Use it directly
|
||||
wname = Wrap.identityWrap(name);
|
||||
} else {
|
||||
int nameEnd = nameStart + name.length();
|
||||
Range rname = new Range(nameStart, nameEnd);
|
||||
wname = new Wrap.RangeWrap(compileSource, rname);
|
||||
}
|
||||
}
|
||||
Wrap guts = Wrap.varWrap(compileSource, typeWrap, sbBrackets.toString(), wname,
|
||||
winit, enhancedDesugaring, anonDeclareWrap);
|
||||
DiagList modDiag = modifierDiagnostics(vt.getModifiers(), dis, true);
|
||||
Snippet snip = new VarSnippet(state.keyMap.keyForVariable(name), userSource, guts,
|
||||
name, subkind, displayType, hasEnhancedType ? fullTypeName : null, anonymousClasses,
|
||||
name, fieldName, subkind, displayType, hasEnhancedType ? fullTypeName : null, anonymousClasses,
|
||||
tds.declareReferences(), modDiag);
|
||||
snippets.add(snip);
|
||||
}
|
||||
@ -659,7 +666,7 @@ class Eval {
|
||||
}
|
||||
Collection<String> declareReferences = null; //TODO
|
||||
snip = new VarSnippet(state.keyMap.keyForVariable(name), userSource, guts,
|
||||
name, SubKind.TEMP_VAR_EXPRESSION_SUBKIND, displayTypeName, fullTypeName, anonymousClasses, declareReferences, null);
|
||||
name, name, SubKind.TEMP_VAR_EXPRESSION_SUBKIND, displayTypeName, fullTypeName, anonymousClasses, declareReferences, null);
|
||||
} else {
|
||||
guts = Wrap.methodReturnWrap(compileSource);
|
||||
snip = new ExpressionSnippet(state.keyMap.keyForExpression(name, typeName), userSource, guts,
|
||||
|
@ -726,7 +726,7 @@ public class JShell implements AutoCloseable {
|
||||
}
|
||||
String value;
|
||||
try {
|
||||
value = executionControl().varValue(snippet.classFullName(), snippet.name());
|
||||
value = executionControl().varValue(snippet.classFullName(), snippet.fieldName());
|
||||
} catch (EngineTerminationException ex) {
|
||||
throw new IllegalStateException(ex.getMessage());
|
||||
} catch (ExecutionControlException ex) {
|
||||
|
@ -65,6 +65,10 @@ class KeyMap {
|
||||
}
|
||||
|
||||
VarKey keyForVariable(String name) {
|
||||
if (name.isEmpty()) {
|
||||
return new VarKey(state, name);
|
||||
}
|
||||
|
||||
return varMap.computeIfAbsent(name, k -> new VarKey(state, name));
|
||||
}
|
||||
|
||||
|
@ -229,7 +229,7 @@ class ReplParser extends JavacParser {
|
||||
} else if ((isVoid || (lastmode & TYPE) != 0) && LAX_IDENTIFIER.test(token.kind)) {
|
||||
// we have "Type Ident", so we can assume it is variable or method declaration
|
||||
pos = token.pos;
|
||||
Name name = ident();
|
||||
Name name = identOrUnderscore();
|
||||
if (token.kind == LPAREN) {
|
||||
// method declaration
|
||||
//mods.flags |= Flags.STATIC;
|
||||
|
@ -101,7 +101,7 @@ final class SnippetMaps {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("package ").append(REPL_PACKAGE).append(";\n");
|
||||
for (Snippet si : keyIndexToSnippet) {
|
||||
if (si != null && si.status().isDefined() && (except == null || !except.contains(si.key()))) {
|
||||
if (si != null && si.status().isDefined() && (except == null || !except.contains(si.key())) && si.name() != null && !si.name().isEmpty()) {
|
||||
sb.append(si.importLine(state));
|
||||
}
|
||||
}
|
||||
|
@ -58,8 +58,10 @@ public class VarSnippet extends DeclarationSnippet {
|
||||
*/
|
||||
final Set<String> anonymousClasses;
|
||||
|
||||
final String fieldName;
|
||||
|
||||
VarSnippet(VarKey key, String userSource, Wrap guts,
|
||||
String name, SubKind subkind, String typeName, String fullTypeName,
|
||||
String name, String fieldName, SubKind subkind, String typeName, String fullTypeName,
|
||||
Set<String> anonymousClasses, Collection<String> declareReferences,
|
||||
DiagList syntheticDiags) {
|
||||
super(key, userSource, guts, name, subkind, null, declareReferences,
|
||||
@ -67,6 +69,11 @@ public class VarSnippet extends DeclarationSnippet {
|
||||
this.typeName = typeName;
|
||||
this.fullTypeName = fullTypeName;
|
||||
this.anonymousClasses = anonymousClasses;
|
||||
this.fieldName = fieldName;
|
||||
}
|
||||
|
||||
String fieldName() {
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
|
57
test/langtools/jdk/jshell/UnnamedTest.java
Normal file
57
test/langtools/jdk/jshell/UnnamedTest.java
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 9999999
|
||||
* @summary Tests for unnamed variables
|
||||
* @library /tools/lib
|
||||
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||
* jdk.compiler/com.sun.tools.javac.main
|
||||
* jdk.jshell
|
||||
* @build Compiler KullaTesting TestingInputStream ExpectedDiagnostic
|
||||
* @run testng UnnamedTest
|
||||
*/
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import jdk.jshell.VarSnippet;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import jdk.jshell.JShell;
|
||||
|
||||
public class UnnamedTest extends KullaTesting {
|
||||
|
||||
@Test
|
||||
public void unnamed() {
|
||||
VarSnippet sn1 = varKey(assertEval("int _ = 0;"));
|
||||
VarSnippet sn2 = varKey(assertEval("String _ = \"x\";"));
|
||||
Assert.assertEquals(getState().varValue(sn1), "0");
|
||||
Assert.assertEquals(getState().varValue(sn2), "\"x\"");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUp(Consumer<JShell.Builder> bc) {
|
||||
super.setUp(bc.andThen(b -> b.compilerOptions("--enable-preview", "--source", System.getProperty("java.specification.version"))));
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user