8316971: Add Lint warning for restricted method calls
Reviewed-by: ihse, vromero
This commit is contained in:
parent
d4c904d819
commit
0d4de8a71f
@ -23,7 +23,7 @@
|
||||
# questions.
|
||||
#
|
||||
|
||||
DISABLED_WARNINGS_java += this-escape
|
||||
DISABLED_WARNINGS_java += this-escape restricted
|
||||
|
||||
DOCLINT += -Xdoclint:all/protected \
|
||||
'-Xdoclint/package:java.*,javax.*'
|
||||
|
@ -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 \
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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();
|
||||
|
@ -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:
|
||||
|
@ -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.
|
||||
**************************************************************************/
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
55
test/langtools/tools/javac/RestrictedMethods.java
Normal file
55
test/langtools/tools/javac/RestrictedMethods.java
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
9
test/langtools/tools/javac/RestrictedMethods.out
Normal file
9
test/langtools/tools/javac/RestrictedMethods.out
Normal 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
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user