Merge
This commit is contained in:
commit
7f05a39aac
langtools
src
jdk.compiler/share/classes/com/sun/tools/javac
comp
parser
resources
tree
jdk.dev/share/classes/com/sun/tools/jdeps
test
Makefile
tools/javac
diags/examples
DiamondRedundantArgs.javaDiamondRedundantArgs1.javaMethodRedundantTypeargs.javaPotentialLambdaFound.java
generics/diamond
lambda
@ -0,0 +1,509 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.sun.tools.javac.comp;
|
||||
|
||||
import com.sun.source.tree.LambdaExpressionTree;
|
||||
import com.sun.tools.javac.code.Source;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.code.Types;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.JCTree.JCBlock;
|
||||
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
|
||||
import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop;
|
||||
import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop;
|
||||
import com.sun.tools.javac.tree.JCTree.JCForLoop;
|
||||
import com.sun.tools.javac.tree.JCTree.JCIf;
|
||||
import com.sun.tools.javac.tree.JCTree.JCLambda;
|
||||
import com.sun.tools.javac.tree.JCTree.JCLambda.ParameterKind;
|
||||
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
|
||||
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
|
||||
import com.sun.tools.javac.tree.JCTree.JCNewClass;
|
||||
import com.sun.tools.javac.tree.JCTree.JCStatement;
|
||||
import com.sun.tools.javac.tree.JCTree.JCSwitch;
|
||||
import com.sun.tools.javac.tree.JCTree.JCTypeApply;
|
||||
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
|
||||
import com.sun.tools.javac.tree.JCTree.JCWhileLoop;
|
||||
import com.sun.tools.javac.tree.JCTree.Tag;
|
||||
import com.sun.tools.javac.tree.TreeCopier;
|
||||
import com.sun.tools.javac.tree.TreeInfo;
|
||||
import com.sun.tools.javac.tree.TreeMaker;
|
||||
import com.sun.tools.javac.tree.TreeScanner;
|
||||
import com.sun.tools.javac.util.Context;
|
||||
import com.sun.tools.javac.util.DefinedBy;
|
||||
import com.sun.tools.javac.util.DefinedBy.Api;
|
||||
import com.sun.tools.javac.util.Filter;
|
||||
import com.sun.tools.javac.util.JCDiagnostic;
|
||||
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType;
|
||||
import com.sun.tools.javac.util.List;
|
||||
import com.sun.tools.javac.util.ListBuffer;
|
||||
import com.sun.tools.javac.util.Log;
|
||||
import com.sun.tools.javac.util.Names;
|
||||
import com.sun.tools.javac.util.Options;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static com.sun.tools.javac.code.Flags.GENERATEDCONSTR;
|
||||
import static com.sun.tools.javac.code.Flags.SYNTHETIC;
|
||||
import static com.sun.tools.javac.code.TypeTag.CLASS;
|
||||
import static com.sun.tools.javac.tree.JCTree.Tag.APPLY;
|
||||
import static com.sun.tools.javac.tree.JCTree.Tag.CLASSDEF;
|
||||
import static com.sun.tools.javac.tree.JCTree.Tag.METHODDEF;
|
||||
import static com.sun.tools.javac.tree.JCTree.Tag.NEWCLASS;
|
||||
import static com.sun.tools.javac.tree.JCTree.Tag.TYPEAPPLY;
|
||||
|
||||
/**
|
||||
* Helper class for defining custom code analysis, such as finding instance creation expression
|
||||
* that can benefit from diamond syntax.
|
||||
*/
|
||||
public class Analyzer {
|
||||
protected static final Context.Key<Analyzer> analyzerKey = new Context.Key<>();
|
||||
|
||||
final Types types;
|
||||
final Log log;
|
||||
final Attr attr;
|
||||
final DeferredAttr deferredAttr;
|
||||
final TreeMaker make;
|
||||
final Names names;
|
||||
|
||||
final EnumSet<AnalyzerMode> analyzerModes;
|
||||
|
||||
public static Analyzer instance(Context context) {
|
||||
Analyzer instance = context.get(analyzerKey);
|
||||
if (instance == null)
|
||||
instance = new Analyzer(context);
|
||||
return instance;
|
||||
}
|
||||
|
||||
protected Analyzer(Context context) {
|
||||
context.put(analyzerKey, this);
|
||||
types = Types.instance(context);
|
||||
log = Log.instance(context);
|
||||
attr = Attr.instance(context);
|
||||
deferredAttr = DeferredAttr.instance(context);
|
||||
make = TreeMaker.instance(context);
|
||||
names = Names.instance(context);
|
||||
Options options = Options.instance(context);
|
||||
String findOpt = options.get("find");
|
||||
//parse modes
|
||||
Source source = Source.instance(context);
|
||||
analyzerModes = AnalyzerMode.getAnalyzerModes(findOpt, source);
|
||||
}
|
||||
|
||||
/**
|
||||
* This enum defines supported analyzer modes, as well as defining the logic for decoding
|
||||
* the {@code -XDfind} option.
|
||||
*/
|
||||
enum AnalyzerMode {
|
||||
DIAMOND("diamond", Source::allowDiamond),
|
||||
LAMBDA("lambda", Source::allowLambda),
|
||||
METHOD("method", Source::allowGraphInference);
|
||||
|
||||
final String opt;
|
||||
final Predicate<Source> sourceFilter;
|
||||
|
||||
AnalyzerMode(String opt, Predicate<Source> sourceFilter) {
|
||||
this.opt = opt;
|
||||
this.sourceFilter = sourceFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to parse the {@code find} option.
|
||||
* Possible modes are separated by colon; a mode can be excluded by
|
||||
* prepending '-' to its name. Finally, the special mode 'all' can be used to
|
||||
* add all modes to the resulting enum.
|
||||
*/
|
||||
static EnumSet<AnalyzerMode> getAnalyzerModes(String opt, Source source) {
|
||||
if (opt == null) {
|
||||
return EnumSet.noneOf(AnalyzerMode.class);
|
||||
}
|
||||
List<String> modes = List.from(opt.split(","));
|
||||
EnumSet<AnalyzerMode> res = EnumSet.noneOf(AnalyzerMode.class);
|
||||
if (modes.contains("all")) {
|
||||
res = EnumSet.allOf(AnalyzerMode.class);
|
||||
}
|
||||
for (AnalyzerMode mode : values()) {
|
||||
if (modes.contains(mode.opt)) {
|
||||
res.add(mode);
|
||||
} else if (modes.contains("-" + mode.opt) || !mode.sourceFilter.test(source)) {
|
||||
res.remove(mode);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A statement analyzer is a work-unit that matches certain AST nodes (of given type {@code S}),
|
||||
* rewrites them to different AST nodes (of type {@code T}) and then generates some meaningful
|
||||
* messages in case the analysis has been successful.
|
||||
*/
|
||||
abstract class StatementAnalyzer<S extends JCTree, T extends JCTree> {
|
||||
|
||||
AnalyzerMode mode;
|
||||
JCTree.Tag tag;
|
||||
|
||||
StatementAnalyzer(AnalyzerMode mode, Tag tag) {
|
||||
this.mode = mode;
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this analyzer allowed to run?
|
||||
*/
|
||||
boolean isEnabled() {
|
||||
return analyzerModes.contains(mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should this analyzer be rewriting the given tree?
|
||||
*/
|
||||
abstract boolean match(S tree);
|
||||
|
||||
/**
|
||||
* Rewrite a given AST node into a new one
|
||||
*/
|
||||
abstract T map(S oldTree, S newTree);
|
||||
|
||||
/**
|
||||
* Entry-point for comparing results and generating diagnostics.
|
||||
*/
|
||||
abstract void process(S oldTree, T newTree, boolean hasErrors);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This analyzer checks if generic instance creation expression can use diamond syntax.
|
||||
*/
|
||||
class DiamondInitializer extends StatementAnalyzer<JCNewClass, JCNewClass> {
|
||||
|
||||
DiamondInitializer() {
|
||||
super(AnalyzerMode.DIAMOND, NEWCLASS);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean match(JCNewClass tree) {
|
||||
return tree.clazz.hasTag(TYPEAPPLY) &&
|
||||
!TreeInfo.isDiamond(tree) &&
|
||||
tree.def == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
JCNewClass map(JCNewClass oldTree, JCNewClass newTree) {
|
||||
if (newTree.clazz.hasTag(TYPEAPPLY)) {
|
||||
((JCTypeApply)newTree.clazz).arguments = List.nil();
|
||||
}
|
||||
return newTree;
|
||||
}
|
||||
|
||||
@Override
|
||||
void process(JCNewClass oldTree, JCNewClass newTree, boolean hasErrors) {
|
||||
if (!hasErrors) {
|
||||
List<Type> inferredArgs = newTree.type.getTypeArguments();
|
||||
List<Type> explicitArgs = oldTree.type.getTypeArguments();
|
||||
for (Type t : inferredArgs) {
|
||||
if (!types.isSameType(t, explicitArgs.head)) {
|
||||
log.warning(oldTree.clazz, "diamond.redundant.args.1",
|
||||
oldTree.clazz.type, newTree.clazz.type);
|
||||
return;
|
||||
}
|
||||
explicitArgs = explicitArgs.tail;
|
||||
}
|
||||
//exact match
|
||||
log.warning(oldTree.clazz, "diamond.redundant.args");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This analyzer checks if anonymous instance creation expression can replaced by lambda.
|
||||
*/
|
||||
class LambdaAnalyzer extends StatementAnalyzer<JCNewClass, JCLambda> {
|
||||
|
||||
LambdaAnalyzer() {
|
||||
super(AnalyzerMode.LAMBDA, NEWCLASS);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean match (JCNewClass tree){
|
||||
Type clazztype = tree.clazz.type;
|
||||
return tree.def != null &&
|
||||
clazztype.hasTag(CLASS) &&
|
||||
types.isFunctionalInterface(clazztype.tsym) &&
|
||||
decls(tree.def).length() == 1;
|
||||
}
|
||||
//where
|
||||
private List<JCTree> decls(JCClassDecl decl) {
|
||||
ListBuffer<JCTree> decls = new ListBuffer<>();
|
||||
for (JCTree t : decl.defs) {
|
||||
if (t.hasTag(METHODDEF)) {
|
||||
JCMethodDecl md = (JCMethodDecl)t;
|
||||
if ((md.getModifiers().flags & GENERATEDCONSTR) == 0) {
|
||||
decls.add(md);
|
||||
}
|
||||
} else {
|
||||
decls.add(t);
|
||||
}
|
||||
}
|
||||
return decls.toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
JCLambda map (JCNewClass oldTree, JCNewClass newTree){
|
||||
JCMethodDecl md = (JCMethodDecl)decls(newTree.def).head;
|
||||
List<JCVariableDecl> params = md.params;
|
||||
JCBlock body = md.body;
|
||||
return make.Lambda(params, body);
|
||||
}
|
||||
@Override
|
||||
void process (JCNewClass oldTree, JCLambda newTree, boolean hasErrors){
|
||||
if (!hasErrors) {
|
||||
log.warning(oldTree.def, "potential.lambda.found");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This analyzer checks if generic method call has redundant type arguments.
|
||||
*/
|
||||
class RedundantTypeArgAnalyzer extends StatementAnalyzer<JCMethodInvocation, JCMethodInvocation> {
|
||||
|
||||
RedundantTypeArgAnalyzer() {
|
||||
super(AnalyzerMode.METHOD, APPLY);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean match (JCMethodInvocation tree){
|
||||
return tree.typeargs != null &&
|
||||
tree.typeargs.nonEmpty();
|
||||
}
|
||||
@Override
|
||||
JCMethodInvocation map (JCMethodInvocation oldTree, JCMethodInvocation newTree){
|
||||
newTree.typeargs = List.nil();
|
||||
return newTree;
|
||||
}
|
||||
@Override
|
||||
void process (JCMethodInvocation oldTree, JCMethodInvocation newTree, boolean hasErrors){
|
||||
if (!hasErrors) {
|
||||
//exact match
|
||||
log.warning(oldTree, "method.redundant.typeargs");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
StatementAnalyzer<JCTree, JCTree>[] analyzers = new StatementAnalyzer[] {
|
||||
new DiamondInitializer(),
|
||||
new LambdaAnalyzer(),
|
||||
new RedundantTypeArgAnalyzer()
|
||||
};
|
||||
|
||||
/**
|
||||
* Analyze an AST node if needed.
|
||||
*/
|
||||
void analyzeIfNeeded(JCTree tree, Env<AttrContext> env) {
|
||||
if (!analyzerModes.isEmpty() &&
|
||||
!env.info.isSpeculative &&
|
||||
TreeInfo.isStatement(tree)) {
|
||||
JCStatement stmt = (JCStatement)tree;
|
||||
analyze(stmt, env);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyze an AST node; this involves collecting a list of all the nodes that needs rewriting,
|
||||
* and speculatively type-check the rewritten code to compare results against previously attributed code.
|
||||
*/
|
||||
void analyze(JCStatement statement, Env<AttrContext> env) {
|
||||
AnalysisContext context = new AnalysisContext();
|
||||
StatementScanner statementScanner = new StatementScanner(context);
|
||||
statementScanner.scan(statement);
|
||||
|
||||
if (!context.treesToAnalyzer.isEmpty()) {
|
||||
|
||||
//add a block to hoist potential dangling variable declarations
|
||||
JCBlock fakeBlock = make.Block(SYNTHETIC, List.of(statement));
|
||||
|
||||
TreeMapper treeMapper = new TreeMapper(context);
|
||||
//TODO: to further refine the analysis, try all rewriting combinations
|
||||
deferredAttr.attribSpeculative(fakeBlock, env, attr.statInfo, treeMapper,
|
||||
t -> new AnalyzeDeferredDiagHandler(context));
|
||||
|
||||
context.treeMap.entrySet().forEach(e -> {
|
||||
context.treesToAnalyzer.get(e.getKey())
|
||||
.process(e.getKey(), e.getValue(), context.errors.nonEmpty());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple deferred diagnostic handler which filters out all messages and keep track of errors.
|
||||
*/
|
||||
class AnalyzeDeferredDiagHandler extends Log.DeferredDiagnosticHandler {
|
||||
AnalysisContext context;
|
||||
|
||||
public AnalyzeDeferredDiagHandler(AnalysisContext context) {
|
||||
super(log, d -> {
|
||||
if (d.getType() == DiagnosticType.ERROR) {
|
||||
context.errors.add(d);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
this.context = context;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is used to pass around contextual information bewteen analyzer classes, such as
|
||||
* trees to be rewritten, errors occurred during the speculative attribution step, etc.
|
||||
*/
|
||||
class AnalysisContext {
|
||||
/** Map from trees to analyzers. */
|
||||
Map<JCTree, StatementAnalyzer<JCTree, JCTree>> treesToAnalyzer = new HashMap<>();
|
||||
|
||||
/** Map from original AST nodes to rewritten AST nodes */
|
||||
Map<JCTree, JCTree> treeMap = new HashMap<>();
|
||||
|
||||
/** Errors in rewritten tree */
|
||||
ListBuffer<JCDiagnostic> errors = new ListBuffer<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclass of {@link com.sun.tools.javac.tree.TreeScanner} which visit AST-nodes w/o crossing
|
||||
* statement boundaries.
|
||||
*/
|
||||
class StatementScanner extends TreeScanner {
|
||||
|
||||
/** context */
|
||||
AnalysisContext context;
|
||||
|
||||
StatementScanner(AnalysisContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void scan(JCTree tree) {
|
||||
if (tree != null) {
|
||||
for (StatementAnalyzer<JCTree, JCTree> analyzer : analyzers) {
|
||||
if (analyzer.isEnabled() &&
|
||||
tree.hasTag(analyzer.tag) &&
|
||||
analyzer.match(tree)) {
|
||||
context.treesToAnalyzer.put(tree, analyzer);
|
||||
break; //TODO: cover cases where multiple matching analyzers are found
|
||||
}
|
||||
}
|
||||
}
|
||||
super.scan(tree);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitClassDef(JCClassDecl tree) {
|
||||
//do nothing (prevents seeing same stuff twice
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodDef(JCMethodDecl tree) {
|
||||
//do nothing (prevents seeing same stuff twice
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitBlock(JCBlock tree) {
|
||||
//do nothing (prevents seeing same stuff twice
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSwitch(JCSwitch tree) {
|
||||
scan(tree.getExpression());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitForLoop(JCForLoop tree) {
|
||||
scan(tree.getInitializer());
|
||||
scan(tree.getCondition());
|
||||
scan(tree.getUpdate());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitForeachLoop(JCEnhancedForLoop tree) {
|
||||
scan(tree.getExpression());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitWhileLoop(JCWhileLoop tree) {
|
||||
scan(tree.getCondition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitDoLoop(JCDoWhileLoop tree) {
|
||||
scan(tree.getCondition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIf(JCIf tree) {
|
||||
scan(tree.getCondition());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclass of TreeCopier that maps nodes matched by analyzers onto new AST nodes.
|
||||
*/
|
||||
class TreeMapper extends TreeCopier<Void> {
|
||||
|
||||
AnalysisContext context;
|
||||
|
||||
TreeMapper(AnalysisContext context) {
|
||||
super(make);
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <Z extends JCTree> Z copy(Z tree, Void _unused) {
|
||||
Z newTree = super.copy(tree, _unused);
|
||||
StatementAnalyzer<JCTree, JCTree> analyzer = context.treesToAnalyzer.get(tree);
|
||||
if (analyzer != null) {
|
||||
newTree = (Z)analyzer.map(tree, newTree);
|
||||
context.treeMap.put(tree, newTree);
|
||||
}
|
||||
return newTree;
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
public JCTree visitLambdaExpression(LambdaExpressionTree node, Void _unused) {
|
||||
JCLambda oldLambda = (JCLambda)node;
|
||||
JCLambda newLambda = (JCLambda)super.visitLambdaExpression(node, _unused);
|
||||
if (oldLambda.paramKind == ParameterKind.IMPLICIT) {
|
||||
//reset implicit lambda parameters (whose type might have been set during attr)
|
||||
newLambda.paramKind = ParameterKind.IMPLICIT;
|
||||
newLambda.params.forEach(p -> p.vartype = null);
|
||||
}
|
||||
return newLambda;
|
||||
}
|
||||
}
|
||||
}
|
@ -83,6 +83,7 @@ public class Attr extends JCTree.Visitor {
|
||||
final Symtab syms;
|
||||
final Resolve rs;
|
||||
final Infer infer;
|
||||
final Analyzer analyzer;
|
||||
final DeferredAttr deferredAttr;
|
||||
final Check chk;
|
||||
final Flow flow;
|
||||
@ -121,6 +122,7 @@ public class Attr extends JCTree.Visitor {
|
||||
make = TreeMaker.instance(context);
|
||||
enter = Enter.instance(context);
|
||||
infer = Infer.instance(context);
|
||||
analyzer = Analyzer.instance(context);
|
||||
deferredAttr = DeferredAttr.instance(context);
|
||||
cfolder = ConstFold.instance(context);
|
||||
target = Target.instance(context);
|
||||
@ -143,11 +145,8 @@ public class Attr extends JCTree.Visitor {
|
||||
allowStaticInterfaceMethods = source.allowStaticInterfaceMethods();
|
||||
sourceName = source.name;
|
||||
relax = (options.isSet("-retrofit") ||
|
||||
options.isSet("-relax"));
|
||||
findDiamonds = options.get("findDiamond") != null &&
|
||||
source.allowDiamond();
|
||||
options.isSet("-relax"));
|
||||
useBeforeDeclarationWarning = options.isSet("useBeforeDeclarationWarning");
|
||||
identifyLambdaCandidate = options.getBoolean("identifyLambdaCandidate", false);
|
||||
|
||||
statInfo = new ResultInfo(KindSelector.NIL, Type.noType);
|
||||
varAssignmentInfo = new ResultInfo(KindSelector.ASG, Type.noType);
|
||||
@ -156,6 +155,8 @@ public class Attr extends JCTree.Visitor {
|
||||
unknownTypeInfo = new ResultInfo(KindSelector.TYP, Type.noType);
|
||||
unknownTypeExprInfo = new ResultInfo(KindSelector.VAL_TYP, Type.noType);
|
||||
recoveryInfo = new RecoveryInfo(deferredAttr.emptyDeferredAttrContext);
|
||||
|
||||
noCheckTree = make.at(-1).Skip();
|
||||
}
|
||||
|
||||
/** Switch: relax some constraints for retrofit mode.
|
||||
@ -182,28 +183,12 @@ public class Attr extends JCTree.Visitor {
|
||||
*/
|
||||
boolean allowStaticInterfaceMethods;
|
||||
|
||||
/** Switch: generates a warning if diamond can be safely applied
|
||||
* to a given new expression
|
||||
*/
|
||||
boolean findDiamonds;
|
||||
|
||||
/**
|
||||
* Internally enables/disables diamond finder feature
|
||||
*/
|
||||
static final boolean allowDiamondFinder = true;
|
||||
|
||||
/**
|
||||
* Switch: warn about use of variable before declaration?
|
||||
* RFE: 6425594
|
||||
*/
|
||||
boolean useBeforeDeclarationWarning;
|
||||
|
||||
/**
|
||||
* Switch: generate warnings whenever an anonymous inner class that is convertible
|
||||
* to a lambda expression is found
|
||||
*/
|
||||
boolean identifyLambdaCandidate;
|
||||
|
||||
/**
|
||||
* Switch: allow strings in switch?
|
||||
*/
|
||||
@ -231,31 +216,32 @@ public class Attr extends JCTree.Visitor {
|
||||
final ResultInfo resultInfo) {
|
||||
InferenceContext inferenceContext = resultInfo.checkContext.inferenceContext();
|
||||
Type owntype;
|
||||
if (!found.hasTag(ERROR) && !resultInfo.pt.hasTag(METHOD) && !resultInfo.pt.hasTag(FORALL)) {
|
||||
if (!ownkind.subset(resultInfo.pkind)) {
|
||||
log.error(tree.pos(), "unexpected.type",
|
||||
resultInfo.pkind.kindNames(),
|
||||
ownkind.kindNames());
|
||||
owntype = types.createErrorType(found);
|
||||
} else if (allowPoly && inferenceContext.free(found)) {
|
||||
//delay the check if there are inference variables in the found type
|
||||
//this means we are dealing with a partially inferred poly expression
|
||||
owntype = resultInfo.pt;
|
||||
inferenceContext.addFreeTypeListener(List.of(found, resultInfo.pt), new FreeTypeListener() {
|
||||
@Override
|
||||
public void typesInferred(InferenceContext inferenceContext) {
|
||||
boolean shouldCheck = !found.hasTag(ERROR) &&
|
||||
!resultInfo.pt.hasTag(METHOD) &&
|
||||
!resultInfo.pt.hasTag(FORALL);
|
||||
if (shouldCheck && !ownkind.subset(resultInfo.pkind)) {
|
||||
log.error(tree.pos(), "unexpected.type",
|
||||
resultInfo.pkind.kindNames(),
|
||||
ownkind.kindNames());
|
||||
owntype = types.createErrorType(found);
|
||||
} else if (allowPoly && inferenceContext.free(found)) {
|
||||
//delay the check if there are inference variables in the found type
|
||||
//this means we are dealing with a partially inferred poly expression
|
||||
owntype = shouldCheck ? resultInfo.pt : found;
|
||||
inferenceContext.addFreeTypeListener(List.of(found, resultInfo.pt),
|
||||
instantiatedContext -> {
|
||||
ResultInfo pendingResult =
|
||||
resultInfo.dup(inferenceContext.asInstType(resultInfo.pt));
|
||||
check(tree, inferenceContext.asInstType(found), ownkind, pendingResult);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
owntype = resultInfo.check(tree, found);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
owntype = found;
|
||||
owntype = shouldCheck ?
|
||||
resultInfo.check(tree, found) :
|
||||
found;
|
||||
}
|
||||
if (tree != noCheckTree) {
|
||||
tree.type = owntype;
|
||||
}
|
||||
tree.type = owntype;
|
||||
return owntype;
|
||||
}
|
||||
|
||||
@ -531,6 +517,10 @@ public class Attr extends JCTree.Visitor {
|
||||
*/
|
||||
Type result;
|
||||
|
||||
/** Synthetic tree to be used during 'fake' checks.
|
||||
*/
|
||||
JCTree noCheckTree;
|
||||
|
||||
/** Visitor method: attribute a tree, catching any completion failure
|
||||
* exceptions. Return the tree's type.
|
||||
*
|
||||
@ -610,7 +600,13 @@ public class Attr extends JCTree.Visitor {
|
||||
/** Derived visitor method: attribute a statement or definition tree.
|
||||
*/
|
||||
public Type attribStat(JCTree tree, Env<AttrContext> env) {
|
||||
return attribTree(tree, env, statInfo);
|
||||
Env<AttrContext> analyzeEnv =
|
||||
env.dup(tree, env.info.dup(env.info.scope.dupUnshared(env.info.scope.owner)));
|
||||
try {
|
||||
return attribTree(tree, env, statInfo);
|
||||
} finally {
|
||||
analyzer.analyzeIfNeeded(tree, analyzeEnv);
|
||||
}
|
||||
}
|
||||
|
||||
/** Attribute a list of expressions, returning a list of types.
|
||||
@ -792,8 +788,8 @@ public class Attr extends JCTree.Visitor {
|
||||
|
||||
Type attribIdentAsEnumType(Env<AttrContext> env, JCIdent id) {
|
||||
Assert.check((env.enclClass.sym.flags() & ENUM) != 0);
|
||||
id.type = env.info.scope.owner.type;
|
||||
id.sym = env.info.scope.owner;
|
||||
id.type = env.info.scope.owner.enclClass().type;
|
||||
id.sym = env.info.scope.owner.enclClass();
|
||||
return id.type;
|
||||
}
|
||||
|
||||
@ -2018,7 +2014,7 @@ public class Attr extends JCTree.Visitor {
|
||||
}
|
||||
});
|
||||
Type constructorType = tree.constructorType = types.createErrorType(clazztype);
|
||||
constructorType = checkId(tree, site,
|
||||
constructorType = checkId(noCheckTree, site,
|
||||
constructor,
|
||||
diamondEnv,
|
||||
diamondResult);
|
||||
@ -2044,7 +2040,7 @@ public class Attr extends JCTree.Visitor {
|
||||
tree.constructor = rs.resolveConstructor(
|
||||
tree.pos(), rsEnv, clazztype, argtypes, typeargtypes);
|
||||
if (cdef == null) { //do not check twice!
|
||||
tree.constructorType = checkId(tree,
|
||||
tree.constructorType = checkId(noCheckTree,
|
||||
clazztype,
|
||||
tree.constructor,
|
||||
rsEnv,
|
||||
@ -2052,12 +2048,6 @@ public class Attr extends JCTree.Visitor {
|
||||
if (rsEnv.info.lastResolveVarargs())
|
||||
Assert.check(tree.constructorType.isErroneous() || tree.varargsElement != null);
|
||||
}
|
||||
if (cdef == null &&
|
||||
!clazztype.isErroneous() &&
|
||||
clazztype.getTypeArguments().nonEmpty() &&
|
||||
findDiamonds) {
|
||||
findDiamond(localEnv, tree, clazztype);
|
||||
}
|
||||
}
|
||||
|
||||
if (cdef != null) {
|
||||
@ -2105,8 +2095,6 @@ public class Attr extends JCTree.Visitor {
|
||||
|
||||
attribStat(cdef, localEnv);
|
||||
|
||||
checkLambdaCandidate(tree, cdef.sym, clazztype);
|
||||
|
||||
// If an outer instance is given,
|
||||
// prefix it to the constructor arguments
|
||||
// and delete it from the new expression
|
||||
@ -2122,7 +2110,7 @@ public class Attr extends JCTree.Visitor {
|
||||
tree.pos(), localEnv, clazztype, argtypes, typeargtypes);
|
||||
Assert.check(!sym.kind.isOverloadError());
|
||||
tree.constructor = sym;
|
||||
tree.constructorType = checkId(tree,
|
||||
tree.constructorType = checkId(noCheckTree,
|
||||
clazztype,
|
||||
tree.constructor,
|
||||
localEnv,
|
||||
@ -2133,60 +2121,16 @@ public class Attr extends JCTree.Visitor {
|
||||
owntype = clazztype;
|
||||
}
|
||||
result = check(tree, owntype, KindSelector.VAL, resultInfo);
|
||||
InferenceContext inferenceContext = resultInfo.checkContext.inferenceContext();
|
||||
if (tree.constructorType != null && inferenceContext.free(tree.constructorType)) {
|
||||
//we need to wait for inference to finish and then replace inference vars in the constructor type
|
||||
inferenceContext.addFreeTypeListener(List.of(tree.constructorType),
|
||||
instantiatedContext -> {
|
||||
tree.constructorType = instantiatedContext.asInstType(tree.constructorType);
|
||||
});
|
||||
}
|
||||
chk.validate(tree.typeargs, localEnv);
|
||||
}
|
||||
//where
|
||||
void findDiamond(Env<AttrContext> env, JCNewClass tree, Type clazztype) {
|
||||
JCTypeApply ta = (JCTypeApply)tree.clazz;
|
||||
List<JCExpression> prevTypeargs = ta.arguments;
|
||||
try {
|
||||
//create a 'fake' diamond AST node by removing type-argument trees
|
||||
ta.arguments = List.nil();
|
||||
ResultInfo findDiamondResult = new ResultInfo(KindSelector.VAL,
|
||||
resultInfo.checkContext.inferenceContext().free(resultInfo.pt) ? Type.noType : pt());
|
||||
Type inferred = deferredAttr.attribSpeculative(tree, env, findDiamondResult).type;
|
||||
Type polyPt = allowPoly ?
|
||||
syms.objectType :
|
||||
clazztype;
|
||||
if (!inferred.isErroneous() &&
|
||||
(allowPoly && pt() == Infer.anyPoly ?
|
||||
types.isSameType(inferred, clazztype) :
|
||||
types.isAssignable(inferred, pt().hasTag(NONE) ? polyPt : pt(), types.noWarnings))) {
|
||||
String key = types.isSameType(clazztype, inferred) ?
|
||||
"diamond.redundant.args" :
|
||||
"diamond.redundant.args.1";
|
||||
log.warning(tree.clazz.pos(), key, clazztype, inferred);
|
||||
}
|
||||
} finally {
|
||||
ta.arguments = prevTypeargs;
|
||||
}
|
||||
}
|
||||
|
||||
private void checkLambdaCandidate(JCNewClass tree, ClassSymbol csym, Type clazztype) {
|
||||
if (allowLambda &&
|
||||
identifyLambdaCandidate &&
|
||||
clazztype.hasTag(CLASS) &&
|
||||
!pt().hasTag(NONE) &&
|
||||
types.isFunctionalInterface(clazztype.tsym)) {
|
||||
Symbol descriptor = types.findDescriptorSymbol(clazztype.tsym);
|
||||
int count = 0;
|
||||
boolean found = false;
|
||||
for (Symbol sym : csym.members().getSymbols()) {
|
||||
if ((sym.flags() & SYNTHETIC) != 0 ||
|
||||
sym.isConstructor()) continue;
|
||||
count++;
|
||||
if (sym.kind != MTH ||
|
||||
!sym.name.equals(descriptor.name)) continue;
|
||||
Type mtype = types.memberType(clazztype, sym);
|
||||
if (types.overrideEquivalent(mtype, types.memberType(clazztype, descriptor))) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (found && count == 1) {
|
||||
log.note(tree.def, "potential.lambda.found");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Make an attributed null check tree.
|
||||
*/
|
||||
@ -2361,6 +2305,7 @@ public class Attr extends JCTree.Visitor {
|
||||
preFlow(that);
|
||||
flow.analyzeLambda(env, that, make, isSpeculativeRound);
|
||||
|
||||
that.type = currentTarget; //avoids recovery at this stage
|
||||
checkLambdaCompatible(that, lambdaType, resultInfo.checkContext);
|
||||
|
||||
if (!isSpeculativeRound) {
|
||||
@ -2801,7 +2746,7 @@ public class Attr extends JCTree.Visitor {
|
||||
that.kind.isUnbound() ? argtypes.tail : argtypes, typeargtypes),
|
||||
new FunctionalReturnContext(resultInfo.checkContext));
|
||||
|
||||
Type refType = checkId(that, lookupHelper.site, refSym, localEnv, checkInfo);
|
||||
Type refType = checkId(noCheckTree, lookupHelper.site, refSym, localEnv, checkInfo);
|
||||
|
||||
if (that.kind.isUnbound() &&
|
||||
resultInfo.checkContext.inferenceContext().free(argtypes.head)) {
|
||||
@ -2823,6 +2768,8 @@ public class Attr extends JCTree.Visitor {
|
||||
//is a no-op (as this has been taken care during method applicability)
|
||||
boolean isSpeculativeRound =
|
||||
resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.SPECULATIVE;
|
||||
|
||||
that.type = currentTarget; //avoids recovery at this stage
|
||||
checkReferenceCompatible(that, desc, refType, resultInfo.checkContext, isSpeculativeRound);
|
||||
if (!isSpeculativeRound) {
|
||||
checkAccessibleTypes(that, localEnv, resultInfo.checkContext.inferenceContext(), desc, currentTarget);
|
||||
@ -3953,7 +3900,7 @@ public class Attr extends JCTree.Visitor {
|
||||
all_multicatchTypes.append(ctype);
|
||||
}
|
||||
}
|
||||
Type t = check(tree, types.lub(multicatchTypes.toList()),
|
||||
Type t = check(noCheckTree, types.lub(multicatchTypes.toList()),
|
||||
KindSelector.TYP, resultInfo);
|
||||
if (t.hasTag(CLASS)) {
|
||||
List<Type> alternatives =
|
||||
|
@ -59,6 +59,10 @@ public class AttrContext {
|
||||
*/
|
||||
boolean isSerializable = false;
|
||||
|
||||
/** Is this a speculative attribution environment?
|
||||
*/
|
||||
boolean isSpeculative = false;
|
||||
|
||||
/** Are arguments to current function applications boxed into an array for varargs?
|
||||
*/
|
||||
Resolve.MethodResolutionPhase pendingResolutionPhase = null;
|
||||
@ -95,6 +99,7 @@ public class AttrContext {
|
||||
info.returnResult = returnResult;
|
||||
info.defaultSuperCallSite = defaultSuperCallSite;
|
||||
info.isSerializable = isSerializable;
|
||||
info.isSpeculative = isSpeculative;
|
||||
return info;
|
||||
}
|
||||
|
||||
|
@ -37,6 +37,7 @@ import com.sun.tools.javac.comp.Attr.ResultInfo;
|
||||
import com.sun.tools.javac.comp.Infer.InferenceContext;
|
||||
import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
|
||||
import com.sun.tools.javac.tree.JCTree.*;
|
||||
import com.sun.tools.javac.util.Log.DeferredDiagnosticHandler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@ -46,6 +47,7 @@ import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static com.sun.tools.javac.code.TypeTag.*;
|
||||
import static com.sun.tools.javac.tree.JCTree.Tag.*;
|
||||
@ -364,28 +366,16 @@ public class DeferredAttr extends JCTree.Visitor {
|
||||
* disabled during speculative type-checking.
|
||||
*/
|
||||
JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
|
||||
final JCTree newTree = new TreeCopier<>(make).copy(tree);
|
||||
Env<AttrContext> speculativeEnv = env.dup(newTree, env.info.dup(env.info.scope.dupUnshared(env.info.scope.owner)));
|
||||
Log.DeferredDiagnosticHandler deferredDiagnosticHandler =
|
||||
new Log.DeferredDiagnosticHandler(log, new Filter<JCDiagnostic>() {
|
||||
public boolean accepts(final JCDiagnostic d) {
|
||||
class PosScanner extends TreeScanner {
|
||||
boolean found = false;
|
||||
return attribSpeculative(tree, env, resultInfo, new TreeCopier<>(make),
|
||||
(newTree)->new DeferredAttrDiagHandler(log, newTree));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scan(JCTree tree) {
|
||||
if (tree != null &&
|
||||
tree.pos() == d.getDiagnosticPosition()) {
|
||||
found = true;
|
||||
}
|
||||
super.scan(tree);
|
||||
}
|
||||
}
|
||||
PosScanner posScanner = new PosScanner();
|
||||
posScanner.scan(newTree);
|
||||
return posScanner.found;
|
||||
}
|
||||
});
|
||||
<Z> JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo, TreeCopier<Z> deferredCopier,
|
||||
Function<JCTree, DeferredDiagnosticHandler> diagHandlerCreator) {
|
||||
final JCTree newTree = deferredCopier.copy(tree);
|
||||
Env<AttrContext> speculativeEnv = env.dup(newTree, env.info.dup(env.info.scope.dupUnshared(env.info.scope.owner)));
|
||||
speculativeEnv.info.isSpeculative = true;
|
||||
Log.DeferredDiagnosticHandler deferredDiagnosticHandler = diagHandlerCreator.apply(newTree);
|
||||
try {
|
||||
attr.attribTree(newTree, speculativeEnv, resultInfo);
|
||||
unenterScanner.scan(newTree);
|
||||
@ -413,6 +403,37 @@ public class DeferredAttr extends JCTree.Visitor {
|
||||
}
|
||||
}
|
||||
|
||||
static class DeferredAttrDiagHandler extends Log.DeferredDiagnosticHandler {
|
||||
|
||||
static class PosScanner extends TreeScanner {
|
||||
DiagnosticPosition pos;
|
||||
boolean found = false;
|
||||
|
||||
PosScanner(DiagnosticPosition pos) {
|
||||
this.pos = pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scan(JCTree tree) {
|
||||
if (tree != null &&
|
||||
tree.pos() == pos) {
|
||||
found = true;
|
||||
}
|
||||
super.scan(tree);
|
||||
}
|
||||
}
|
||||
|
||||
DeferredAttrDiagHandler(Log log, JCTree newTree) {
|
||||
super(log, new Filter<JCDiagnostic>() {
|
||||
public boolean accepts(JCDiagnostic d) {
|
||||
PosScanner posScanner = new PosScanner(d.getDiagnosticPosition());
|
||||
posScanner.scan(newTree);
|
||||
return posScanner.found;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A deferred context is created on each method check. A deferred context is
|
||||
* used to keep track of information associated with the method check, such as
|
||||
@ -1221,7 +1242,7 @@ public class DeferredAttr extends JCTree.Visitor {
|
||||
|
||||
@Override
|
||||
public void visitNewClass(JCNewClass tree) {
|
||||
result = (TreeInfo.isDiamond(tree) || attr.findDiamonds) ?
|
||||
result = TreeInfo.isDiamond(tree) ?
|
||||
ArgumentExpressionKind.POLY : ArgumentExpressionKind.NO_POLY;
|
||||
}
|
||||
|
||||
|
@ -1176,12 +1176,14 @@ public class LambdaToMethod extends TreeTranslator {
|
||||
@Override
|
||||
public void visitClassDef(JCClassDecl tree) {
|
||||
List<Frame> prevStack = frameStack;
|
||||
int prevLambdaCount = lambdaCount;
|
||||
SyntheticMethodNameCounter prevSyntheticMethodNameCounts =
|
||||
syntheticMethodNameCounts;
|
||||
Map<ClassSymbol, Symbol> prevClinits = clinits;
|
||||
DiagnosticSource prevSource = log.currentSource();
|
||||
try {
|
||||
log.useSource(tree.sym.sourcefile);
|
||||
lambdaCount = 0;
|
||||
syntheticMethodNameCounts = new SyntheticMethodNameCounter();
|
||||
prevClinits = new HashMap<>();
|
||||
if (tree.sym.owner.kind == MTH) {
|
||||
@ -1208,6 +1210,7 @@ public class LambdaToMethod extends TreeTranslator {
|
||||
finally {
|
||||
log.useSource(prevSource.getFile());
|
||||
frameStack = prevStack;
|
||||
lambdaCount = prevLambdaCount;
|
||||
syntheticMethodNameCounts = prevSyntheticMethodNameCounts;
|
||||
clinits = prevClinits;
|
||||
}
|
||||
|
@ -251,19 +251,19 @@ public class JavacParser implements Parser {
|
||||
* mode = NOPARAMS : no parameters allowed for type
|
||||
* mode = TYPEARG : type argument
|
||||
*/
|
||||
static final int EXPR = 0x1;
|
||||
static final int TYPE = 0x2;
|
||||
static final int NOPARAMS = 0x4;
|
||||
static final int TYPEARG = 0x8;
|
||||
static final int DIAMOND = 0x10;
|
||||
protected static final int EXPR = 0x1;
|
||||
protected static final int TYPE = 0x2;
|
||||
protected static final int NOPARAMS = 0x4;
|
||||
protected static final int TYPEARG = 0x8;
|
||||
protected static final int DIAMOND = 0x10;
|
||||
|
||||
/** The current mode.
|
||||
*/
|
||||
private int mode = 0;
|
||||
protected int mode = 0;
|
||||
|
||||
/** The mode of the term that was parsed last.
|
||||
*/
|
||||
private int lastmode = 0;
|
||||
protected int lastmode = 0;
|
||||
|
||||
/* ---------- token management -------------- */
|
||||
|
||||
@ -326,7 +326,7 @@ public class JavacParser implements Parser {
|
||||
|
||||
/** Skip forward until a suitable stop token is found.
|
||||
*/
|
||||
private void skip(boolean stopAtImport, boolean stopAtMemberDecl, boolean stopAtIdentifier, boolean stopAtStatement) {
|
||||
protected void skip(boolean stopAtImport, boolean stopAtMemberDecl, boolean stopAtIdentifier, boolean stopAtStatement) {
|
||||
while (true) {
|
||||
switch (token.kind) {
|
||||
case SEMI:
|
||||
@ -403,11 +403,11 @@ public class JavacParser implements Parser {
|
||||
}
|
||||
}
|
||||
|
||||
private JCErroneous syntaxError(int pos, String key, TokenKind... args) {
|
||||
protected JCErroneous syntaxError(int pos, String key, TokenKind... args) {
|
||||
return syntaxError(pos, List.<JCTree>nil(), key, args);
|
||||
}
|
||||
|
||||
private JCErroneous syntaxError(int pos, List<JCTree> errs, String key, TokenKind... args) {
|
||||
protected JCErroneous syntaxError(int pos, List<JCTree> errs, String key, TokenKind... args) {
|
||||
setErrorEndPos(pos);
|
||||
JCErroneous err = F.at(pos).Erroneous(errs);
|
||||
reportSyntaxError(err, key, (Object[])args);
|
||||
@ -427,7 +427,7 @@ public class JavacParser implements Parser {
|
||||
* Report a syntax using the given the position parameter and arguments,
|
||||
* unless one was already reported at the same position.
|
||||
*/
|
||||
private void reportSyntaxError(int pos, String key, Object... args) {
|
||||
protected void reportSyntaxError(int pos, String key, Object... args) {
|
||||
JCDiagnostic.DiagnosticPosition diag = new JCDiagnostic.SimpleDiagnosticPosition(pos);
|
||||
reportSyntaxError(diag, key, args);
|
||||
}
|
||||
@ -436,7 +436,7 @@ public class JavacParser implements Parser {
|
||||
* Report a syntax error using the given DiagnosticPosition object and
|
||||
* arguments, unless one was already reported at the same position.
|
||||
*/
|
||||
private void reportSyntaxError(JCDiagnostic.DiagnosticPosition diagPos, String key, Object... args) {
|
||||
protected void reportSyntaxError(JCDiagnostic.DiagnosticPosition diagPos, String key, Object... args) {
|
||||
int pos = diagPos.getPreferredPosition();
|
||||
if (pos > S.errPos() || pos == Position.NOPOS) {
|
||||
if (token.kind == EOF) {
|
||||
@ -459,14 +459,14 @@ public class JavacParser implements Parser {
|
||||
/** Generate a syntax error at current position unless one was already
|
||||
* reported at the same position.
|
||||
*/
|
||||
private JCErroneous syntaxError(String key) {
|
||||
protected JCErroneous syntaxError(String key) {
|
||||
return syntaxError(token.pos, key);
|
||||
}
|
||||
|
||||
/** Generate a syntax error at current position unless one was
|
||||
* already reported at the same position.
|
||||
*/
|
||||
private JCErroneous syntaxError(String key, TokenKind arg) {
|
||||
protected JCErroneous syntaxError(String key, TokenKind arg) {
|
||||
return syntaxError(token.pos, key, arg);
|
||||
}
|
||||
|
||||
@ -500,7 +500,7 @@ public class JavacParser implements Parser {
|
||||
}
|
||||
|
||||
/** Diagnose a modifier flag from the set, if any. */
|
||||
void checkNoMods(long mods) {
|
||||
protected void checkNoMods(long mods) {
|
||||
if (mods != 0) {
|
||||
long lowestMod = mods & -mods;
|
||||
error(token.pos, "mod.not.allowed.here",
|
||||
@ -521,7 +521,7 @@ public class JavacParser implements Parser {
|
||||
* @param tree The tree to be used as index in the hashtable
|
||||
* @param dc The doc comment to associate with the tree, or null.
|
||||
*/
|
||||
void attach(JCTree tree, Comment dc) {
|
||||
protected void attach(JCTree tree, Comment dc) {
|
||||
if (keepDocComments && dc != null) {
|
||||
// System.out.println("doc comment = ");System.out.println(dc);//DEBUG
|
||||
docComments.putComment(tree, dc);
|
||||
@ -530,19 +530,19 @@ public class JavacParser implements Parser {
|
||||
|
||||
/* -------- source positions ------- */
|
||||
|
||||
private void setErrorEndPos(int errPos) {
|
||||
protected void setErrorEndPos(int errPos) {
|
||||
endPosTable.setErrorEndPos(errPos);
|
||||
}
|
||||
|
||||
private void storeEnd(JCTree tree, int endpos) {
|
||||
protected void storeEnd(JCTree tree, int endpos) {
|
||||
endPosTable.storeEnd(tree, endpos);
|
||||
}
|
||||
|
||||
private <T extends JCTree> T to(T t) {
|
||||
protected <T extends JCTree> T to(T t) {
|
||||
return endPosTable.to(t);
|
||||
}
|
||||
|
||||
private <T extends JCTree> T toP(T t) {
|
||||
protected <T extends JCTree> T toP(T t) {
|
||||
return endPosTable.toP(t);
|
||||
}
|
||||
|
||||
@ -574,7 +574,7 @@ public class JavacParser implements Parser {
|
||||
/**
|
||||
* Ident = IDENTIFIER
|
||||
*/
|
||||
Name ident() {
|
||||
protected Name ident() {
|
||||
if (token.kind == IDENTIFIER) {
|
||||
Name name = token.name();
|
||||
nextToken();
|
||||
@ -789,7 +789,7 @@ public class JavacParser implements Parser {
|
||||
return term(TYPE);
|
||||
}
|
||||
|
||||
JCExpression term(int newmode) {
|
||||
protected JCExpression term(int newmode) {
|
||||
int prevmode = mode;
|
||||
mode = newmode;
|
||||
JCExpression t = term();
|
||||
@ -1669,7 +1669,7 @@ public class JavacParser implements Parser {
|
||||
}
|
||||
|
||||
/** Accepts all identifier-like tokens */
|
||||
Filter<TokenKind> LAX_IDENTIFIER = new Filter<TokenKind>() {
|
||||
protected Filter<TokenKind> LAX_IDENTIFIER = new Filter<TokenKind>() {
|
||||
public boolean accepts(TokenKind t) {
|
||||
return t == IDENTIFIER || t == UNDERSCORE || t == ASSERT || t == ENUM;
|
||||
}
|
||||
@ -2408,7 +2408,7 @@ public class JavacParser implements Parser {
|
||||
* | ASSERT Expression [ ":" Expression ] ";"
|
||||
* | ";"
|
||||
*/
|
||||
JCStatement parseSimpleStatement() {
|
||||
public JCStatement parseSimpleStatement() {
|
||||
int pos = token.pos;
|
||||
switch (token.kind) {
|
||||
case LBRACE:
|
||||
@ -2706,7 +2706,7 @@ public class JavacParser implements Parser {
|
||||
*
|
||||
* @param kind Whether to parse an ANNOTATION or TYPE_ANNOTATION
|
||||
*/
|
||||
List<JCAnnotation> annotationsOpt(Tag kind) {
|
||||
protected List<JCAnnotation> annotationsOpt(Tag kind) {
|
||||
if (token.kind != MONKEYS_AT) return List.nil(); // optimization
|
||||
ListBuffer<JCAnnotation> buf = new ListBuffer<>();
|
||||
int prevmode = mode;
|
||||
@ -2732,7 +2732,7 @@ public class JavacParser implements Parser {
|
||||
* | NATIVE | SYNCHRONIZED | TRANSIENT | VOLATILE | "@"
|
||||
* | "@" Annotation
|
||||
*/
|
||||
JCModifiers modifiersOpt() {
|
||||
protected JCModifiers modifiersOpt() {
|
||||
return modifiersOpt(null);
|
||||
}
|
||||
protected JCModifiers modifiersOpt(JCModifiers partial) {
|
||||
@ -2914,7 +2914,7 @@ public class JavacParser implements Parser {
|
||||
* @param reqInit Is an initializer always required?
|
||||
* @param dc The documentation comment for the variable declarations, or null.
|
||||
*/
|
||||
<T extends ListBuffer<? super JCVariableDecl>> T variableDeclaratorsRest(int pos,
|
||||
protected <T extends ListBuffer<? super JCVariableDecl>> T variableDeclaratorsRest(int pos,
|
||||
JCModifiers mods,
|
||||
JCExpression type,
|
||||
Name name,
|
||||
@ -3117,7 +3117,7 @@ public class JavacParser implements Parser {
|
||||
|
||||
/** ImportDeclaration = IMPORT [ STATIC ] Ident { "." Ident } [ "." "*" ] ";"
|
||||
*/
|
||||
JCTree importDeclaration() {
|
||||
protected JCTree importDeclaration() {
|
||||
int pos = token.pos;
|
||||
nextToken();
|
||||
boolean importStatic = false;
|
||||
@ -3159,7 +3159,7 @@ public class JavacParser implements Parser {
|
||||
* @param mods Any modifiers starting the class or interface declaration
|
||||
* @param dc The documentation comment for the class, or null.
|
||||
*/
|
||||
JCStatement classOrInterfaceOrEnumDeclaration(JCModifiers mods, Comment dc) {
|
||||
protected JCStatement classOrInterfaceOrEnumDeclaration(JCModifiers mods, Comment dc) {
|
||||
if (token.kind == CLASS) {
|
||||
return classDeclaration(mods, dc);
|
||||
} else if (token.kind == INTERFACE) {
|
||||
@ -3569,7 +3569,7 @@ public class JavacParser implements Parser {
|
||||
* TypeParametersOpt = ["<" TypeParameter {"," TypeParameter} ">"]
|
||||
* }
|
||||
*/
|
||||
List<JCTypeParameter> typeParametersOpt() {
|
||||
protected List<JCTypeParameter> typeParametersOpt() {
|
||||
if (token.kind == LT) {
|
||||
ListBuffer<JCTypeParameter> typarams = new ListBuffer<>();
|
||||
nextToken();
|
||||
@ -4004,7 +4004,7 @@ public class JavacParser implements Parser {
|
||||
allowTypeAnnotations = true;
|
||||
}
|
||||
}
|
||||
void checkAnnotationsAfterTypeParams(int pos) {
|
||||
protected void checkAnnotationsAfterTypeParams(int pos) {
|
||||
if (!allowAnnotationsAfterTypeParams) {
|
||||
log.error(pos, "annotations.after.type.params.not.supported.in.source", source.name);
|
||||
allowAnnotationsAfterTypeParams = true;
|
||||
@ -4092,7 +4092,7 @@ public class JavacParser implements Parser {
|
||||
/**
|
||||
* Store the last error position.
|
||||
*/
|
||||
protected int errorEndPos = Position.NOPOS;
|
||||
public int errorEndPos = Position.NOPOS;
|
||||
|
||||
public AbstractEndPosTable(JavacParser parser) {
|
||||
this.parser = parser;
|
||||
@ -4119,13 +4119,13 @@ public class JavacParser implements Parser {
|
||||
* will be set only if it is greater than the last stored error position.
|
||||
* @param errPos The error position
|
||||
*/
|
||||
protected void setErrorEndPos(int errPos) {
|
||||
public void setErrorEndPos(int errPos) {
|
||||
if (errPos > errorEndPos) {
|
||||
errorEndPos = errPos;
|
||||
}
|
||||
}
|
||||
|
||||
protected void setParser(JavacParser parser) {
|
||||
public void setParser(JavacParser parser) {
|
||||
this.parser = parser;
|
||||
}
|
||||
}
|
||||
|
@ -1196,9 +1196,6 @@ compiler.warn.file.from.future=\
|
||||
compiler.note.compressed.diags=\
|
||||
Some messages have been simplified; recompile with -Xdiags:verbose to get full output
|
||||
|
||||
compiler.note.potential.lambda.found=\
|
||||
This anonymous inner class creation can be turned into a lambda expression.
|
||||
|
||||
# 0: boolean, 1: symbol
|
||||
compiler.note.lambda.stat=\
|
||||
Translating lambda expression\n\
|
||||
@ -1640,14 +1637,20 @@ compiler.warn.raw.class.use=\
|
||||
|
||||
# 0: unused, 1: unused
|
||||
compiler.warn.diamond.redundant.args=\
|
||||
redundant type arguments in new expression (use diamond operator instead).
|
||||
Redundant type arguments in new expression (use diamond operator instead).
|
||||
|
||||
# 0: type, 1: type
|
||||
# 0: type, 1: list of type
|
||||
compiler.warn.diamond.redundant.args.1=\
|
||||
redundant type arguments in new expression (use diamond operator instead).\n\
|
||||
Redundant type arguments in new expression (use diamond operator instead).\n\
|
||||
explicit: {0}\n\
|
||||
inferred: {1}
|
||||
|
||||
compiler.warn.potential.lambda.found=\
|
||||
This anonymous inner class creation can be turned into a lambda expression.
|
||||
|
||||
compiler.warn.method.redundant.typeargs=\
|
||||
Redundant type arguments in method call.
|
||||
|
||||
# 0: symbol, 1: message segment
|
||||
compiler.warn.varargs.redundant.trustme.anno=\
|
||||
Redundant {0} annotation. {1}
|
||||
|
@ -313,6 +313,14 @@ public class TreeInfo {
|
||||
}
|
||||
}
|
||||
|
||||
/** Return true if the tree corresponds to a statement */
|
||||
public static boolean isStatement(JCTree tree) {
|
||||
return (tree instanceof JCStatement) &&
|
||||
!tree.hasTag(CLASSDEF) &&
|
||||
!tree.hasTag(Tag.BLOCK) &&
|
||||
!tree.hasTag(METHODDEF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the AST corresponds to a static select of the kind A.B
|
||||
*/
|
||||
|
@ -554,8 +554,9 @@ class JdepsTask {
|
||||
classpaths.addAll(PlatformClassPath.getModules(options.mpath));
|
||||
if (options.mpath != null) {
|
||||
initialArchives.addAll(PlatformClassPath.getModules(options.mpath));
|
||||
} else {
|
||||
classpaths.addAll(PlatformClassPath.getJarFiles());
|
||||
}
|
||||
classpaths.addAll(PlatformClassPath.getJarFiles());
|
||||
// add all classpath archives to the source locations for reporting
|
||||
sourceLocations.addAll(classpaths);
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ OSNAME = $(shell uname -s)
|
||||
ifeq ($(OSNAME), SunOS)
|
||||
SLASH_JAVA = /java
|
||||
PLATFORM = solaris
|
||||
JT_PLATFORM = solaris
|
||||
ARCH = $(shell uname -p)
|
||||
ifeq ($(ARCH), i386)
|
||||
ARCH=i586
|
||||
@ -30,7 +29,6 @@ endif
|
||||
ifeq ($(OSNAME), Linux)
|
||||
SLASH_JAVA = /java
|
||||
PLATFORM = linux
|
||||
JT_PLATFORM = linux
|
||||
ARCH = $(shell uname -m)
|
||||
ifeq ($(ARCH), i386)
|
||||
ARCH=i586
|
||||
@ -38,7 +36,6 @@ ifeq ($(OSNAME), Linux)
|
||||
endif
|
||||
ifeq ($(OSNAME), Darwin)
|
||||
PLATFORM = bsd
|
||||
JT_PLATFORM = linux
|
||||
ARCH = $(shell uname -m)
|
||||
ifeq ($(ARCH), i386)
|
||||
ARCH=i586
|
||||
@ -55,7 +52,6 @@ endif
|
||||
|
||||
ifeq ($(PLATFORM), windows)
|
||||
SLASH_JAVA = J:
|
||||
JT_PLATFORM = win32
|
||||
ifeq ($(word 1, $(PROCESSOR_IDENTIFIER)),ia64)
|
||||
ARCH=ia64
|
||||
else
|
||||
@ -93,8 +89,8 @@ ifdef JPRT_JTREG_HOME
|
||||
else
|
||||
JTREG_HOME = $(SLASH_JAVA)/re/jtreg/4.1/promoted/latest/binaries/jtreg
|
||||
endif
|
||||
JTREG = $(JTREG_HOME)/$(JT_PLATFORM)/bin/jtreg
|
||||
JTDIFF = $(JTREG_HOME)/$(JT_PLATFORM)/bin/jtdiff
|
||||
JTREG = $(JTREG_HOME)/bin/jtreg
|
||||
JTDIFF = $(JTREG_HOME)/bin/jtdiff
|
||||
|
||||
# Default JCK to run
|
||||
ifdef JPRT_JCK_HOME
|
||||
@ -105,21 +101,19 @@ endif
|
||||
|
||||
# Default JDK for JTREG and JCK
|
||||
#
|
||||
# JT_JAVA is the version of java used to run jtreg/JCK. Since it is now
|
||||
# standard to execute tests in sameVM mode, it should normally be set the
|
||||
# same as TESTJAVA (although not necessarily so.)
|
||||
# JT_JAVA is the version of java used to run jtreg/JCK.
|
||||
#
|
||||
ifdef JPRT_JAVA_HOME
|
||||
JT_JAVA = $(JPRT_JAVA_HOME)
|
||||
else
|
||||
JT_JAVA = $(SLASH_JAVA)/re/jdk/1.7.0/archive/fcs/binaries/$(PLATFORM)-$(ARCH)
|
||||
JT_JAVA = $(SLASH_JAVA)/re/jdk/1.9.0/archive/fcs/binaries/$(PLATFORM)-$(ARCH)
|
||||
endif
|
||||
|
||||
# Default JDK to test
|
||||
ifdef JPRT_IMPORT_PRODUCT_HOME
|
||||
TESTJAVA = $(JPRT_IMPORT_PRODUCT_HOME)
|
||||
else
|
||||
TESTJAVA = $(SLASH_JAVA)/re/jdk/1.7.0/promoted/latest/binaries/$(PLATFORM)-$(ARCH)
|
||||
TESTJAVA = $(SLASH_JAVA)/re/jdk/1.9.0/promoted/latest/binaries/$(PLATFORM)-$(ARCH)
|
||||
endif
|
||||
|
||||
# PRODUCT_HOME is a JPRT variable pointing to a directory containing the output from
|
||||
@ -152,7 +146,7 @@ endif
|
||||
ifdef CONCURRENCY
|
||||
JTREG_OPTIONS += -agentvm -concurrency:$(CONCURRENCY)
|
||||
else
|
||||
JTREG_OPTIONS += -samevm
|
||||
JTREG_OPTIONS += -agentvm
|
||||
endif
|
||||
|
||||
ifdef JCK_CONCURRENCY
|
||||
|
@ -22,8 +22,8 @@
|
||||
*/
|
||||
|
||||
// key: compiler.warn.diamond.redundant.args
|
||||
// options: -XDfindDiamond
|
||||
// options: -XDfind=diamond
|
||||
|
||||
class Foo<X> {
|
||||
Foo<String> fs = new Foo<String>();
|
||||
class DiamondRedundantArgs<X> {
|
||||
DiamondRedundantArgs<String> fs = new DiamondRedundantArgs<String>();
|
||||
}
|
||||
|
@ -22,8 +22,8 @@
|
||||
*/
|
||||
|
||||
// key: compiler.warn.diamond.redundant.args.1
|
||||
// options: -XDfindDiamond
|
||||
// options: -XDfind=diamond
|
||||
|
||||
class Foo<X> {
|
||||
Foo<?> fs = new Foo<String>();
|
||||
class DiamondRedundantArgs1<X> {
|
||||
DiamondRedundantArgs1<?> fs = new DiamondRedundantArgs1<String>();
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.warn.method.redundant.typeargs
|
||||
// options: -XDfind=method
|
||||
|
||||
class MethodRedundantTypeargs {
|
||||
<Z> Z id(Z z) { return z; }
|
||||
|
||||
void test() {
|
||||
String s = this.<String>id("");
|
||||
}
|
||||
}
|
@ -21,8 +21,8 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// key: compiler.note.potential.lambda.found
|
||||
// options: -XDidentifyLambdaCandidate=true
|
||||
// key: compiler.warn.potential.lambda.found
|
||||
// options: -XDfind=lambda
|
||||
|
||||
class PotentialLambdaFound {
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 6939780 7020044 8009459 8021338
|
||||
* @bug 6939780 7020044 8009459 8021338 8064365
|
||||
*
|
||||
* @summary add a warning to detect diamond sites
|
||||
* @author mcimadamore
|
||||
* @compile/ref=T6939780_7.out -Xlint:-options -source 7 T6939780.java -XDrawDiagnostics -XDfindDiamond
|
||||
* @compile/ref=T6939780_8.out T6939780.java -XDrawDiagnostics -XDfindDiamond
|
||||
* @compile/ref=T6939780_7.out -Xlint:-options -source 7 T6939780.java -XDrawDiagnostics -XDfind=diamond
|
||||
* @compile/ref=T6939780_8.out T6939780.java -XDrawDiagnostics -XDfind=diamond
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
T6939780.java:21:28: compiler.warn.diamond.redundant.args: T6939780.Foo<java.lang.Number>, T6939780.Foo<java.lang.Number>
|
||||
T6939780.java:21:28: compiler.warn.diamond.redundant.args
|
||||
T6939780.java:22:28: compiler.warn.diamond.redundant.args.1: T6939780.Foo<java.lang.Integer>, T6939780.Foo<java.lang.Number>
|
||||
T6939780.java:30:19: compiler.warn.diamond.redundant.args: T6939780.Foo<java.lang.Number>, T6939780.Foo<java.lang.Number>
|
||||
3 warnings
|
||||
T6939780.java:30:19: compiler.warn.diamond.redundant.args
|
||||
T6939780.java:31:19: compiler.warn.diamond.redundant.args.1: T6939780.Foo<java.lang.Integer>, T6939780.Foo<java.lang.Number>
|
||||
4 warnings
|
||||
|
@ -1,7 +1,7 @@
|
||||
T6939780.java:20:33: compiler.warn.diamond.redundant.args: T6939780.Foo<java.lang.Number>, T6939780.Foo<java.lang.Number>
|
||||
T6939780.java:21:28: compiler.warn.diamond.redundant.args: T6939780.Foo<java.lang.Number>, T6939780.Foo<java.lang.Number>
|
||||
T6939780.java:20:33: compiler.warn.diamond.redundant.args
|
||||
T6939780.java:21:28: compiler.warn.diamond.redundant.args
|
||||
T6939780.java:22:28: compiler.warn.diamond.redundant.args.1: T6939780.Foo<java.lang.Integer>, T6939780.Foo<java.lang.Number>
|
||||
T6939780.java:29:19: compiler.warn.diamond.redundant.args: T6939780.Foo<java.lang.Number>, T6939780.Foo<java.lang.Number>
|
||||
T6939780.java:30:19: compiler.warn.diamond.redundant.args: T6939780.Foo<java.lang.Number>, T6939780.Foo<java.lang.Number>
|
||||
T6939780.java:29:19: compiler.warn.diamond.redundant.args
|
||||
T6939780.java:30:19: compiler.warn.diamond.redundant.args
|
||||
T6939780.java:31:19: compiler.warn.diamond.redundant.args.1: T6939780.Foo<java.lang.Integer>, T6939780.Foo<java.lang.Number>
|
||||
6 warnings
|
||||
|
@ -1,10 +1,10 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 7002837
|
||||
* @bug 7002837 8064365
|
||||
*
|
||||
* @summary Diamond: javac generates diamond inference errors when in 'finder' mode
|
||||
* @author mcimadamore
|
||||
* @compile/fail/ref=T7002837.out -Werror -XDrawDiagnostics -XDfindDiamond T7002837.java
|
||||
* @compile/fail/ref=T7002837.out -Werror -XDrawDiagnostics -XDfind=diamond T7002837.java
|
||||
*
|
||||
*/
|
||||
|
||||
|
44
langtools/test/tools/javac/lambda/8066974/T8066974.java
Normal file
44
langtools/test/tools/javac/lambda/8066974/T8066974.java
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 8066974
|
||||
* @summary Compiler doesn't infer method's generic type information in lambda body
|
||||
* @compile/fail/ref=T8066974.out -XDrawDiagnostics T8066974.java
|
||||
*/
|
||||
class T8066974 {
|
||||
static class Throwing<E extends Throwable> { }
|
||||
static class RuntimeThrowing extends Throwing<RuntimeException> { }
|
||||
static class CheckedThrowing extends Throwing<Exception> { }
|
||||
|
||||
interface Parameter {
|
||||
<E extends Throwable> Object m(Throwing<E> tw) throws E;
|
||||
}
|
||||
|
||||
interface Mapper<R> {
|
||||
R m(Parameter p);
|
||||
}
|
||||
|
||||
<Z> Z map(Mapper<Z> mz) { return null; }
|
||||
|
||||
<Z extends Throwable> Mapper<Throwing<Z>> mapper(Throwing<Z> tz) throws Z { return null; }
|
||||
|
||||
static class ThrowingMapper<X extends Throwable> implements Mapper<Throwing<X>> {
|
||||
ThrowingMapper(Throwing<X> arg) throws X { }
|
||||
|
||||
@Override
|
||||
public Throwing<X> m(Parameter p) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
void testRuntime(RuntimeThrowing rt) {
|
||||
map(p->p.m(rt));
|
||||
map(mapper(rt));
|
||||
map(new ThrowingMapper<>(rt));
|
||||
}
|
||||
|
||||
void testChecked(CheckedThrowing ct) {
|
||||
map(p->p.m(ct));
|
||||
map(mapper(ct));
|
||||
map(new ThrowingMapper<>(ct));
|
||||
}
|
||||
}
|
4
langtools/test/tools/javac/lambda/8066974/T8066974.out
Normal file
4
langtools/test/tools/javac/lambda/8066974/T8066974.out
Normal file
@ -0,0 +1,4 @@
|
||||
T8066974.java:40:19: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception
|
||||
T8066974.java:41:19: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception
|
||||
T8066974.java:42:13: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception
|
||||
3 errors
|
19
langtools/test/tools/javac/lambda/8067792/T8067792.java
Normal file
19
langtools/test/tools/javac/lambda/8067792/T8067792.java
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 8067792
|
||||
* @summary Javac crashes in finder mode with nested implicit lambdas
|
||||
* @compile/fail/ref=T8067792.out -XDrawDiagnostics -Werror -XDfind=lambda T8067792.java
|
||||
*/
|
||||
|
||||
import java.util.stream.*;
|
||||
import java.util.*;
|
||||
|
||||
class T8067792 {
|
||||
void test(Stream<List<?>> sl) {
|
||||
Runnable r = new Runnable() {
|
||||
public void run() {
|
||||
Stream<List<?>> constructor = sl.filter(c -> true);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
4
langtools/test/tools/javac/lambda/8067792/T8067792.out
Normal file
4
langtools/test/tools/javac/lambda/8067792/T8067792.out
Normal file
@ -0,0 +1,4 @@
|
||||
T8067792.java:13:37: compiler.warn.potential.lambda.found
|
||||
- compiler.err.warnings.and.werror
|
||||
1 error
|
||||
1 warning
|
@ -1,9 +1,9 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 8003280
|
||||
* @bug 8003280 8064365
|
||||
* @summary Add lambda tests
|
||||
* simple test for lambda candidate check
|
||||
* @compile/fail/ref=LambdaConv18.out -XDrawDiagnostics -XDidentifyLambdaCandidate=true LambdaConv18.java
|
||||
* @compile/fail/ref=LambdaConv18.out -XDrawDiagnostics -XDfind=lambda LambdaConv18.java
|
||||
*/
|
||||
|
||||
class LambdaConv18 {
|
||||
|
@ -1,4 +1,5 @@
|
||||
LambdaConv18.java:23:5: compiler.err.cant.resolve.location: kindname.class, NonExistent, , , (compiler.misc.location: kindname.class, LambdaConv18, null)
|
||||
LambdaConv18.java:20:24: compiler.note.potential.lambda.found
|
||||
LambdaConv18.java:20:24: compiler.warn.potential.lambda.found
|
||||
LambdaConv18.java:23:26: compiler.err.cant.resolve.location: kindname.class, NonExistent, , , (compiler.misc.location: kindname.class, LambdaConv18, null)
|
||||
2 errors
|
||||
1 warning
|
||||
|
100
langtools/test/tools/javac/lambda/lambdaNaming/TestNonSerializableLambdaNameStability.java
Normal file
100
langtools/test/tools/javac/lambda/lambdaNaming/TestNonSerializableLambdaNameStability.java
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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 8067422
|
||||
* @summary Check that the lambda names are not unnecessarily unstable
|
||||
* @library /tools/lib
|
||||
* @build ToolBox
|
||||
* @run main TestNonSerializableLambdaNameStability
|
||||
*/
|
||||
|
||||
import com.sun.tools.classfile.ClassFile;
|
||||
import com.sun.tools.classfile.Method;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.tools.StandardLocation;
|
||||
|
||||
public class TestNonSerializableLambdaNameStability {
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
new TestNonSerializableLambdaNameStability().run();
|
||||
}
|
||||
|
||||
String lambdaSource = "public class L%d {\n" +
|
||||
" public static class A {\n" +
|
||||
" private Runnable r = () -> { };\n" +
|
||||
" }\n" +
|
||||
" public static class B {\n" +
|
||||
" private Runnable r = () -> { };\n" +
|
||||
" }\n" +
|
||||
" private Runnable r = () -> { };\n" +
|
||||
"}\n";
|
||||
|
||||
String expectedLambdaMethodName = "lambda$new$0";
|
||||
|
||||
void run() throws Exception {
|
||||
List<String> sources = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
sources.add(String.format(lambdaSource, i));
|
||||
}
|
||||
|
||||
ToolBox tb = new ToolBox();
|
||||
|
||||
try (ToolBox.MemoryFileManager fm = new ToolBox.MemoryFileManager()) {
|
||||
tb.new JavacTask()
|
||||
.sources(sources.toArray(new String[sources.size()]))
|
||||
.fileManager(fm)
|
||||
.run();
|
||||
|
||||
for (String file : fm.files.get(StandardLocation.CLASS_OUTPUT).keySet()) {
|
||||
byte[] fileBytes = fm.getFileBytes(StandardLocation.CLASS_OUTPUT, file);
|
||||
try (InputStream in = new ByteArrayInputStream(fileBytes)) {
|
||||
boolean foundLambdaMethod = false;
|
||||
ClassFile cf = ClassFile.read(in);
|
||||
StringBuilder seenMethods = new StringBuilder();
|
||||
String sep = "";
|
||||
for (Method m : cf.methods) {
|
||||
String methodName = m.getName(cf.constant_pool);
|
||||
if (expectedLambdaMethodName.equals(methodName)) {
|
||||
foundLambdaMethod = true;
|
||||
break;
|
||||
}
|
||||
seenMethods.append(sep);
|
||||
seenMethods.append(methodName);
|
||||
sep = ", ";
|
||||
}
|
||||
|
||||
if (!foundLambdaMethod) {
|
||||
throw new AbstractMethodError("Did not find the lambda method, " +
|
||||
"found methods: " + seenMethods.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -23,10 +23,10 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8003280
|
||||
* @bug 8003280 8064365
|
||||
* @summary Add lambda tests
|
||||
* spurious crashes when running in 'diamond finder' mode
|
||||
* @compile -XDfindDiamond DiamondFinder.java
|
||||
* @compile -XDfind=diamond DiamondFinder.java
|
||||
*/
|
||||
import java.util.*;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user