8249197: JShell: variable declaration with unicode type name gets garbled result

8249199: JShell: Consistent representation of unicode

Reviewed-by: jlahoda
This commit is contained in:
Robert Field 2020-07-23 10:37:06 -07:00
parent 5088193336
commit 6e198fec0b
3 changed files with 93 additions and 15 deletions

View File

@ -24,15 +24,13 @@
*/ */
package jdk.jshell; package jdk.jshell;
import java.util.ArrayList; import java.util.*;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.lang.model.element.Modifier; import javax.lang.model.element.Modifier;
import javax.lang.model.element.Name;
import com.sun.source.tree.ArrayTypeTree; import com.sun.source.tree.ArrayTypeTree;
import com.sun.source.tree.AssignmentTree; import com.sun.source.tree.AssignmentTree;
import com.sun.source.tree.ClassTree; import com.sun.source.tree.ClassTree;
@ -49,9 +47,7 @@ import com.sun.tools.javac.tree.Pretty;
import java.io.IOException; import java.io.IOException;
import java.io.StringWriter; import java.io.StringWriter;
import java.io.Writer; import java.io.Writer;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;
import jdk.jshell.ExpressionToTypeInfo.ExpressionInfo; import jdk.jshell.ExpressionToTypeInfo.ExpressionInfo;
import jdk.jshell.ExpressionToTypeInfo.ExpressionInfo.AnonymousDescription; import jdk.jshell.ExpressionToTypeInfo.ExpressionInfo.AnonymousDescription;
import jdk.jshell.ExpressionToTypeInfo.ExpressionInfo.AnonymousDescription.VariableDesc; import jdk.jshell.ExpressionToTypeInfo.ExpressionInfo.AnonymousDescription.VariableDesc;
@ -304,6 +300,7 @@ class Eval {
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();
// String name = userReadableName(vt.getName(), compileSource);
String typeName; String typeName;
String fullTypeName; String fullTypeName;
String displayType; String displayType;
@ -400,13 +397,18 @@ class Eval {
winit = Wrap.simpleWrap(sinit); winit = Wrap.simpleWrap(sinit);
subkind = SubKind.VAR_DECLARATION_SUBKIND; subkind = SubKind.VAR_DECLARATION_SUBKIND;
} }
Wrap wname;
int nameStart = compileSource.lastIndexOf(name, nameMax); int nameStart = compileSource.lastIndexOf(name, nameMax);
if (nameStart < 0) { if (nameStart < 0) {
throw new AssertionError("Name '" + name + "' not found"); // 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);
} }
int nameEnd = nameStart + name.length(); Wrap guts = Wrap.varWrap(compileSource, typeWrap, sbBrackets.toString(), wname,
Range rname = new Range(nameStart, nameEnd);
Wrap guts = Wrap.varWrap(compileSource, typeWrap, sbBrackets.toString(), rname,
winit, enhancedDesugaring, anonDeclareWrap); winit, enhancedDesugaring, anonDeclareWrap);
DiagList modDiag = modifierDiagnostics(vt.getModifiers(), dis, true); DiagList modDiag = modifierDiagnostics(vt.getModifiers(), dis, true);
Snippet snip = new VarSnippet(state.keyMap.keyForVariable(name), userSource, guts, Snippet snip = new VarSnippet(state.keyMap.keyForVariable(name), userSource, guts,
@ -417,6 +419,26 @@ class Eval {
return snippets; return snippets;
} }
private String userReadableName(Name nn, String compileSource) {
String s = nn.toString();
if (s.length() > 0 && Character.isJavaIdentifierStart(s.charAt(0)) && compileSource.contains(s)) {
return s;
}
String l = nameInUnicode(nn, false);
if (compileSource.contains(l)) {
return l;
}
return nameInUnicode(nn, true);
}
private String nameInUnicode(Name nn, boolean upper) {
return nn.codePoints()
.mapToObj(cp -> (cp > 0x7F)
? String.format(upper ? "\\u%04X" : "\\u%04x", cp)
: "" + (char) cp)
.collect(Collectors.joining());
}
/**Convert anonymous classes in "init" to member classes, based /**Convert anonymous classes in "init" to member classes, based
* on the additional information from ExpressionInfo.anonymousClasses. * on the additional information from ExpressionInfo.anonymousClasses.
* *
@ -680,6 +702,7 @@ class Eval {
TreeDissector dis = TreeDissector.createByFirstClass(pt); TreeDissector dis = TreeDissector.createByFirstClass(pt);
ClassTree klassTree = (ClassTree) unitTree; ClassTree klassTree = (ClassTree) unitTree;
// String name = userReadableName(klassTree.getSimpleName(), compileSource);
String name = klassTree.getSimpleName().toString(); String name = klassTree.getSimpleName().toString();
DiagList modDiag = modifierDiagnostics(klassTree.getModifiers(), dis, false); DiagList modDiag = modifierDiagnostics(klassTree.getModifiers(), dis, false);
TypeDeclKey key = state.keyMap.keyForClass(name); TypeDeclKey key = state.keyMap.keyForClass(name);
@ -730,6 +753,7 @@ class Eval {
final TreeDissector dis = TreeDissector.createByFirstClass(pt); final TreeDissector dis = TreeDissector.createByFirstClass(pt);
final MethodTree mt = (MethodTree) unitTree; final MethodTree mt = (MethodTree) unitTree;
//String name = userReadableName(mt.getName(), compileSource);
final String name = mt.getName().toString(); final String name = mt.getName().toString();
if (objectMethods.contains(name)) { if (objectMethods.contains(name)) {
// The name matches a method on Object, short of an overhaul, this // The name matches a method on Object, short of an overhaul, this

View File

@ -80,7 +80,7 @@ abstract class Wrap implements GeneralWrap {
* @param source the snippet's masked source code * @param source the snippet's masked source code
* @param wtype variable's denotable type suitable for field declaration * @param wtype variable's denotable type suitable for field declaration
* @param brackets any [] that should be appended to the type * @param brackets any [] that should be appended to the type
* @param rname range in source that denotes the name of the * @param wname a wrap of the source that denotes the name of the variable
* @param winit Initializer or null * @param winit Initializer or null
* @param enhanced if the real inferred type of the variable is potentially * @param enhanced if the real inferred type of the variable is potentially
* non-denotable, this must be true * non-denotable, this must be true
@ -88,9 +88,8 @@ abstract class Wrap implements GeneralWrap {
* an initialization method * an initialization method
*/ */
public static Wrap varWrap(String source, Wrap wtype, String brackets, public static Wrap varWrap(String source, Wrap wtype, String brackets,
Range rname, Wrap winit, boolean enhanced, Wrap wname, Wrap winit, boolean enhanced,
Wrap anonDeclareWrap) { Wrap anonDeclareWrap) {
RangeWrap wname = new RangeWrap(source, rname);
List<Object> components = new ArrayList<>(); List<Object> components = new ArrayList<>();
components.add(new VarDeclareWrap(wtype, brackets, wname)); components.add(new VarDeclareWrap(wtype, brackets, wname));
Wrap wmeth; Wrap wmeth;

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2020, 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 8248157
* @summary test Unicode characters in Snippets
* @build KullaTesting TestingInputStream
* @run testng UnicodeTest
*/
import jdk.jshell.Snippet;
import jdk.jshell.DeclarationSnippet;
import org.testng.annotations.Test;
import jdk.jshell.Snippet.Status;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import static jdk.jshell.Snippet.Status.VALID;
import static jdk.jshell.Snippet.SubKind.*;
@Test
public class UnicodeTest extends KullaTesting {
public void testVarDeclarationKey() {
assertVarKeyMatch("int \\u00aa;", true, "\u00aa", VAR_DECLARATION_SUBKIND, "int", added(VALID));
assertEval("\\u00aa", "0");
}
public void testVarDeclarationWithInitializerKey() {
assertVarKeyMatch("double \\u00ba\\u0044\\u0577 = 9.4;", true, "\u00ba\u0044\u0577",
VAR_DECLARATION_WITH_INITIALIZER_SUBKIND, "double", added(VALID));
assertEval("\\u00ba\\u0044\\u0577", "9.4");
}
}