fix problem with default methods overloads + test

This commit is contained in:
Renaud Pawlak 2020-03-11 13:18:54 +01:00
parent 3b581e8bd0
commit 2eab7c0cb9
13 changed files with 200 additions and 52 deletions

View File

@ -160,8 +160,10 @@ public class Util {
* Gets the tree that corresponds to the given element (this is a slow
* implementation - do not use intensively).
*
* @param context the transpiler's context
* @param element the element to lookup
* @param context
* the transpiler's context
* @param element
* the element to lookup
* @return the javac AST that corresponds to that element
*/
public static JCTree lookupTree(JSweetContext context, Element element) {
@ -224,9 +226,12 @@ public class Util {
/**
* Recursively adds files to the given list.
*
* @param extension the extension to filter with
* @param file the root file/directory to look into recursively
* @param files the list to add the files matching the extension
* @param extension
* the extension to filter with
* @param file
* the root file/directory to look into recursively
* @param files
* the list to add the files matching the extension
*/
public static void addFiles(String extension, File file, Collection<File> files) {
addFiles(f -> f.getName().endsWith(extension), file, files);
@ -235,10 +240,13 @@ public class Util {
/**
* Recursively adds files to the given list.
*
* @param filter the filter predicate to apply (only files matching the
* predicate will be added)
* @param file the root file/directory to look into recursively
* @param files the list to add the files matching the extension
* @param filter
* the filter predicate to apply (only files matching the
* predicate will be added)
* @param file
* the root file/directory to look into recursively
* @param files
* the list to add the files matching the extension
*/
public static void addFiles(Predicate<File> filter, File file, Collection<File> files) {
if (file.isDirectory()) {
@ -371,8 +379,8 @@ public class Util {
}
/**
* Fills the given map with all the variables beeing accessed within the given
* code tree.
* Fills the given map with all the variables beeing accessed within the
* given code tree.
*/
public static void fillAllVariableAccesses(final Map<String, VarSymbol> vars, final JCTree tree) {
new TreeScanner() {
@ -393,7 +401,8 @@ public class Util {
}
/**
* Finds the method declaration within the given type, for the given invocation.
* Finds the method declaration within the given type, for the given
* invocation.
*/
public static MethodSymbol findMethodDeclarationInType(Types types, TypeSymbol typeSymbol,
JCMethodInvocation invocation) {
@ -403,7 +412,8 @@ public class Util {
}
/**
* Finds the method in the given type that matches the given name and signature.
* Finds the method in the given type that matches the given name and
* signature.
*/
public static MethodSymbol findMethodDeclarationInType(Types types, TypeSymbol typeSymbol, String methodName,
MethodType methodType) {
@ -411,7 +421,8 @@ public class Util {
}
/**
* Finds the method in the given type that matches the given name and signature.
* Finds the method in the given type that matches the given name and
* signature.
*/
public static MethodSymbol findMethodDeclarationInType(Types types, TypeSymbol typeSymbol, String methodName,
MethodType methodType, boolean overrides) {
@ -434,7 +445,8 @@ public class Util {
// return the best match
if (logger.isTraceEnabled()) {
logger.trace("method declaration match for " + typeSymbol + "." + methodName + " - " + methodType + " : "
+ bestMatch + " score=" + lastScore);
+ (bestMatch == null ? "" : bestMatch.getEnclosingElement() + ".") + bestMatch + " score="
+ lastScore);
}
return bestMatch;
}
@ -447,7 +459,7 @@ public class Util {
int score = 0;
boolean isAbstract = (candidate.flags() & Flags.ABSTRACT) != 0;
boolean isAbstract = ((candidate.flags() & Flags.ABSTRACT) != 0) && !candidate.isDefault();
if (isAbstract) {
score -= 30;
}
@ -471,8 +483,8 @@ public class Util {
if (typeSymbol.getEnclosedElements() != null) {
for (Element element : typeSymbol.getEnclosedElements()) {
if ((element instanceof MethodSymbol) && (methodName.equals(element.getSimpleName().toString())
|| ((MethodSymbol) element).getKind() == ElementKind.CONSTRUCTOR
&& ("this".equals(methodName) /* || "super".equals(methodName) */))) {
|| ((MethodSymbol) element).getKind() == ElementKind.CONSTRUCTOR && ("this".equals(
methodName) /* || "super".equals(methodName) */))) {
MethodSymbol methodSymbol = (MethodSymbol) element;
if (methodType == null) {
collector.add(methodSymbol);
@ -575,8 +587,8 @@ public class Util {
}
/**
* Find first declaration (of any kind) matching the given name (and optionally
* the given number of arguments for methods)
* Find first declaration (of any kind) matching the given name (and
* optionally the given number of arguments for methods)
*/
public static Symbol findFirstDeclarationInClassAndSuperClasses(TypeSymbol typeSymbol, String name,
ElementKind kind, Integer methodArgsCount) {
@ -586,7 +598,8 @@ public class Util {
if (typeSymbol.getEnclosedElements() != null) {
for (Element element : typeSymbol.getEnclosedElements()) {
if (name.equals(element.getSimpleName().toString()) && element.getKind() == kind
&& (methodArgsCount == null || methodArgsCount.equals(((ExecutableElement)element).getParameters().size()))) {
&& (methodArgsCount == null
|| methodArgsCount.equals(((ExecutableElement) element).getParameters().size()))) {
return (Symbol) element;
}
}
@ -658,10 +671,13 @@ public class Util {
/**
* Tells if a method can be invoked with some given parameter types.
*
* @param types a reference to the types in the compilation scope
* @param from the caller method signature to test (contains the parameter
* types)
* @param target the callee method signature
* @param types
* a reference to the types in the compilation scope
* @param from
* the caller method signature to test (contains the parameter
* types)
* @param target
* the callee method signature
* @return true if the callee can be invoked by the caller
*/
public static boolean isInvocable(Types types, MethodType from, MethodType target) {
@ -697,8 +713,8 @@ public class Util {
}
/**
* Fills the given set with all the default methods found in the current type
* and super interfaces.
* Fills the given set with all the default methods found in the current
* type and super interfaces.
*/
public static void findDefaultMethodsInType(Set<Entry<JCClassDecl, JCMethodDecl>> defaultMethods,
JSweetContext context, ClassSymbol classSymbol) {
@ -752,7 +768,7 @@ public class Util {
public static boolean isVarargs(VarSymbol varSym) {
return (varSym.flags_field & Flags.VARARGS) == Flags.VARARGS;
}
/**
* Gets the file from a Java file object.
*/
@ -794,12 +810,14 @@ public class Util {
private final static Pattern REGEX_CHARS = Pattern.compile("([\\\\*+\\[\\](){}\\$.?\\^|])");
/**
* This function will escape special characters within a string to ensure that
* the string will not be parsed as a regular expression. This is helpful with
* accepting using input that needs to be used in functions that take a regular
* expression as an argument (such as String.replaceAll(), or String.split()).
* This function will escape special characters within a string to ensure
* that the string will not be parsed as a regular expression. This is
* helpful with accepting using input that needs to be used in functions
* that take a regular expression as an argument (such as
* String.replaceAll(), or String.split()).
*
* @param regex - argument which we wish to escape.
* @param regex
* - argument which we wish to escape.
* @return - Resulting string with the following characters escaped:
* [](){}+*^?$.\
*/
@ -846,8 +864,10 @@ public class Util {
/**
* Get the relative path to reach a symbol from another one.
*
* @param fromSymbol the start path
* @param toSymbol the end path
* @param fromSymbol
* the start path
* @param toSymbol
* the end path
* @return the '/'-separated path
* @see #getRelativePath(String, String)
*/
@ -878,8 +898,10 @@ public class Util {
* <p>
* Bug fix: Renaud Pawlak
*
* @param fromPath the path to start from
* @param toPath the path to reach
* @param fromPath
* the path to start from
* @param toPath
* the path to reach
*/
public static String getRelativePath(String fromPath, String toPath) {
StringBuilder relativePath = null;
@ -934,7 +956,8 @@ public class Util {
/**
* Removes the extensions of the given file name.
*
* @param fileName the given file name (can contain path)
* @param fileName
* the given file name (can contain path)
* @return the file name without the extension
*/
public static String removeExtension(String fileName) {
@ -947,11 +970,13 @@ public class Util {
}
/**
* Tells if the given directory or any of its sub-directory contains one of the
* given files.
* Tells if the given directory or any of its sub-directory contains one of
* the given files.
*
* @param dir the directory to look into
* @param files the files to be found
* @param dir
* the directory to look into
* @param files
* the files to be found
* @return true if one of the given files is found
*/
public static boolean containsFile(File dir, File[] files) {
@ -1121,8 +1146,8 @@ public class Util {
}
/**
* Recursively looks up one of the given types in the type hierachy of the given
* class.
* Recursively looks up one of the given types in the type hierachy of the
* given class.
*
* @return true if one of the given names is found as a superclass or a
* superinterface
@ -1277,8 +1302,8 @@ public class Util {
}
/**
* Tells if that variable is a non-static final field initialized with a literal
* value.
* Tells if that variable is a non-static final field initialized with a
* literal value.
*/
public static boolean isConstantOrNullField(JCVariableDecl var) {
return !var.getModifiers().getFlags().contains(Modifier.STATIC) && (var.init == null
@ -1343,10 +1368,10 @@ public class Util {
*
* <p>
* This method aims at overcoming TypeScrit limitation that forces a parent
* class to be declared before its child class (it is not the case in Java). So
* far this is a partial implementation that should cover most cases... for a
* 100% coverage we would need a much more complicated implementation that is
* probably not worth it.
* class to be declared before its child class (it is not the case in Java).
* So far this is a partial implementation that should cover most cases...
* for a 100% coverage we would need a much more complicated implementation
* that is probably not worth it.
*/
public static List<JCClassDecl> getSortedClassDeclarations(List<JCTree> decls) {
// return (List<JCClassDecl>)(Object)decls;
@ -1380,8 +1405,8 @@ public class Util {
}
/**
* Finds the first inner class declaration of the given name in the given class
* hierarchy.
* Finds the first inner class declaration of the given name in the given
* class hierarchy.
*/
public static ClassSymbol findInnerClassDeclaration(ClassSymbol clazz, String name) {
if (clazz == null) {

View File

@ -71,6 +71,17 @@ import source.structural.TwoClassesInSameFile;
import source.structural.WrappedParametersOwner;
import source.structural.WrongConstructsInInterfaces;
import source.structural.WrongThisAccessOnStatic;
import source.structural.defaultMethods.AbstractViewController;
import source.structural.defaultMethods.CC1;
import source.structural.defaultMethods.CC2;
import source.structural.defaultMethods.FinalViewController;
import source.structural.defaultMethods.I1;
import source.structural.defaultMethods.I2;
import source.structural.defaultMethods.I3;
import source.structural.defaultMethods.I4;
import source.structural.defaultMethods.I5;
import source.structural.defaultMethods.II1;
import source.structural.defaultMethods.IntermediateAbstractViewController;
import source.structural.fieldmethodclash.Person;
import source.structural.fieldmethodclash.User;
import source.structural.globalclasses.Globals;
@ -534,4 +545,12 @@ public class StructuralTests extends AbstractTest {
}, getSourceFile(AnonymousInInterface.class));
}
@Test
public void testDefaultMethodsHierarchy() {
eval(ModuleKind.commonjs, (logHandler, r) -> {
logHandler.assertNoProblems();
}, getSourceFile(II1.class), getSourceFile(CC1.class), getSourceFile(CC2.class), getSourceFile(I1.class), getSourceFile(I2.class), getSourceFile(I3.class), getSourceFile(I4.class), getSourceFile(I5.class), getSourceFile(AbstractViewController.class), getSourceFile(IntermediateAbstractViewController.class), getSourceFile(FinalViewController.class));
}
}

View File

@ -0,0 +1,5 @@
package source.structural.defaultMethods;
public class AbstractViewController implements I4 {
}

View File

@ -0,0 +1,5 @@
package source.structural.defaultMethods;
public class CC1 {
}

View File

@ -0,0 +1,5 @@
package source.structural.defaultMethods;
public class CC2 extends CC1 {
}

View File

@ -0,0 +1,10 @@
package source.structural.defaultMethods;
public class FinalViewController extends IntermediateAbstractViewController implements I5 {
@Override
public void o2(boolean b, CC1 cc1, II1 ii1) {
System.out.println("o2-overriden");
}
}

View File

@ -0,0 +1,11 @@
package source.structural.defaultMethods;
public interface I1 {
default void m1() {
System.out.println("m1");
}
void m();
}

View File

@ -0,0 +1,17 @@
package source.structural.defaultMethods;
public interface I2 extends I1 {
default void m2() {
System.out.println("m2");
}
default void o1(String s) {
System.out.println("o1-s");
}
default void o1(Integer i) {
System.out.println("o1-i");
}
}

View File

@ -0,0 +1,9 @@
package source.structural.defaultMethods;
public interface I3 {
default void m3() {
System.out.println("m3");
}
}

View File

@ -0,0 +1,9 @@
package source.structural.defaultMethods;
public interface I4 {
default void m4() {
System.out.println("m4");
}
}

View File

@ -0,0 +1,13 @@
package source.structural.defaultMethods;
public interface I5 {
default void o2(boolean b, CC1 cc1, II1 ii1) {
System.out.println("o2-s");
}
default void o2(boolean b, CC2 cc2, II1 ii1) {
System.out.println("o2-i");
}
}

View File

@ -0,0 +1,5 @@
package source.structural.defaultMethods;
public interface II1 {
}

View File

@ -0,0 +1,15 @@
package source.structural.defaultMethods;
public class IntermediateAbstractViewController extends AbstractViewController implements I2, I3 {
@Override
public void m() {
System.out.println("m");
}
@Override
public void o1(String s) {
System.out.println("o1-overriden");
}
}