001/* 002 * Copyright (c) 2012-2021 Institut National des Sciences Appliquées de Lyon (INSA Lyon) and others 003 * 004 * This program and the accompanying materials are made available under the 005 * terms of the Eclipse Public License 2.0 which is available at 006 * http://www.eclipse.org/legal/epl-2.0. 007 * 008 * SPDX-License-Identifier: EPL-2.0 009 */ 010 011package org.eclipse.golo.runtime; 012 013import org.eclipse.golo.compiler.macro.Macro; 014 015import java.lang.reflect.*; 016import java.util.function.Predicate; 017import java.util.stream.Stream; 018 019import static org.eclipse.golo.runtime.TypeMatching.compareTypes; 020import static org.eclipse.golo.runtime.DecoratorsHelper.isMethodDecorated; 021import static org.eclipse.golo.runtime.TypeMatching.argumentsNumberMatches; 022 023public final class Extractors { 024 private Extractors() { 025 throw new UnsupportedOperationException("don't instantiate"); 026 } 027 028 public static Stream<Constructor<?>> getConstructors(Class<?> klass) { 029 if (klass == null) { 030 return Stream.empty(); 031 } 032 return Stream.of(klass.getConstructors()); 033 } 034 035 public static Stream<Method> getFunctions(Class<?> klass) { 036 return getMethods(klass).filter(Extractors::isFunction); 037 } 038 039 public static Stream<Method> getMacros(Class<?> klass) { 040 return getMethods(klass).filter(Extractors::isMacro); 041 } 042 043 public static Stream<Method> getMethods(Class<?> klass) { 044 if (klass == null) { 045 return Stream.empty(); 046 } 047 return Stream.concat( 048 Stream.of(klass.getDeclaredMethods()), 049 Stream.of(klass.getMethods())) 050 .distinct() 051 .sorted((m1, m2) -> { 052 if (m1.isVarArgs() && !m2.isVarArgs()) { 053 return 1; 054 } 055 if (m2.isVarArgs() && !m1.isVarArgs()) { 056 return -1; 057 } 058 return compareTypes(m1.getParameterTypes(), m2.getParameterTypes()); 059 }); 060 } 061 062 public static Stream<Field> getFields(Class<?> klass) { 063 if (klass == null) { 064 return Stream.empty(); 065 } 066 return Stream.concat( 067 Stream.of(klass.getDeclaredFields()), 068 Stream.of(klass.getFields())) 069 .distinct(); 070 } 071 072 public static Stream<String> getImportedNames(Class<?> klass) { 073 if (klass == null) { 074 return Stream.empty(); 075 } 076 return Stream.of(Module.imports(klass)); 077 } 078 079 public static Stream<Member> getMembers(Class<?> klass) { 080 if (klass == null) { 081 return Stream.empty(); 082 } 083 return Stream.concat(getMethods(klass), getFields(klass)); 084 } 085 086 public static boolean isPublic(Member m) { 087 return Modifier.isPublic(m.getModifiers()); 088 } 089 090 public static boolean isStatic(Member m) { 091 return Modifier.isStatic(m.getModifiers()); 092 } 093 094 public static boolean isConcrete(Member m) { 095 return !Modifier.isAbstract(m.getModifiers()); 096 } 097 098 public static boolean isFunction(Method m) { 099 return isConcrete(m) && isPublic(m) && isStatic(m) && !m.isAnnotationPresent(Macro.class); 100 } 101 102 public static boolean isMacro(Method m) { 103 return isConcrete(m) && isPublic(m) && isStatic(m) && m.isAnnotationPresent(Macro.class); 104 } 105 106 public static Predicate<Member> isNamed(String name) { 107 return m -> m.getName().equals(name); 108 } 109 110 public static Predicate<Method> matchFunctionReference(String name, int arity, boolean varargs) { 111 return m -> 112 m.getName().equals(name) 113 && (isMethodDecorated(m) || argumentsNumberMatches(m.getParameterCount(), arity, varargs)) 114 && (arity < 0 || m.isVarArgs() == varargs); 115 } 116 117 public static <T extends AnnotatedElement & Member> T checkDeprecation(Class<?> caller, T object) { 118 if (object.isAnnotationPresent(Deprecated.class)) { 119 Warnings.deprecatedElement( 120 (object instanceof Executable ? ((Executable) object).toGenericString() 121 : object instanceof Field ? ((Field) object).toGenericString() 122 : object.getName()), 123 caller.getName()); 124 } 125 return object; 126 } 127 128}