mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-20 04:43:32 +00:00
8168444: (jdeprscan) improper handling of primitives and primitive array types
Reviewed-by: psandoz, jjg
This commit is contained in:
parent
4a269851c9
commit
d6bf03fe8e
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, 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
|
||||
@ -97,21 +97,70 @@ public class Scan {
|
||||
finder = f;
|
||||
}
|
||||
|
||||
Pattern typePattern = Pattern.compile("\\[*L(.*);");
|
||||
|
||||
// "flattens" an array type name to its component type
|
||||
// and a reference type "Lpkg/pkg/pkg/name;" to its base name
|
||||
// "pkg/pkg/pkg/name".
|
||||
// TODO: deal with primitive types
|
||||
String flatten(String typeName) {
|
||||
Matcher matcher = typePattern.matcher(typeName);
|
||||
/**
|
||||
* Given a descriptor type, extracts and returns the class name from it, if any.
|
||||
* These types are obtained from field descriptors (JVMS 4.3.2) and method
|
||||
* descriptors (JVMS 4.3.3). They have one of the following forms:
|
||||
*
|
||||
* I // or any other primitive, or V for void
|
||||
* [I // array of primitives, including multi-dimensional
|
||||
* Lname; // the named class
|
||||
* [Lname; // array whose component is the named class (also multi-d)
|
||||
*
|
||||
* This method extracts and returns the class name, or returns empty for primitives, void,
|
||||
* or array of primitives.
|
||||
*
|
||||
* Returns nullable reference instead of Optional because downstream
|
||||
* processing can throw checked exceptions.
|
||||
*
|
||||
* @param descType the type from a descriptor
|
||||
* @return the extracted class name, or null
|
||||
*/
|
||||
String nameFromDescType(String descType) {
|
||||
Matcher matcher = descTypePattern.matcher(descType);
|
||||
if (matcher.matches()) {
|
||||
return matcher.group(1);
|
||||
} else {
|
||||
return typeName;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Pattern descTypePattern = Pattern.compile("\\[*L(.*);");
|
||||
|
||||
/**
|
||||
* Given a ref type name, extracts and returns the class name from it, if any.
|
||||
* Ref type names are obtained from a Class_info structure (JVMS 4.4.1) and from
|
||||
* Fieldref_info, Methodref_info, and InterfaceMethodref_info structures (JVMS 4.4.2).
|
||||
* They represent named classes or array classes mentioned by name, and they
|
||||
* represent class or interface types that have the referenced field or method
|
||||
* as a member. They have one of the following forms:
|
||||
*
|
||||
* [I // array of primitives, including multi-dimensional
|
||||
* name // the named class
|
||||
* [Lname; // array whose component is the named class (also multi-d)
|
||||
*
|
||||
* Notably, a plain class name doesn't have the L prefix and ; suffix, and
|
||||
* primitives and void do not occur.
|
||||
*
|
||||
* Returns nullable reference instead of Optional because downstream
|
||||
* processing can throw checked exceptions.
|
||||
*
|
||||
* @param refType a reference type name
|
||||
* @return the extracted class name, or null
|
||||
*/
|
||||
String nameFromRefType(String refType) {
|
||||
Matcher matcher = refTypePattern.matcher(refType);
|
||||
if (matcher.matches()) {
|
||||
return matcher.group(1);
|
||||
} else if (refType.startsWith("[")) {
|
||||
return null;
|
||||
} else {
|
||||
return refType;
|
||||
}
|
||||
}
|
||||
|
||||
Pattern refTypePattern = Pattern.compile("\\[+L(.*);");
|
||||
|
||||
String typeKind(ClassFile cf) {
|
||||
AccessFlags flags = cf.access_flags;
|
||||
if (flags.is(ACC_ENUM)) {
|
||||
@ -381,10 +430,12 @@ public class Scan {
|
||||
*/
|
||||
void checkClasses(ClassFile cf, CPEntries entries) throws ConstantPoolException {
|
||||
for (ConstantPool.CONSTANT_Class_info ci : entries.classes) {
|
||||
String className = ci.getName();
|
||||
DeprData dd = db.getTypeDeprecated(flatten(className));
|
||||
if (dd != null) {
|
||||
printType("scan.out.usesclass", cf, className, dd.isForRemoval());
|
||||
String name = nameFromRefType(ci.getName());
|
||||
if (name != null) {
|
||||
DeprData dd = db.getTypeDeprecated(name);
|
||||
if (dd != null) {
|
||||
printType("scan.out.usesclass", cf, name, dd.isForRemoval());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -393,8 +444,8 @@ public class Scan {
|
||||
* Checks methods referred to from the constant pool.
|
||||
*
|
||||
* @param cf the ClassFile of this class
|
||||
* @param nti the NameAndType_info from a MethodRef or InterfaceMethodRef entry
|
||||
* @param clname the class name
|
||||
* @param nti the NameAndType_info from a MethodRef or InterfaceMethodRef entry
|
||||
* @param msgKey message key for localization
|
||||
* @throws ConstantPoolException if a constant pool entry cannot be found
|
||||
*/
|
||||
@ -404,10 +455,13 @@ public class Scan {
|
||||
String msgKey) throws ConstantPoolException {
|
||||
String name = nti.getName();
|
||||
String type = nti.getType();
|
||||
clname = resolveMember(cf, flatten(clname), name, type, true, true);
|
||||
DeprData dd = db.getMethodDeprecated(clname, name, type);
|
||||
if (dd != null) {
|
||||
printMethod(msgKey, cf, clname, name, type, dd.isForRemoval());
|
||||
clname = nameFromRefType(clname);
|
||||
if (clname != null) {
|
||||
clname = resolveMember(cf, clname, name, type, true, true);
|
||||
DeprData dd = db.getMethodDeprecated(clname, name, type);
|
||||
if (dd != null) {
|
||||
printMethod(msgKey, cf, clname, name, type, dd.isForRemoval());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -419,15 +473,17 @@ public class Scan {
|
||||
*/
|
||||
void checkFieldRef(ClassFile cf,
|
||||
ConstantPool.CONSTANT_Fieldref_info fri) throws ConstantPoolException {
|
||||
String clname = fri.getClassName();
|
||||
String clname = nameFromRefType(fri.getClassName());
|
||||
CONSTANT_NameAndType_info nti = fri.getNameAndTypeInfo();
|
||||
String name = nti.getName();
|
||||
String type = nti.getType();
|
||||
|
||||
clname = resolveMember(cf, flatten(clname), name, type, false, true);
|
||||
DeprData dd = db.getFieldDeprecated(clname, name);
|
||||
if (dd != null) {
|
||||
printField("scan.out.usesfield", cf, clname, name, dd.isForRemoval());
|
||||
if (clname != null) {
|
||||
clname = resolveMember(cf, clname, name, type, false, true);
|
||||
DeprData dd = db.getFieldDeprecated(clname, name);
|
||||
if (dd != null) {
|
||||
printField("scan.out.usesfield", cf, clname, name, dd.isForRemoval());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -439,10 +495,12 @@ public class Scan {
|
||||
*/
|
||||
void checkFields(ClassFile cf) throws ConstantPoolException {
|
||||
for (Field f : cf.fields) {
|
||||
String type = cf.constant_pool.getUTF8Value(f.descriptor.index);
|
||||
DeprData dd = db.getTypeDeprecated(flatten(type));
|
||||
if (dd != null) {
|
||||
printHasField(cf, f.getName(cf.constant_pool), type, dd.isForRemoval());
|
||||
String type = nameFromDescType(cf.constant_pool.getUTF8Value(f.descriptor.index));
|
||||
if (type != null) {
|
||||
DeprData dd = db.getTypeDeprecated(type);
|
||||
if (dd != null) {
|
||||
printHasField(cf, f.getName(cf.constant_pool), type, dd.isForRemoval());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -461,16 +519,21 @@ public class Scan {
|
||||
DeprData dd;
|
||||
|
||||
for (String parm : sig.getParameters()) {
|
||||
dd = db.getTypeDeprecated(flatten(parm));
|
||||
if (dd != null) {
|
||||
printHasMethodParmType(cf, mname, parm, dd.isForRemoval());
|
||||
parm = nameFromDescType(parm);
|
||||
if (parm != null) {
|
||||
dd = db.getTypeDeprecated(parm);
|
||||
if (dd != null) {
|
||||
printHasMethodParmType(cf, mname, parm, dd.isForRemoval());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String ret = sig.getReturnType();
|
||||
dd = db.getTypeDeprecated(flatten(ret));
|
||||
if (dd != null) {
|
||||
printHasMethodRetType(cf, mname, ret, dd.isForRemoval());
|
||||
String ret = nameFromDescType(sig.getReturnType());
|
||||
if (ret != null) {
|
||||
dd = db.getTypeDeprecated(ret);
|
||||
if (dd != null) {
|
||||
printHasMethodRetType(cf, mname, ret, dd.isForRemoval());
|
||||
}
|
||||
}
|
||||
|
||||
// check overrides
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
#jdepr 1
|
||||
#jdepr1
|
||||
METHOD,jdk/deprcases/members/ExampleAnnotation,name()Ljava/lang/String;,,false
|
||||
FIELD,jdk/deprcases/members/ExampleClass,field1,,false
|
||||
FIELD,jdk/deprcases/members/ExampleClass,field2,,false
|
||||
|
||||
|
Can't render this file because it has a wrong number of fields in line 2.
|
@ -0,0 +1,18 @@
|
||||
#jdepr1
|
||||
CLASS,V,,,false
|
||||
CLASS,Z,,,false
|
||||
CLASS,B,,,false
|
||||
CLASS,S,,,false
|
||||
CLASS,C,,,false
|
||||
CLASS,I,,,false
|
||||
CLASS,J,,,false
|
||||
CLASS,F,,,false
|
||||
CLASS,D,,,false
|
||||
CLASS,[Z,,,false
|
||||
CLASS,[B,,,false
|
||||
CLASS,[S,,,false
|
||||
CLASS,[C,,,false
|
||||
CLASS,[I,,,false
|
||||
CLASS,[J,,,false
|
||||
CLASS,[F,,,false
|
||||
CLASS,[D,,,false
|
||||
|
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 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 8168444
|
||||
* @summary Test of jdeprscan handling of primitives and primitive arrays.
|
||||
* @modules jdk.jdeps/com.sun.tools.jdeprscan
|
||||
* @build jdk.jdeprscan.TestPrims
|
||||
* @run testng jdk.jdeprscan.TestPrims
|
||||
*/
|
||||
|
||||
package jdk.jdeprscan;
|
||||
|
||||
import com.sun.tools.jdeprscan.Main;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.util.regex.Pattern;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.testng.Assert.assertFalse;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
public class TestPrims {
|
||||
|
||||
@Test
|
||||
public void test() throws IOException {
|
||||
final String TESTSRC = System.getProperty("test.src");
|
||||
final String TESTCLASSPATH = System.getProperty("test.class.path");
|
||||
String CSV_FILE = TESTSRC + File.separator + "TestPrims.csv";
|
||||
|
||||
ByteArrayOutputStream outBaos = new ByteArrayOutputStream();
|
||||
ByteArrayOutputStream errBaos = new ByteArrayOutputStream();
|
||||
boolean mainResult;
|
||||
|
||||
try (PrintStream out = new PrintStream(outBaos, false, "UTF-8");
|
||||
PrintStream err = new PrintStream(errBaos, false, "UTF-8")) {
|
||||
mainResult = Main.call(
|
||||
out, err,
|
||||
"--class-path", TESTCLASSPATH,
|
||||
"--Xload-csv", CSV_FILE,
|
||||
"jdk.jdeprscan.TestPrims$Usage");
|
||||
// assertion is checked below after output is dumped
|
||||
}
|
||||
|
||||
byte[] outBytes = outBaos.toByteArray();
|
||||
byte[] errBytes = errBaos.toByteArray();
|
||||
ByteArrayInputStream outbais = new ByteArrayInputStream(outBytes);
|
||||
ByteArrayInputStream errbais = new ByteArrayInputStream(errBytes);
|
||||
|
||||
System.out.println("--- stdout ---");
|
||||
outbais.transferTo(System.out);
|
||||
System.out.println("--- end stdout ---");
|
||||
|
||||
System.out.println("--- stderr ---");
|
||||
errbais.transferTo(System.out);
|
||||
System.out.println("--- end stderr ---");
|
||||
|
||||
String outString = new String(outBytes, "UTF-8");
|
||||
String errString = new String(errBytes, "UTF-8");
|
||||
|
||||
// matches message "class <classname> uses deprecated class [I"
|
||||
boolean outMatch = Pattern.compile("^class ").matcher(outString).find();
|
||||
|
||||
// matches message "error: cannot find class [I"
|
||||
boolean errMatch = Pattern.compile("^error: ").matcher(errString).find();
|
||||
|
||||
if (!mainResult) {
|
||||
System.out.println("FAIL: Main.call returned false");
|
||||
}
|
||||
|
||||
if (outMatch) {
|
||||
System.out.println("FAIL: stdout contains unexpected error message");
|
||||
}
|
||||
|
||||
if (errMatch) {
|
||||
System.out.println("FAIL: stderr contains unexpected error message");
|
||||
}
|
||||
|
||||
assertTrue(mainResult && !outMatch && !errMatch);
|
||||
}
|
||||
|
||||
static class Usage {
|
||||
void prims(boolean z, byte b, short s, char c,
|
||||
int i, long j, float f, double d) { }
|
||||
|
||||
void primsArrays(boolean[] z, byte[] b, short[] s, char[] c,
|
||||
int[] i, long[] j, float[] f, double[] d) { }
|
||||
|
||||
boolean zfield;
|
||||
byte bfield;
|
||||
short sfield;
|
||||
char cfield;
|
||||
int ifield;
|
||||
long jfield;
|
||||
float ffield;
|
||||
double dfield;
|
||||
|
||||
boolean[] azfield;
|
||||
byte[] abfield;
|
||||
short[] asfield;
|
||||
char[] acfield;
|
||||
int[] aifield;
|
||||
long[] ajfield;
|
||||
float[] affield;
|
||||
double[] adfield;
|
||||
|
||||
|
||||
Object[] clones() {
|
||||
return new Object[] {
|
||||
azfield.clone(),
|
||||
abfield.clone(),
|
||||
asfield.clone(),
|
||||
acfield.clone(),
|
||||
aifield.clone(),
|
||||
ajfield.clone(),
|
||||
affield.clone(),
|
||||
adfield.clone()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user