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;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.Name;
import com.sun.source.tree.ArrayTypeTree;
import com.sun.source.tree.AssignmentTree;
import com.sun.source.tree.ClassTree;
@ -49,9 +47,7 @@ import com.sun.tools.javac.tree.Pretty;
import java.io.IOException;
import java.io.StringWriter;
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.AnonymousDescription;
import jdk.jshell.ExpressionToTypeInfo.ExpressionInfo.AnonymousDescription.VariableDesc;
@ -304,6 +300,7 @@ class Eval {
for (Tree unitTree : units) {
VariableTree vt = (VariableTree) unitTree;
String name = vt.getName().toString();
// String name = userReadableName(vt.getName(), compileSource);
String typeName;
String fullTypeName;
String displayType;
@ -400,13 +397,18 @@ class Eval {
winit = Wrap.simpleWrap(sinit);
subkind = SubKind.VAR_DECLARATION_SUBKIND;
}
Wrap wname;
int nameStart = compileSource.lastIndexOf(name, nameMax);
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();
Range rname = new Range(nameStart, nameEnd);
Wrap guts = Wrap.varWrap(compileSource, typeWrap, sbBrackets.toString(), 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,
@ -417,6 +419,26 @@ class Eval {
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
* on the additional information from ExpressionInfo.anonymousClasses.
*
@ -680,6 +702,7 @@ class Eval {
TreeDissector dis = TreeDissector.createByFirstClass(pt);
ClassTree klassTree = (ClassTree) unitTree;
// String name = userReadableName(klassTree.getSimpleName(), compileSource);
String name = klassTree.getSimpleName().toString();
DiagList modDiag = modifierDiagnostics(klassTree.getModifiers(), dis, false);
TypeDeclKey key = state.keyMap.keyForClass(name);
@ -730,6 +753,7 @@ class Eval {
final TreeDissector dis = TreeDissector.createByFirstClass(pt);
final MethodTree mt = (MethodTree) unitTree;
//String name = userReadableName(mt.getName(), compileSource);
final String name = mt.getName().toString();
if (objectMethods.contains(name)) {
// 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 wtype variable's denotable type suitable for field declaration
* @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 enhanced if the real inferred type of the variable is potentially
* non-denotable, this must be true
@ -88,9 +88,8 @@ abstract class Wrap implements GeneralWrap {
* an initialization method
*/
public static Wrap varWrap(String source, Wrap wtype, String brackets,
Range rname, Wrap winit, boolean enhanced,
Wrap wname, Wrap winit, boolean enhanced,
Wrap anonDeclareWrap) {
RangeWrap wname = new RangeWrap(source, rname);
List<Object> components = new ArrayList<>();
components.add(new VarDeclareWrap(wtype, brackets, wname));
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");
}
}