1.1 --- a/javahints/src/org/netbeans/modules/javahints/Bundle.properties Thu Apr 19 13:03:28 2012 -0400
1.2 +++ b/javahints/src/org/netbeans/modules/javahints/Bundle.properties Thu Apr 19 22:21:36 2012 +0200
1.3 @@ -130,6 +130,8 @@
1.4 FIX_ConvertAnonymousToInner=Convert Anonymous to Inner
1.5
1.6
1.7 +DN_NPECheck=Null Dereference
1.8 +DESC_NPECheck=Checks various problems related to dereferencing nulls
1.9 ERR_DereferencingNull=Dereferencing null
1.10 ERR_PossiblyDereferencingNull=Possibly Dereferencing null
1.11 ERR_AssigningNullToNotNull=Assigning Null to NotNull Variable
2.1 --- a/javahints/src/org/netbeans/modules/javahints/NPECheck.java Thu Apr 19 13:03:28 2012 -0400
2.2 +++ b/javahints/src/org/netbeans/modules/javahints/NPECheck.java Thu Apr 19 22:21:36 2012 +0200
2.3 @@ -1,7 +1,7 @@
2.4 /*
2.5 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
2.6 *
2.7 - * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
2.8 + * Copyright 1997-2012 Sun Microsystems, Inc. All rights reserved.
2.9 *
2.10 * The contents of this file are subject to the terms of either the GNU
2.11 * General Public License Version 2 only ("GPL") or the Common
2.12 @@ -23,42 +23,24 @@
2.13 *
2.14 * Contributor(s):
2.15 *
2.16 - * Portions Copyrighted 2007 Sun Microsystems, Inc.
2.17 + * Portions Copyrighted 2007-2012 Sun Microsystems, Inc.
2.18 */
2.19
2.20 package org.netbeans.modules.javahints;
2.21
2.22 -import com.sun.source.tree.AssignmentTree;
2.23 -import com.sun.source.tree.BinaryTree;
2.24 -import com.sun.source.tree.BreakTree;
2.25 -import com.sun.source.tree.ClassTree;
2.26 -import com.sun.source.tree.ConditionalExpressionTree;
2.27 -import com.sun.source.tree.ContinueTree;
2.28 -import com.sun.source.tree.IdentifierTree;
2.29 -import com.sun.source.tree.IfTree;
2.30 -import com.sun.source.tree.LiteralTree;
2.31 -import com.sun.source.tree.MemberSelectTree;
2.32 -import com.sun.source.tree.MethodInvocationTree;
2.33 -import com.sun.source.tree.NewClassTree;
2.34 -import com.sun.source.tree.ReturnTree;
2.35 -import com.sun.source.tree.ThrowTree;
2.36 -import com.sun.source.tree.Tree;
2.37 +import com.sun.source.tree.*;
2.38 import com.sun.source.tree.Tree.Kind;
2.39 -import com.sun.source.tree.VariableTree;
2.40 -import com.sun.source.tree.WhileLoopTree;
2.41 import com.sun.source.util.TreePath;
2.42 import com.sun.source.util.TreePathScanner;
2.43 import java.util.ArrayList;
2.44 -import java.util.Collections;
2.45 import java.util.EnumSet;
2.46 import java.util.HashMap;
2.47 import java.util.HashSet;
2.48 -import java.util.LinkedList;
2.49 +import java.util.IdentityHashMap;
2.50 import java.util.List;
2.51 import java.util.Map;
2.52 import java.util.Map.Entry;
2.53 import java.util.Set;
2.54 -import java.util.WeakHashMap;
2.55 import javax.lang.model.element.AnnotationMirror;
2.56 import javax.lang.model.element.Element;
2.57 import javax.lang.model.element.ElementKind;
2.58 @@ -66,83 +48,172 @@
2.59 import javax.lang.model.element.TypeElement;
2.60 import javax.lang.model.element.VariableElement;
2.61 import org.netbeans.api.java.source.CompilationInfo;
2.62 -import org.netbeans.api.java.source.SourceUtils;
2.63 -import org.netbeans.api.project.FileOwnerQuery;
2.64 -import org.netbeans.api.project.Project;
2.65 -import org.netbeans.api.project.ProjectUtils;
2.66 -import org.netbeans.modules.java.hints.spi.AbstractHint;
2.67 -import org.netbeans.modules.java.hints.spi.support.FixFactory;
2.68 import org.netbeans.spi.editor.hints.ErrorDescription;
2.69 -import org.netbeans.spi.editor.hints.ErrorDescriptionFactory;
2.70 -import org.netbeans.spi.editor.hints.Fix;
2.71 -import org.netbeans.spi.project.AuxiliaryConfiguration;
2.72 -import org.openide.filesystems.FileObject;
2.73 import org.openide.util.NbBundle;
2.74 -import org.w3c.dom.Node;
2.75 -import org.w3c.dom.NodeList;
2.76
2.77 import static org.netbeans.modules.javahints.NPECheck.State.*;
2.78 +import org.netbeans.spi.java.hints.*;
2.79
2.80 -/**
2.81 +/**XXX: null initializer to a non-null variable!
2.82 *
2.83 * @author lahvac
2.84 */
2.85 -public class NPECheck extends AbstractHint {
2.86 +@Hint(displayName="#DN_NPECheck", description="#DESC_NPECheck", category="bugs", enabled=false)
2.87 +public class NPECheck {
2.88
2.89 - public NPECheck() {
2.90 - super(false, true, HintSeverity.WARNING, "null");
2.91 + @TriggerPattern("$var = $expr")
2.92 + public static ErrorDescription assignment(HintContext ctx) {
2.93 + Element e = ctx.getInfo().getTrees().getElement(ctx.getVariables().get("$var"));
2.94 +
2.95 + if (e == null || !VARIABLE_ELEMENT.contains(e.getKind())) {
2.96 + return null;
2.97 + }
2.98 +
2.99 + TreePath expr = ctx.getVariables().get("$expr");
2.100 + State r = computeExpressionsState(ctx.getInfo()).get(expr.getLeaf());
2.101 +
2.102 + State elementState = getStateFromAnnotations(e);
2.103 +
2.104 + if (elementState != null && elementState.isNotNull()) {
2.105 + String key = null;
2.106 +
2.107 + if (r == NULL) {
2.108 + key = "ERR_AssigningNullToNotNull";
2.109 + }
2.110 +
2.111 + if (r == POSSIBLE_NULL_REPORT) {
2.112 + key = "ERR_PossibleAssigingNullToNotNull";
2.113 + }
2.114 +
2.115 + if (key != null) {
2.116 + return ErrorDescriptionFactory.forTree(ctx, ctx.getPath(), NbBundle.getMessage(NPECheck.class, key));
2.117 + }
2.118 + }
2.119 +
2.120 + return null;
2.121 + }
2.122 +
2.123 + @TriggerPattern("$select.$variable")
2.124 + public static ErrorDescription memberSelect(HintContext ctx) {
2.125 + TreePath select = ctx.getVariables().get("$select");
2.126 + State r = computeExpressionsState(ctx.getInfo()).get(select.getLeaf());
2.127 +
2.128 + if (r == State.NULL) {
2.129 + String displayName = NbBundle.getMessage(NPECheck.class, "ERR_DereferencingNull");
2.130 +
2.131 + return ErrorDescriptionFactory.forName(ctx, ctx.getPath(), displayName);
2.132 + }
2.133 +
2.134 + if (r == State.POSSIBLE_NULL_REPORT) {
2.135 + String displayName = NbBundle.getMessage(NPECheck.class, "ERR_PossiblyDereferencingNull");
2.136 +
2.137 + return ErrorDescriptionFactory.forName(ctx, ctx.getPath(), displayName);
2.138 + }
2.139 +
2.140 + return null;
2.141 + }
2.142 +
2.143 + @TriggerTreeKind(Kind.METHOD_INVOCATION)
2.144 + public static List<ErrorDescription> methodInvocation(HintContext ctx) {
2.145 + MethodInvocationTree mit = (MethodInvocationTree) ctx.getPath().getLeaf();
2.146 + List<State> paramStates = new ArrayList<State>(mit.getArguments().size());
2.147 + Map<Tree, State> expressionsState = computeExpressionsState(ctx.getInfo());
2.148 +
2.149 + for (Tree param : mit.getArguments()) {
2.150 + State r = expressionsState.get(param);
2.151 + paramStates.add(r != null ? r : State.POSSIBLE_NULL);
2.152 + }
2.153 +
2.154 + Element e = ctx.getInfo().getTrees().getElement(ctx.getPath());
2.155 +
2.156 + if (e == null || e.getKind() != ElementKind.METHOD) {
2.157 + return null;
2.158 + }
2.159 +
2.160 + ExecutableElement ee = (ExecutableElement) e;
2.161 + int index = 0;
2.162 + List<ErrorDescription> result = new ArrayList<ErrorDescription>();
2.163 +
2.164 + for (VariableElement param : ee.getParameters()) {
2.165 + if (getStateFromAnnotations(param) == NOT_NULL) {
2.166 + switch (paramStates.get(index)) {
2.167 + case NULL:
2.168 + result.add(ErrorDescriptionFactory.forTree(ctx, mit.getArguments().get(index), NbBundle.getMessage(NPECheck.class, "ERR_NULL_TO_NON_NULL_ARG")));
2.169 + break;
2.170 + case POSSIBLE_NULL_REPORT:
2.171 + result.add(ErrorDescriptionFactory.forTree(ctx, mit.getArguments().get(index), NbBundle.getMessage(NPECheck.class, "ERR_POSSIBLENULL_TO_NON_NULL_ARG")));
2.172 + break;
2.173 + }
2.174 + }
2.175 + }
2.176 +
2.177 + return result;
2.178 + }
2.179 +
2.180 + private static final Object KEY_EXPRESSION_STATE = new Object();
2.181 + //Cancelling:
2.182 + private static Map<Tree, State> computeExpressionsState(CompilationInfo info) {
2.183 + Map<Tree, State> result = (Map<Tree, State>) info.getCachedValue(KEY_EXPRESSION_STATE);
2.184 +
2.185 + if (result != null) {
2.186 + return result;
2.187 + }
2.188 +
2.189 + VisitorImpl v = new VisitorImpl(info);
2.190 +
2.191 + v.scan(info.getCompilationUnit(), null);
2.192 +
2.193 + info.putCachedValue(KEY_EXPRESSION_STATE, result = v.expressionState, CompilationInfo.CacheClearPolicy.ON_TASK_END);
2.194 +
2.195 + return result;
2.196 + }
2.197 +
2.198 + private static State getStateFromAnnotations(Element e) {
2.199 + return getStateFromAnnotations(e, State.POSSIBLE_NULL);
2.200 }
2.201
2.202 - @Override
2.203 - public String getDescription() {
2.204 - return "NPE";
2.205 + private static State getStateFromAnnotations(Element e, State def) {
2.206 + for (AnnotationMirror am : e.getAnnotationMirrors()) {
2.207 + String simpleName = ((TypeElement) am.getAnnotationType().asElement()).getSimpleName().toString();
2.208 +
2.209 + if ("Nullable".equals(simpleName) || "NullAllowed".equals(simpleName)) {
2.210 + return State.POSSIBLE_NULL_REPORT;
2.211 + }
2.212 +
2.213 + if ("CheckForNull".equals(simpleName)) {
2.214 + return State.POSSIBLE_NULL_REPORT;
2.215 + }
2.216 +
2.217 + if ("NotNull".equals(simpleName) || "NonNull".equals(simpleName)) {
2.218 + return State.NOT_NULL;
2.219 + }
2.220 + }
2.221 +
2.222 + return def;
2.223 }
2.224 -
2.225 - public Set<Kind> getTreeKinds() {
2.226 - return EnumSet.of(Kind.METHOD);
2.227 - }
2.228 -
2.229 - public List<ErrorDescription> run(CompilationInfo compilationInfo, TreePath treePath) {
2.230 - VisitorImpl v = new VisitorImpl(compilationInfo);
2.231
2.232 - v.scan(treePath, null);
2.233 + private static final class VisitorImpl extends TreePathScanner<State, Void> {
2.234
2.235 - return v.warnings;
2.236 - }
2.237 -
2.238 - public String getId() {
2.239 - return NPECheck.class.getName();
2.240 - }
2.241 -
2.242 - public String getDisplayName() {
2.243 - return "NPE";
2.244 - }
2.245 -
2.246 - public void cancel() {
2.247 - }
2.248 -
2.249 - private final class VisitorImpl extends TreePathScanner<State, Void> {
2.250 -
2.251 - private CompilationInfo info;
2.252 - private List<ErrorDescription> warnings;
2.253 -
2.254 + private final CompilationInfo info;
2.255 private Map<VariableElement, State> variable2State = new HashMap<VariableElement, NPECheck.State>();
2.256 private Map<VariableElement, State> testedTo = new HashMap<VariableElement, NPECheck.State>();
2.257 + private final Map<Tree, State> expressionState = new IdentityHashMap<Tree, State>();
2.258
2.259 public VisitorImpl(CompilationInfo info) {
2.260 this.info = info;
2.261 - this.warnings = new LinkedList<ErrorDescription>();
2.262 }
2.263
2.264 - private void report(TreePath path, String key) {
2.265 - long start = info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), path.getLeaf());
2.266 - long end = info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), path.getLeaf());
2.267 + @Override
2.268 + public State scan(Tree tree, Void p) {
2.269 + State r = super.scan(tree, p);
2.270 +
2.271 + if (r != null) {
2.272 + expressionState.put(tree, r);
2.273 + }
2.274 +
2.275 + return r;
2.276 + }
2.277
2.278 - String displayName = NbBundle.getMessage(NPECheck.class, key);
2.279 - List<Fix> fixes = FixFactory.createSuppressWarnings(info, path, "null");
2.280 - warnings.add(ErrorDescriptionFactory.createErrorDescription(getSeverity().toEditorSeverity(), displayName, fixes, info.getFileObject(), (int) start, (int) end));
2.281 - }
2.282 -
2.283 @Override
2.284 public State visitAssignment(AssignmentTree node, Void p) {
2.285 Element e = info.getTrees().getElement(new TreePath(getCurrentPath(), node.getVariable()));
2.286 @@ -157,24 +228,6 @@
2.287
2.288 scan(node.getVariable(), p);
2.289
2.290 - State elementState = getStateFromAnnotations(e);
2.291 -
2.292 - if (elementState != null && elementState.isNotNull()) {
2.293 - String key = null;
2.294 -
2.295 - if (r == NULL) {
2.296 - key = "ERR_AssigningNullToNotNull";
2.297 - }
2.298 -
2.299 - if (r == POSSIBLE_NULL_REPORT) {
2.300 - key = "ERR_PossibleAssigingNullToNotNull";
2.301 - }
2.302 -
2.303 - if (key != null) {
2.304 - report(getCurrentPath(), key);
2.305 - }
2.306 - }
2.307 -
2.308 return r;
2.309 }
2.310
2.311 @@ -196,37 +249,29 @@
2.312 @Override
2.313 public State visitMemberSelect(MemberSelectTree node, Void p) {
2.314 State expr = scan(node.getExpression(), p);
2.315 -
2.316 - long start = info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), node);
2.317 - long end = info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), node);
2.318 -
2.319 boolean wasNPE = false;
2.320
2.321 if (expr == State.NULL) {
2.322 - String displayName = NbBundle.getMessage(NPECheck.class, "ERR_DereferencingNull");
2.323 - List<Fix> fixes = FixFactory.createSuppressWarnings(info, getCurrentPath(), "null");
2.324 - warnings.add(ErrorDescriptionFactory.createErrorDescription(getSeverity().toEditorSeverity(), displayName, fixes, info.getFileObject(), (int) start, (int) end));
2.325 -
2.326 wasNPE = true;
2.327 }
2.328
2.329 if (expr == State.POSSIBLE_NULL_REPORT) {
2.330 - String displayName = NbBundle.getMessage(NPECheck.class, "ERR_PossiblyDereferencingNull");
2.331 - List<Fix> fixes = FixFactory.createSuppressWarnings(info, getCurrentPath(), "null");
2.332 - warnings.add(ErrorDescriptionFactory.createErrorDescription(getSeverity().toEditorSeverity(), displayName, fixes, info.getFileObject(), (int) start, (int) end));
2.333 -
2.334 wasNPE = true;
2.335 }
2.336
2.337 - if (wasNPE) {
2.338 - Element e = info.getTrees().getElement(new TreePath(getCurrentPath(), node.getExpression()));
2.339 + Element e = info.getTrees().getElement(new TreePath(getCurrentPath(), node.getExpression()));
2.340 +
2.341 + if (isVariableElement(e)) {
2.342 + State r = getStateFromAnnotations(e);
2.343
2.344 - if (isVariableElement(e)) {
2.345 + if (wasNPE) {
2.346 variable2State.put((VariableElement) e, NOT_NULL_BE_NPE);
2.347 }
2.348 +
2.349 + return r;
2.350 }
2.351
2.352 - return super.visitMemberSelect(node, p);
2.353 + return State.POSSIBLE_NULL;
2.354 }
2.355
2.356 @Override
2.357 @@ -484,12 +529,10 @@
2.358 @Override
2.359 public State visitMethodInvocation(MethodInvocationTree node, Void p) {
2.360 scan(node.getTypeArguments(), p);
2.361 -
2.362 - State methodSelectState = scan(node.getMethodSelect(), p);
2.363 - List<State> paramStates = new ArrayList<State>(node.getArguments().size());
2.364 + scan(node.getMethodSelect(), p);
2.365
2.366 for (Tree param : node.getArguments()) {
2.367 - paramStates.add(scan(param, p));
2.368 + scan(param, p);
2.369 }
2.370
2.371 Element e = info.getTrees().getElement(getCurrentPath());
2.372 @@ -498,22 +541,6 @@
2.373 return State.POSSIBLE_NULL;
2.374 }
2.375
2.376 - ExecutableElement ee = (ExecutableElement) e;
2.377 - int index = 0;
2.378 -
2.379 - for (VariableElement param : ee.getParameters()) {
2.380 - if (getStateFromAnnotations(param) == NOT_NULL) {
2.381 - switch (paramStates.get(index)) {
2.382 - case NULL:
2.383 - report(new TreePath(getCurrentPath(), node.getArguments().get(index)), "ERR_NULL_TO_NON_NULL_ARG");
2.384 - break;
2.385 - case POSSIBLE_NULL_REPORT:
2.386 - report(new TreePath(getCurrentPath(), node.getArguments().get(index)), "ERR_POSSIBLENULL_TO_NON_NULL_ARG");
2.387 - break;
2.388 - }
2.389 - }
2.390 - }
2.391 -
2.392 return getStateFromAnnotations(e);
2.393 }
2.394
2.395 @@ -569,48 +596,8 @@
2.396 return null;
2.397 }
2.398
2.399 - private State getStateFromAnnotations(Element e) {
2.400 - return getStateFromAnnotations(e, State.POSSIBLE_NULL);
2.401 - }
2.402 -
2.403 - private State getStateFromAnnotations(Element e, State def) {
2.404 - for (AnnotationMirror am : e.getAnnotationMirrors()) {
2.405 - String simpleName = ((TypeElement) am.getAnnotationType().asElement()).getSimpleName().toString();
2.406 -
2.407 - if ("Nullable".equals(simpleName)) {
2.408 - return State.POSSIBLE_NULL_REPORT;
2.409 - }
2.410 -
2.411 - if ("CheckForNull".equals(simpleName)) {
2.412 - return State.POSSIBLE_NULL_REPORT;
2.413 - }
2.414 -
2.415 - if ("NotNull".equals(simpleName)) {
2.416 - return State.NOT_NULL;
2.417 - }
2.418 - }
2.419 -
2.420 - if (e.getKind() == ElementKind.METHOD) {
2.421 - String fqn = getFQN((ExecutableElement) e);
2.422 - Project owner = findProject(info, e);
2.423 -
2.424 - if (owner != null && findCheckForNullNames(owner).contains(fqn)) {
2.425 - return State.POSSIBLE_NULL_REPORT;
2.426 - }
2.427 - }
2.428 -
2.429 - return def;
2.430 - }
2.431 }
2.432
2.433 - private String getFQN(ExecutableElement ee) {
2.434 - TypeElement te = (TypeElement) ee.getEnclosingElement();
2.435 -
2.436 - return te.getQualifiedName().toString() + "." + ee.getSimpleName().toString();
2.437 - }
2.438 -
2.439 - private static final Set<ElementKind> LOCAL_VARIABLES = EnumSet.of(ElementKind.EXCEPTION_PARAMETER, ElementKind.LOCAL_VARIABLE, ElementKind.PARAMETER);
2.440 -
2.441 static enum State {
2.442 NULL,
2.443 POSSIBLE_NULL,
2.444 @@ -695,56 +682,6 @@
2.445
2.446 }
2.447
2.448 - private static final Map<TypeElement, Project> class2Project = new WeakHashMap<TypeElement, Project>();
2.449 -
2.450 - private static Project findProject(CompilationInfo info, Element e) {
2.451 - TypeElement owner = info.getElementUtilities().outermostTypeElement(e);
2.452 -
2.453 - if (owner == null) return null;
2.454 -
2.455 - Project p = class2Project.get(owner);
2.456 -
2.457 - if (p == null) {
2.458 - FileObject source = SourceUtils.getFile(e, info.getClasspathInfo());
2.459 -
2.460 - if (source != null) {
2.461 - p = FileOwnerQuery.getOwner(source);
2.462 -
2.463 - if (p != null) {
2.464 - class2Project.put(owner, p);
2.465 - }
2.466 - }
2.467 - }
2.468 -
2.469 - return p;
2.470 - }
2.471 -
2.472 - private static final Map<Project, Set<String>> project2CheckForNullNames = new WeakHashMap<Project, Set<String>>();
2.473 -
2.474 - private static Set<String> findCheckForNullNames(Project p) {
2.475 - Set<String> set = project2CheckForNullNames.get(p);
2.476 -
2.477 - if (set == null) {
2.478 - project2CheckForNullNames.put(p, set = new HashSet<String>());
2.479 - AuxiliaryConfiguration ac = ProjectUtils.getAuxiliaryConfiguration(p);
2.480 -
2.481 - if (ac != null) {
2.482 - org.w3c.dom.Element configurationFragment = ac.getConfigurationFragment("npe-check-hints", "http://www.netbeans.org/ns/npe-check-hints/1", true);
2.483 -
2.484 - if (configurationFragment != null) {
2.485 - NodeList nl = configurationFragment.getElementsByTagName("check-for-null");
2.486 -
2.487 - for (int cntr = 0; cntr < nl.getLength(); cntr++) {
2.488 - Node n = nl.item(cntr);
2.489 - set.add(n.getTextContent());
2.490 - }
2.491 - }
2.492 - }
2.493 - }
2.494 -
2.495 - return set;
2.496 - }
2.497 -
2.498 private static boolean isVariableElement(Element ve) {
2.499 return ve != null && VARIABLE_ELEMENT.contains(ve.getKind());
2.500 }
3.1 --- a/javahints/test/unit/src/org/netbeans/modules/javahints/NPECheckTest.java Thu Apr 19 13:03:28 2012 -0400
3.2 +++ b/javahints/test/unit/src/org/netbeans/modules/javahints/NPECheckTest.java Thu Apr 19 22:21:36 2012 +0200
3.3 @@ -1,7 +1,7 @@
3.4 /*
3.5 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3.6 *
3.7 - * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
3.8 + * Copyright 1997-2012 Sun Microsystems, Inc. All rights reserved.
3.9 *
3.10 * The contents of this file are subject to the terms of either the GNU
3.11 * General Public License Version 2 only ("GPL") or the Common
3.12 @@ -23,88 +23,92 @@
3.13 *
3.14 * Contributor(s):
3.15 *
3.16 - * Portions Copyrighted 2007 Sun Microsystems, Inc.
3.17 + * Portions Copyrighted 2007-2012 Sun Microsystems, Inc.
3.18 */
3.19
3.20 package org.netbeans.modules.javahints;
3.21
3.22 -import com.sun.source.util.TreePath;
3.23 -import java.util.List;
3.24 -import org.netbeans.api.java.source.CompilationInfo;
3.25 -import org.netbeans.modules.java.hints.infrastructure.TreeRuleTestBase;
3.26 -import org.netbeans.spi.editor.hints.ErrorDescription;
3.27 -import org.openide.util.NbBundle;
3.28 +import org.netbeans.junit.NbTestCase;
3.29 +import org.netbeans.modules.java.hints.test.api.HintTest;
3.30
3.31 /**
3.32 *
3.33 * @author lahvac
3.34 */
3.35 -public class NPECheckTest extends TreeRuleTestBase {
3.36 +public class NPECheckTest extends NbTestCase {
3.37
3.38 public NPECheckTest(String testName) {
3.39 super(testName);
3.40 }
3.41
3.42 public void testSimpleNull1() throws Exception {
3.43 - performAnalysisTest("test/Test.java", "package test; class Test {private void te|st() {Object o; o = null; o.toString();}}", "0:67-0:77:verifier:DN");
3.44 + performAnalysisTest("test/Test.java", "package test; class Test {private void test() {Object o; o = null; o.toString();}}", "0:69-0:77:verifier:DN");
3.45 }
3.46
3.47 public void testSimpleNull2() throws Exception {
3.48 - performAnalysisTest("test/Test.java", "package test; class Test {private void te|st() {Object o = null; o.toString();}}", "0:64-0:74:verifier:DN");
3.49 + performAnalysisTest("test/Test.java", "package test; class Test {private void test() {Object o = null; o.toString();}}", "0:66-0:74:verifier:DN");
3.50 }
3.51
3.52 public void testIf1() throws Exception {
3.53 - performAnalysisTest("test/Test.java", "package test; class Test {private void te|st(Object o) {if (o == null) {o.toString();}}}", "0:71-0:81:verifier:DN");
3.54 + performAnalysisTest("test/Test.java", "package test; class Test {private void test(Object o) {if (o == null) {o.toString();}}}", "0:73-0:81:verifier:DN");
3.55 }
3.56
3.57 public void testIf2() throws Exception {
3.58 - performAnalysisTest("test/Test.java", "package test; class Test {private void te|st(Object o) {if (o == null) {o = \"\";} o.length();}}");
3.59 + HintTest.create()
3.60 + .input("package test; class Test {private void test(Object o) {if (o == null) {o = \"\";} o.length();}}", false)
3.61 + .run(NPECheck.class)
3.62 + .assertWarnings();
3.63 }
3.64
3.65 public void testIf3() throws Exception {
3.66 - performAnalysisTest("test/Test.java", "package test; class Test {private void te|st() {String s = null; if (s == null) {s = \"\";} s.length();}}");
3.67 + performAnalysisTest("test/Test.java", "package test; class Test {private void test() {String s = null; if (s == null) {s = \"\";} s.length();}}");
3.68 }
3.69
3.70 public void testIf4() throws Exception {
3.71 - performAnalysisTest("test/Test.java", "package test; class Test {private void te|st() {String s = null; if (s == null) {s = \"\";} else {s = \"\";} s.length();}}");
3.72 + performAnalysisTest("test/Test.java", "package test; class Test {private void test() {String s = null; if (s == null) {s = \"\";} else {s = \"\";} s.length();}}");
3.73 }
3.74
3.75 public void testIf5() throws Exception {
3.76 - performAnalysisTest("test/Test.java", "package test; class Test {private void te|st() {String s = null; if (s == null) {s = \"\";} else {s = null;} s.length();}}", "0:106-0:114:verifier:Possibly Dereferencing null");
3.77 + performAnalysisTest("test/Test.java", "package test; class Test {private void test() {String s = null; if (s == null) {s = \"\";} else {s = null;} s.length();}}", "0:108-0:114:verifier:Possibly Dereferencing null");
3.78 }
3.79
3.80 public void testIf6() throws Exception {
3.81 - performAnalysisTest("test/Test.java", "package test; class Test {private void te|st(Object o) {if (null == o) {o.toString();}}}", "0:71-0:81:verifier:DN");
3.82 + performAnalysisTest("test/Test.java", "package test; class Test {private void test(Object o) {if (null == o) {o.toString();}}}", "0:73-0:81:verifier:DN");
3.83 }
3.84
3.85 public void testIf7() throws Exception {
3.86 - performAnalysisTest("test/Test.java", "package test; class Test {private void te|st() {String o = null; if (o != null) {o.toString();}}}");
3.87 + performAnalysisTest("test/Test.java", "package test; class Test {private void test() {String o = null; if (o != null) {o.toString();}}}");
3.88 }
3.89
3.90 public void testIf8() throws Exception {
3.91 - performAnalysisTest("test/Test.java", "package test; class Test {private void te|st() {String o = null; if (null != o) {o.toString();}}}");
3.92 + performAnalysisTest("test/Test.java", "package test; class Test {private void test() {String o = null; if (null != o) {o.toString();}}}");
3.93 }
3.94
3.95 public void testIf9() throws Exception {
3.96 - performAnalysisTest("test/Test.java",
3.97 - "package test; class Test {private void te|st(String s) {if (s == null) {} s.length();}}}",
3.98 - "0:73-0:81:verifier:Possibly Dereferencing null");
3.99 + HintTest.create()
3.100 + .input("package test; class Test {private void test(String s) {if (s == null) {} s.length();}}")
3.101 + .run(NPECheck.class)
3.102 + .assertWarnings("0:75-0:81:verifier:Possibly Dereferencing null");
3.103 }
3.104
3.105 public void testIfa() throws Exception {
3.106 - performAnalysisTest("test/Test.java",
3.107 - "package test; class Test {private void te|st(String s1, String s2) {if (s1 == null) {s1 = s2;} s1.length();}}}");
3.108 + HintTest.create()
3.109 + .input("package test; class Test {private void test(String s1, String s2) {if (s1 == null) {s1 = s2;} s1.length();}}")
3.110 + .run(NPECheck.class)
3.111 + .assertWarnings();
3.112 }
3.113
3.114 public void testIfb() throws Exception {
3.115 - performAnalysisTest("test/Test.java",
3.116 - "package test; class Test {private void te|st(@Null String s) {if (s == null) {throw new UnsupportedOperationException();} s.length();}} @interface Null {}}");
3.117 + HintTest.create()
3.118 + .input("package test; class Test {private void test(@Null String s) {if (s == null) {throw new UnsupportedOperationException();} s.length();}} @interface Null {}")
3.119 + .run(NPECheck.class)
3.120 + .assertWarnings();
3.121 }
3.122
3.123 public void testIfc() throws Exception {
3.124 performAnalysisTest("test/Test.java",
3.125 "package test; class Test {\n"+
3.126 - " private void te|st(int i, @CheckForNull String o) {\n" +
3.127 + " private void test(int i, @CheckForNull String o) {\n" +
3.128 " if (i > 2 && o != null && o.length() > 2) {\n" +
3.129 " }\n" +
3.130 " }\n" +
3.131 @@ -119,24 +123,24 @@
3.132 " }\n" +
3.133 " }\n" +
3.134 " @interface CheckForNull{}\n" +
3.135 - "}\n", 42);
3.136 + "}\n");
3.137 }
3.138
3.139 public void testTernary1() throws Exception {
3.140 - performAnalysisTest("test/Test.java", "package test; class Test {private void te|st(int i) {String s = i == 0 ? \"\" : null; s.length();}}");
3.141 + performAnalysisTest("test/Test.java", "package test; class Test {private void test(int i) {String s = i == 0 ? \"\" : null; s.length();}}");
3.142 }
3.143
3.144 public void testTernary2() throws Exception {
3.145 performAnalysisTest("test/Test.java",
3.146 - "package test; class Test {private void te|st(String s) {Object o = s == null ? \"\" : s; s = s.toString();}}",
3.147 - "0:90-0:100:verifier:Possibly Dereferencing null");
3.148 + "package test; class Test {private void test(String s) {Object o = s == null ? \"\" : s; s = s.toString();}}",
3.149 + "0:92-0:100:verifier:Possibly Dereferencing null");
3.150 }
3.151
3.152 public void testTernary3() throws Exception {
3.153 performAnalysisTest("test/Test.java",
3.154 "package test;\n" +
3.155 "class Test {\n" +
3.156 - " public void te|st() {" +
3.157 + " public void test() {" +
3.158 " String e = null;" +
3.159 " String f = e == null ? \"\" : e.trim();" +
3.160 " }" +
3.161 @@ -144,66 +148,66 @@
3.162 }
3.163
3.164 public void testNewClass() throws Exception {
3.165 - performAnalysisTest("test/Test.java", "package test; class Test {private void te|st() {String s = null; if (s == null) {s = new String(\"\");} s.length();}}");
3.166 + performAnalysisTest("test/Test.java", "package test; class Test {private void test() {String s = null; if (s == null) {s = new String(\"\");} s.length();}}");
3.167 }
3.168
3.169 public void testCheckForNull1() throws Exception {
3.170 - performAnalysisTest("test/Test.java", "package test; class Test {private void te|st() {String s = get(); s.length();} @Nullable private String get() {return \"\";} @interface Nullable {}}", "0:65-0:73:verifier:Possibly Dereferencing null");
3.171 + performAnalysisTest("test/Test.java", "package test; class Test {private void test() {String s = get(); s.length();} @Nullable private String get() {return \"\";} @interface Nullable {}}", "0:67-0:73:verifier:Possibly Dereferencing null");
3.172 }
3.173
3.174 public void testCheckForNull2() throws Exception {
3.175 - performAnalysisTest("test/Test.java", "package test; class Test {private void te|st() {s.length();} @Nullable private String s; @interface Nullable {}}", "0:47-0:55:verifier:Possibly Dereferencing null");
3.176 + performAnalysisTest("test/Test.java", "package test; class Test {private void test() {s.length();} @Nullable private String s; @interface Nullable {}}", "0:49-0:55:verifier:Possibly Dereferencing null");
3.177 }
3.178
3.179 public void testAssignNullToNotNull() throws Exception {
3.180 - performAnalysisTest("test/Test.java", "package test; class Test {private void te|st() {s = null;} @NotNull private String s; @interface NotNull {}}", "0:47-0:55:verifier:ANNNV");
3.181 + performAnalysisTest("test/Test.java", "package test; class Test {private void test() {s = null;} @NotNull private String s; @interface NotNull {}}", "0:47-0:55:verifier:ANNNV");
3.182 }
3.183
3.184 public void testPossibleAssignNullToNotNull() throws Exception {
3.185 - performAnalysisTest("test/Test.java", "package test; class Test {private void te|st(int i) {String s2 = null; if (i == 0) {s2 = \"\";} s = s2;} @NotNull private String s; @interface NotNull {}}", "0:93-0:99:verifier:PANNNV");
3.186 + performAnalysisTest("test/Test.java", "package test; class Test {private void test(int i) {String s2 = null; if (i == 0) {s2 = \"\";} s = s2;} @NotNull private String s; @interface NotNull {}}", "0:93-0:99:verifier:PANNNV");
3.187 }
3.188
3.189 public void testNullCheckAnd1() throws Exception {
3.190 - performAnalysisTest("test/Test.java", "package test; class Test {private void te|st() {String s = null; if (s != null && s.length() > 0) {}}}");
3.191 + performAnalysisTest("test/Test.java", "package test; class Test {private void test() {String s = null; if (s != null && s.length() > 0) {}}}");
3.192 }
3.193
3.194 public void testNullCheckAnd2() throws Exception {
3.195 - performAnalysisTest("test/Test.java", "package test; class Test {private void te|st() {String s = null; if (s == null && s.length() > 0) {}}}", "0:81-0:89:verifier:DN");
3.196 + performAnalysisTest("test/Test.java", "package test; class Test {private void test() {String s = null; if (s == null && s.length() > 0) {}}}", "0:83-0:89:verifier:DN");
3.197 }
3.198
3.199 public void testNullCheckOr1() throws Exception {
3.200 - performAnalysisTest("test/Test.java", "package test; class Test {private void test() {String s = null; if (s != null || s.length() > 0) {}}}", 89 - 48, "0:81-0:89:verifier:DN");
3.201 + performAnalysisTest("test/Test.java", "package test; class Test {private void test() {String s = null; if (s != null || s.length() > 0) {}}}", "0:83-0:89:verifier:DN");
3.202 }
3.203
3.204 public void testNullCheckOr2() throws Exception {
3.205 - performAnalysisTest("test/Test.java", "package test; class Test {private void test() {String s = null; if (s == null || s.length() > 0) {}}}", 89 - 48);
3.206 + performAnalysisTest("test/Test.java", "package test; class Test {private void test() {String s = null; if (s == null || s.length() > 0) {}}}");
3.207 }
3.208
3.209 public void testContinue1() throws Exception {
3.210 performAnalysisTest("test/Test.java",
3.211 - "package test; class Test {private void te|st(String[] sa) {for (String s : sa) {if (s == null) continue; s.length();}}}");
3.212 + "package test; class Test {private void test(String[] sa) {for (String s : sa) {if (s == null) continue; s.length();}}}");
3.213 }
3.214
3.215 public void testCondition1() throws Exception {
3.216 performAnalysisTest("test/Test.java",
3.217 - "package test; class Test {private void test(String sa) {boolean b = sa != null && (sa.length() == 0 || sa.length() == 1);}}", 71 - 30);
3.218 + "package test; class Test {private void test(String sa) {boolean b = sa != null && (sa.length() == 0 || sa.length() == 1);}}");
3.219 }
3.220
3.221 public void testCondition2() throws Exception {
3.222 performAnalysisTest("test/Test.java",
3.223 - "package test; class Test {private void test(String sa) {boolean b = sa == null || (sa.length() == 0 && sa.length() == 1);}}", 71 - 30);
3.224 + "package test; class Test {private void test(String sa) {boolean b = sa == null || (sa.length() == 0 && sa.length() == 1);}}");
3.225 }
3.226
3.227 public void testCondition3() throws Exception {
3.228 performAnalysisTest("test/Test.java",
3.229 - "package test; class Test {private void te|st(int i) {Object o2 = i < 1 ? null : \"\"; boolean b = true && o2 != null && o2.toString() != \"\";}}");
3.230 + "package test; class Test {private void test(int i) {Object o2 = i < 1 ? null : \"\"; boolean b = true && o2 != null && o2.toString() != \"\";}}");
3.231 }
3.232
3.233 public void testWhileAndIf() throws Exception {
3.234 performAnalysisTest("test/Test.java",
3.235 "package test;\n" +
3.236 "class Test {\n" +
3.237 - " private void tes|t(int i, boolean b, Object o2) {\n" +
3.238 + " private void test(int i, boolean b, Object o2) {\n" +
3.239 " Object o = null;\n" +
3.240 " while (--i > 0) {\n" +
3.241 " if (b) {\n" +
3.242 @@ -213,28 +217,28 @@
3.243 " o.toString();\n" +
3.244 " }" +
3.245 "}",
3.246 - "9:8-9:18:verifier:DN");
3.247 + "9:10-9:18:verifier:DN");
3.248 }
3.249
3.250 public void testWhile1() throws Exception {
3.251 performAnalysisTest("test/Test.java",
3.252 "package test;\n" +
3.253 "class Test {\n" +
3.254 - " private void tes|t(String o) {\n" +
3.255 + " private void test(String o) {\n" +
3.256 " while (o != null && o.length() > 1) {\n" +
3.257 " o = o.substring(1);\n" +
3.258 " }\n" +
3.259 " o.toString();\n" +
3.260 " }" +
3.261 "}",
3.262 - "6:8-6:18:verifier:Possibly Dereferencing null");
3.263 + "6:10-6:18:verifier:Possibly Dereferencing null");
3.264 }
3.265
3.266 public void testWhile2() throws Exception {
3.267 performAnalysisTest("test/Test.java",
3.268 "package test;\n" +
3.269 "class Test {\n" +
3.270 - " private void tes|t(@CheckForNull String o) {\n" +
3.271 + " private void test(@CheckForNull String o) {\n" +
3.272 " while (o != null) {\n" +
3.273 " o = o.substring(1);\n" +
3.274 " }\n" +
3.275 @@ -245,13 +249,13 @@
3.276
3.277 public void testParameter1() throws Exception {
3.278 performAnalysisTest("test/Test.java",
3.279 - "package test; class Test {private void te|st(int i) {String s = null; ttt(s);} private void ttt(@NotNull String s){}} @interface NotNull {}",
3.280 + "package test; class Test {private void test(int i) {String s = null; ttt(s);} private void ttt(@NotNull String s){}} @interface NotNull {}",
3.281 "0:73-0:74:verifier:ERR_NULL_TO_NON_NULL_ARG");
3.282 }
3.283
3.284 public void testParameter2() throws Exception {
3.285 performAnalysisTest("test/Test.java",
3.286 - "package test; class Test {private void te|st(int i) {ttt(t());} private void ttt(@NotNull String s){} private @CheckForNull String t() {return \"\";} } @interface NotNull {} @interface CheckForNull {}",
3.287 + "package test; class Test {private void test(int i) {ttt(t());} private void ttt(@NotNull String s){} private @CheckForNull String t() {return \"\";} } @interface NotNull {} @interface CheckForNull {}",
3.288 "0:56-0:59:verifier:ERR_POSSIBLENULL_TO_NON_NULL_ARG");
3.289 }
3.290
3.291 @@ -259,64 +263,64 @@
3.292 performAnalysisTest("test/Test.java",
3.293 "package test;\n" +
3.294 "class Test {\n" +
3.295 - " private void tes|t(@CheckForNull String o) {\n" +
3.296 + " private void test(@CheckForNull String o) {\n" +
3.297 " o.toString();\n" +
3.298 " o.toString();\n" +
3.299 " o.toString();\n" +
3.300 " }" +
3.301 " @interface CheckForNull {}\n" +
3.302 - "}", "3:8-3:18:verifier:Possibly Dereferencing null");
3.303 + "}", "3:10-3:18:verifier:Possibly Dereferencing null");
3.304 }
3.305
3.306 public void testNoMultipleReports2() throws Exception {
3.307 performAnalysisTest("test/Test.java",
3.308 "package test;\n" +
3.309 "class Test {\n" +
3.310 - " private void tes|t(@CheckForNull String o) {\n" +
3.311 + " private void test(@CheckForNull String o) {\n" +
3.312 " if (o.length() > 1 && o.length() > 2);\n" +
3.313 " }" +
3.314 " @interface CheckForNull {}\n" +
3.315 - "}", "3:12-3:20:verifier:Possibly Dereferencing null");
3.316 + "}", "3:14-3:20:verifier:Possibly Dereferencing null");
3.317 }
3.318
3.319 public void testNoMultipleReports3() throws Exception {
3.320 performAnalysisTest("test/Test.java",
3.321 "package test;\n" +
3.322 "class Test {\n" +
3.323 - " private void tes|t(@CheckForNull String o) {\n" +
3.324 + " private void test(@CheckForNull String o) {\n" +
3.325 " boolean b = o.length() > 1 && o.length() > 2;\n" +
3.326 " }" +
3.327 " @interface CheckForNull {}\n" +
3.328 - "}", "3:20-3:28:verifier:Possibly Dereferencing null");
3.329 + "}", "3:22-3:28:verifier:Possibly Dereferencing null");
3.330 }
3.331
3.332 public void testNoMultipleReports4() throws Exception {
3.333 performAnalysisTest("test/Test.java",
3.334 "package test;\n" +
3.335 "class Test {\n" +
3.336 - " private void tes|t(@CheckForNull String o) {\n" +
3.337 + " private void test(@CheckForNull String o) {\n" +
3.338 " boolean b = o.length() > 1 && o.length() > 2 ? false : true;\n" +
3.339 " }" +
3.340 " @interface CheckForNull {}\n" +
3.341 - "}", "3:20-3:28:verifier:Possibly Dereferencing null");
3.342 + "}", "3:22-3:28:verifier:Possibly Dereferencing null");
3.343 }
3.344
3.345 public void testCCE() throws Exception {
3.346 - performAnalysisTest("test/Test.java",
3.347 - "package test;\n" +
3.348 - "class Test {\n" +
3.349 - " private void tes|t() {\n" +
3.350 - " c.s Object method = new Object();\n" +
3.351 - " }" +
3.352 - "}"/*, "3:20-3:28:verifier:Possibly Dereferencing null"*/);
3.353 + HintTest.create()
3.354 + .input("package test;\n" +
3.355 + "class Test {\n" +
3.356 + " private void test() {\n" +
3.357 + " c.s Object method = new Object();\n" +
3.358 + " }" +
3.359 + "}", false)
3.360 + .run(NPECheck.class)
3.361 + .assertWarnings(/*"3:20-3:28:verifier:Possibly Dereferencing null"*/);
3.362 }
3.363
3.364 - @Override
3.365 - protected List<ErrorDescription> computeErrors(CompilationInfo info, TreePath path) {
3.366 - return new NPECheck().run(info, path);
3.367 - }
3.368 -
3.369 - static {
3.370 - NbBundle.setBranding("test");
3.371 + private void performAnalysisTest(String fileName, String code, String... golden) throws Exception {
3.372 + HintTest.create()
3.373 + .input(fileName, code)
3.374 + .run(NPECheck.class)
3.375 + .assertWarnings(golden);
3.376 }
3.377 }