Package com.google.errorprone.dataflow.nullnesspropagation

Source Code of com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest

/*
* Copyright 2014 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.errorprone.dataflow.nullnesspropagation;

import static com.google.errorprone.BugPattern.Category.JDK;
import static com.google.errorprone.BugPattern.MaturityLevel.EXPERIMENTAL;
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
import static com.google.errorprone.dataflow.DataFlow.expressionDataflow;
import static com.google.errorprone.fixes.SuggestedFix.replace;
import static com.google.errorprone.matchers.Description.NO_MATCH;
import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.Matchers.staticMethod;

import com.google.common.base.Joiner;
import com.google.errorprone.BugPattern;
import com.google.errorprone.CompilationTestHelper;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;

import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.Tree;
import com.sun.source.util.TreePath;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import java.util.ArrayList;
import java.util.List;

/**
* @author deminguyen@google.com (Demi Nguyen)
*/
@RunWith(JUnit4.class)
public class NullnessPropagationTest {
 
  private CompilationTestHelper compilationHelper;
 
  /**
   * This method triggers the {@code BugPattern} used to test nullness propagation
   *
   * @param obj Variable whose nullness value is being checked
   */
  public static void triggerNullnessChecker(Object obj) {}

  /*
   * Methods that should never be called. These methods exist to force tests that pass a primitive
   * to decide whether they are testing (a) that primitive itself is null in which case they should
   * call triggerNullnessCheckerOnPrimitive or (b) that the result of autoboxing the primitive is
   * null, in which case it should call triggerNullnessCheckerOnBoxed. Of course, in either case,
   * the value should never be null. (The analysis isn't yet smart enough to detect this in all
   * cases.)
   *
   * Any call to these methods will produce a special error.
   */

  public static void triggerNullnessChecker(boolean b) {}

  public static void triggerNullnessChecker(byte b) {}

  public static void triggerNullnessChecker(char c) {}

  public static void triggerNullnessChecker(double d) {}

  public static void triggerNullnessChecker(float f) {}

  public static void triggerNullnessChecker(int i) {}

  public static void triggerNullnessChecker(long l) {}

  public static void triggerNullnessChecker(short s) {}

  /**
   * This method also triggers the {@code BugPattern} used to test nullness propagation, but it is
   * intended to be used only in the rare case of testing the result of boxing a primitive.
   */
  public static void triggerNullnessCheckerOnBoxed(Object obj) {}

  /*
   * These methods also trigger the {@code BugPattern} used to test nullness propagation, but they
   * are careful not to autobox their inputs.
   */

  public static void triggerNullnessCheckerOnPrimitive(boolean b) {}

  public static void triggerNullnessCheckerOnPrimitive(byte b) {}

  public static void triggerNullnessCheckerOnPrimitive(char c) {}

  public static void triggerNullnessCheckerOnPrimitive(double d) {}

  public static void triggerNullnessCheckerOnPrimitive(float f) {}

  public static void triggerNullnessCheckerOnPrimitive(int i) {}

  public static void triggerNullnessCheckerOnPrimitive(long l) {}

  public static void triggerNullnessCheckerOnPrimitive(short s) {}

  @Before
  public void setUp() {
    compilationHelper = CompilationTestHelper.newInstance(new NullnessPropagationChecker());
  }
 
  @Test
  public void testTransferFunctions1() throws Exception {
    compilationHelper.assertCompileFailsWithMessages(
        compilationHelper.fileManager().sources(
            getClass(), "NullnessPropagationTransferCases1.java"));
  }

  @Test
  public void testTransferFunctions2() throws Exception {
    compilationHelper.assertCompileFailsWithMessages(
        compilationHelper.fileManager().sources(
            getClass(), "NullnessPropagationTransferCases2.java"));
  }

  @Test
  public void testTransferFunctions3() throws Exception {
    compilationHelper.assertCompileFailsWithMessages(
        compilationHelper.fileManager().sources(
            getClass(), "NullnessPropagationTransferCases3.java"));
  }
 
  @Test
  public void testTransferFunctions4() throws Exception {
    compilationHelper.assertCompileFailsWithMessages(
        compilationHelper.fileManager().sources(
            getClass(), "NullnessPropagationTransferCases4.java"));
  }
 
  @Test
  public void testTransferFunctions5() throws Exception {
    compilationHelper.assertCompileFailsWithMessages(
        compilationHelper.fileManager().sources(
            getClass(), "NullnessPropagationTransferCases5.java"));
  }

  @Test
  public void testTransferFunctions6() throws Exception {
    compilationHelper.assertCompileFailsWithMessages(
        compilationHelper.fileManager().sources(
            getClass(), "NullnessPropagationTransferCases6.java"));
  }

  @Test
  public void testTransferFunctions7() throws Exception {
    compilationHelper.assertCompileFailsWithMessages(
        compilationHelper.fileManager().sources(
            getClass(), "NullnessPropagationTransferCases7.java"));
  }

  /**
   * BugPattern to test dataflow analysis using nullness propagation
   */
  @BugPattern(name = "NullnessPropagationChecker",
      summary = "Test checker for NullnessPropagationTest",
      explanation = "Outputs an error for each call to triggerNullnessChecker, describing its "
          + "argument as nullable or non-null",
      category = JDK, severity = ERROR, maturity = EXPERIMENTAL)
  public static final class NullnessPropagationChecker
      extends BugChecker implements MethodInvocationTreeMatcher {
    private static final NullnessPropagationTransfer NULLNESS_PROPAGATION =
        new NullnessPropagationTransfer();
   
    private static final String AMBIGUOUS_CALL_MESSAGE = "AMBIGUOUS CALL: use "
        + "triggerNullnessCheckerOnPrimitive if you want to test the primitive for nullness";
   
    private static final Matcher<ExpressionTree> TRIGGER_CALL_MATCHER = anyOf(
        staticMethod(NullnessPropagationTest.class.getName(), "triggerNullnessCheckerOnPrimitive"),
        staticMethod(NullnessPropagationTest.class.getName(), "triggerNullnessCheckerOnBoxed"),
        staticMethod(
            NullnessPropagationTest.class.getName(), "triggerNullnessChecker(java.lang.Object)"));
   
    private static final Matcher<ExpressionTree> AMBIGUOUS_CALL_FALLBACK_MATCHER =
        staticMethod(NullnessPropagationTest.class.getName(), "triggerNullnessChecker");
   
    @Override
    public Description matchMethodInvocation(
        MethodInvocationTree methodInvocation, VisitorState state) {
      if (!TRIGGER_CALL_MATCHER.matches(methodInvocation, state)) {
        if (AMBIGUOUS_CALL_FALLBACK_MATCHER.matches(methodInvocation, state)) {
          return Description.builder(methodInvocation, pattern)
              .setMessage(AMBIGUOUS_CALL_MESSAGE).build();
        }
        return NO_MATCH;
      }

      TreePath root = state.getPath();
      List<Object> values = new ArrayList<>();
      for (Tree arg : methodInvocation.getArguments()) {
        TreePath argPath = new TreePath(root, arg);
        values.add(expressionDataflow(argPath, state.context, NULLNESS_PROPAGATION));
      }

      String fixString = "(" + Joiner.on(", ").join(values) + ")";
      return describeMatch(methodInvocation, replace(methodInvocation, fixString));
    }
  }
}
TOP

Related Classes of com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.