aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorReinier Zwitserloot <reinier@zwitserloot.com>2015-10-06 00:25:32 +0200
committerReinier Zwitserloot <reinier@zwitserloot.com>2015-10-06 00:25:32 +0200
commit9d8c4e4099bef9b7854cc5d77bc996c3b3bf0e41 (patch)
tree6ca48925c989d3f314fbeef08931a1940b5c03cf /src
parentb4d69f5cb8b093718bb7ffb539e5875df52ca48e (diff)
downloadlombok-9d8c4e4099bef9b7854cc5d77bc996c3b3bf0e41.tar.gz
lombok-9d8c4e4099bef9b7854cc5d77bc996c3b3bf0e41.tar.bz2
lombok-9d8c4e4099bef9b7854cc5d77bc996c3b3bf0e41.zip
New feature: FieldDefaults can now be configured to apply to _every_ file, regardless of annotations.
Diffstat (limited to 'src')
-rw-r--r--src/core/lombok/ConfigurationKeys.java14
-rw-r--r--src/core/lombok/eclipse/handlers/HandleFieldDefaults.java81
-rw-r--r--src/core/lombok/javac/handlers/HandleFieldDefaults.java75
-rw-r--r--src/core/lombok/javac/handlers/HandleVal.java14
-rw-r--r--src/utils/lombok/eclipse/Eclipse.java19
5 files changed, 142 insertions, 61 deletions
diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java
index 67d51895..dd6732ed 100644
--- a/src/core/lombok/ConfigurationKeys.java
+++ b/src/core/lombok/ConfigurationKeys.java
@@ -396,6 +396,20 @@ public class ConfigurationKeys {
// ----- FieldDefaults -----
/**
+ * lombok configuration: {@code lombok.fieldDefaults.defaultPrivate} = {@code true} | {@code false}.
+ *
+ * If set to <code>true</code> <em>any</em> field without an access modifier or {@code @PackagePrivate} is marked as {@code private} by lombok, in all source files compiled.
+ */
+ public static final ConfigurationKey<Boolean> FIELD_DEFAULTS_PRIVATE_EVERYWHERE = new ConfigurationKey<Boolean>("lombok.fieldDefaults.defaultPrivate", "If true, fields without any access modifier, in any file (lombok annotated or not) are marked as private. Use @PackagePrivate or an explicit modifier to override this.") {};
+
+ /**
+ * lombok configuration: {@code lombok.fieldDefaults.defaultFinal} = {@code true} | {@code false}.
+ *
+ * If set to <code>true</code> <em>any</em> field without {@code @NonFinal} is marked as {@code final} by lombok, in all source files compiled.
+ */
+ public static final ConfigurationKey<Boolean> FIELD_DEFAULTS_FINAL_EVERYWHERE = new ConfigurationKey<Boolean>("lombok.fieldDefaults.defaultFinal", "If true, fields, in any file (lombok annotated or not) are marked as final. Use @NonFinal to override this.") {};
+
+ /**
* lombok configuration: {@code lombok.fieldDefaults.flagUsage} = {@code WARNING} | {@code ERROR}.
*
* If set, <em>any</em> usage of {@code @FieldDefaults} results in a warning / error.
diff --git a/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java b/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java
index 33e796b7..f97a721b 100644
--- a/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java
+++ b/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java
@@ -23,12 +23,17 @@ package lombok.eclipse.handlers;
import static lombok.core.handlers.HandlerUtil.*;
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
+
+import java.util.Arrays;
+
import lombok.AccessLevel;
import lombok.ConfigurationKeys;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
import lombok.core.HandlerPriority;
-import lombok.eclipse.EclipseAnnotationHandler;
+import lombok.eclipse.Eclipse;
+import lombok.eclipse.EclipseASTAdapter;
+import lombok.eclipse.EclipseASTVisitor;
import lombok.eclipse.EclipseNode;
import lombok.experimental.FieldDefaults;
import lombok.experimental.NonFinal;
@@ -37,16 +42,19 @@ import lombok.experimental.PackagePrivate;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
+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;
/**
* Handles the {@code lombok.FieldDefaults} annotation for eclipse.
*/
-@ProviderFor(EclipseAnnotationHandler.class)
+@ProviderFor(EclipseASTVisitor.class)
@HandlerPriority(-2048) //-2^11; to ensure @Value picks up on messing with the fields' 'final' state, run earlier.
-public class HandleFieldDefaults extends EclipseAnnotationHandler<FieldDefaults> {
+public class HandleFieldDefaults extends EclipseASTAdapter {
public boolean generateFieldDefaultsForType(EclipseNode typeNode, EclipseNode pos, AccessLevel level, boolean makeFinal, boolean checkForTypeLevelFieldDefaults) {
if (checkForTypeLevelFieldDefaults) {
if (hasAnnotation(FieldDefaults.class, typeNode)) {
@@ -105,29 +113,60 @@ public class HandleFieldDefaults extends EclipseAnnotationHandler<FieldDefaults>
fieldNode.rebuild();
}
- public void handle(AnnotationValues<FieldDefaults> annotation, Annotation ast, EclipseNode annotationNode) {
- handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.FIELD_DEFAULTS_FLAG_USAGE, "@FieldDefaults");
-
- EclipseNode node = annotationNode.up();
- FieldDefaults instance = annotation.getInstance();
- AccessLevel level = instance.level();
- boolean makeFinal = instance.makeFinal();
+ private static final char[] FIELD_DEFAULTS = "FieldDefaults".toCharArray();
+
+ @Override public void visitType(EclipseNode typeNode, TypeDeclaration type) {
+ AnnotationValues<FieldDefaults> fieldDefaults = null;
+ EclipseNode source = typeNode;
- if (level == AccessLevel.NONE && !makeFinal) {
- annotationNode.addError("This does nothing; provide either level or makeFinal or both.");
- return;
+ boolean levelIsExplicit = false;
+ boolean makeFinalIsExplicit = false;
+ FieldDefaults fd = null;
+ for (EclipseNode jn : typeNode.down()) {
+ if (jn.getKind() != Kind.ANNOTATION) continue;
+ Annotation ann = (Annotation) jn.get();
+ TypeReference typeTree = ann.type;
+ if (typeTree == null) continue;
+ if (typeTree instanceof SingleTypeReference) {
+ char[] t = ((SingleTypeReference) typeTree).token;
+ if (!Arrays.equals(t, FIELD_DEFAULTS)) continue;
+ } else if (typeTree instanceof QualifiedTypeReference) {
+ char[][] t = ((QualifiedTypeReference) typeTree).tokens;
+ if (!Eclipse.nameEquals(t, "lombok.experimental.FieldDefaults")) continue;
+ } else {
+ continue;
+ }
+
+ if (!typeMatches(FieldDefaults.class, jn, typeTree)) continue;
+
+ source = jn;
+ fieldDefaults = createAnnotation(FieldDefaults.class, jn);
+ levelIsExplicit = fieldDefaults.isExplicit("level");
+ makeFinalIsExplicit = fieldDefaults.isExplicit("makeFinal");
+
+ handleExperimentalFlagUsage(jn, ConfigurationKeys.FIELD_DEFAULTS_FLAG_USAGE, "@FieldDefaults");
+
+ fd = fieldDefaults.getInstance();
+ if (!levelIsExplicit && !makeFinalIsExplicit) {
+ jn.addError("This does nothing; provide either level or makeFinal or both.");
+ }
+
+ if (levelIsExplicit && fd.level() == AccessLevel.NONE) {
+ jn.addError("AccessLevel.NONE doesn't mean anything here. Pick another value.");
+ levelIsExplicit = false;
+ }
+ break;
}
- if (level == AccessLevel.PACKAGE) {
- annotationNode.addError("Setting 'level' to PACKAGE does nothing. To force fields as package private, use the @PackagePrivate annotation on the field.");
- }
+ if (fd == null && (type.modifiers & (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation)) != 0) return;
- if (!makeFinal && annotation.isExplicit("makeFinal")) {
- annotationNode.addError("Setting 'makeFinal' to false does nothing. To force fields to be non-final, use the @NonFinal annotation on the field.");
- }
+ boolean defaultToPrivate = Boolean.TRUE.equals(typeNode.getAst().readConfiguration(ConfigurationKeys.FIELD_DEFAULTS_PRIVATE_EVERYWHERE));
+ boolean defaultToFinal = Boolean.TRUE.equals(typeNode.getAst().readConfiguration(ConfigurationKeys.FIELD_DEFAULTS_FINAL_EVERYWHERE));
- if (node == null) return;
+ if (!defaultToPrivate && !defaultToFinal && fieldDefaults == null) return;
+ AccessLevel fdAccessLevel = (fieldDefaults != null && levelIsExplicit) ? fd.level() : defaultToPrivate ? AccessLevel.PRIVATE : null;
+ boolean fdToFinal = (fieldDefaults != null && makeFinalIsExplicit) ? fd.makeFinal() : defaultToFinal;
- generateFieldDefaultsForType(node, annotationNode, level, makeFinal, false);
+ generateFieldDefaultsForType(typeNode, source, fdAccessLevel, fdToFinal, false);
}
}
diff --git a/src/core/lombok/javac/handlers/HandleFieldDefaults.java b/src/core/lombok/javac/handlers/HandleFieldDefaults.java
index 95effded..5fb46afe 100644
--- a/src/core/lombok/javac/handlers/HandleFieldDefaults.java
+++ b/src/core/lombok/javac/handlers/HandleFieldDefaults.java
@@ -31,23 +31,24 @@ import lombok.core.HandlerPriority;
import lombok.experimental.FieldDefaults;
import lombok.experimental.NonFinal;
import lombok.experimental.PackagePrivate;
-import lombok.javac.JavacAnnotationHandler;
+import lombok.javac.JavacASTAdapter;
+import lombok.javac.JavacASTVisitor;
import lombok.javac.JavacNode;
import org.mangosdk.spi.ProviderFor;
import com.sun.tools.javac.code.Flags;
+import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
-import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
/**
* Handles the {@code lombok.FieldDefaults} annotation for eclipse.
*/
-@ProviderFor(JavacAnnotationHandler.class)
+@ProviderFor(JavacASTVisitor.class)
@HandlerPriority(-2048) //-2^11; to ensure @Value picks up on messing with the fields' 'final' state, run earlier.
-public class HandleFieldDefaults extends JavacAnnotationHandler<FieldDefaults> {
+public class HandleFieldDefaults extends JavacASTAdapter {
public boolean generateFieldDefaultsForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, boolean makeFinal, boolean checkForTypeLevelFieldDefaults) {
if (checkForTypeLevelFieldDefaults) {
if (hasAnnotation(FieldDefaults.class, typeNode)) {
@@ -72,13 +73,13 @@ public class HandleFieldDefaults extends JavacAnnotationHandler<FieldDefaults> {
//Skip fields that start with $
if (fieldDecl.name.toString().startsWith("$")) continue;
- setFieldDefaultsForField(field, errorNode.get(), level, makeFinal);
+ setFieldDefaultsForField(field, level, makeFinal);
}
return true;
}
- public void setFieldDefaultsForField(JavacNode fieldNode, DiagnosticPosition pos, AccessLevel level, boolean makeFinal) {
+ public void setFieldDefaultsForField(JavacNode fieldNode, AccessLevel level, boolean makeFinal) {
JCVariableDecl field = (JCVariableDecl) fieldNode.get();
if (level != null && level != AccessLevel.NONE) {
if ((field.mods.flags & (Flags.PUBLIC | Flags.PRIVATE | Flags.PROTECTED)) == 0) {
@@ -99,31 +100,53 @@ public class HandleFieldDefaults extends JavacAnnotationHandler<FieldDefaults> {
fieldNode.rebuild();
}
- @Override public void handle(AnnotationValues<FieldDefaults> annotation, JCAnnotation ast, JavacNode annotationNode) {
- handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.FIELD_DEFAULTS_FLAG_USAGE, "@FieldDefaults");
+ @Override public void visitType(JavacNode typeNode, JCClassDecl type) {
+ AnnotationValues<FieldDefaults> fieldDefaults = null;
+ JavacNode source = typeNode;
- deleteAnnotationIfNeccessary(annotationNode, FieldDefaults.class);
- deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel");
- JavacNode node = annotationNode.up();
- FieldDefaults instance = annotation.getInstance();
- AccessLevel level = instance.level();
- boolean makeFinal = instance.makeFinal();
-
- if (level == AccessLevel.NONE && !makeFinal) {
- annotationNode.addError("This does nothing; provide either level or makeFinal or both.");
- return;
+ boolean levelIsExplicit = false;
+ boolean makeFinalIsExplicit = false;
+ FieldDefaults fd = null;
+ for (JavacNode jn : typeNode.down()) {
+ if (jn.getKind() != Kind.ANNOTATION) continue;
+ JCAnnotation ann = (JCAnnotation) jn.get();
+ JCTree typeTree = ann.annotationType;
+ if (typeTree == null) continue;
+ String typeTreeToString = typeTree.toString();
+ if (!typeTreeToString.equals("FieldDefaults") && !typeTreeToString.equals("lombok.experimental.FieldDefaults")) continue;
+ if (!typeMatches(FieldDefaults.class, jn, typeTree)) continue;
+
+ source = jn;
+ fieldDefaults = createAnnotation(FieldDefaults.class, jn);
+ levelIsExplicit = fieldDefaults.isExplicit("level");
+ makeFinalIsExplicit = fieldDefaults.isExplicit("makeFinal");
+
+ handleExperimentalFlagUsage(jn, ConfigurationKeys.FIELD_DEFAULTS_FLAG_USAGE, "@FieldDefaults");
+
+ fd = fieldDefaults.getInstance();
+ if (!levelIsExplicit && !makeFinalIsExplicit) {
+ jn.addError("This does nothing; provide either level or makeFinal or both.");
+ }
+
+ if (levelIsExplicit && fd.level() == AccessLevel.NONE) {
+ jn.addError("AccessLevel.NONE doesn't mean anything here. Pick another value.");
+ levelIsExplicit = false;
+ }
+
+ deleteAnnotationIfNeccessary(jn, FieldDefaults.class);
+ deleteImportFromCompilationUnit(jn, "lombok.AccessLevel");
+ break;
}
- if (level == AccessLevel.PACKAGE) {
- annotationNode.addError("Setting 'level' to PACKAGE does nothing. To force fields as package private, use the @PackagePrivate annotation on the field.");
- }
+ if (fd == null && (type.mods.flags & (Flags.INTERFACE | Flags.ANNOTATION)) != 0) return;
- if (!makeFinal && annotation.isExplicit("makeFinal")) {
- annotationNode.addError("Setting 'makeFinal' to false does nothing. To force fields to be non-final, use the @NonFinal annotation on the field.");
- }
+ boolean defaultToPrivate = Boolean.TRUE.equals(typeNode.getAst().readConfiguration(ConfigurationKeys.FIELD_DEFAULTS_PRIVATE_EVERYWHERE));
+ boolean defaultToFinal = Boolean.TRUE.equals(typeNode.getAst().readConfiguration(ConfigurationKeys.FIELD_DEFAULTS_FINAL_EVERYWHERE));
- if (node == null) return;
+ if (!defaultToPrivate && !defaultToFinal && fieldDefaults == null) return;
+ AccessLevel fdAccessLevel = (fieldDefaults != null && levelIsExplicit) ? fd.level() : defaultToPrivate ? AccessLevel.PRIVATE : null;
+ boolean fdToFinal = (fieldDefaults != null && makeFinalIsExplicit) ? fd.makeFinal() : defaultToFinal;
- generateFieldDefaultsForType(node, annotationNode, level, makeFinal, false);
+ generateFieldDefaultsForType(typeNode, source, fdAccessLevel, fdToFinal, false);
}
}
diff --git a/src/core/lombok/javac/handlers/HandleVal.java b/src/core/lombok/javac/handlers/HandleVal.java
index 9eadd750..337ab2d7 100644
--- a/src/core/lombok/javac/handlers/HandleVal.java
+++ b/src/core/lombok/javac/handlers/HandleVal.java
@@ -51,11 +51,11 @@ import com.sun.tools.javac.util.List;
@ResolutionResetNeeded
public class HandleVal extends JavacASTAdapter {
@Override public void visitLocal(JavacNode localNode, JCVariableDecl local) {
- if (local.vartype == null || (!local.vartype.toString().equals("val") && !local.vartype.toString().equals("lombok.val"))) return;
-
- JCTree source = local.vartype;
-
- if (!typeMatches(val.class, localNode, local.vartype)) return;
+ JCTree typeTree = local.vartype;
+ if (typeTree == null) return;
+ String typeTreeToString = typeTree.toString();
+ if (!typeTreeToString.equals("val") && !typeTreeToString.equals("lombok.val")) return;
+ if (!typeMatches(val.class, localNode, typeTree)) return;
handleFlagUsage(localNode, ConfigurationKeys.VAL_FLAG_USAGE, "val");
@@ -88,7 +88,7 @@ public class HandleVal extends JavacASTAdapter {
local.mods.flags |= Flags.FINAL;
if (!localNode.shouldDeleteLombokAnnotations()) {
- JCAnnotation valAnnotation = recursiveSetGeneratedBy(localNode.getTreeMaker().Annotation(local.vartype, List.<JCExpression>nil()), source, localNode.getContext());
+ JCAnnotation valAnnotation = recursiveSetGeneratedBy(localNode.getTreeMaker().Annotation(local.vartype, List.<JCExpression>nil()), typeTree, localNode.getContext());
local.mods.annotations = local.mods.annotations == null ? List.of(valAnnotation) : local.mods.annotations.append(valAnnotation);
}
@@ -156,7 +156,7 @@ public class HandleVal extends JavacASTAdapter {
local.vartype = JavacResolution.createJavaLangObject(localNode.getAst());
throw e;
} finally {
- recursiveSetGeneratedBy(local.vartype, source, localNode.getContext());
+ recursiveSetGeneratedBy(local.vartype, typeTree, localNode.getContext());
}
}
}
diff --git a/src/utils/lombok/eclipse/Eclipse.java b/src/utils/lombok/eclipse/Eclipse.java
index c2a863d5..18b22256 100644
--- a/src/utils/lombok/eclipse/Eclipse.java
+++ b/src/utils/lombok/eclipse/Eclipse.java
@@ -98,15 +98,20 @@ public class Eclipse {
* string containing the same fully qualified name with dots in the string.
*/
public static boolean nameEquals(char[][] typeName, String string) {
- StringBuilder sb = new StringBuilder();
- boolean first = true;
- for (char[] elem : typeName) {
- if (first) first = false;
- else sb.append('.');
- sb.append(elem);
+ int pos = 0, len = string.length();
+ for (int i = 0; i < typeName.length; i++) {
+ char[] t = typeName[i];
+ if (i > 0) {
+ if (pos == len) return false;
+ if (string.charAt(pos++) != '.') return false;
+ }
+ for (int j = 0; j < t.length; j++) {
+ if (pos == len) return false;
+ if (string.charAt(pos++) != t[j]) return false;
+ }
}
- return string.contentEquals(sb);
+ return true;
}
public static boolean hasClinit(TypeDeclaration parent) {