# HG changeset patch
# Parent e1dbe19baa32de8787416f6956295cfaecb8b724
diff --git a/java.hints.declarative/src/org/netbeans/modules/java/hints/declarative/conditionapi/Context.java b/java.hints.declarative/src/org/netbeans/modules/java/hints/declarative/conditionapi/Context.java
--- a/java.hints.declarative/src/org/netbeans/modules/java/hints/declarative/conditionapi/Context.java
+++ b/java.hints.declarative/src/org/netbeans/modules/java/hints/declarative/conditionapi/Context.java
@@ -40,6 +40,7 @@
package org.netbeans.modules.java.hints.declarative.conditionapi;
import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.tree.Scope;
import com.sun.source.tree.Tree.Kind;
import com.sun.source.util.TreePath;
import java.util.ArrayList;
@@ -57,6 +58,7 @@
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import org.netbeans.api.annotations.common.CheckForNull;
@@ -292,6 +294,31 @@
return cut.getPackageName() != null ? cut.getPackageName().toString() : "";
}
+
+ /**Checks whether the given Java element is available in the particular source
+ * code or not.
+ *
+ * The elementDescription
format is as follows:
+ *
+ * - for type (class, enum, interface or annotation type)
+ * - the FQN of the type
+ * - for field or enum constant
+ * - the FQN of the enclosing type
.
field name
+ * - for method
+ * - the FQN of the enclosing type
.
method name(
comma separated parameter types)
+ * The parameter types may include type parameters, but these are ignored. The last parameter type can use ellipsis (...) to denote vararg method.
+ * - for constructor
+ * - the FQN of the enclosing type
.
simple name of enclosing type(
comma separated parameter types)
+ * See method format for more details on parameter types.
+ *
+ *
+ * @param elementDescription the description of the element that should be checked for existence
+ * @return true if and only the specified element exists while processing the current source
+ * @since nb74
+ */
+ public boolean isAvailable(@NonNull String description) {
+ return ctx.getInfo().getElementUtilities().findElement(description) != null;
+ }
static final class APIAccessorImpl extends APIAccessor {
diff --git a/java.hints.declarative/src/org/netbeans/modules/java/hints/declarative/conditionapi/DefaultRuleUtilities.java b/java.hints.declarative/src/org/netbeans/modules/java/hints/declarative/conditionapi/DefaultRuleUtilities.java
--- a/java.hints.declarative/src/org/netbeans/modules/java/hints/declarative/conditionapi/DefaultRuleUtilities.java
+++ b/java.hints.declarative/src/org/netbeans/modules/java/hints/declarative/conditionapi/DefaultRuleUtilities.java
@@ -162,4 +162,29 @@
Pattern p = Pattern.compile(regexp.toString());
return p;
}
+
+ /**Checks whether the given Java element is available in the particular source
+ * code or not.
+ *
+ * The elementDescription
format is as follows:
+ *
+ * - for type (class, enum, interface or annotation type)
+ * - the FQN of the type
+ * - for field or enum constant
+ * - the FQN of the enclosing type
.
field name
+ * - for method
+ * - the FQN of the enclosing type
.
method name(
comma separated parameter types)
+ * The parameter types may include type parameters, but these are ignored. The last parameter type can use ellipsis (...) to denote vararg method.
+ * - for constructor
+ * - the FQN of the enclosing type
.
simple name of enclosing type(
comma separated parameter types)
+ * See method format for more details on parameter types.
+ *
+ *
+ * @param elementDescription the description of the element that should be checked for existence
+ * @return true if and only the specified element exists while processing the current source
+ * @since nb74
+ */
+ public boolean isAvailable(@NonNull String elementDescription) {
+ return context.isAvailable(elementDescription);
+ }
}
diff --git a/java.hints.declarative/test/unit/src/org/netbeans/modules/java/hints/declarative/conditionapi/matchWithBind.hint b/java.hints.declarative/test/unit/src/org/netbeans/modules/java/hints/declarative/conditionapi/isAvailable.hint
copy from java.hints.declarative/test/unit/src/org/netbeans/modules/java/hints/declarative/conditionapi/matchWithBind.hint
copy to java.hints.declarative/test/unit/src/org/netbeans/modules/java/hints/declarative/conditionapi/isAvailable.hint
--- a/java.hints.declarative/test/unit/src/org/netbeans/modules/java/hints/declarative/conditionapi/matchWithBind.hint
+++ b/java.hints.declarative/test/unit/src/org/netbeans/modules/java/hints/declarative/conditionapi/isAvailable.hint
@@ -1,4 +1,7 @@
- return $expr;
-=> return $o != $t; :: matchesWithBind($expr, "$o == $t")
-=> return $t == $o; :: matchesWithBind($expr, "$t != $o")
+1 + 1 :: isAvailable("java.lang.ThreadLocal.initialValue()")
+=> 2
;;
+
+2 + 2 :: isAvailable("unknown.Class")
+=> 2
+;;
diff --git a/java.hints.declarative/test/unit/src/org/netbeans/modules/java/hints/declarative/conditionapi/matchWithBind.test b/java.hints.declarative/test/unit/src/org/netbeans/modules/java/hints/declarative/conditionapi/isAvailable.test
copy from java.hints.declarative/test/unit/src/org/netbeans/modules/java/hints/declarative/conditionapi/matchWithBind.test
copy to java.hints.declarative/test/unit/src/org/netbeans/modules/java/hints/declarative/conditionapi/isAvailable.test
--- a/java.hints.declarative/test/unit/src/org/netbeans/modules/java/hints/declarative/conditionapi/matchWithBind.test
+++ b/java.hints.declarative/test/unit/src/org/netbeans/modules/java/hints/declarative/conditionapi/isAvailable.test
@@ -1,28 +1,21 @@
-%%TestCase bind-works-1
+%%TestCase is-available-1
package test;
-public class Test {
- private boolean t(int v1, int v2) {
- return v1 == v2;
+public class Test extends ThreadLocal {
+ private int t() {
+ return 1 + 1;
}
}
%%=>
package test;
-public class Test {
- private boolean t(int v1, int v2) {
- return v1 != v2;
+public class Test extends ThreadLocal {
+ private int t() {
+ return 2;
}
}
-%%TestCase scope-works-1
+%%TestCase is-not-available-1
package test;
public class Test {
- private boolean t(int v1, int v2) {
- return v1 != v2;
+ private int t() {
+ return 2 + 2;
}
}
-%%=>
-package test;
-public class Test {
- private boolean t(int v1, int v2) {
- return v1 == v2;
- }
-}
diff --git a/java.hints/src/org/netbeans/modules/java/hints/bugs/CollectionRemove.java b/java.hints/src/org/netbeans/modules/java/hints/bugs/CollectionRemove.java
--- a/java.hints/src/org/netbeans/modules/java/hints/bugs/CollectionRemove.java
+++ b/java.hints/src/org/netbeans/modules/java/hints/bugs/CollectionRemove.java
@@ -264,55 +264,8 @@
return info.getTypeUtilities().isCastable(type1, type2);
}
- private static final Pattern SPLIT = Pattern.compile("(.+)\\.([^.]+)\\((.*)\\)");
-
private static ExecutableElement resolveMethod(CompilationInfo info, String name) {
- Matcher m = SPLIT.matcher(name);
-
- if (!m.matches()) {
- throw new IllegalArgumentException();
- }
-
- String className = m.group(1);
- String methodName = m.group(2);
- String paramsSpec = m.group(3);
-
- TypeElement te = info.getElements().getTypeElement(className);
-
- if (te == null) {
- return null;
- }
-
- String[] paramList = paramsSpec.split(",");
- List params = new LinkedList();
-
- TypeElement topLevel = info.getTopLevelElements().get(0);
-
- for (String t : paramList) {
- params.add(info.getTreeUtilities().parseType(t, topLevel));
- }
-
- for (ExecutableElement ee : ElementFilter.methodsIn(te.getEnclosedElements())) {
- if (!methodName.equals(ee.getSimpleName().toString()) || ee.getParameters().size() != params.size()) {
- continue;
- }
-
- Iterator designed = params.iterator();
- boolean found = true;
-
- for (VariableElement param : ee.getParameters()) {
- if (!info.getTypes().isSameType(info.getTypes().erasure(param.asType()), designed.next())) {
- found = false;
- break;
- }
- }
-
- if (found) {
- return ee;
- }
- }
-
- return null;
+ return (ExecutableElement) info.getElementUtilities().findElement(name);
}
private static ExecutableElement findEnclosingMethod(CompilationInfo info, TreePath path) {
diff --git a/java.source/apichanges.xml b/java.source/apichanges.xml
--- a/java.source/apichanges.xml
+++ b/java.source/apichanges.xml
@@ -108,6 +108,19 @@
+
+
+ Added ElementUtilities.findElement
+
+
+
+
+
+ Added a new method to find an element based on its description:
+ ElementUtilities.findElement
.
+
+
+
Added several methods to support Java 8 features.
diff --git a/java.source/nbproject/project.properties b/java.source/nbproject/project.properties
--- a/java.source/nbproject/project.properties
+++ b/java.source/nbproject/project.properties
@@ -46,7 +46,7 @@
javadoc.title=Java Source
javadoc.arch=${basedir}/arch.xml
javadoc.apichanges=${basedir}/apichanges.xml
-spec.version.base=0.113
+spec.version.base=0.114
test.qa-functional.cp.extra=${refactoring.java.dir}/modules/ext/nb-javac-api.jar
test.unit.run.cp.extra=${o.n.core.dir}/core/core.jar:\
${o.n.core.dir}/lib/boot.jar:\
diff --git a/java.source/src/org/netbeans/api/java/source/ElementUtilities.java b/java.source/src/org/netbeans/api/java/source/ElementUtilities.java
--- a/java.source/src/org/netbeans/api/java/source/ElementUtilities.java
+++ b/java.source/src/org/netbeans/api/java/source/ElementUtilities.java
@@ -46,6 +46,7 @@
import com.sun.javadoc.Doc;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.Scope;
+import com.sun.source.tree.Tree;
import com.sun.source.util.TreePath;
import com.sun.source.util.Trees;
import com.sun.tools.javac.api.JavacScope;
@@ -94,11 +95,14 @@
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
+import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
+import org.netbeans.api.annotations.common.CheckForNull;
import org.netbeans.api.annotations.common.NonNull;
import org.netbeans.api.annotations.common.NullAllowed;
+import org.netbeans.modules.java.source.ElementHandleAccessor;
import org.netbeans.modules.java.source.builder.ElementsService;
import org.netbeans.modules.java.source.JavadocEnv;
@@ -547,7 +551,107 @@
*/
public boolean isEffectivelyFinal(VariableElement e) {
return (((Symbol) e).flags() & (Flags.EFFECTIVELY_FINAL | Flags.FINAL)) != 0;
- };
+ }
+
+ /**Looks up the given Java element.
+ *
+ * The elementDescription
format is as follows:
+ *
+ * - for type (class, enum, interface or annotation type)
+ * - the FQN of the type
+ * - for field or enum constant
+ * - the FQN of the enclosing type
.
field name
+ * - for method
+ * - the FQN of the enclosing type
.
method name(
comma separated parameter types)
+ * The parameter types may include type parameters, but these are ignored. The last parameter type can use ellipsis (...) to denote vararg method.
+ * - for constructor
+ * - the FQN of the enclosing type
.
simple name of enclosing type(
comma separated parameter types)
+ * See method format for more details on parameter types.
+ *
+ *
+ * @param elementDescription the description of the element that should be checked for existence
+ * @return the found element, or null if not available
+ * @since 0.114
+ */
+ public @CheckForNull Element findElement(@NonNull String description) {
+ if (description.contains("(")) {
+ //method:
+ String methodFullName = description.substring(0, description.indexOf('('));
+ String className = methodFullName.substring(0, methodFullName.lastIndexOf('.'));
+ TypeElement clazz = info.getElements().getTypeElement(className);
+
+ if (clazz == null) return null;
+
+ String methodSimpleName = methodFullName.substring(methodFullName.lastIndexOf('.') + 1);
+ boolean constructor = clazz.getSimpleName().contentEquals(methodSimpleName);
+ String parameters = description.substring(description.indexOf('(') + 1, description.lastIndexOf(')') + 1);
+
+ int paramIndex = 0;
+ int lastParamStart = 0;
+ int angleDepth = 0;
+ //XXX:
+ List types = new ArrayList();
+
+ while (paramIndex < parameters.length()) {
+ switch (parameters.charAt(paramIndex)) {
+ case '<': angleDepth++; break;
+ case '>': angleDepth--; break; //TODO: check underflow
+ case ',':
+ if (angleDepth > 0) break;
+ case ')':
+ if (paramIndex > lastParamStart) {
+ String type = parameters.substring(lastParamStart, paramIndex).replace("...", "[]");
+ //TODO: handle varargs
+ types.add(info.getTypes().erasure(info.getTreeUtilities().parseType(type, info.getTopLevelElements().get(0)/*XXX*/)));
+ lastParamStart = paramIndex + 1;
+ }
+ break;
+ }
+
+ paramIndex++;
+ }
+
+ OUTER: for (ExecutableElement ee : constructor ? ElementFilter.constructorsIn(clazz.getEnclosedElements()) : ElementFilter.methodsIn(clazz.getEnclosedElements())) {
+ if ((constructor || ee.getSimpleName().contentEquals(methodSimpleName)) && ee.getParameters().size() == types.size()) {
+ Iterator extends TypeMirror> real = ((ExecutableType) info.getTypes().erasure(ee.asType())).getParameterTypes().iterator();
+ Iterator expected = types.iterator();
+
+ while (real.hasNext() && expected.hasNext()) {
+ if (!info.getTypes().isSameType(real.next(), expected.next())) {
+ continue OUTER;
+ }
+ }
+
+ assert real.hasNext() == expected.hasNext();
+
+ return ee;
+ }
+ }
+ }
+
+ //field or class:
+ TypeElement el = info.getElements().getTypeElement(description);
+
+ if (el != null) return el;
+
+ int dot = description.lastIndexOf('.');
+
+ if (dot != (-1)) {
+ String simpleName = description.substring(dot + 1);
+
+ el = info.getElements().getTypeElement(description.substring(0, dot));
+
+ if (el != null) {
+ for (VariableElement var : ElementFilter.fieldsIn(el.getEnclosedElements())) {
+ if (var.getSimpleName().contentEquals(simpleName)) {
+ return var;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
// private implementation --------------------------------------------------
diff --git a/java.source/test/unit/src/org/netbeans/api/java/source/ElementsTest.java b/java.source/test/unit/src/org/netbeans/api/java/source/ElementUtilitiesTest.java
copy from java.source/test/unit/src/org/netbeans/api/java/source/ElementsTest.java
copy to java.source/test/unit/src/org/netbeans/api/java/source/ElementUtilitiesTest.java
--- a/java.source/test/unit/src/org/netbeans/api/java/source/ElementsTest.java
+++ b/java.source/test/unit/src/org/netbeans/api/java/source/ElementUtilitiesTest.java
@@ -1,7 +1,7 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
- * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 1997-2013 Oracle and/or its affiliates. All rights reserved.
*
* Oracle and Java are registered trademarks of Oracle and/or its affiliates.
* Other names may be trademarks of their respective owners.
@@ -26,23 +26,17 @@
*
* Contributor(s):
*
- * Portions Copyrighted 2007 Sun Microsystems, Inc.
+ * Portions Copyrighted 2007-2013 Sun Microsystems, Inc.
*/
package org.netbeans.api.java.source;
-import com.sun.source.tree.AnnotationTree;
-import com.sun.source.tree.MethodTree;
-import com.sun.source.util.TreePath;
import java.io.File;
import java.io.IOException;
-import java.nio.charset.Charset;
-import java.util.List;
import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.type.TypeKind;
import org.netbeans.junit.NbTestCase;
-import org.netbeans.spi.queries.FileEncodingQueryImplementation;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
@@ -50,23 +44,15 @@
*
* @author Jan Lahoda
*/
-public class ElementsTest extends NbTestCase {
+public class ElementUtilitiesTest extends NbTestCase {
- public ElementsTest(String name) {
+ public ElementUtilitiesTest(String name) {
super(name);
}
protected void setUp() throws Exception {
clearWorkDir();
- SourceUtilsTestUtil.prepareTest(new String[0], new Object[] {new FileEncodingQueryImplementation() {
- @Override
- public Charset getEncoding(FileObject file) {
- if (file.equals(testFO))
- return Charset.forName("UTF-8");
- else
- return null;
- }
- }});
+ SourceUtilsTestUtil.prepareTest(new String[0], new Object[0]);
}
private FileObject sourceRoot;
@@ -91,63 +77,82 @@
prepareTest();
TestUtilities.copyStringToFile(FileUtil.toFile(testFO),
- "public class Vecernicek {" +
+ "public class Test {" +
"}");
JavaSource javaSource = JavaSource.forFileObject(testFO);
javaSource.runUserActionTask(new Task() {
public void run(CompilationController controller) throws IOException {
controller.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED);
- TypeElement typeElement = controller.getElements().getTypeElement("Vecernicek");
- assertNotNull(typeElement);
- }
- }, true);
-
- TestUtilities.copyStringToFile(FileUtil.toFile(testFO),
- "public class Večerníček {" +
- "}");
- testFO.refresh();
- javaSource = JavaSource.forFileObject(testFO);
- javaSource.runUserActionTask(new Task() {
- public void run(CompilationController controller) throws IOException {
- controller.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED);
- TypeElement typeElement = controller.getElements().getTypeElement("Večerníček");
- assertNotNull(typeElement);
+
+ {
+ Element wait = controller.getElementUtilities().findElement("java.lang.Object.wait(long)");
+ assertNotNull(wait);
+ assertEquals(ElementKind.METHOD, wait.getKind());
+ ExecutableElement waitMethod = (ExecutableElement) wait;
+ assertEquals("wait", waitMethod.getSimpleName().toString());
+ assertEquals(1, waitMethod.getParameters().size());
+ assertEquals(TypeKind.LONG, waitMethod.getParameters().get(0).asType().getKind());
+ assertEquals(controller.getElements().getTypeElement("java.lang.Object"), waitMethod.getEnclosingElement());
+ }
+
+ {
+ Element arrayListInit = controller.getElementUtilities().findElement("java.util.ArrayList.ArrayList(java.util.Collection)");
+ assertNotNull(arrayListInit);
+ assertEquals(ElementKind.CONSTRUCTOR, arrayListInit.getKind());
+ ExecutableElement arrayListInitMethod = (ExecutableElement) arrayListInit;
+ assertEquals("", arrayListInitMethod.getSimpleName().toString());
+ assertEquals(1, arrayListInitMethod.getParameters().size());
+ assertEquals("java.util.Collection", controller.getTypes().erasure(arrayListInitMethod.getParameters().get(0).asType()).toString());
+ assertEquals(controller.getElements().getTypeElement("java.util.ArrayList"), arrayListInitMethod.getEnclosingElement());
+ }
+
+ {
+ Element arrayListAdd = controller.getElementUtilities().findElement("java.util.ArrayList.add(int, Object)");
+ assertNotNull(arrayListAdd);
+ assertEquals(ElementKind.METHOD, arrayListAdd.getKind());
+ ExecutableElement arrayListAddMethod = (ExecutableElement) arrayListAdd;
+ assertEquals("add", arrayListAddMethod.getSimpleName().toString());
+ assertEquals(2, arrayListAddMethod.getParameters().size());
+ assertEquals(TypeKind.INT, arrayListAddMethod.getParameters().get(0).asType().getKind());
+ assertEquals("java.lang.Object", controller.getTypes().erasure(arrayListAddMethod.getParameters().get(1).asType()).toString());
+ assertEquals(controller.getElements().getTypeElement("java.util.ArrayList"), arrayListAddMethod.getEnclosingElement());
+ }
+
+ {
+ Element arraysAsList = controller.getElementUtilities().findElement("java.util.Arrays.asList(Object...)");
+ assertNotNull(arraysAsList);
+ assertEquals(ElementKind.METHOD, arraysAsList.getKind());
+ ExecutableElement arraysAsListMethod = (ExecutableElement) arraysAsList;
+ assertEquals("asList", arraysAsListMethod.getSimpleName().toString());
+ assertEquals(1, arraysAsListMethod.getParameters().size());
+ assertEquals(TypeKind.ARRAY, arraysAsListMethod.getParameters().get(0).asType().getKind());
+ assertEquals(controller.getElements().getTypeElement("java.util.Arrays"), arraysAsListMethod.getEnclosingElement());
+ }
+
+ {
+ Element hashCode = controller.getElementUtilities().findElement("java.lang.Object.hashCode()");
+ assertNotNull(hashCode);
+ assertEquals(ElementKind.METHOD, hashCode.getKind());
+ ExecutableElement hashCodeMethod = (ExecutableElement) hashCode;
+ assertEquals("hashCode", hashCodeMethod.getSimpleName().toString());
+ assertEquals(0, hashCodeMethod.getParameters().size());
+ assertEquals(controller.getElements().getTypeElement("java.lang.Object"), hashCodeMethod.getEnclosingElement());
+ }
+
+ {
+ Element bigIntegerOne = controller.getElementUtilities().findElement("java.math.BigInteger.ONE");
+ assertNotNull(bigIntegerOne);
+ assertEquals(ElementKind.FIELD, bigIntegerOne.getKind());
+ assertEquals("ONE", bigIntegerOne.getSimpleName().toString());
+ assertEquals(controller.getElements().getTypeElement("java.math.BigInteger"), bigIntegerOne.getEnclosingElement());
+ }
+
+ {
+ Element bigInteger = controller.getElementUtilities().findElement("java.math.BigInteger");
+ assertEquals(controller.getElements().getTypeElement("java.math.BigInteger"), bigInteger);
+ }
}
}, true);
}
- public void test175535() throws Exception {
- prepareTest();
- FileObject otherFO = FileUtil.createData(sourceRoot, "test/A.java");
- TestUtilities.copyStringToFile(FileUtil.toFile(otherFO),
- "package test;" +
- "public class A implements Runnable {" +
- " @Override" +
- " public void run() {}" +
- "}");
- TestUtilities.copyStringToFile(FileUtil.toFile(testFO),
- "public class Test {" +
- "}");
- SourceUtilsTestUtil.compileRecursively(sourceRoot);
- JavaSource javaSource = JavaSource.forFileObject(testFO);
- javaSource.runUserActionTask(new Task() {
- public void run(CompilationController controller) throws IOException {
- controller.toPhase(JavaSource.Phase.RESOLVED);
- TypeElement typeElement = controller.getElements().getTypeElement("test.A");
- assertNotNull(typeElement);
- Element el = typeElement.getEnclosedElements().get(1);
- assertNotNull(el);
- assertEquals("run", el.getSimpleName().toString());
- TreePath mpath = controller.getTrees().getPath(el);
- MethodTree mtree = (MethodTree) mpath.getLeaf();
- assertNotNull(mtree);
- List extends AnnotationTree> annotations = mtree.getModifiers().getAnnotations();
- TypeMirror annotation = controller.getTrees().getTypeMirror(new TreePath(mpath, annotations.get(0)));
- assertNotNull(annotation);
- Element e = controller.getTrees().getElement(new TreePath(mpath, annotations.get(0)));
- assertNotNull(e);
- assertEquals(((DeclaredType)annotation).asElement(), e);
- }
- }, true);
- }
}