8316971: Add Lint warning for restricted method calls

Reviewed-by: ihse, vromero
This commit is contained in:
Maurizio Cimadamore 2023-10-04 09:36:53 +00:00
parent d4c904d819
commit 0d4de8a71f
15 changed files with 119 additions and 4 deletions

View File

@ -23,7 +23,7 @@
# questions.
#
DISABLED_WARNINGS_java += this-escape
DISABLED_WARNINGS_java += this-escape restricted
DOCLINT += -Xdoclint:all/protected \
'-Xdoclint/package:java.*,javax.*'

View File

@ -91,7 +91,7 @@ $(eval $(call SetupJavaCompilation, BUILD_JDK_MICROBENCHMARK, \
TARGET_RELEASE := $(TARGET_RELEASE_NEWJDK_UPGRADED), \
SMALL_JAVA := false, \
CLASSPATH := $(MICROBENCHMARK_CLASSPATH), \
DISABLED_WARNINGS := this-escape processing rawtypes cast serial preview, \
DISABLED_WARNINGS := restricted this-escape processing rawtypes cast serial preview, \
SRC := $(MICROBENCHMARK_SRC), \
BIN := $(MICROBENCHMARK_CLASSES), \
JAVAC_FLAGS := --add-exports java.base/sun.security.util=ALL-UNNAMED \

View File

@ -389,13 +389,18 @@ public class Flags {
*/
public static final long SEALED = 1L<<62; // ClassSymbols
/**
* Flag to indicate restricted method declaration.
*/
public static final long RESTRICTED = 1L<<62; // MethodSymbols
/**
* Flag to indicate that the class/interface was declared with the non-sealed modifier.
*/
public static final long NON_SEALED = 1L<<63; // ClassSymbols
/**
* Describe modifier flags as they migh appear in source code, i.e.,
* Describe modifier flags as they might appear in source code, i.e.,
* separated by spaces and in the order suggested by JLS 8.1.1.
*/
public static String toSource(long flags) {

View File

@ -335,7 +335,12 @@ public class Lint
/**
* Warn about use of preview features.
*/
PREVIEW("preview");
PREVIEW("preview"),
/**
* Warn about use of restricted methods.
*/
RESTRICTED("restricted");
LintCategory(String option) {
this(option, false);

View File

@ -220,6 +220,7 @@ public class Symtab {
public final Type functionalInterfaceType;
public final Type previewFeatureType;
public final Type previewFeatureInternalType;
public final Type restrictedType;
public final Type typeDescriptorType;
public final Type recordType;
public final Type switchBootstrapsType;
@ -610,6 +611,7 @@ public class Symtab {
functionalInterfaceType = enterClass("java.lang.FunctionalInterface");
previewFeatureType = enterClass("jdk.internal.javac.PreviewFeature");
previewFeatureInternalType = enterSyntheticAnnotation("jdk.internal.PreviewFeature+Annotation");
restrictedType = enterClass("jdk.internal.javac.Restricted");
typeDescriptorType = enterClass("java.lang.invoke.TypeDescriptor");
recordType = enterClass("java.lang.Record");
switchBootstrapsType = enterClass("java.lang.runtime.SwitchBootstraps");

View File

@ -379,6 +379,11 @@ public class Annotate {
&& types.isSameType(c.type, syms.valueBasedType)) {
toAnnotate.flags_field |= Flags.VALUE_BASED;
}
if (!c.type.isErroneous()
&& types.isSameType(c.type, syms.restrictedType)) {
toAnnotate.flags_field |= Flags.RESTRICTED;
}
}
List<T> buf = List.nil();

View File

@ -4742,6 +4742,7 @@ public class Attr extends JCTree.Visitor {
new ResultInfo(resultInfo.pkind, resultInfo.pt.getReturnType(), resultInfo.checkContext, resultInfo.checkMode),
env, TreeInfo.args(env.tree), resultInfo.pt.getParameterTypes(),
resultInfo.pt.getTypeArguments());
chk.checkRestricted(tree.pos(), sym);
break;
}
case PCK: case ERR:

View File

@ -283,6 +283,15 @@ public class Check {
preview.reportPreviewWarning(pos, Warnings.DeclaredUsingPreview(kindName(sym), sym));
}
/** Log a preview warning.
* @param pos Position to be used for error reporting.
* @param msg A Warning describing the problem.
*/
public void warnRestrictedAPI(DiagnosticPosition pos, Symbol sym) {
if (lint.isEnabled(LintCategory.RESTRICTED))
log.warning(LintCategory.RESTRICTED, pos, Warnings.RestrictedMethod(sym.enclClass(), sym));
}
/** Warn about unchecked operation.
* @param pos Position to be used for error reporting.
* @param msg A string describing the problem.
@ -3850,6 +3859,12 @@ public class Check {
}
}
void checkRestricted(DiagnosticPosition pos, Symbol s) {
if (s.kind == MTH && (s.flags() & RESTRICTED) != 0) {
deferredLintHandler.report(() -> warnRestrictedAPI(pos, s));
}
}
/* *************************************************************************
* Check for recursive annotation elements.
**************************************************************************/

View File

@ -1509,6 +1509,9 @@ public class ClassReader {
} else if (proxy.type.tsym.flatName() == syms.valueBasedInternalType.tsym.flatName()) {
Assert.check(sym.kind == TYP);
sym.flags_field |= VALUE_BASED;
} else if (proxy.type.tsym.flatName() == syms.restrictedType.tsym.flatName()) {
Assert.check(sym.kind == MTH);
sym.flags_field |= RESTRICTED;
} else {
if (proxy.type.tsym == syms.annotationTargetType.tsym) {
target = proxy;
@ -1522,6 +1525,9 @@ public class ClassReader {
setFlagIfAttributeTrue(proxy, sym, names.reflective, PREVIEW_REFLECTIVE);
} else if (proxy.type.tsym == syms.valueBasedType.tsym && sym.kind == TYP) {
sym.flags_field |= VALUE_BASED;
} else if (proxy.type.tsym == syms.restrictedType.tsym) {
Assert.check(sym.kind == MTH);
sym.flags_field |= RESTRICTED;
}
proxies.append(proxy);
}

View File

@ -1917,6 +1917,11 @@ compiler.err.is.preview=\
compiler.warn.is.preview.reflective=\
{0} is a reflective preview API and may be removed in a future release.
# 0: symbol, 1: symbol
compiler.warn.restricted.method=\
{0}.{1} is a restricted method.\n\
(Restricted methods are unsafe and, if used incorrectly, might crash the Java runtime or corrupt memory)
# 0: symbol
compiler.warn.has.been.deprecated.module=\
module {0} has been deprecated

View File

@ -282,6 +282,9 @@ javac.opt.Xlint.desc.varargs=\
javac.opt.Xlint.desc.preview=\
Warn about use of preview language features.
javac.opt.Xlint.desc.restricted=\
Warn about use of restricted methods.
javac.opt.Xlint.desc.synchronization=\
Warn about synchronization attempts on instances of value-based classes.

View File

@ -173,6 +173,7 @@ import javax.tools.StandardLocation;
* <tr><th scope="row">{@code preview} <td>use of preview language features
* <tr><th scope="row">{@code rawtypes} <td>use of raw types
* <tr><th scope="row">{@code removal} <td>use of API that has been marked for removal
* <tr><th scope="row">{@code restricted} <td>use of restricted methods
* <tr><th scope="row">{@code requires-automatic} <td>use of automatic modules in the {@code requires} clauses
* <tr><th scope="row">{@code requires-transitive-automatic} <td>automatic modules in {@code requires transitive}
* <tr><th scope="row">{@code serial} <td>{@link java.base/java.io.Serializable Serializable} classes

View File

@ -0,0 +1,55 @@
/*
* @test /nodynamiccopyright/
* @bug 8316971
* @summary Smoke test for restricted method call warnings
* @compile/fail/ref=RestrictedMethods.out -Xlint:restricted -Werror -XDrawDiagnostics --enable-preview --source ${jdk.version} RestrictedMethods.java
* @compile -Werror --enable-preview --source ${jdk.version} RestrictedMethods.java
*/
import java.lang.foreign.MemorySegment;
import java.util.function.Function;
class RestrictedMethods {
MemorySegment warn = MemorySegment.NULL.reinterpret(10); // warning here
@SuppressWarnings("restricted")
MemorySegment suppressed = MemorySegment.NULL.reinterpret(10); // no warning here
Function<Integer, MemorySegment> warn_ref = MemorySegment.NULL::reinterpret; // warning here
@SuppressWarnings("restricted")
Function<Integer, MemorySegment> suppressed_ref = MemorySegment.NULL::reinterpret; // no warning here
void testWarn() {
MemorySegment.NULL.reinterpret(10); // warning here
}
@SuppressWarnings("restricted")
void testSuppressed() {
MemorySegment.NULL.reinterpret(10); // no warning here
}
Function<Integer, MemorySegment> testWarnRef() {
return MemorySegment.NULL::reinterpret; // warning here
}
@SuppressWarnings("restricted")
Function<Integer, MemorySegment> testSuppressedRef() {
return MemorySegment.NULL::reinterpret; // no warning here
}
@SuppressWarnings("restricted")
static class Nested {
MemorySegment suppressedNested = MemorySegment.NULL.reinterpret(10); // no warning here
Function<Integer, MemorySegment> suppressedNested_ref = MemorySegment.NULL::reinterpret; // no warning here
void testSuppressedNested() {
MemorySegment.NULL.reinterpret(10); // no warning here
}
Function<Integer, MemorySegment> testSuppressedNestedRef() {
return MemorySegment.NULL::reinterpret; // no warning here
}
}
}

View File

@ -0,0 +1,9 @@
RestrictedMethods.java:14:44: compiler.warn.restricted.method: java.lang.foreign.MemorySegment, reinterpret(long)
RestrictedMethods.java:18:49: compiler.warn.restricted.method: java.lang.foreign.MemorySegment, reinterpret(long)
RestrictedMethods.java:24:27: compiler.warn.restricted.method: java.lang.foreign.MemorySegment, reinterpret(long)
RestrictedMethods.java:33:16: compiler.warn.restricted.method: java.lang.foreign.MemorySegment, reinterpret(long)
- compiler.err.warnings.and.werror
- compiler.note.preview.filename: RestrictedMethods.java, DEFAULT
- compiler.note.preview.recompile
1 error
4 warnings

View File

@ -215,3 +215,6 @@ compiler.misc.illegal.signature # the compiler can
# this one needs a forged class file to be reproduced
compiler.err.annotation.unrecognized.attribute.name
# this one is transitional (waiting for FFM API to exit preview)
compiler.warn.restricted.method