提交 f1f39f49 编写于 作者: M mcimadamore

7192245: Add parser support for default methods

Summary: Add support for 'default' keyword in modifier position
Reviewed-by: jjg
上级 ab01ae43
......@@ -67,6 +67,7 @@ public class Flags {
if ((mask&NATIVE) != 0) flags.add(Flag.NATIVE);
if ((mask&INTERFACE) != 0) flags.add(Flag.INTERFACE);
if ((mask&ABSTRACT) != 0) flags.add(Flag.ABSTRACT);
if ((mask&DEFAULT) != 0) flags.add(Flag.DEFAULT);
if ((mask&STRICTFP) != 0) flags.add(Flag.STRICTFP);
if ((mask&BRIDGE) != 0) flags.add(Flag.BRIDGE);
if ((mask&SYNTHETIC) != 0) flags.add(Flag.SYNTHETIC);
......@@ -252,6 +253,11 @@ public class Flags {
*/
public static final long CLASH = 1L<<42;
/**
* Flag that marks either a default method or an interface containing default methods
*/
public static final long DEFAULT = 1L<<43;
/** Modifier masks.
*/
public static final int
......@@ -267,7 +273,10 @@ public class Flags {
MethodFlags = AccessFlags | ABSTRACT | STATIC | NATIVE |
SYNCHRONIZED | FINAL | STRICTFP;
public static final long
LocalVarFlags = FINAL | PARAMETER;
ExtendedStandardFlags = (long)StandardFlags | DEFAULT,
InterfaceDefaultMethodMask = ABSTRACT | PUBLIC | STRICTFP | SYNCHRONIZED | DEFAULT,
LocalVarFlags = FINAL | PARAMETER;
public static Set<Modifier> asModifierSet(long flags) {
Set<Modifier> modifiers = modifierSets.get(flags);
......@@ -320,6 +329,7 @@ public class Flags {
NATIVE("native"),
INTERFACE("interface"),
ABSTRACT("abstract"),
DEFAULT("default"),
STRICTFP("strictfp"),
BRIDGE("bridge"),
SYNTHETIC("synthetic"),
......
......@@ -203,6 +203,9 @@ public enum Source {
public boolean allowMethodReferences() {
return compareTo(JDK1_8) >= 0;
}
public boolean allowDefaultMethods() {
return compareTo(JDK1_8) >= 0;
}
public boolean allowEffectivelyFinalInInnerClasses() {
return compareTo(JDK1_8) >= 0;
}
......
......@@ -873,6 +873,7 @@ public class Attr extends JCTree.Visitor {
public void visitMethodDef(JCMethodDecl tree) {
MethodSymbol m = tree.sym;
boolean isDefaultMethod = (m.flags() & DEFAULT) != 0;
Lint lint = env.info.lint.augment(m.annotations, m.flags());
Lint prevLint = chk.setLint(lint);
......@@ -952,8 +953,8 @@ public class Attr extends JCTree.Visitor {
// Empty bodies are only allowed for
// abstract, native, or interface methods, or for methods
// in a retrofit signature class.
if ((owner.flags() & INTERFACE) == 0 &&
(tree.mods.flags & (ABSTRACT | NATIVE)) == 0 &&
if (isDefaultMethod || ((owner.flags() & INTERFACE) == 0 &&
(tree.mods.flags & (ABSTRACT | NATIVE)) == 0) &&
!relax)
log.error(tree.pos(), "missing.meth.body.or.decl.abstract");
if (tree.defaultValue != null) {
......@@ -961,7 +962,7 @@ public class Attr extends JCTree.Visitor {
log.error(tree.pos(),
"default.allowed.in.intf.annotation.member");
}
} else if ((owner.flags() & INTERFACE) != 0) {
} else if ((owner.flags() & INTERFACE) != 0 && !isDefaultMethod) {
log.error(tree.body.pos(), "intf.meth.cant.have.body");
} else if ((tree.mods.flags & ABSTRACT) != 0) {
log.error(tree.pos(), "abstract.meth.cant.have.body");
......
......@@ -1121,8 +1121,14 @@ public class Check {
mask = PRIVATE;
} else
mask = ConstructorFlags;
} else if ((sym.owner.flags_field & INTERFACE) != 0)
mask = implicit = InterfaceMethodFlags;
} else if ((sym.owner.flags_field & INTERFACE) != 0) {
if ((flags & DEFAULT) != 0) {
mask = InterfaceDefaultMethodMask;
implicit = PUBLIC;
} else {
mask = implicit = InterfaceMethodFlags;
}
}
else {
mask = MethodFlags;
}
......@@ -1169,7 +1175,7 @@ public class Check {
default:
throw new AssertionError();
}
long illegal = flags & StandardFlags & ~mask;
long illegal = flags & ExtendedStandardFlags & ~mask;
if (illegal != 0) {
if ((illegal & INTERFACE) != 0) {
log.error(pos, "intf.not.allowed.here");
......@@ -1185,7 +1191,7 @@ public class Check {
// in the presence of inner classes. Should it be deleted here?
checkDisjoint(pos, flags,
ABSTRACT,
PRIVATE | STATIC))
PRIVATE | STATIC | DEFAULT))
&&
checkDisjoint(pos, flags,
ABSTRACT | INTERFACE,
......@@ -1209,7 +1215,7 @@ public class Check {
STRICTFP))) {
// skip
}
return flags & (mask | ~StandardFlags) | implicit;
return flags & (mask | ~ExtendedStandardFlags) | implicit;
}
......
......@@ -116,6 +116,8 @@ public class JavacParser implements Parser {
fac.options.isSet("allowLambda"); //pre-lambda guard
this.allowMethodReferences = source.allowMethodReferences() &&
fac.options.isSet("allowMethodReferences"); //pre-lambda guard
this.allowDefaultMethods = source.allowDefaultMethods() &&
fac.options.isSet("allowDefaultMethods"); //pre-lambda guard
this.keepDocComments = keepDocComments;
docComments = newDocCommentTable(keepDocComments);
this.keepLineMap = keepLineMap;
......@@ -185,6 +187,10 @@ public class JavacParser implements Parser {
*/
boolean allowMethodReferences;
/** Switch: should we allow default methods in interfaces?
*/
boolean allowDefaultMethods;
/** Switch: should we keep docComments?
*/
boolean keepDocComments;
......@@ -2311,6 +2317,7 @@ public class JavacParser implements Parser {
case SYNCHRONIZED: flag = Flags.SYNCHRONIZED; break;
case STRICTFP : flag = Flags.STRICTFP; break;
case MONKEYS_AT : flag = Flags.ANNOTATION; break;
case DEFAULT : checkDefaultMethods(); flag = Flags.DEFAULT; break;
case ERROR : flag = 0; nextToken(); break;
default: break loop;
}
......@@ -3361,6 +3368,12 @@ public class JavacParser implements Parser {
allowMethodReferences = true;
}
}
void checkDefaultMethods() {
if (!allowDefaultMethods) {
log.error(token.pos, "default.methods.not.supported.in.source", source.name);
allowDefaultMethods = true;
}
}
/*
* a functional source tree and end position mappings
......
......@@ -2174,6 +2174,11 @@ compiler.err.method.references.not.supported.in.source=\
method references are not supported in -source {0}\n\
(use -source 8 or higher to enable method references)
# 0: string
compiler.err.default.methods.not.supported.in.source=\
default methods are not supported in -source {0}\n\
(use -source 8 or higher to enable default methods)
########################################
# Diagnostics for verbose resolution
# used by Resolve (debug only)
......
......@@ -248,7 +248,7 @@ public class Pretty extends JCTree.Visitor {
public void printFlags(long flags) throws IOException {
if ((flags & SYNTHETIC) != 0) print("/*synthetic*/ ");
print(TreeInfo.flagNames(flags));
if ((flags & StandardFlags) != 0) print(" ");
if ((flags & ExtendedStandardFlags) != 0) print(" ");
if ((flags & ANNOTATION) != 0) print("@");
}
......
......@@ -790,8 +790,8 @@ public class TreeInfo {
* pre: flags != 0
*/
public static long firstFlag(long flags) {
int flag = 1;
while ((flag & StandardFlags) != 0 && (flag & flags) == 0)
long flag = 1;
while ((flag & flags & ExtendedStandardFlags) == 0)
flag = flag << 1;
return flag;
}
......@@ -799,7 +799,7 @@ public class TreeInfo {
/** Return flags as a string, separated by " ".
*/
public static String flagNames(long flags) {
return Flags.toString(flags & StandardFlags).trim();
return Flags.toString(flags & ExtendedStandardFlags).trim();
}
/** Operator precedences values.
......
/*
* Copyright (c) 2012, 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 7192245
* @summary Automatic test for checking set of allowed modifiers on interface methods
*/
import com.sun.source.util.JavacTask;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import javax.tools.Diagnostic;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
public class TestDefaultMethodsSyntax {
static int checkCount = 0;
enum VersionKind {
PRE_LAMBDA("7"),
LAMBDA("8");
String versionString;
VersionKind(String versionString) {
this.versionString = versionString;
}
List<String> getOptions() {
return Arrays.asList("-XDallowDefaultMethods", "-source", versionString);
}
}
enum ModifierKind {
NONE(""),
PUBLIC("public"),
PROTECTED("protected"),
PRIVATE("private"),
ABSTRACT("abstract"),
STATIC("static"),
NATIVE("native"),
SYNCHRONIZED("synchronized"),
FINAL("final"),
STRICTFP("strictfp"),
DEFAULT("default");
String modStr;
private ModifierKind(String modStr) {
this.modStr = modStr;
}
boolean isAllowed(EnclosingKind ek, ModifierKind otherMod) {
if (this == otherMod) return false;
switch (this) {
case NONE:
return true;
case ABSTRACT:
return otherMod != PRIVATE;
case NATIVE:
return otherMod != ABSTRACT &&
otherMod != STRICTFP;
case FINAL:
case STATIC:
case SYNCHRONIZED:
case STRICTFP:
return otherMod != ABSTRACT;
case PUBLIC:
return true;
case PROTECTED:
return ek == EnclosingKind.ABSTRACT_CLASS;
case DEFAULT:
return otherMod != ABSTRACT;
default:
return true;
}
}
static boolean intersect(ModifierKind mk, ModifierKind... mks) {
for (ModifierKind mk2 : mks) {
if (mk == mk2) return true;
}
return false;
}
static boolean compatible(MethodKind mk, ModifierKind mod1, ModifierKind mod2, EnclosingKind ek) {
if (intersect(ABSTRACT, mod1, mod2) || intersect(NATIVE, mod1, mod2)) {
return mk == MethodKind.NO_BODY;
} else if (intersect(DEFAULT, mod1, mod2)) {
return mk == MethodKind.BODY;
} else {
return ek == EnclosingKind.INTERFACE ?
mk == MethodKind.NO_BODY : mk == MethodKind.BODY;
}
}
boolean compatible(EnclosingKind ek) {
switch (this) {
case STATIC:
case PRIVATE:
case PROTECTED:
return ek != EnclosingKind.INTERFACE;
default:
return true;
}
}
static boolean compatible(ModifierKind m1, ModifierKind m2, EnclosingKind ek) {
Result res1 = allowedModifierPairs[m1.ordinal()][m2.ordinal()];
Result res2 = allowedModifierPairs[m2.ordinal()][m1.ordinal()];
if (res1 != res2) {
throw new AssertionError(String.format("Ill-formed table: [%s,%s] != [%s,%s]", m1, m2, m2, m1));
} else {
return res1.compatible(ek, m1, m2);
}
}
interface Result {
boolean compatible(EnclosingKind ek, ModifierKind m1, ModifierKind m2);
}
static final Result T = new Result() {
@Override
public boolean compatible(EnclosingKind ek, ModifierKind m1, ModifierKind m2) {
return true;
}
};
static final Result F = new Result() {
@Override
public boolean compatible(EnclosingKind ek, ModifierKind m1, ModifierKind m2) {
return false;
}
};
static final Result C = new Result() {
@Override
public boolean compatible(EnclosingKind ek, ModifierKind m1, ModifierKind m2) {
return ek != EnclosingKind.INTERFACE;
}
};
static final Result I = new Result() {
@Override
public boolean compatible(EnclosingKind ek, ModifierKind m1, ModifierKind m2) {
return ek == EnclosingKind.INTERFACE;
}
};
static Result[][] allowedModifierPairs = {
/* NONE PUBLIC PROTECTED PRIVATE ABSTRACT STATIC NATIVE SYNCHRONIZED FINAL STRICTFP DEFAULT */
/* NONE */ { T , T , C , C , T , C , C , C , C , C , I },
/* PUBLIC */ { T , F , F , F , T , C , C , C , C , C , I },
/* PROTECTED */ { C , F , F , F , C , C , C , C , C , C , F },
/* PRIVATE */ { C , F , F , F , F , C , C , C , C , C , F },
/* ABSTRACT */ { T , T , C , F , F , F , F , F , F , F , F },
/* STATIC */ { C , C , C , C , F , F , C , C , C , C , F },
/* NATIVE */ { C , C , C , C , F , C , F , C , C , F , F },
/* SYNCHRONIZED */ { C , C , C , C , F , C , C , F , C , C , I },
/* FINAL */ { C , C , C , C , F , C , C , C , F , C , F },
/* STRICTFP */ { C , C , C , C , F , C , F , C , C , F , I },
/* DEFAULT */ { I , I , F , F , F , F , F , I , F , I , F }};
}
enum MethodKind {
NO_BODY("void m();"),
BODY("void m() { }");
String methStr;
private MethodKind(String methStr) {
this.methStr = methStr;
}
}
enum EnclosingKind {
ABSTRACT_CLASS("abstract class Test "),
INTERFACE("interface Test ");
String enclStr;
EnclosingKind(String enclStr) {
this.enclStr = enclStr;
}
}
public static void main(String... args) throws Exception {
//create default shared JavaCompiler - reused across multiple compilations
JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
for (VersionKind vk : VersionKind.values()) {
for (EnclosingKind ek : EnclosingKind.values()) {
for (MethodKind mk : MethodKind.values()) {
for (ModifierKind modk1 : ModifierKind.values()) {
for (ModifierKind modk2 : ModifierKind.values()) {
new TestDefaultMethodsSyntax(vk, ek, mk, modk1, modk2).run(comp, fm);
}
}
}
}
}
System.out.println("Total check executed: " + checkCount);
}
VersionKind vk;
EnclosingKind ek;
MethodKind mk;
ModifierKind modk1, modk2;
JavaSource source;
DiagnosticChecker diagChecker;
TestDefaultMethodsSyntax(VersionKind vk, EnclosingKind ek, MethodKind mk, ModifierKind modk1, ModifierKind modk2) {
this.vk = vk;
this.ek = ek;
this.mk = mk;
this.modk1 = modk1;
this.modk2 = modk2;
this.source = new JavaSource();
this.diagChecker = new DiagnosticChecker();
}
class JavaSource extends SimpleJavaFileObject {
String template = "#EK {\n" +
" #MOD1 #MOD2 #METH\n" +
"}\n";
String source;
public JavaSource() {
super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
source = template.replaceAll("#EK", ek.enclStr)
.replaceAll("#MOD1", modk1.modStr)
.replaceAll("#MOD2", modk2.modStr)
.replaceAll("#METH", mk.methStr);
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return source;
}
}
void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception {
JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker,
vk.getOptions(), null, Arrays.asList(source));
try {
ct.analyze();
} catch (Throwable ex) {
throw new AssertionError("Error thrown when analyzing the following source:\n" + source.getCharContent(true));
}
check();
}
void check() {
boolean errorExpected = !ModifierKind.compatible(modk1, modk2, ek);
errorExpected |= !ModifierKind.compatible(mk, modk1, modk2, ek);
errorExpected |= !modk1.compatible(ek) || !modk2.compatible(ek);
errorExpected |= ModifierKind.intersect(ModifierKind.DEFAULT, modk1, modk2) &&
vk == VersionKind.PRE_LAMBDA;
checkCount++;
if (diagChecker.errorFound != errorExpected) {
throw new AssertionError("Problem when compiling source:\n" + source.getCharContent(true) +
"\nfound error: " + diagChecker.errorFound);
}
}
static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
boolean errorFound;
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
errorFound = true;
}
}
}
}
/*
* Copyright (c) 2012, 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.
*/
// key: compiler.err.default.methods.not.supported.in.source
// options: -source 7 -Xlint:-options
interface DefaultMethodNotSupported {
default void m() { }
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册