8064365: Better support for finder capabilities in target-typing context
Summary: Add new framework to allow for easy creation of finder-like capabilities.
Reviewed-by: jjg, jlahoda
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Analyzer.java Fri Dec 12 18:07:24 2014 +0000
@@ -0,0 +1,493 @@
+/*
+ * 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.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.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.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;
+ }
+ }
+}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Thu Dec 11 18:23:17 2014 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Fri Dec 12 18:07:24 2014 +0000
@@ -83,6 +83,7 @@
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 @@
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 @@
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);
@@ -182,16 +181,6 @@
*/
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
@@ -199,12 +188,6 @@
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?
*/
boolean allowStringsInSwitch;
@@ -610,7 +593,13 @@
/** 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 +781,8 @@
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;
}
@@ -2052,12 +2041,6 @@
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 +2088,6 @@
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
@@ -2135,58 +2116,6 @@
result = check(tree, owntype, KindSelector.VAL, resultInfo);
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.
*/
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java Thu Dec 11 18:23:17 2014 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java Fri Dec 12 18:07:24 2014 +0000
@@ -59,6 +59,10 @@
*/
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 @@
info.returnResult = returnResult;
info.defaultSuperCallSite = defaultSuperCallSite;
info.isSerializable = isSerializable;
+ info.isSpeculative = isSpeculative;
return info;
}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Thu Dec 11 18:23:17 2014 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Fri Dec 12 18:07:24 2014 +0000
@@ -37,6 +37,7 @@
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.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 @@
* 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 @@
}
}
+ 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 @@
@Override
public void visitNewClass(JCNewClass tree) {
- result = (TreeInfo.isDiamond(tree) || attr.findDiamonds) ?
+ result = TreeInfo.isDiamond(tree) ?
ArgumentExpressionKind.POLY : ArgumentExpressionKind.NO_POLY;
}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Thu Dec 11 18:23:17 2014 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Fri Dec 12 18:07:24 2014 +0000
@@ -1196,9 +1196,6 @@
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 @@
# 0: unused, 1: unused
compiler.warn.diamond.redundant.args=\
- redundant type arguments in new expression (use diamond operator instead).
-
-# 0: type, 1: type
+ Redundant type arguments in new expression (use diamond operator instead).
+
+# 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}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java Thu Dec 11 18:23:17 2014 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java Fri Dec 12 18:07:24 2014 +0000
@@ -313,6 +313,14 @@
}
}
+ /** 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
*/
--- a/langtools/test/tools/javac/diags/examples/DiamondRedundantArgs.java Thu Dec 11 18:23:17 2014 -0800
+++ b/langtools/test/tools/javac/diags/examples/DiamondRedundantArgs.java Fri Dec 12 18:07:24 2014 +0000
@@ -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>();
}
--- a/langtools/test/tools/javac/diags/examples/DiamondRedundantArgs1.java Thu Dec 11 18:23:17 2014 -0800
+++ b/langtools/test/tools/javac/diags/examples/DiamondRedundantArgs1.java Fri Dec 12 18:07:24 2014 +0000
@@ -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>();
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/MethodRedundantTypeargs.java Fri Dec 12 18:07:24 2014 +0000
@@ -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("");
+ }
+}
--- a/langtools/test/tools/javac/diags/examples/PotentialLambdaFound.java Thu Dec 11 18:23:17 2014 -0800
+++ b/langtools/test/tools/javac/diags/examples/PotentialLambdaFound.java Fri Dec 12 18:07:24 2014 +0000
@@ -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 {
--- a/langtools/test/tools/javac/generics/diamond/6939780/T6939780.java Thu Dec 11 18:23:17 2014 -0800
+++ b/langtools/test/tools/javac/generics/diamond/6939780/T6939780.java Fri Dec 12 18:07:24 2014 +0000
@@ -4,8 +4,8 @@
*
* @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
*
*/
--- a/langtools/test/tools/javac/generics/diamond/6939780/T6939780_7.out Thu Dec 11 18:23:17 2014 -0800
+++ b/langtools/test/tools/javac/generics/diamond/6939780/T6939780_7.out Fri Dec 12 18:07:24 2014 +0000
@@ -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
--- a/langtools/test/tools/javac/generics/diamond/6939780/T6939780_8.out Thu Dec 11 18:23:17 2014 -0800
+++ b/langtools/test/tools/javac/generics/diamond/6939780/T6939780_8.out Fri Dec 12 18:07:24 2014 +0000
@@ -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
--- a/langtools/test/tools/javac/generics/diamond/7002837/T7002837.java Thu Dec 11 18:23:17 2014 -0800
+++ b/langtools/test/tools/javac/generics/diamond/7002837/T7002837.java Fri Dec 12 18:07:24 2014 +0000
@@ -4,7 +4,7 @@
*
* @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
*
*/
--- a/langtools/test/tools/javac/lambda/LambdaConv18.java Thu Dec 11 18:23:17 2014 -0800
+++ b/langtools/test/tools/javac/lambda/LambdaConv18.java Fri Dec 12 18:07:24 2014 +0000
@@ -3,7 +3,7 @@
* @bug 8003280
* @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 {
--- a/langtools/test/tools/javac/lambda/LambdaConv18.out Thu Dec 11 18:23:17 2014 -0800
+++ b/langtools/test/tools/javac/lambda/LambdaConv18.out Fri Dec 12 18:07:24 2014 +0000
@@ -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
--- a/langtools/test/tools/javac/lambda/speculative/DiamondFinder.java Thu Dec 11 18:23:17 2014 -0800
+++ b/langtools/test/tools/javac/lambda/speculative/DiamondFinder.java Fri Dec 12 18:07:24 2014 +0000
@@ -26,7 +26,7 @@
* @bug 8003280
* @summary Add lambda tests
* spurious crashes when running in 'diamond finder' mode
- * @compile -XDfindDiamond DiamondFinder.java
+ * @compile -XDfind=diamond DiamondFinder.java
*/
import java.util.*;