content: /*
   * Copyright 2016 HuntBugs contributors
   * 
   * 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 one.util.huntbugs.testdata;
  
  import java.io.IOException;
  import java.util.List;
  import java.util.concurrent.ThreadLocalRandom;
  
  import one.util.huntbugs.registry.anno.AssertNoWarning;
  import one.util.huntbugs.registry.anno.AssertWarning;
  
  /**
   * @author Tagir Valeev
   *
   */
  public class TestKnownComparison {
      private static Integer val = 0; 
      private Integer f = 0;
      private final int finalField;
      private char ch;
      private boolean flag;
      
      @AssertWarning("ResultOfComparisonIsStaticallyKnownDeadCode")
      public void testFinalField() {
          if(finalField > 15) {
              System.out.println("Never!");
          }
      }
  
      @AssertWarning("ResultOfComparisonIsStaticallyKnown")
      public void testFinalFieldOutside() {
          if(finalField < 15) {
              System.out.println("Always!");
          }
          System.out.println("Outside!");
      }
      
      @AssertWarning("ResultOfComparisonIsStaticallyKnownDeadCode")
      public void testFinalFieldReturn() {
          if(finalField < 15) {
              System.out.println("Always!");
              return;
          }
          System.out.println("Outside!");
      }
      
      @AssertWarning("ResultOfComparisonIsStaticallyKnownDeadCode")
      public void testCompoundStore() {
          int a, b;
          a = b = 0;
          if(a > 15) {
              System.out.println(b);
          }
      }
      
      @AssertWarning("ResultOfComparisonIsStaticallyKnownDeadCode")
      public TestKnownComparison() {
          finalField = 10;
          if(Math.random() > 0.5) {
              flag = true;
          }
          testInstanceFieldOk2(true);
          if(finalField != 10) {
              System.out.println("Never!");
          }
      }
      
      @AssertWarning("ResultOfComparisonIsStaticallyKnownDeadCode")
      public void testSideEffectFree() {
          f = 10;
          int x = getFinalField();
          if(f != 10) {
              System.out.println("Never: "+x);
          }
      }
      
      private int getFinalField() {
          return finalField;
      }
  
      @AssertWarning("ResultOfComparisonIsStaticallyKnownDeadCode")
      public TestKnownComparison(boolean b) {
          if(ch + 1 == 5) {
              System.out.println("Never! "+b);
          }
          finalField = 10;
      }
      
      @AssertWarning("ResultOfComparisonIsStaticallyKnown")
      public void testBooleanStringCompare() {
          boolean b = false;
          String s = "false";
          if(String.valueOf(b).equals(s)) {
              System.out.println("Always!");
          }
      }
      
      @AssertWarning("ResultOfComparisonIsStaticallyKnown")
      public void testTernaryConstCompare(int a) {
          int x = a == 5 ? a : 5;
          if (x == 5) {
              System.out.println("Ok");
          }
      }
      
      @AssertWarning("ResultOfComparisonIsStaticallyKnown")
      public void testBooleanAssignment(int a, int b) {
          boolean val = a == 5 && b > 10;
          if(val && a == 5) {
              System.out.println("ok");
          }
      }
  
      @AssertWarning("ResultOfComparisonIsStaticallyKnownDeadCode")
      public void testBooleanAssignmentNot(int a, int b) {
          boolean val = a != 5 || b > 10;
          if(!val && a != 5) {
              System.out.println("ok");
          }
      }
      
      @AssertNoWarning("*")
      public void testBooleanAssignmentTernary(int a, int b) {
          boolean val = a > 5 ? b > 10 : b < 10;
          if(val && a == 5) {
              System.out.println("ok");
          }
      }
      
      @AssertWarning("ResultOfComparisonIsStaticallyKnownDeadCode")
      public void testIfConstCompare(int a) {
          if (a == 5) {
              System.out.println("A is 5");
              if (a > 6) {
                  System.out.println("Cannot be");
              }
          }
      }
      
      @AssertWarning("ResultOfComparisonIsStaticallyKnownDeadCode")
      public void testIfConstNotCompare(int a, int b) {
          if (a != 5 || b != 10) {
              System.out.println("A is 5 and B is 10");
          } else {
              if (a > 6) {
                  System.out.println("Cannot be");
              }
          }
      }
      
      @AssertWarning("ResultOfComparisonIsStaticallyKnownDeadCode")
      public void testIfConstStrings(String x) {
          if (x.equals("123")) {
              if (x.length() == 4) {
                  System.out.println("Cannot be");
              }
          }
      }
      
      @AssertWarning("ResultOfComparisonIsStaticallyKnownDeadCode")
      public void testIfConstStringsNot(String x) {
          if (!x.equals("123") || Math.random() > 0.5) {
              System.out.println("x is not 123 or random is big");
          } else {
              if (x.length() == 4) {
                  System.out.println("Cannot be");
              }
          }
      }
      
      @AssertWarning("ResultOfComparisonIsStaticallyKnown")
      public void testTernaryConstCompare2(int a) {
          int x = a != 5 ? 7 : a + 2;
          if (x == 7) {
              System.out.println("Ok");
          }
      }
      
      @AssertWarning("ResultOfComparisonIsStaticallyKnown")
      public void testIntegerStringCompare() {
          int x = 100;
          String s = "100";
          if(String.valueOf(x).equals(s)) {
              System.out.println("Always!");
          }
      }
      
      @AssertWarning("ResultOfComparisonIsStaticallyKnown")
      public void testBooleanBoxingCompare() {
          boolean b = false;
          Boolean boxed = b;
          if(boxed.equals(false)) {
              System.out.println("Always!");
          }
      }
      
      @AssertWarning("ResultOfComparisonIsStaticallyKnownDeadCode")
      public void testAnd(int x) {
          int a = 2;
          int b = 3;
          if (a > b && x > 2) {
              System.out.println("Never ever!");
          }
      }
  
      @AssertWarning("ResultOfComparisonIsStaticallyKnownDeadCode")
      public void testArrayLength(boolean x) {
          int[] a = {1, 2, 3};
          int[] b = {4, 5, 6};
          int[] c = x ? a : b;
          if (c.length > 5) {
              System.out.println("Never ever!");
          }
      }
      
      @AssertWarning("ResultOfComparisonIsStaticallyKnownDeadCode")
      public void testAnd2(int x) {
          int a = 2;
          int b = 3;
          if (x > 2 && a > b) {
              System.out.println("Never ever!");
          }
      }
  
      @AssertWarning("ResultOfComparisonIsStaticallyKnown")
      public void test() {
          int a = 2;
          int b = 3;
          if (a < b) {
              System.out.println("Why not?");
          }
      }
  
      @AssertWarning("ResultOfComparisonIsStaticallyKnown")
      public void testOr(int x) {
          int a = 2;
          int b = 3;
          if (x > 3 || a < b) {
              System.out.println("Why not?");
          }
      }
  
      @AssertWarning("ResultOfComparisonIsStaticallyKnown")
      public void testInc() {
          int a = 2;
          int b = 3;
          b++;
          if (a < b) {
              System.out.println("Why not?");
          }
      }
  
      @AssertNoWarning("ResultOfComparisonIsStaticallyKnown")
      public void testIncrement(boolean f) {
          int a = 2;
          int b = 3;
          if (f)
              a += 2;
          if (a < b) {
              System.out.println("Why not?");
          }
      }
  
      @AssertWarning("ResultOfComparisonIsStaticallyKnownDeadCode")
      public int testTernary() {
          int a = 2;
          return a == 2 ? 1 : -1;
      }
  
      @AssertWarning("ResultOfComparisonIsStaticallyKnownDeadCode")
      public int testLoopBreak() {
          int a = 2;
          int b = 1;
          while (true) {
              b = 2;
              if (++a > 4)
                  break;
              System.out.println("Iteration!");
          }
          return b == 2 ? 1 : -1;
      }
  
      @AssertNoWarning("*")
      public void testFor() {
          for (int i = 0; i < 10; i++) {
              if (i == 0)
                  System.out.println("First!");
              System.out.println("Iteration!");
          }
      }
  
      @AssertNoWarning("*")
      public void testSubFor(List<String> l2) {
          for (int i = 0, n = l2.size(); i < n; i++) {
              if (i - 1 == 0)
                  System.out.println("First!");
              System.out.println("Iteration!");
          }
      }
  
      @AssertNoWarning("*")
      public void testForContinue(boolean b) {
          for (int i = 0; i < 10; i++) {
              if (b && i == 0 || !b && i == 2) {
                  System.out.println("First!");
              } else
                  continue;
              System.out.println("Iteration!");
          }
      }
  
      @AssertNoWarning("*")
      public void testNestedForForSwitch(boolean b) {
          System.out.println(b);
          for (int pass = 0; pass < 2; pass++) {
              if (pass == 1)
                  System.out.println("Second pass");
              double start = 1;
              for (double x = start; x < 1024; x *= 2) {
                  double q = x * 2;
                  switch (pass) {
                  case 0:
                      System.out.println(q);
                      if (x < 10) {
                          System.out.println("Loop");
                          for (int z = 0; z < 10; z++)
                              System.out.println(z);
                      }
                      System.out.println("Continue");
                      continue;
                  case 1:
                      if (x > 128)
                          continue;
                      System.out.println(x + "1");
                      break;
                  }
              }
          }
      }
  
      @AssertNoWarning("*")
      public void testNestedForFor() {
          for (int a = 0; a < 10; a++) {
              if (a % 2 == 0) {
                  for (int iter = 0; iter < 10; iter++) {
                      System.out.println("test");
                      if (iter > 3)
                          continue;
                      for (int b = a; b < 10; b++) {
                          if (b % 2 == 0) {
                              for (int c = (a == b) ? iter + 3 : 1; c < 20; c++) {
                                  if (a == b) {
                                      System.out.println("Equal");
                                  }
                                  System.out.println("InnerInner");
                              }
                              System.out.println("Inner");
                          }
                      }
                  }
                  System.out.println("Outer");
              }
          }
      }
  
      @AssertNoWarning("*")
      public void testIncInLoop() {
          int x = 10;
          for (int i = 0; i < 10; i++) {
              x -= 4;
              if (x > 0)
                  System.out.println("X!");
              System.out.println("Iteration!");
          }
      }
  
      @AssertWarning("ResultOfComparisonIsStaticallyKnownDeadCode")
      public void testInLambda(int x) {
          Runnable r = () -> {
              int a = 2;
              int b = 3;
              if (a > b && x > 2) {
                  System.out.println("Never ever!");
              }
          };
          r.run();
      }
  
      @AssertNoWarning("ResultOfComparisonIsStaticallyKnownDeadCode")
      public void testInLambdaFP(int x) {
          Runnable r = () -> {
              int a = 2;
              if (x > a) {
                  System.out.println("Can be");
              }
          };
          r.run();
      }
  
      @AssertNoWarning("*")
      public void testComplexLoop(int x) {
          int s = -1;
          for (int i = 0; i < x; i++) {
              if (i < 3) {
                  System.out.println(1);
                  if (s < 0)
                      continue;
              }
              if (i < 5) {
                  System.out.println(2);
                  if (s < 0)
                      s = i;
                  continue;
              } else if (s < 0)
                  continue;
              System.out.println(3);
          }
      }
  
      @AssertNoWarning("*")
      public void testComplexLoop(String ssType, String type) {
          if (ssType == null)
              return;
          int istart = -1;
          for (int i = 0; i < 100; i++) {
              if (i == 1) {
                  System.out.println(0);
              } else {
                  System.out.println(1);
              }
              if (type.equals("test")) {
                  System.out.println(2);
                  --i;
                  if (istart < 0)
                      continue;
              } else if (type.equals("test2")) {
                  System.out.println(3);
                  if (istart < 0)
                      istart = i;
                  continue;
              } else if (istart < 0) {
                  continue;
              }
              if (type.equals("test3")) {
                  System.out.println(4);
                  if (i >= 0 && i <= 10)
                      continue;
                  System.out.println(5);
              }
              System.out.println(6);
              istart = -1;
          }
      }
      
      @AssertNoWarning("*")
      public void testComplexLoop2(String type) {
          int x = -1;
          for (int i = 0; i < 100; i++) {
              if (type.equals("test")) {
                  System.out.println(2);
                  if (x < 0)
                      continue;
              } else if (type.equals("test2")) {
                  System.out.println(3);
                  if (x < 0)
                      x = i;
                  continue;
              }
              x = -1;
          }
      }
  
      @AssertWarning("ResultOfComparisonIsStaticallyKnownDeadCode")
      public void testComplexLoop3(String type) {
          int x = -1;
          for (int i = 0; i < 100; i++) {
              if (type.equals("test")) {
                  System.out.println(2);
                  if (x < 0)
                      continue;
              } else if (type.equals("test2")) {
                  x = 0;
                  System.out.println(3);
                  if (x < 0)
                      x = i;
                  continue;
              }
              x = -1;
          }
      }
  
      @AssertNoWarning("*")
      public void testAssert(String type) {
          int x = 1;
          assert x > 0 && !type.isEmpty();
          System.out.println(x+":"+type);
      }
  
      @AssertWarning("ResultOfComparisonIsStaticallyKnownDeadCode")
      public static void testStaticField() {
          val = 3;
          if(val > 3) {
              System.out.println("Never");
          }
      }
  
      @AssertNoWarning("*")
      public static void testStaticFieldOk() {
          val = 2;
          testStaticField();
          if(val > 2) {
              System.out.println("Never");
          }
      }
      
      @AssertWarning("ResultOfComparisonIsStaticallyKnownDeadCode")
      public void testInstanceField() {
          f = 3;
          if(f > 3) {
              System.out.println("Never");
          }
      }
      
      @AssertNoWarning("*")
      public void testInstanceFieldOk() {
          f = 2;
          testInstanceField();
          if(f > 2) {
              System.out.println("Never");
          }
      }
      
      @AssertNoWarning("*")
      public void testInstanceFieldOk2(boolean b) {
          f = 2;
          int x = 0;
          if(b) x = f++;
          if(f > 2) {
              System.out.println("Never");
          }
          System.out.println(x);
      }
      
      @AssertNoWarning("*")
      public void testInstanceFieldOk3(int x) {
          if(x > 0)
              f = 2;
          if(f > 2) {
              System.out.println("Never");
          }
          System.out.println(x);
      }
      
      @AssertNoWarning("*")
      public void testFieldLoop() {
          f = 0;
          while(f < 10) {
              if(Math.random() > 0.5) {
                  f++;
                  System.out.println(f);
              } else {
                  f = 1;
                  System.out.println(f+"!");
              }
          }
      }
      
      private int[] getArray() {
          return new int[10];
      }
  
      @AssertNoWarning("*")
      public void testArray(boolean b) {
          int x = 0;
          if(b)
              x = getArray().length;
          if(x > 0) {
              System.out.println("a");
          }
      }
      
      @AssertWarning("ResultOfComparisonIsStaticallyKnownDeadCode")
      @AssertNoWarning("ResultOfComparisonIsStaticallyKnown")
      static class TestInitial {
          static long x = 2;
          
          static {
              if(x < 1) {
                  System.out.println("Cannot be");
              }
          }
      }
      
      @AssertNoWarning("*")
      public static class TestFieldAssignment {
          private int x = 1;
          
          public TestFieldAssignment(String s) {
              this();
              try {
                  x = Integer.parseInt(s);
              } catch (NumberFormatException e) {
                  e.printStackTrace();
              }
          }
          
          public TestFieldAssignment() {
          }
  
          public void test() {
              if(x > 0) {
                  System.out.println("!!!");
              }
          }
      }
      
      @AssertWarning("ResultOfComparisonIsStaticallyKnownDeadCode")
      public void testAioobe(int[] x, int y) {
          int a = 0;
          try {
              a = x[y];
              if(a > 0) {
                  a = 0;
              }
          }
          catch(IndexOutOfBoundsException ex) {
              if(a > 0) {
                  a = 0;
              }
          }
          System.out.println(a);
      }
  
      @AssertNoWarning("*")
      public void testFieldDoWhile() {
          do {
              if(f == 5) {
                  System.out.println(f);
              }
              doSomeProcessing();
              f = 5;
          } while(ch < 10);
      }
      
      private void doSomeProcessing() {
          f++;
          ch--;
      }
      
      @AssertNoWarning("*")
      public void testBooleanFlag() {
          if(flag) {
              System.out.println("a");
          }
      }
  
      @AssertWarning("ResultOfComparisonIsStaticallyKnownDeadCode")
      public void testCompareToKnown(int a, int b) {
          if(a == 5 && b == a) {
              System.out.println(b == 5 ? 1 : 2);
          }
      }
      
      @AssertWarning("ResultOfComparisonIsStaticallyKnownDeadCode")
      public void testWhileExitCondition(int i) {
          while(i != 10) {
              System.out.println(i++);
          }
          if(i != 10) {
              System.out.println("Never");
          }
      }
  
      @AssertWarning("ResultOfComparisonIsStaticallyKnown")
      public void testNestedSwitch(int i, int j) {
          switch(i) {
          case 1:
              switch(j) {
              case 2:
                  System.out.println("1-2");
                  break;
              }
              break;
          case 2:
              switch(j) {
              case 3:
                  if(i == 2)
                      System.out.println("2-3");
                  break;
              }
              break;
          case 3:
              return;
          case 4:
              return;
          default:
              break;
          }
      }
      
      @AssertNoWarning("*")
      public static void catchInfiniteLoop(int[] arr, int offset) {
          while (true) {
              try {
                  arr[offset++] = 1;
                  break;
              } catch (IndexOutOfBoundsException ex) {
                  System.out.println("Retrying...");
                  offset = 0;
              }
          }
          System.out.println("done");
      }
      
      @AssertNoWarning("*")
      public void testSwitchPassthru(int x) {
          int a = 3;
          for(int i=0; i<10; i++) {
              switch(x) {
              case 1:
                  System.out.println(x);
                  a = 2;
                  if(Math.random() > 0.5)
                      return;
              case 2:
                  if(a == 3) {
                      System.out.println("Always");
                  }
                  break;
              default:
                  System.out.println("Default");
              }
          }
      }
      
      @AssertNoWarning("*")
      public void testSwitchMisplacedDefault(int x) {
          int a = 3;
          switch(x) {
          case 3:
              System.out.println("3");
              break;
          default:
              System.out.println("Default");
              a = 2;
          case 1:
          case 2:
              if(a == 3) {
                  System.out.println("Possible");
              }
          }
      }
      
      @AssertWarning("ResultOfComparisonIsStaticallyKnown")
      public void testSwitchMisplacedDefault2(int x) {
          int a = 3;
          switch(x) {
          default:
          case 3:
              System.out.println("3");
              a = 2;
              break;
          case 1:
          case 2:
              if(a == 3) {
                  System.out.println("Always");
              }
          }
      }
      
      @AssertWarning("ResultOfComparisonIsStaticallyKnown")
      public void testCatch(String s) {
          try {
              if(s.equals("test")) {
                  throw new IOException();
              }
              System.out.println(s);
          }
          catch(IOException ex) {
              if(s.equals("test")) {
                  System.out.println("Always!");
              }
          }
      }
      
      @AssertNoWarning("*")
      public void testOrNested(int x) {
          if(Math.random() > 0.5 && (x == 1 || x == 2)) {
              if(x == 1) {
                  System.out.println(2);
              } else {
                  System.out.println(1);
              }
              System.out.println("ok");
          }
      }
      
      @AssertNoWarning("*")
      static class ArrayTest {
          int[] arr;
          
          public ArrayTest(boolean b) {
              // such construction is incorrectly handled by procyon
              // arr = b ? new int[] {1,2} : new int[] {1};
              if(b) {
                  arr = new int[] {1,2};
              } else {
                  arr = new int[] {1};
              }
          }
          
          public void testArrayLength() {
              if(arr.length > 1) {
                  System.out.println("Big");
              }
          }
      }
      
      @AssertNoWarning("*")
      public void testFinally() {
          int i = 0;
          try {
              i = ThreadLocalRandom.current().nextInt();
          }
          finally {
              try {
                  System.out.println("Finish");
              }
              finally {
                  if(i == 5) {
                      System.out.println("Hello");
                  }
              }
          }
      }
  
      // procyon does not perfectly merge these finally blocks 
      //@AssertNoWarning("*")
      public void testNestedFinally() {
          int i = 0;
          try {
              i = ThreadLocalRandom.current().nextInt();
          } catch(Throwable t) {
              t.printStackTrace();
          }
          finally {
              try {
                  System.out.println("Finish");
              }
              finally {
                  if(i == 5) {
                      System.out.println("Hello");
                  }
              }
          }
      }
      
      @AssertWarning("ResultOfComparisonIsStaticallyKnown")
      public void testSystemExit(int x) {
          if(x != 5) {
              System.out.println("Oops");
              System.exit(0);
          }
          if(x == 5) {
              System.out.println("Always");
          }
      }
  
      // procyon bug
  //    @AssertNoWarning("*")
  //    public int testRetries(Scanner sc) {
  //        int cnt = 0;
  //        while(true) {
  //            try {
  //                return sc.nextInt();
  //            }
  //            catch(InputMismatchException ime) {
  //                if(cnt < 20) {
  //                    cnt++;
  //                } else {
  //                    throw ime;
  //                }
  //            }
  //        }
  //    }
  }
  