static { getExtendsClause = getMethod(JCClassDecl.class, "getExtendsClause", new Class<?>[0]); getExtendsClause.setAccessible(true); if (getJavaCompilerVersion() < 8) { getEndPosition = getMethod(DiagnosticPosition.class, "getEndPosition", java.util.Map.class); storeEnd = getMethod(java.util.Map.class, "put", Object.class, Object.class); } else { getEndPosition = getMethod( DiagnosticPosition.class, "getEndPosition", "com.sun.tools.javac.tree.EndPosTable"); Method storeEndMethodTemp; Class<?> endPosTable; try { endPosTable = Class.forName("com.sun.tools.javac.tree.EndPosTable"); } catch (ClassNotFoundException ex) { throw sneakyThrow(ex); } try { storeEndMethodTemp = endPosTable.getMethod("storeEnd", JCTree.class, int.class); } catch (NoSuchMethodException e) { try { endPosTable = Class.forName("com.sun.tools.javac.parser.JavacParser$AbstractEndPosTable"); storeEndMethodTemp = endPosTable.getDeclaredMethod("storeEnd", JCTree.class, int.class); } catch (NoSuchMethodException ex) { throw sneakyThrow(ex); } catch (ClassNotFoundException ex) { throw sneakyThrow(ex); } } storeEnd = storeEndMethodTemp; } getEndPosition.setAccessible(true); storeEnd.setAccessible(true); }
private static Method getMethod(Class<?> clazz, String name, String... paramTypes) { try { Class<?>[] c = new Class[paramTypes.length]; for (int i = 0; i < paramTypes.length; i++) c[i] = Class.forName(paramTypes[i]); return clazz.getMethod(name, c); } catch (NoSuchMethodException e) { throw sneakyThrow(e); } catch (ClassNotFoundException e) { throw sneakyThrow(e); } }
private static Method getMethod(Class<?> clazz, String name, Class<?>... paramTypes) { try { return clazz.getMethod(name, paramTypes); } catch (NoSuchMethodException e) { throw sneakyThrow(e); } }
/** * Removes the annotation from javac's AST (it remains in lombok's AST), then removes any import * statement that imports this exact annotation (not star imports). Only does this if the * DeleteLombokAnnotations class is in the context. */ public static void deleteAnnotationIfNeccessary( JavacNode annotation, Class<? extends Annotation> annotationType) { if (inNetbeansEditor(annotation)) return; if (!annotation.shouldDeleteLombokAnnotations()) return; JavacNode parentNode = annotation.directUp(); switch (parentNode.getKind()) { case FIELD: case ARGUMENT: case LOCAL: JCVariableDecl variable = (JCVariableDecl) parentNode.get(); variable.mods.annotations = filterList(variable.mods.annotations, annotation.get()); break; case METHOD: JCMethodDecl method = (JCMethodDecl) parentNode.get(); method.mods.annotations = filterList(method.mods.annotations, annotation.get()); break; case TYPE: try { JCClassDecl type = (JCClassDecl) parentNode.get(); type.mods.annotations = filterList(type.mods.annotations, annotation.get()); } catch (ClassCastException e) { // something rather odd has been annotated. Better to just break only delombok instead of // everything. } break; default: // This really shouldn't happen, but if it does, better just break delombok instead of // breaking everything. return; } parentNode.getAst().setChanged(); deleteImportFromCompilationUnit(annotation, annotationType.getName()); }
@SuppressWarnings("unchecked") private <T> T readObject(JCTree tree, String fieldName, T defaultValue) { Class<?> tClass = tree.getClass(); Map<String, Field> c = reflectionCache.get(tClass); if (c == null) reflectionCache.put(tClass, c = new HashMap<String, Field>()); Field f = c.get(fieldName); if (f == null) { try { f = tClass.getDeclaredField(fieldName); } catch (Exception e) { return defaultValue; } f.setAccessible(true); c.put(fieldName, f); } try { return (T) f.get(tree); } catch (Exception e) { return defaultValue; } }
/** * Creates an instance of {@code AnnotationValues} for the provided AST Node. * * @param type An annotation class type, such as {@code lombok.Getter.class}. * @param node A Lombok AST node representing an annotation in source code. */ public static <A extends Annotation> AnnotationValues<A> createAnnotation( Class<A> type, final JavacNode node) { Map<String, AnnotationValue> values = new HashMap<String, AnnotationValue>(); JCAnnotation anno = (JCAnnotation) node.get(); List<JCExpression> arguments = anno.getArguments(); for (Method m : type.getDeclaredMethods()) { if (!Modifier.isPublic(m.getModifiers())) continue; String name = m.getName(); java.util.List<String> raws = new ArrayList<String>(); java.util.List<Object> guesses = new ArrayList<Object>(); java.util.List<Object> expressions = new ArrayList<Object>(); final java.util.List<DiagnosticPosition> positions = new ArrayList<DiagnosticPosition>(); boolean isExplicit = false; for (JCExpression arg : arguments) { String mName; JCExpression rhs; if (arg instanceof JCAssign) { JCAssign assign = (JCAssign) arg; mName = assign.lhs.toString(); rhs = assign.rhs; } else { rhs = arg; mName = "value"; } if (!mName.equals(name)) continue; isExplicit = true; if (rhs instanceof JCNewArray) { List<JCExpression> elems = ((JCNewArray) rhs).elems; for (JCExpression inner : elems) { raws.add(inner.toString()); expressions.add(inner); guesses.add(calculateGuess(inner)); positions.add(inner.pos()); } } else { raws.add(rhs.toString()); expressions.add(rhs); guesses.add(calculateGuess(rhs)); positions.add(rhs.pos()); } } values.put( name, new AnnotationValue(node, raws, expressions, guesses, isExplicit) { @Override public void setError(String message, int valueIdx) { if (valueIdx < 0) node.addError(message); else node.addError(message, positions.get(valueIdx)); } @Override public void setWarning(String message, int valueIdx) { if (valueIdx < 0) node.addWarning(message); else node.addWarning(message, positions.get(valueIdx)); } }); } return new AnnotationValues<A>(type, values, node); }
/** * Checks if the given TypeReference node is likely to be a reference to the provided class. * * @param type An actual type. This method checks if {@code typeNode} is likely to be a reference * to this type. * @param node A Lombok AST node. Any node in the appropriate compilation unit will do (used to * get access to import statements). * @param typeNode A type reference to check. */ public static boolean typeMatches(Class<?> type, JavacNode node, JCTree typeNode) { String typeName = typeNode.toString(); TypeResolver resolver = new TypeResolver(node.getImportList()); return resolver.typeMatches(node, type.getName(), typeName); }