Commits

Jan Lahoda  committed a7413bb

Adding NetBeans demo

  • Participants
  • Parent commits 1814f87

Comments (0)

Files changed (11)

File nb/build.xml

+<?xml version="1.0" encoding="UTF-8"?>
+<!-- You may freely edit this file. See harness/README in the NetBeans platform -->
+<!-- for some information on what you could do (e.g. targets to override). -->
+<!-- If you delete this file and reopen the project it will be recreated. -->
+<project name="j1.tutorial.javac.analysis.netbeans" default="netbeans" basedir=".">
+    <description>Builds, tests, and runs the project j1.tutorial.javac.analysis.netbeans.</description>
+    <import file="nbproject/build-impl.xml"/>
+</project>

File nb/manifest.mf

+Manifest-Version: 1.0
+OpenIDE-Module: j1.tutorial.javac.analysis.netbeans
+OpenIDE-Module-Localizing-Bundle: j1/tutorial/javac/analysis/netbeans/Bundle.properties
+OpenIDE-Module-Specification-Version: 1.0
+

File nb/nbproject/build-impl.xml

+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+*** GENERATED FROM project.xml - DO NOT EDIT  ***
+***         EDIT ../build.xml INSTEAD         ***
+-->
+<project name="j1.tutorial.javac.analysis.netbeans-impl" basedir="..">
+    <property file="nbproject/private/platform-private.properties"/>
+    <property file="nbproject/platform.properties"/>
+    <macrodef name="property" uri="http://www.netbeans.org/ns/nb-module-project/2">
+        <attribute name="name"/>
+        <attribute name="value"/>
+        <sequential>
+            <property name="@{name}" value="${@{value}}"/>
+        </sequential>
+    </macrodef>
+    <property file="${user.properties.file}"/>
+    <nbmproject2:property name="harness.dir" value="nbplatform.${nbplatform.active}.harness.dir" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
+    <nbmproject2:property name="netbeans.dest.dir" value="nbplatform.${nbplatform.active}.netbeans.dest.dir" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
+    <fail message="You must define 'nbplatform.${nbplatform.active}.harness.dir'">
+        <condition>
+            <not>
+                <available file="${harness.dir}" type="dir"/>
+            </not>
+        </condition>
+    </fail>
+    <import file="${harness.dir}/build.xml"/>
+</project>

File nb/nbproject/genfiles.properties

+build.xml.data.CRC32=6d1a44d7
+build.xml.script.CRC32=3f225f80
+build.xml.stylesheet.CRC32=a56c6a5b@2.53
+# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
+# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
+nbproject/build-impl.xml.data.CRC32=6d1a44d7
+nbproject/build-impl.xml.script.CRC32=f8ade015
+nbproject/build-impl.xml.stylesheet.CRC32=68e521fc@2.53

File nb/nbproject/platform.properties

+nbplatform.active=default

File nb/nbproject/project.properties

+javac.source=1.6
+javac.compilerargs=-Xlint -Xlint:-serial

File nb/nbproject/project.xml

+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://www.netbeans.org/ns/project/1">
+    <type>org.netbeans.modules.apisupport.project</type>
+    <configuration>
+        <data xmlns="http://www.netbeans.org/ns/nb-module-project/3">
+            <code-name-base>j1.tutorial.javac.analysis.netbeans</code-name-base>
+            <standalone/>
+            <module-dependencies>
+                <dependency>
+                    <code-name-base>org.netbeans.libs.javacapi</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>7.11.0.3</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.netbeans.modules.java.source</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>0.105.0.23.1.20.6</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.netbeans.spi.editor.hints</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>0</release-version>
+                        <specification-version>1.26.0.7.31</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.netbeans.spi.java.hints</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>1.5.0.5.1.20.23.6</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.util</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>8.26</specification-version>
+                    </run-dependency>
+                </dependency>
+            </module-dependencies>
+            <test-dependencies>
+                <test-type>
+                    <name>unit</name>
+                    <test-dependency>
+                        <code-name-base>org.netbeans.insane</code-name-base>
+                        <compile-dependency/>
+                    </test-dependency>
+                    <test-dependency>
+                        <code-name-base>org.netbeans.libs.junit4</code-name-base>
+                        <compile-dependency/>
+                    </test-dependency>
+                    <test-dependency>
+                        <code-name-base>org.netbeans.modules.java.hints.test</code-name-base>
+                        <compile-dependency/>
+                    </test-dependency>
+                    <test-dependency>
+                        <code-name-base>org.netbeans.modules.nbjunit</code-name-base>
+                        <compile-dependency/>
+                    </test-dependency>
+                </test-type>
+            </test-dependencies>
+            <public-packages/>
+        </data>
+    </configuration>
+</project>

File nb/src/j1/tutorial/javac/analysis/netbeans/Bundle.properties

+OpenIDE-Module-Name=J1 NetBeans Warnings

File nb/src/j1/tutorial/javac/analysis/netbeans/CollectionRemove.java

+package j1.tutorial.javac.analysis.netbeans;
+
+import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.MethodInvocationTree;
+import com.sun.source.util.TreePath;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.WildcardType;
+import org.netbeans.spi.editor.hints.ErrorDescription;
+import org.netbeans.spi.java.hints.ConstraintVariableType;
+import org.netbeans.spi.java.hints.ErrorDescriptionFactory;
+import org.netbeans.spi.java.hints.Hint;
+import org.netbeans.spi.java.hints.HintContext;
+import org.netbeans.spi.java.hints.TriggerPattern;
+import org.openide.util.NbBundle.Messages;
+
+@Hint(displayName = "#DN_CollectionRemove", description = "#DESC_CollectionRemove", category = "general")
+@Messages({
+    "DN_CollectionRemove=Collection Remove",
+    "DESC_CollectionRemove=Collection Remove"
+})
+public class CollectionRemove {
+
+    @TriggerPattern(value = "$collection.remove($val)",
+                    constraints = {
+                        @ConstraintVariableType(variable = "$collection", type = "java.util.Collection"),
+                        @ConstraintVariableType(variable = "$val", type = "java.lang.Object")
+                    })
+    public static ErrorDescription computeWarning(final HintContext ctx) {
+        TreePath collection = ctx.getVariables().get("$collection");
+        if (collection == null) return null;
+        
+        final ExecutableElement checkAgainst = Utilities.resolveMethod(ctx, "java.util.Collection.add(java.lang.Object)");
+        TypeMirror site = ctx.getInfo().getTrees().getTypeMirror(collection);
+
+        if (   site != null
+            && site.getKind() == TypeKind.DECLARED) {
+            TypeMirror actualMethodType = ctx.getInfo().getTypes().asMemberOf((DeclaredType) site, checkAgainst);
+            TypeMirror expectedType = ((ExecutableType) actualMethodType).getParameterTypes().get(0);
+
+            if (expectedType.getKind() == TypeKind.WILDCARD) {
+                expectedType = ((WildcardType) expectedType).getExtendsBound();
+                if (expectedType == null) {
+                    expectedType = ctx.getInfo().getElements().getTypeElement("java.lang.Object").asType();
+                }
+            }
+            
+            ExpressionTree argument = ((MethodInvocationTree) ctx.getPath().getLeaf()).getArguments().get(0);
+            TypeMirror actualType = ctx.getInfo().getTrees().getTypeMirror(new TreePath(ctx.getPath(), argument));
+
+            if (!ctx.getInfo().getTypes().isAssignable(actualType, expectedType)) {
+                return ErrorDescriptionFactory.forTree(ctx, argument, "Suspicious parameter type: " + actualType + ", should be assignable to: " + expectedType);
+            }
+        }
+
+        return null;
+    }
+
+}

File nb/src/j1/tutorial/javac/analysis/netbeans/Utilities.java

+package j1.tutorial.javac.analysis.netbeans;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.ElementFilter;
+import org.netbeans.spi.java.hints.HintContext;
+
+public class Utilities {
+    private static final Pattern SPLIT = Pattern.compile("(.+)\\.([^.]+)\\((.*)\\)");
+    
+    public static ExecutableElement resolveMethod(HintContext ctx, 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 = ctx.getInfo().getElements().getTypeElement(className);
+
+        if (te == null) {
+            return null;
+        }
+
+        String[] paramList = paramsSpec.split(",");
+        List<TypeMirror> params = new LinkedList<TypeMirror>();
+
+        for (String t : paramList) {
+            TypeElement param = ctx.getInfo().getElements().getTypeElement(t);
+            params.add(ctx.getInfo().getTypes().erasure(param.asType()));
+        }
+
+        for (ExecutableElement ee : ElementFilter.methodsIn(te.getEnclosedElements())) {
+            if (!methodName.equals(ee.getSimpleName().toString()) || ee.getParameters().size() != params.size()) {
+                continue;
+            }
+            
+            Iterator<TypeMirror> designed = params.iterator();
+            boolean found = true;
+
+            for (VariableElement param : ee.getParameters()) {
+                if (!ctx.getInfo().getTypes().isSameType(ctx.getInfo().getTypes().erasure(param.asType()), designed.next())) {
+                    found = false;
+                    break;
+                }
+            }
+
+            if (found) {
+                return ee;
+            }
+        }
+        
+        return null;
+    }
+    
+}

File nb/test/unit/src/j1/tutorial/javac/analysis/netbeans/CollectionRemoveTest.java

+package j1.tutorial.javac.analysis.netbeans;
+
+import org.junit.Test;
+import org.netbeans.junit.NbTestCase;
+import org.netbeans.modules.java.hints.test.api.HintTest;
+
+public class CollectionRemoveTest extends NbTestCase {
+    
+    public CollectionRemoveTest(String name) {
+        super(name);
+    }
+
+    @Test
+    public void testSimple1() throws Exception {
+        HintTest.create()
+                .input("package test;" +
+                       "public class Test {" +
+                       "    private void test () {" +
+                       "        java.util.List<String> l = null;" +
+                       "        l.remove(new Object());" +
+                       "    }" +
+                       "}")
+                .run(CollectionRemove.class)
+                .assertWarnings("0:115-0:127:verifier:Suspicious parameter type: java.lang.Object, should be assignable to: java.lang.String");
+    }
+
+    @Test
+    public void testSimple3() throws Exception {
+        HintTest.create()
+                .input("package test;" +
+                       "public class Test {" +
+                       "    private void test () {" +
+                       "        java.util.List<String> l = null;" +
+                       "        l.remove(Integer.valueOf(1));" +
+                       "    }" +
+                       "}")
+                .run(CollectionRemove.class)
+                .assertWarnings("0:115-0:133:verifier:Suspicious parameter type: java.lang.Integer, should be assignable to: java.lang.String");
+    }
+
+    @Test
+    public void testPass() throws Exception {
+        HintTest.create()
+                .input("package test;" +
+                       "public class Test {" +
+                       "    private void test () {" +
+                       "        java.util.List<String> l = null;" +
+                       "        l.remove(\"\");" +
+                       "    }" +
+                       "}")
+                .run(CollectionRemove.class)
+                .assertWarnings();
+    }
+    
+    @Test
+    public void testSuperWildcard() throws Exception {
+        HintTest.create()
+                .input("package test;" +
+                       "public class Test {" +
+                       "    private void test () {" +
+                       "        java.util.List<? super String> l = null;" +
+                       "        l.remove(\"\");" +
+                       "    }" +
+                       "}")
+                .run(CollectionRemove.class)
+                .assertWarnings();
+    }
+
+    @Test
+    public void testWildcard() throws Exception {
+        HintTest.create()
+                .input("package test;" +
+                       "public class Test {" +
+                       "    private void test () {" +
+                       "        java.util.List<?> l = null;" +
+                       "        l.remove(\"\");" +
+                       "    }" +
+                       "}")
+                .run(CollectionRemove.class)
+                .assertWarnings();
+    }
+
+    @Test
+    public void testCollectionRemoveInteger() throws Exception {
+        HintTest.create()
+                .input("package test;" +
+                       "public class Test {" +
+                       "    private void test () {" +
+                       "        java.util.List<String> l = null;" +
+                       "        l.remove(0);" +
+                       "    }" +
+                       "}")
+                .run(CollectionRemove.class)
+                .assertWarnings();
+    }
+
+    @Test
+    public void testCollectionRemoveInteger2() throws Exception {
+        HintTest.create()
+                .input("package test;" +
+                       "public class Test {" +
+                       "    private void test () {" +
+                       "        java.util.List<String> l = null;" +
+                       "        l.subList(0, 0).remove(0);" +
+                       "    }" +
+                       "}")
+                .run(CollectionRemove.class)
+                .assertWarnings();
+    }
+    
+    @Test
+    public void testCollectionRemoveError() throws Exception {
+        HintTest.create()
+                .input("package test;" +
+                       "public class Test {" +
+                       "    private void test () {" +
+                       "        Undefined l = null;" +
+                       "        l.remove(\"\");" +
+                       "    }" +
+                       "}", 
+                       false)
+                .run(CollectionRemove.class)
+                .assertWarnings();
+    }
+
+//    @Test
+//    public void testExtends1() throws Exception {
+//        HintTest.create()
+//                .input("package test;" +
+//                       "public class Test extends java.util.LinkedList<String> {" +
+//                       "    private void test () {" +
+//                       "        remove(new Object());" +
+//                       "    }" +
+//                       "}")
+//                .run(CollectionRemove.class)
+//                .assertWarnings("0:115-0:127:verifier:Suspicious parameter type: java.lang.Object, should be assignable to: java.lang.String");
+//    }
+//
+//    @Test
+//    public void testExtends2() throws Exception {
+//        HintTest.create()
+//                .input("package test;" +
+//                       "public class Test extends java.util.LinkedList<String> {" +
+//                       "    private void test () {" +
+//                       "        new Runnable() {" +
+//                       "            public void run() {" +
+//                       "                remove(new Object());" +
+//                       "            }" +
+//                       "        };" +
+//                       "    }" +
+//                       "}")
+//                .run(CollectionRemove.class)
+//                .assertWarnings("0:166-0:186:verifier:Suspicious parameter type: java.lang.Object, should be assignable to: java.lang.String");
+//    }
+//
+//    @Test
+//    public void testInsideItsOverride196606() throws Exception {
+//        HintTest.create()
+//                .input("package test;" +
+//                       "public class Test extends java.util.ArrayList<String> {" +
+//                       "    @Override public boolean remove(Object o) {" +
+//                       "        return super.remove(o);\n" +
+//                       "    }" +
+//                       "}")
+//                .run(CollectionRemove.class)
+//                .assertWarnings();
+//    }
+}