diff --git a/java.source.base/apichanges.xml b/java.source.base/apichanges.xml --- a/java.source.base/apichanges.xml +++ b/java.source.base/apichanges.xml @@ -49,6 +49,28 @@ Java Source API + + + Allow to return also unimplemented default methods + + + + + +

+ findUnimplementedMethods and findOverridableMethods + work better with interface default methods: they are treated as implemented, + but overridable. +

+

+ Allow ElementUtilities.findUnimplementedMethods enumerate + also default methods whose implementations are not provided by class or + superclasses. +

+
+ + +
Code Generator uses caret location to insert members diff --git a/java.source.base/nbproject/project.properties b/java.source.base/nbproject/project.properties --- a/java.source.base/nbproject/project.properties +++ b/java.source.base/nbproject/project.properties @@ -47,7 +47,7 @@ javadoc.title=Java Source Base javadoc.arch=${basedir}/arch.xml javadoc.apichanges=${basedir}/apichanges.xml -spec.version.base=2.14.0 +spec.version.base=2.15.0 test.qa-functional.cp.extra=${refactoring.java.dir}/modules/ext/nb-javac-api.jar test.unit.run.cp.extra=${o.n.core.dir}/core/core.jar:\ ${o.n.core.dir}/lib/boot.jar:\ diff --git a/java.source.base/src/org/netbeans/api/java/source/ElementUtilities.java b/java.source.base/src/org/netbeans/api/java/source/ElementUtilities.java --- a/java.source.base/src/org/netbeans/api/java/source/ElementUtilities.java +++ b/java.source.base/src/org/netbeans/api/java/source/ElementUtilities.java @@ -74,6 +74,7 @@ import com.sun.tools.javadoc.DocEnv; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; @@ -567,7 +568,24 @@ * @since 0.20 */ public List findUnimplementedMethods(TypeElement impl) { - return findUnimplementedMethods(impl, impl); + return findUnimplementedMethods(impl, impl, true); + } + + /** + * Finds all unimplemented methods in the given type and supertypes, bud include + * also interface default methods. + *

+ * If the platform configured for the type is older than JDK8, the method is equivalent + * to {@link #findUnimplementedMethods(javax.lang.model.element.TypeElement)}. + * + * @param impl the implementation type + * @param includeDefaults if true, will also return interface default methods, which + * are not overriden in supertypes. + * @return unimplemented (and/or default) methods. + * @since 2.15 + */ + public List findUnimplementedMethods(TypeElement impl, boolean includeDefaults) { + return findUnimplementedMethods(impl, impl, true); } /**Find all methods in given type and its supertypes, which are overridable. @@ -786,24 +804,43 @@ // private implementation -------------------------------------------------- private static final Set NOT_OVERRIDABLE = EnumSet.of(Modifier.STATIC, Modifier.FINAL, Modifier.PRIVATE); - - private List findUnimplementedMethods(TypeElement impl, TypeElement element) { + + private List findUnimplementedMethods(TypeElement impl, TypeElement element, boolean includeDefaults) { List undef = new ArrayList(); Types types = JavacTypes.instance(ctx); com.sun.tools.javac.code.Types implTypes = com.sun.tools.javac.code.Types.instance(ctx); DeclaredType implType = (DeclaredType)impl.asType(); if (element.getKind().isInterface() || element.getModifiers().contains(Modifier.ABSTRACT)) { for (Element e : element.getEnclosedElements()) { - if (e.getKind() == ElementKind.METHOD && e.getModifiers().contains(Modifier.ABSTRACT)) { - ExecutableElement ee = (ExecutableElement)e; - Element eeImpl = getImplementationOf(ee, impl); - if ((eeImpl == null || (eeImpl == ee && impl != element)) && implTypes.asSuper((Type)implType, (Symbol)ee.getEnclosingElement()) != null) + if (e.getKind() != ElementKind.METHOD) { + continue; + } + if (element.getKind().isInterface()) { + if (e.getModifiers().contains(Modifier.STATIC)) { + continue; + } else if (e.getModifiers().contains(Modifier.DEFAULT) && !includeDefaults) { + continue; + } + } else if (!e.getModifiers().contains(Modifier.ABSTRACT)) { + continue; + } + ExecutableElement ee = (ExecutableElement)e; + ExecutableElement eeImpl = (ExecutableElement)getImplementationOf(ee, impl); + if (eeImpl == null) { + if (implTypes.asSuper((Type)implType, (Symbol)ee.getEnclosingElement()) != null) { undef.add(ee); + } + } else if (impl != element && implTypes.asSuper((Type)implType, (Symbol)ee.getEnclosingElement()) != null) { + if (eeImpl == ee) { + undef.add(ee); + } else if (includeDefaults && eeImpl.getModifiers().contains(Modifier.DEFAULT)) { + undef.add((ExecutableElement)eeImpl); + } } } } for (TypeMirror t : types.directSupertypes(element.asType())) { - for (ExecutableElement ee : findUnimplementedMethods(impl, (TypeElement) ((DeclaredType) t).asElement())) { + for (ExecutableElement ee : findUnimplementedMethods(impl, (TypeElement) ((DeclaredType) t).asElement(), includeDefaults)) { //check if "the same" method has already been added: boolean exists = false; ExecutableType eeType = (ExecutableType)types.asMemberOf(implType, ee); diff --git a/java.source.base/src/org/netbeans/modules/java/source/builder/ElementsService.java b/java.source.base/src/org/netbeans/modules/java/source/builder/ElementsService.java --- a/java.source.base/src/org/netbeans/modules/java/source/builder/ElementsService.java +++ b/java.source.base/src/org/netbeans/modules/java/source/builder/ElementsService.java @@ -49,6 +49,7 @@ import com.sun.tools.javac.util.Name; import com.sun.tools.javac.util.Names; import com.sun.tools.javac.code.Scope; +import com.sun.tools.javac.code.Source; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Symbol.ClassSymbol; import com.sun.tools.javac.code.Symbol.MethodSymbol; @@ -58,6 +59,9 @@ import com.sun.tools.javac.model.JavacTypes; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.ListBuffer; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import javax.lang.model.element.*; import static javax.lang.model.element.ElementKind.*; import javax.lang.model.type.*; @@ -70,6 +74,7 @@ private com.sun.tools.javac.code.Types jctypes; private Names names; private Types types; + private final boolean allowDefaultMethods; private static final Context.Key KEY = new Context.Key(); @@ -86,6 +91,7 @@ jctypes = com.sun.tools.javac.code.Types.instance(context); names = Names.instance(context); types = JavacTypes.instance(context); + allowDefaultMethods = Source.instance(context).allowDefaultMethods(); } /** @@ -214,7 +220,17 @@ } public Element getImplementationOf(ExecutableElement method, TypeElement origin) { - return ((MethodSymbol)method).implementation((TypeSymbol)origin, jctypes, true); + MethodSymbol implmethod = ((MethodSymbol)method).implementation((TypeSymbol)origin, jctypes, true); + if (implmethod == null || implmethod == method) { + //look for default implementations + if (allowDefaultMethods) { + MethodSymbol prov = jctypes.interfaceCandidates(((TypeSymbol) origin).type, (MethodSymbol) method).head; + if (prov != null && prov.overrides((MethodSymbol) method, (TypeSymbol) origin, jctypes, true)) { + implmethod = prov; + } + } + } + return implmethod; } public boolean isSynthetic(Element e) { @@ -225,10 +241,10 @@ MethodSymbol m = (MethodSymbol)method; ClassSymbol origin = (ClassSymbol)m.owner; MethodSymbol bridgeCandidate = null; - for (Type t = jctypes.supertype(origin.type); t.hasTag(TypeTag.CLASS); t = jctypes.supertype(t)) { - TypeSymbol c = t.tsym; + for (Type t = jctypes.supertype(origin.type); t.hasTag(TypeTag.CLASS); t = jctypes.supertype(t)) { + TypeSymbol c = t.tsym; for (Symbol sym : c.members().getSymbolsByName(m.name)) { - if (m.overrides(sym, origin, jctypes, false)) { + if (m.overrides(sym, origin, jctypes, false)) { if ((sym.flags() & Flags.BRIDGE) > 0) { if (bridgeCandidate == null) { bridgeCandidate = (MethodSymbol)sym; @@ -237,8 +253,20 @@ return (MethodSymbol)sym; } } - } - } + } + } + if (allowDefaultMethods) { + MethodSymbol prov = jctypes.interfaceCandidates(((TypeSymbol) origin).type, (MethodSymbol) method).head; + if (prov != null && m.overrides(prov, origin, jctypes, true)) { + if ((prov.flags() & Flags.BRIDGE) > 0) { + if (bridgeCandidate == null) { + bridgeCandidate = (MethodSymbol)prov; + } + } else { + return (MethodSymbol)prov; + } + } + } return bridgeCandidate; } }