diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/lombok/core/AnnotationValues.java | 39 | ||||
-rw-r--r-- | src/core/lombok/eclipse/Eclipse.java | 32 | ||||
-rw-r--r-- | src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java | 60 | ||||
-rw-r--r-- | src/core/lombok/eclipse/handlers/HandleLog.java | 284 | ||||
-rw-r--r-- | src/core/lombok/eclipse/handlers/HandleSynchronized.java | 2 | ||||
-rw-r--r-- | src/core/lombok/extern/apachecommons/Log.java | 75 | ||||
-rw-r--r-- | src/core/lombok/extern/jul/Log.java | 75 | ||||
-rw-r--r-- | src/core/lombok/extern/log4j/Log.java | 75 | ||||
-rw-r--r-- | src/core/lombok/extern/slf4j/Log.java | 74 | ||||
-rw-r--r-- | src/core/lombok/javac/Javac.java | 5 | ||||
-rw-r--r-- | src/core/lombok/javac/handlers/HandleLog.java | 203 | ||||
-rw-r--r-- | src/core/lombok/javac/handlers/HandleSynchronized.java | 2 | ||||
-rw-r--r-- | src/core/lombok/javac/handlers/JavacHandlerUtil.java | 30 | ||||
-rw-r--r-- | src/delombok/lombok/delombok/PrettyCommentsPrinter.java | 22 |
14 files changed, 938 insertions, 40 deletions
diff --git a/src/core/lombok/core/AnnotationValues.java b/src/core/lombok/core/AnnotationValues.java index db4c6d09..6cecedc7 100644 --- a/src/core/lombok/core/AnnotationValues.java +++ b/src/core/lombok/core/AnnotationValues.java @@ -53,29 +53,20 @@ public class AnnotationValues<A extends Annotation> { /** Guesses for each raw expression. If the raw expression is a literal expression, the guess will * likely be right. If not, it'll be wrong. */ public final List<Object> valueGuesses; + + /** A list of the actual expressions. List is size 1 unless an array is provided. */ + public final List<Object> expressions; + private final LombokNode<?, ?, ?> node; private final boolean isExplicit; /** - * 'raw' should be the exact expression, for example '5+7', 'AccessLevel.PUBLIC', or 'int.class'. - * 'valueGuess' should be a likely guess at the real value intended. - * - * For classes, supply the class name (qualified or not) as a string.<br /> - * For enums, supply the simple name part (everything after the last dot) as a string.<br /> - */ - public AnnotationValue(LombokNode<?, ?, ?> node, String raw, Object valueGuess, boolean isExplicit) { - this.node = node; - this.raws = Collections.singletonList(raw); - this.valueGuesses = Collections.singletonList(valueGuess); - this.isExplicit = isExplicit; - } - - /** * Like the other constructor, but used for when the annotation method is initialized with an array value. */ - public AnnotationValue(LombokNode<?, ?, ?> node, List<String> raws, List<Object> valueGuesses, boolean isExplicit) { + public AnnotationValue(LombokNode<?, ?, ?> node, List<String> raws, List<Object> expressions, List<Object> valueGuesses, boolean isExplicit) { this.node = node; this.raws = raws; + this.expressions = expressions; this.valueGuesses = valueGuesses; this.isExplicit = isExplicit; } @@ -310,6 +301,14 @@ public class AnnotationValues<A extends Annotation> { return v == null ? Collections.<String>emptyList() : v.raws; } + /** + * Returns the actual expressions used for the provided {@code annotationMethodName}. + */ + public List<Object> getActualExpressions(String annotationMethodName) { + AnnotationValue v = values.get(annotationMethodName); + return v == null ? Collections.<Object>emptyList() : v.expressions; + } + public boolean isExplicit(String annotationMethodName) { AnnotationValue annotationValue = values.get(annotationMethodName); return annotationValue != null && annotationValue.isExplicit(); @@ -325,6 +324,16 @@ public class AnnotationValues<A extends Annotation> { return l.isEmpty() ? null : l.get(0); } + /** + * Convenience method to return the first result in a {@link #getActualExpressions(String)} call. + * + * You should use this method if the annotation method is not an array type. + */ + public Object getActualExpression(String annotationMethodName) { + List<Object> l = getActualExpressions(annotationMethodName); + return l.isEmpty() ? null : l.get(0); + } + /** Generates an error message on the stated annotation value (you should only call this method if you know it's there!) */ public void setError(String annotationMethodName, String message) { setError(annotationMethodName, message, -1); diff --git a/src/core/lombok/eclipse/Eclipse.java b/src/core/lombok/eclipse/Eclipse.java index ac8505af..c4632fba 100644 --- a/src/core/lombok/eclipse/Eclipse.java +++ b/src/core/lombok/eclipse/Eclipse.java @@ -30,6 +30,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.WeakHashMap; import lombok.core.AnnotationValues; import lombok.core.TypeLibrary; @@ -515,6 +516,7 @@ public class Eclipse { if (!Modifier.isPublic(m.getModifiers())) continue; String name = m.getName(); List<String> raws = new ArrayList<String>(); + List<Object> expressionValues = new ArrayList<Object>(); List<Object> guesses = new ArrayList<Object>(); Expression fullExpression = null; Expression[] expressions = null; @@ -535,6 +537,7 @@ public class Eclipse { StringBuffer sb = new StringBuffer(); ex.print(0, sb); raws.add(sb.toString()); + expressionValues.add(ex); guesses.add(calculateValue(ex)); } } @@ -542,7 +545,7 @@ public class Eclipse { final Expression fullExpr = fullExpression; final Expression[] exprs = expressions; - values.put(name, new AnnotationValue(annotationNode, raws, guesses, isExplicit) { + values.put(name, new AnnotationValue(annotationNode, raws, expressionValues, guesses, isExplicit) { @Override public void setError(String message, int valueIdx) { Expression ex; if (valueIdx == -1) ex = fullExpr; @@ -612,12 +615,16 @@ public class Eclipse { } } + private static Map<ASTNode, ASTNode> generatedNodes = new WeakHashMap<ASTNode, ASTNode>(); + public static ASTNode getGeneratedBy(ASTNode node) { - try { - return (ASTNode) generatedByField.get(node); - } catch (Exception t) { - //ignore - no $generatedBy exists when running in ecj. - return null; + if (generatedByField != null) { + try { + return (ASTNode) generatedByField.get(node); + } catch (Exception e) {} + } + synchronized (generatedNodes) { + return generatedNodes.get(node); } } @@ -626,12 +633,15 @@ public class Eclipse { } public static ASTNode setGeneratedBy(ASTNode node, ASTNode source) { - try { - generatedByField.set(node, source); - } catch (Exception t) { - //ignore - no $generatedBy exists when running in ecj. + if (generatedByField != null) { + try { + generatedByField.set(node, source); + return node; + } catch (Exception e) {} + } + synchronized (generatedNodes) { + generatedNodes.put(node, source); } - return node; } } diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index 5005752b..019ae637 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -23,6 +23,7 @@ package lombok.eclipse.handlers; import static lombok.eclipse.Eclipse.*; +import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -42,6 +43,7 @@ import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration; import org.eclipse.jdt.internal.compiler.ast.AllocationExpression; import org.eclipse.jdt.internal.compiler.ast.Annotation; +import org.eclipse.jdt.internal.compiler.ast.Clinit; import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; import org.eclipse.jdt.internal.compiler.ast.EqualExpression; import org.eclipse.jdt.internal.compiler.ast.Expression; @@ -406,9 +408,17 @@ public class EclipseHandlerUtil { /** * Inserts a field into an existing type. The type must represent a {@code TypeDeclaration}. + * The field carries the @{@link SuppressWarnings}("all") annotation. */ - public static void injectField(EclipseNode type, FieldDeclaration field) { + public static void injectFieldSuppressWarnings(EclipseNode type, FieldDeclaration field) { field.annotations = createSuppressWarningsAll(field, field.annotations); + injectField(type, field); + } + + /** + * Inserts a field into an existing type. The type must represent a {@code TypeDeclaration}. + */ + public static void injectField(EclipseNode type, FieldDeclaration field) { TypeDeclaration parent = (TypeDeclaration) type.get(); if (parent.fields == null) { @@ -421,9 +431,24 @@ public class EclipseHandlerUtil { parent.fields = newArray; } + if ((field.modifiers & Modifier.STATIC) != 0) { + if (!hasClinit(parent)) { + parent.addClinit(); + } + } + type.add(field, Kind.FIELD).recursiveSetHandled(); } + private static boolean hasClinit(TypeDeclaration parent) { + if (parent.methods == null) return false; + + for (AbstractMethodDeclaration method : parent.methods) { + if (method instanceof Clinit) return true; + } + return false; + } + /** * Inserts a method into an existing type. The type must represent a {@code TypeDeclaration}. */ @@ -435,25 +460,42 @@ public class EclipseHandlerUtil { parent.methods = new AbstractMethodDeclaration[1]; parent.methods[0] = method; } else { - boolean injectionComplete = false; if (method instanceof ConstructorDeclaration) { for (int i = 0 ; i < parent.methods.length ; i++) { if (parent.methods[i] instanceof ConstructorDeclaration && (parent.methods[i].bits & ASTNode.IsDefaultConstructor) != 0) { EclipseNode tossMe = type.getNodeFor(parent.methods[i]); - parent.methods[i] = method; + + AbstractMethodDeclaration[] withoutGeneratedConstructor = new AbstractMethodDeclaration[parent.methods.length - 1]; + + System.arraycopy(parent.methods, 0, withoutGeneratedConstructor, 0, i); + System.arraycopy(parent.methods, i + 1, withoutGeneratedConstructor, i, parent.methods.length - i - 1); + + parent.methods = withoutGeneratedConstructor; if (tossMe != null) tossMe.up().removeChild(tossMe); - injectionComplete = true; break; } } } - if (!injectionComplete) { - AbstractMethodDeclaration[] newArray = new AbstractMethodDeclaration[parent.methods.length + 1]; - System.arraycopy(parent.methods, 0, newArray, 0, parent.methods.length); - newArray[parent.methods.length] = method; - parent.methods = newArray; + int insertionPoint; + for (insertionPoint = 0; insertionPoint < parent.methods.length; insertionPoint++) { + AbstractMethodDeclaration current = parent.methods[insertionPoint]; + if (current instanceof Clinit) continue; + if (method instanceof ConstructorDeclaration) { + if (current instanceof ConstructorDeclaration) continue; + break; + } + if (Eclipse.isGenerated(current)) continue; + break; + } + AbstractMethodDeclaration[] newArray = new AbstractMethodDeclaration[parent.methods.length + 1]; + System.arraycopy(parent.methods, 0, newArray, 0, insertionPoint); + if (insertionPoint <= parent.methods.length) { + System.arraycopy(parent.methods, insertionPoint, newArray, insertionPoint + 1, parent.methods.length - insertionPoint); } + + newArray[insertionPoint] = method; + parent.methods = newArray; } type.add(method, Kind.METHOD).recursiveSetHandled(); diff --git a/src/core/lombok/eclipse/handlers/HandleLog.java b/src/core/lombok/eclipse/handlers/HandleLog.java new file mode 100644 index 00000000..736e6e43 --- /dev/null +++ b/src/core/lombok/eclipse/handlers/HandleLog.java @@ -0,0 +1,284 @@ +/* + * Copyright © 2009 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.eclipse.handlers; + +import static lombok.eclipse.Eclipse.fromQualifiedName; +import static lombok.eclipse.handlers.EclipseHandlerUtil.*; + +import java.lang.reflect.Modifier; +import java.util.Arrays; + +import lombok.core.AnnotationValues; +import lombok.eclipse.Eclipse; +import lombok.eclipse.EclipseAnnotationHandler; +import lombok.eclipse.EclipseNode; +import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult; + +import org.eclipse.jdt.internal.compiler.ast.Annotation; +import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess; +import org.eclipse.jdt.internal.compiler.ast.Expression; +import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; +import org.eclipse.jdt.internal.compiler.ast.MessageSend; +import org.eclipse.jdt.internal.compiler.ast.NameReference; +import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference; +import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; +import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.mangosdk.spi.ProviderFor; + +public class HandleLog { + + private HandleLog() { + throw new UnsupportedOperationException(); + } + + public static boolean processAnnotation(LoggingFramework framework, AnnotationValues<? extends java.lang.annotation.Annotation> annotation, Annotation source, EclipseNode annotationNode) { + Expression annotationValue = (Expression) annotation.getActualExpression("value"); + if (annotationValue != null && !(annotationValue instanceof ClassLiteralAccess)) { + return true; + } + ClassLiteralAccess loggingType = (ClassLiteralAccess)annotationValue; + + EclipseNode owner = annotationNode.up(); + switch (owner.getKind()) { + case TYPE: + TypeDeclaration typeDecl = null; + if (owner.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) owner.get(); + int modifiers = typeDecl == null ? 0 : typeDecl.modifiers; + + boolean notAClass = (modifiers & + (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation)) != 0; + + if (typeDecl == null || notAClass) { + annotationNode.addError("@Log is legal only on classes and enums."); + return false; + } + + if (fieldExists("log", owner) != MemberExistsResult.NOT_EXISTS) { + annotationNode.addWarning("Field 'log' already exists."); + return true; + } + + if (loggingType == null) { + loggingType = selfType(owner, source); + } + + injectField(owner, createField(framework, source, loggingType)); + owner.rebuild(); + return true; + default: + annotationNode.addError("@Log is legal only on types."); + return true; + } + } + + private static ClassLiteralAccess selfType(EclipseNode type, Annotation source) { + int pS = source.sourceStart, pE = source.sourceEnd; + long p = (long)pS << 32 | pE; + + TypeDeclaration typeDeclaration = (TypeDeclaration)type.get(); + TypeReference typeReference = new SingleTypeReference(typeDeclaration.name, p); + Eclipse.setGeneratedBy(typeReference, source); + + ClassLiteralAccess result = new ClassLiteralAccess(source.sourceEnd, typeReference); + Eclipse.setGeneratedBy(result, source); + + return result; + } + + private static FieldDeclaration createField(LoggingFramework framework, Annotation source, ClassLiteralAccess loggingType) { + int pS = source.sourceStart, pE = source.sourceEnd; + long p = (long)pS << 32 | pE; + + // private static final <loggerType> log = <factoryMethod>(<parameter>); + + FieldDeclaration fieldDecl = new FieldDeclaration("log".toCharArray(), 0, -1); + Eclipse.setGeneratedBy(fieldDecl, source); + fieldDecl.declarationSourceEnd = -1; + fieldDecl.modifiers = Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL; + + fieldDecl.type = createTypeReference(framework.getLoggerTypeName(), source); + + MessageSend factoryMethodCall = new MessageSend(); + Eclipse.setGeneratedBy(factoryMethodCall, source); + + factoryMethodCall.receiver = createNameReference(framework.getLoggerFactoryTypeName(), source); + factoryMethodCall.selector = framework.getLoggerFactoryMethodName().toCharArray(); + + Expression parameter = framework.createFactoryParameter(loggingType, source); + + factoryMethodCall.arguments = new Expression[] { parameter }; + factoryMethodCall.nameSourcePosition = p; + factoryMethodCall.sourceStart = pS; + factoryMethodCall.sourceEnd = factoryMethodCall.statementEnd = pE; + + fieldDecl.initialization = factoryMethodCall; + + return fieldDecl; + } + + private static TypeReference createTypeReference(String typeName, Annotation source) { + int pS = source.sourceStart, pE = source.sourceEnd; + long p = (long)pS << 32 | pE; + + TypeReference typeReference; + if (typeName.contains(".")) { + + char[][] typeNameTokens = fromQualifiedName(typeName); + long[] pos = new long[typeNameTokens.length]; + Arrays.fill(pos, p); + + typeReference = new QualifiedTypeReference(typeNameTokens, pos); + } + else { + typeReference = null; + } + + Eclipse.setGeneratedBy(typeReference, source); + return typeReference; + } + + private static NameReference createNameReference(String name, Annotation source) { + int pS = source.sourceStart, pE = source.sourceEnd; + long p = (long)pS << 32 | pE; + + char[][] nameTokens = fromQualifiedName(name); + long[] pos = new long[nameTokens.length]; + Arrays.fill(pos, p); + + QualifiedNameReference nameReference = new QualifiedNameReference(nameTokens, pos, pS, pE); + nameReference.statementEnd = pE; + + Eclipse.setGeneratedBy(nameReference, source); + return nameReference; + } + + /** + * Handles the {@link lombok.extern.apachecommons.Log} annotation for Eclipse. + */ + @ProviderFor(EclipseAnnotationHandler.class) + public static class HandleCommonsLog implements EclipseAnnotationHandler<lombok.extern.apachecommons.Log> { + @Override public boolean handle(AnnotationValues<lombok.extern.apachecommons.Log> annotation, Annotation source, EclipseNode annotationNode) { + return processAnnotation(LoggingFramework.COMMONS, annotation, source, annotationNode); + } + } + + /** + * Handles the {@link lombok.extern.jul.Log} annotation for Eclipse. + */ + @ProviderFor(EclipseAnnotationHandler.class) + public static class HandleJulLog implements EclipseAnnotationHandler<lombok.extern.jul.Log> { + @Override public boolean handle(AnnotationValues<lombok.extern.jul.Log> annotation, Annotation source, EclipseNode annotationNode) { + return processAnnotation(LoggingFramework.JUL, annotation, source, annotationNode); + } + } + + /** + * Handles the {@link lombok.extern.log4j.Log} annotation for Eclipse. + */ + @ProviderFor(EclipseAnnotationHandler.class) + public static class HandleLog4jLog implements EclipseAnnotationHandler<lombok.extern.log4j.Log> { + @Override public boolean handle(AnnotationValues<lombok.extern.log4j.Log> annotation, Annotation source, EclipseNode annotationNode) { + return processAnnotation(LoggingFramework.LOG4J, annotation, source, annotationNode); + } + } + + /** + * Handles the {@link lombok.extern.slf4j.Log} annotation for Eclipse. + */ + @ProviderFor(EclipseAnnotationHandler.class) + public static class HandleSlf4jLog implements EclipseAnnotationHandler<lombok.extern.slf4j.Log> { + @Override public boolean handle(AnnotationValues<lombok.extern.slf4j.Log> annotation, Annotation source, EclipseNode annotationNode) { + return processAnnotation(LoggingFramework.SLF4J, annotation, source, annotationNode); + } + } + + enum LoggingFramework { + // private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(TargetType.class); + COMMONS(lombok.extern.jul.Log.class, "org.apache.commons.logging.Log", "org.apache.commons.logging.LogFactory", "getLog"), + + // private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(TargetType.class.getName()); + JUL(lombok.extern.jul.Log.class, "java.util.logging.Logger", "java.util.logging.Logger", "getLogger") { + @Override public Expression createFactoryParameter(ClassLiteralAccess type, Annotation source) { + int pS = source.sourceStart, pE = source.sourceEnd; + long p = (long)pS << 32 | pE; + + MessageSend factoryParameterCall = new MessageSend(); + Eclipse.setGeneratedBy(factoryParameterCall, source); + + factoryParameterCall.receiver = super.createFactoryParameter(type, source); + factoryParameterCall.selector = "getName".toCharArray(); + + factoryParameterCall.nameSourcePosition = p; + factoryParameterCall.sourceStart = pS; + factoryParameterCall.sourceEnd = factoryParameterCall.statementEnd = pE; + + return factoryParameterCall; + } + }, + + // private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(TargetType.class); + LOG4J(lombok.extern.jul.Log.class, "org.apache.log4j.Logger", "org.apache.log4j.Logger", "getLogger"), + + // private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TargetType.class); + SLF4J(lombok.extern.slf4j.Log.class, "org.slf4j.Logger", "org.slf4j.LoggerFactory", "getLogger"), + + ; + + private final Class<? extends java.lang.annotation.Annotation> annotationClass; + private final String loggerTypeName; + private final String loggerFactoryTypeName; + private final String loggerFactoryMethodName; + + LoggingFramework(Class<? extends java.lang.annotation.Annotation> annotationClass, String loggerTypeName, String loggerFactoryTypeName, String loggerFactoryMethodName) { + this.annotationClass = annotationClass; + this.loggerTypeName = loggerTypeName; + this.loggerFactoryTypeName = loggerFactoryTypeName; + this.loggerFactoryMethodName = loggerFactoryMethodName; + } + + final Class<? extends java.lang.annotation.Annotation> getAnnotationClass() { + return annotationClass; + } + + final String getLoggerTypeName() { + return loggerTypeName; + } + + final String getLoggerFactoryTypeName() { + return loggerFactoryTypeName; + } + + final String getLoggerFactoryMethodName() { + return loggerFactoryMethodName; + } + + Expression createFactoryParameter(ClassLiteralAccess loggingType, Annotation source){ + TypeReference copy = Eclipse.copyType(loggingType.type, source); + ClassLiteralAccess result = new ClassLiteralAccess(source.sourceEnd, copy); + Eclipse.setGeneratedBy(result, source); + return result; + }; + } +} diff --git a/src/core/lombok/eclipse/handlers/HandleSynchronized.java b/src/core/lombok/eclipse/handlers/HandleSynchronized.java index fde36192..b77099b5 100644 --- a/src/core/lombok/eclipse/handlers/HandleSynchronized.java +++ b/src/core/lombok/eclipse/handlers/HandleSynchronized.java @@ -101,7 +101,7 @@ public class HandleSynchronized implements EclipseAnnotationHandler<Synchronized fieldDecl.type = new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, new long[] { 0, 0, 0 }); Eclipse.setGeneratedBy(fieldDecl.type, source); fieldDecl.initialization = arrayAlloc; - injectField(annotationNode.up().up(), fieldDecl); + injectFieldSuppressWarnings(annotationNode.up().up(), fieldDecl); } if (method.statements == null) return false; diff --git a/src/core/lombok/extern/apachecommons/Log.java b/src/core/lombok/extern/apachecommons/Log.java new file mode 100644 index 00000000..4c82a2a7 --- /dev/null +++ b/src/core/lombok/extern/apachecommons/Log.java @@ -0,0 +1,75 @@ +/* + * Copyright © 2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.extern.apachecommons; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Causes lombok to generate a logger field. + * Example: + * <pre> + * @Log + * public class LogExample { + * } + * </pre> + * + * will generate: + * + * <pre> + * public class LogExample { + * private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class); + * } + * </pre> + * + * If you do not want to use the annotated class as the logger parameter, you can specify an alternate class. + * Example: + * <pre> + * @Log(java.util.List.class) + * public class LogExample { + * } + * </pre> + * + * will generate: + * + * <pre> + * public class LogExample { + * private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(java.util.List.class); + * } + * </pre> + * + * This annotation is valid for classes and enumerations.<br /> + * + * @see lombok.extern.jul.Log lombok.extern.jul.Log + * @see lombok.extern.log4j.Log lombok.extern.log4j.Log + * @see lombok.extern.slf4j.Log lombok.extern.slf4j.Log + */ +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.TYPE) +public @interface Log { + /** + * If you do not want to use the annotated class as the logger parameter, you can specify an alternate class here. + */ + Class<?> value() default void.class; +}
\ No newline at end of file diff --git a/src/core/lombok/extern/jul/Log.java b/src/core/lombok/extern/jul/Log.java new file mode 100644 index 00000000..a66db671 --- /dev/null +++ b/src/core/lombok/extern/jul/Log.java @@ -0,0 +1,75 @@ +/* + * Copyright © 2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.extern.jul; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Causes lombok to generate a logger field. + * Example: + * <pre> + * @Log + * public class LogExample { + * } + * </pre> + * + * will generate: + * + * <pre> + * public class LogExample { + * private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName()); + * } + * </pre> + * + * If you do not want to use the annotated class as the logger parameter, you can specify an alternate class. + * Example: + * <pre> + * @Log(java.util.List.class) + * public class LogExample { + * } + * </pre> + * + * will generate: + * + * <pre> + * public class LogExample { + * private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(java.util.List.class.getName()); + * } + * </pre> + * + * This annotation is valid for classes and enumerations.<br /> + * + * @see lombok.extern.apachecommons.Log lombok.extern.apachecommons.Log + * @see lombok.extern.log4j.Log lombok.extern.log4j.Log + * @see lombok.extern.slf4j.Log lombok.extern.slf4j.Log + */ +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.TYPE) +public @interface Log { + /** + * If you do not want to use the annotated class as the logger parameter, you can specify an alternate class here. + */ + Class<?> value() default void.class; +}
\ No newline at end of file diff --git a/src/core/lombok/extern/log4j/Log.java b/src/core/lombok/extern/log4j/Log.java new file mode 100644 index 00000000..151b5e98 --- /dev/null +++ b/src/core/lombok/extern/log4j/Log.java @@ -0,0 +1,75 @@ +/* + * Copyright © 2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.extern.log4j; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Causes lombok to generate a logger field. + * Example: + * <pre> + * @Log + * public class LogExample { + * } + * </pre> + * + * will generate: + * + * <pre> + * public class LogExample { + * private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class); + * } + * </pre> + * + * If you do not want to use the annotated class as the logger parameter, you can specify an alternate class. + * Example: + * <pre> + * @Log(java.util.List.class) + * public class LogExample { + * } + * </pre> + * + * will generate: + * + * <pre> + * public class LogExample { + * private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(java.util.List.class); + * } + * </pre> + * + * This annotation is valid for classes and enumerations.<br /> + * + * @see lombok.extern.apachecommons.Log lombok.extern.apachecommons.Log + * @see lombok.extern.jul.Log lombok.extern.jul.Log + * @see lombok.extern.slf4j.Log lombok.extern.slf4j.Log + */ +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.TYPE) +public @interface Log { + /** + * If you do not want to use the annotated class as the logger parameter, you can specify an alternate class here. + */ + Class<?> value() default void.class; +}
\ No newline at end of file diff --git a/src/core/lombok/extern/slf4j/Log.java b/src/core/lombok/extern/slf4j/Log.java new file mode 100644 index 00000000..5431847a --- /dev/null +++ b/src/core/lombok/extern/slf4j/Log.java @@ -0,0 +1,74 @@ +/* + * Copyright © 2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.extern.slf4j; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +/** + * Causes lombok to generate a logger field. + * Example: + * <pre> + * @Log + * public class LogExample { + * } + * </pre> + * + * will generate: + * + * <pre> + * public class LogExample { + * private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class); + * } + * </pre> + * + * If you do not want to use the annotated class as the logger parameter, you can specify an alternate class. + * Example: + * <pre> + * @Log(java.util.List.class) + * public class LogExample { + * } + * </pre> + * + * will generate: + * + * <pre> + * public class LogExample { + * private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(java.util.List.class); + * } + * </pre> + * + * This annotation is valid for classes and enumerations.<br /> + * + * @see lombok.extern.apachecommons.Log lombok.extern.apachecommons.Log + * @see lombok.extern.jul.Log lombok.extern.jul.Log + * @see lombok.extern.log4j.Log lombok.extern.log4j.Log + */ +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.TYPE) +public @interface Log { + /** + * If you do not want to use the annotated class as the logger parameter, you can specify an alternate class here. + */ + Class<?> value() default void.class; +} diff --git a/src/core/lombok/javac/Javac.java b/src/core/lombok/javac/Javac.java index 58a24207..6d9800ab 100644 --- a/src/core/lombok/javac/Javac.java +++ b/src/core/lombok/javac/Javac.java @@ -90,6 +90,7 @@ public class Javac { String name = m.getName(); List<String> raws = new ArrayList<String>(); List<Object> guesses = new ArrayList<Object>(); + List<Object> expressions = new ArrayList<Object>(); final List<DiagnosticPosition> positions = new ArrayList<DiagnosticPosition>(); boolean isExplicit = false; @@ -112,17 +113,19 @@ public class Javac { 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, guesses, isExplicit) { + 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)); diff --git a/src/core/lombok/javac/handlers/HandleLog.java b/src/core/lombok/javac/handlers/HandleLog.java new file mode 100644 index 00000000..03e40d7f --- /dev/null +++ b/src/core/lombok/javac/handlers/HandleLog.java @@ -0,0 +1,203 @@ +/* + * Copyright © 2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.javac.handlers; + +import static lombok.javac.handlers.JavacHandlerUtil.*; + +import java.lang.annotation.Annotation; + +import lombok.core.AnnotationValues; +import lombok.javac.JavacAnnotationHandler; +import lombok.javac.JavacNode; +import lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult; + +import org.mangosdk.spi.ProviderFor; + +import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.tree.TreeMaker; +import com.sun.tools.javac.tree.JCTree.JCAnnotation; +import com.sun.tools.javac.tree.JCTree.JCClassDecl; +import com.sun.tools.javac.tree.JCTree.JCExpression; +import com.sun.tools.javac.tree.JCTree.JCFieldAccess; +import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; +import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.Name; + +public class HandleLog { + + private HandleLog() { + throw new UnsupportedOperationException(); + } + + public static boolean processAnnotation(LoggingFramework framework, AnnotationValues<?> annotation, JavacNode annotationNode) { + markAnnotationAsProcessed(annotationNode, framework.getAnnotationClass()); + +// String loggingClassName = annotation.getRawExpression("value"); +// if (loggingClassName == null) loggingClassName = "void"; +// if (loggingClassName.endsWith(".class")) loggingClassName = loggingClassName.substring(0, loggingClassName.length() - 6); + + JCExpression annotationValue = (JCExpression) annotation.getActualExpression("value"); + JCFieldAccess loggingType = null; + if (annotationValue != null) { + if (!(annotationValue instanceof JCFieldAccess)) return true; + loggingType = (JCFieldAccess) annotationValue; + if (!loggingType.name.contentEquals("class")) return true; + } + + + JavacNode typeNode = annotationNode.up(); + switch (typeNode.getKind()) { + case TYPE: + if ((((JCClassDecl)typeNode.get()).mods.flags & Flags.INTERFACE)!= 0) { + annotationNode.addError("@Log is legal only on classes and enums."); + return true; + } + + if (fieldExists("log", typeNode)!= MemberExistsResult.NOT_EXISTS) { + annotationNode.addWarning("Field 'log' already exists."); + return true; + } + + if (loggingType == null) { + loggingType = selfType(typeNode); + } + createField(framework, typeNode, loggingType); + return true; + default: + annotationNode.addError("@Log is legal only on types."); + return true; + } + } + + private static JCFieldAccess selfType(JavacNode typeNode) { + TreeMaker maker = typeNode.getTreeMaker(); + Name name = ((JCClassDecl) typeNode.get()).name; + return maker.Select(maker.Ident(name), typeNode.toName("class")); + } + + private static boolean createField(LoggingFramework framework, JavacNode typeNode, JCFieldAccess loggingType) { + TreeMaker maker = typeNode.getTreeMaker(); + + // private static final <loggerType> log = <factoryMethod>(<parameter>); + JCExpression loggerType = chainDotsString(maker, typeNode, framework.getLoggerTypeName()); + JCExpression factoryMethod = chainDotsString(maker, typeNode, framework.getLoggerFactoryMethodName()); + + JCExpression loggerName = framework.createFactoryParameter(typeNode, loggingType); + JCMethodInvocation factoryMethodCall = maker.Apply(List.<JCExpression>nil(), factoryMethod, List.<JCExpression>of(loggerName)); + + JCVariableDecl fieldDecl = maker.VarDef( + maker.Modifiers(Flags.PRIVATE | Flags.FINAL | Flags.STATIC), + typeNode.toName("log"), loggerType, factoryMethodCall); + + injectField(typeNode, fieldDecl); + return true; + } + + /** + * Handles the {@link lombok.extern.apachecommons.Log} annotation for javac. + */ + @ProviderFor(JavacAnnotationHandler.class) + public static class HandleCommonsLog implements JavacAnnotationHandler<lombok.extern.apachecommons.Log> { + @Override public boolean handle(AnnotationValues<lombok.extern.apachecommons.Log> annotation, JCAnnotation ast, JavacNode annotationNode) { + return processAnnotation(LoggingFramework.COMMONS, annotation, annotationNode); + } + } + + /** + * Handles the {@link lombok.extern.jul.Log} annotation for javac. + */ + @ProviderFor(JavacAnnotationHandler.class) + public static class HandleJulLog implements JavacAnnotationHandler<lombok.extern.jul.Log> { + @Override public boolean handle(AnnotationValues<lombok.extern.jul.Log> annotation, JCAnnotation ast, JavacNode annotationNode) { + return processAnnotation(LoggingFramework.JUL, annotation, annotationNode); + } + } + + /** + * Handles the {@link lombok.extern.log4j.Log} annotation for javac. + */ + @ProviderFor(JavacAnnotationHandler.class) + public static class HandleLog4jLog implements JavacAnnotationHandler<lombok.extern.log4j.Log> { + @Override public boolean handle(AnnotationValues<lombok.extern.log4j.Log> annotation, JCAnnotation ast, JavacNode annotationNode) { + return processAnnotation(LoggingFramework.LOG4J, annotation, annotationNode); + } + } + + /** + * Handles the {@link lombok.extern.slf4j.Log} annotation for javac. + */ + @ProviderFor(JavacAnnotationHandler.class) + public static class HandleSlf4jLog implements JavacAnnotationHandler<lombok.extern.slf4j.Log> { + @Override public boolean handle(AnnotationValues<lombok.extern.slf4j.Log> annotation, JCAnnotation ast, JavacNode annotationNode) { + return processAnnotation(LoggingFramework.SLF4J, annotation, annotationNode); + } + } + + enum LoggingFramework { + // private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(TargetType.class); + COMMONS(lombok.extern.jul.Log.class, "org.apache.commons.logging.Log", "org.apache.commons.logging.LogFactory.getLog"), + + // private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(TargetType.class.getName()); + JUL(lombok.extern.jul.Log.class, "java.util.logging.Logger", "java.util.logging.Logger.getLogger") { + @Override public JCExpression createFactoryParameter(JavacNode typeNode, JCFieldAccess loggingType) { + TreeMaker maker = typeNode.getTreeMaker(); + JCExpression method = maker.Select(loggingType, typeNode.toName("getName")); + return maker.Apply(List.<JCExpression>nil(), method, List.<JCExpression>nil()); + } + }, + + // private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(TargetType.class); + LOG4J(lombok.extern.jul.Log.class, "org.apache.log4j.Logger", "org.apache.log4j.Logger.getLogger"), + + // private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TargetType.class); + SLF4J(lombok.extern.slf4j.Log.class, "org.slf4j.Logger", "org.slf4j.LoggerFactory.getLogger"), + + ; + + private final Class<? extends Annotation> annotationClass; + private final String loggerTypeName; + private final String loggerFactoryName; + + LoggingFramework(Class<? extends Annotation> annotationClass, String loggerTypeName, String loggerFactoryName) { + this.annotationClass = annotationClass; + this.loggerTypeName = loggerTypeName; + this.loggerFactoryName = loggerFactoryName; + } + + final Class<? extends Annotation> getAnnotationClass() { + return annotationClass; + } + + final String getLoggerTypeName() { + return loggerTypeName; + } + + final String getLoggerFactoryMethodName() { + return loggerFactoryName; + } + + JCExpression createFactoryParameter(JavacNode typeNode, JCFieldAccess loggingType) { + return loggingType; + } + } +} diff --git a/src/core/lombok/javac/handlers/HandleSynchronized.java b/src/core/lombok/javac/handlers/HandleSynchronized.java index 2f900eb8..a095aaf1 100644 --- a/src/core/lombok/javac/handlers/HandleSynchronized.java +++ b/src/core/lombok/javac/handlers/HandleSynchronized.java @@ -89,7 +89,7 @@ public class HandleSynchronized implements JavacAnnotationHandler<Synchronized> JCVariableDecl fieldDecl = maker.VarDef( maker.Modifiers(Flags.PRIVATE | Flags.FINAL | (isStatic ? Flags.STATIC : 0)), methodNode.toName(lockName), objectType, newObjectArray); - injectField(methodNode.up(), fieldDecl); + injectFieldSuppressWarnings(methodNode.up(), fieldDecl); } if (method.body == null) return false; diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index 79436327..5dacf2ca 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -392,13 +392,26 @@ public class JavacHandlerUtil { /** * Adds the given new field declaration to the provided type AST Node. + * The field carries the @{@link SuppressWarnings}("all") annotation. + * Also takes care of updating the JavacAST. + */ + public static void injectFieldSuppressWarnings(JavacNode typeNode, JCVariableDecl field) { + injectField(typeNode, field, true); + } + + /** + * Adds the given new field declaration to the provided type AST Node. * * Also takes care of updating the JavacAST. */ public static void injectField(JavacNode typeNode, JCVariableDecl field) { + injectField(typeNode, field, false); + } + + private static void injectField(JavacNode typeNode, JCVariableDecl field, boolean addSuppressWarnings) { JCClassDecl type = (JCClassDecl) typeNode.get(); - addSuppressWarningsAll(field.mods, typeNode, field.pos); + if (addSuppressWarnings) addSuppressWarningsAll(field.mods, typeNode, field.pos); type.defs = type.defs.append(field); typeNode.add(field, Kind.FIELD).recursiveSetHandled(); @@ -476,6 +489,21 @@ public class JavacHandlerUtil { return e; } + + + /** + * In javac, dotted access of any kind, from {@code java.lang.String} to {@code var.methodName} + * is represented by a fold-left of {@code Select} nodes with the leftmost string represented by + * a {@code Ident} node. This method generates such an expression. + * + * For example, maker.Select(maker.Select(maker.Ident(NAME[java]), NAME[lang]), NAME[String]). + * + * @see com.sun.tools.javac.tree.JCTree.JCIdent + * @see com.sun.tools.javac.tree.JCTree.JCFieldAccess + */ + public static JCExpression chainDotsString(TreeMaker maker, JavacNode node, String elems) { + return chainDots(maker, node, elems.split("\\.")); + } /** * Searches the given field node for annotations and returns each one that matches the provided regular expression pattern. diff --git a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java index 16c06f50..57f0a1d8 100644 --- a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java +++ b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java @@ -337,7 +337,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { * Traversal methods *************************************************************************/ - /** Exception to propogate IOException through visitXXX methods */ + /** Exception to propagate IOException through visitXXX methods */ private static class UncheckedIOException extends Error { static final long serialVersionUID = -4032692679158424751L; UncheckedIOException(IOException e) { @@ -657,6 +657,11 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { } } print(" "); + // <Added for delombok by Reinier Zwitserloot> + if ((tree.mods.flags & INTERFACE) != 0) { + removeImplicitModifiersForInterfaceMembers(tree.defs); + } + // </Added for delombok by Reinier Zwitserloot> if ((tree.mods.flags & ENUM) != 0) { printEnumBody(tree.defs); } else { @@ -668,6 +673,21 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { } } + // Added for delombok by Reinier Zwitserloot + private void removeImplicitModifiersForInterfaceMembers(List<JCTree> defs) { + for (JCTree def :defs) { + if (def instanceof JCVariableDecl) { + ((JCVariableDecl) def).mods.flags &= ~(Flags.PUBLIC | Flags.STATIC | Flags.FINAL); + } + if (def instanceof JCMethodDecl) { + ((JCMethodDecl) def).mods.flags &= ~(Flags.PUBLIC | Flags.ABSTRACT); + } + if (def instanceof JCClassDecl) { + ((JCClassDecl) def).mods.flags &= ~(Flags.PUBLIC | Flags.STATIC); + } + } + } + public void visitMethodDef(JCMethodDecl tree) { try { boolean isConstructor = tree.name == tree.name.table.fromChars("<init>".toCharArray(), 0, 6); |