From 7dba9c850c675cc8066fa3e7c79e836bb7ad8203 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Mon, 29 Nov 2010 16:43:36 +0100 Subject: Added 'val' as a type which the 'val' fake keyword must resolve to before val works, as a gesture to make val less 'magical'. It even works, in eclipse. Next up: javac. --- src/core/lombok/val.java | 29 ++++++++++++++++++ .../lombok/eclipse/agent/PatchVal.java | 35 ++++++++++++++++++---- usage_examples/valExample_pre.jpage | 1 + website/features/val.html | 4 +++ 4 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 src/core/lombok/val.java diff --git a/src/core/lombok/val.java b/src/core/lombok/val.java new file mode 100644 index 00000000..baab0f90 --- /dev/null +++ b/src/core/lombok/val.java @@ -0,0 +1,29 @@ +/* + * 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; + +/** + * Use {@code val} as the type of any local variable declaration (even in a for-each statement), and the type will be inferred from the initializing expression. + * For example: {@code val x = 10.0;} will infer {@code double}, and {@code val y = new ArrayList();} will infer {@code ArrayList}. The local variable + * will also be made final. + */ +public class val {} diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java index b93fc4f1..b6523c3c 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java @@ -188,21 +188,47 @@ public class PatchVal { return expr.resolveType(scope); } + public static boolean matches(String key, char[] array) { + if (array == null || key.length() != array.length) return false; + for (int i = 0; i < array.length; i++) { + if (key.charAt(i) != array[i]) return false; + } + + return true; + } + public static boolean handleValForLocalDeclaration(LocalDeclaration local, BlockScope scope) { if (local == null || !LocalDeclaration.class.equals(local.getClass())) return false; boolean decomponent = false; + boolean isVal = false; + if (local.type instanceof SingleTypeReference) { char[] token = ((SingleTypeReference)local.type).token; - if (token == null || token.length != 3) return false; - else if (token[0] != 'v' || token[1] != 'a' || token[2] != 'l') return false; - } else return false; + if (matches("val", token)) isVal = true; + } + + if (local.type instanceof QualifiedTypeReference) { + char[][] tokens = ((QualifiedTypeReference)local.type).tokens; + if (tokens != null && tokens.length == 2 && matches("lombok", tokens[0]) && matches("val", tokens[1])) isVal = true; + } + + if (!isVal) return false; + + TypeBinding resolvedType = local.type.resolvedType; + if (resolvedType == null) resolvedType = local.type.resolveType(scope, false); + if (resolvedType == null) return false; + + char[] pkg = resolvedType.qualifiedPackageName(); + char[] nm = resolvedType.qualifiedSourceName(); + if (!matches("lombok", pkg) || !matches("val", nm)) return false; Expression init = local.initialization; if (init == null && Reflection.initCopyField != null) { try { init = (Expression) Reflection.initCopyField.get(local); } catch (Exception e) { + // init remains null. } } @@ -211,12 +237,11 @@ public class PatchVal { init = (Expression) Reflection.iterableCopyField.get(local); decomponent = true; } catch (Exception e) { + // init remains null. } } TypeReference replacement = null; - if (init != null && decomponent) { - } if (init != null) { TypeBinding resolved = decomponent ? getForEachComponentType(init, scope) : init.resolveType(scope); diff --git a/usage_examples/valExample_pre.jpage b/usage_examples/valExample_pre.jpage index 8b9dadc3..a621640f 100644 --- a/usage_examples/valExample_pre.jpage +++ b/usage_examples/valExample_pre.jpage @@ -1,5 +1,6 @@ import java.util.ArrayList; import java.util.HashMap; +import lombok.val; public class ValExample { public String example() { diff --git a/website/features/val.html b/website/features/val.html index a3ce58e0..4e05f8ca 100644 --- a/website/features/val.html +++ b/website/features/val.html @@ -18,6 +18,10 @@ NEW in Lombok 0.10: You can use val as the type of a local variable declaration instead of actually writing the type. When you do this, the type will be inferred from the initializer expression. The local variable will also be made final. This feature works on local variables and on foreach loops only, not on fields. The initializer expression is required. +

+ val is actually a 'type' of sorts, and exists as a real class in the lombok package. You must import it for val to work (or use lombok.val as the type). + The existence of this type on a local variable declaration triggers both the adding of the final keyword as well as copying the type of the initializing expression which overwrites + the 'fake' val type.

WARNING: This feature does not currently work in NetBeans. We're working on fixing that.

-- cgit