// A test for the @MatchesRegex annotation.

import org.checkerframework.common.value.qual.*;

public class RegexMatching {
  void stringConstants() {
    @MatchesRegex("a*") String a = "a";
    @MatchesRegex("a*") String blank = "";
    // :: error: (assignment)
    @MatchesRegex("a*") String b = "b";

    // NOTE: these tests show that there are implicit anchors in the regular expressions
    // used by @MatchesRegex.
    // :: error: (assignment)
    @MatchesRegex("a*") String ab = "ab";
    // :: error: (assignment)
    @MatchesRegex("a*") String baa = "baa";

    @MatchesRegex("a") String a1 = "a";
    // :: error: (assignment)
    @MatchesRegex("a") String blank1 = "";
    // :: error: (assignment)
    @MatchesRegex("a") String b1 = "b";

    @MatchesRegex("\\s") String space = " ";
    @MatchesRegex("\\s+") String severalSpaces = "      ";
    // :: error: (assignment)
    @MatchesRegex("\\s") String b2 = "b";

    @MatchesRegex("[^abc]") String d = "d";
    @MatchesRegex("[^abc]") String d1 = String.valueOf(new char[] {'d'});
    // :: error: (assignment)
    @MatchesRegex("[^abc]") String c = "c";
  }

  void severalString(@StringVal({"a", "aa"}) String aaa, @StringVal({"aa", "b"}) String aab) {
    @MatchesRegex("a*") String a = aaa;
    // :: error: (assignment)
    @MatchesRegex("a*") String a1 = aab;

    @MatchesRegex("a+") String a2 = aaa;
    // :: error: (assignment)
    @MatchesRegex("a+") String a3 = aab;
  }

  void multipleRegexes(@StringVal({"a", "aa"}) String aaa, @StringVal({"aa", "b"}) String aab) {
    @MatchesRegex({"a*", "b*"}) String a = aaa;
    @MatchesRegex({"a*", "b*"}) String a1 = aab;

    // :: error: (assignment)
    @MatchesRegex({"aa", "b*"}) String a2 = aaa;
    @MatchesRegex({"aa", "b*"}) String a3 = aab;
  }

  void regexSubtypingConstant(@MatchesRegex({"a", "b"}) String ab) {
    // :: error: (assignment)
    @MatchesRegex("a") String a = ab;
    @MatchesRegex({"a", "b"}) String ab1 = ab;
    @MatchesRegex({"a", "b", "c"}) String abc = ab;
    // :: error: (assignment)
    @StringVal("a") String a1 = ab;
    // :: error: (assignment)
    @StringVal({"a", "b"}) String ab2 = ab;
    // :: error: (assignment)
    @StringVal({"a", "b", "c"}) String abc1 = ab;
  }

  void regexSubtyping2(@MatchesRegex({"a*", "b*"}) String ab) {
    // :: error: (assignment)
    @MatchesRegex("a*") String a = ab;
    @MatchesRegex({"a*", "b*"}) String ab1 = ab;
    @MatchesRegex({"a*", "b*", "c*"}) String abc = ab;
    // :: error: (assignment)
    @StringVal("a*") String a1 = ab;
    // :: error: (assignment)
    @StringVal({"a*", "b*"}) String ab2 = ab;
    // :: error: (assignment)
    @StringVal({"a*", "b*", "c*"}) String abc1 = ab;
  }

  void lubRegexes(
      @MatchesRegex({"a*"}) String astar, @MatchesRegex({"b*"}) String bstar, boolean b) {
    String s;
    if (b) {
      s = astar;
    } else {
      s = bstar;
    }
    @MatchesRegex({"a*", "b*"}) String s1 = s;
    // :: error: (assignment)
    @MatchesRegex({"a*"}) String s2 = s;
    // :: error: (assignment)
    @MatchesRegex({"b*"}) String s3 = s;
  }

  void lubRegexWithStringVal(
      @MatchesRegex({"a*"}) String astar, @StringVal({"b"}) String bval, boolean b) {
    String s;
    if (b) {
      s = astar;
    } else {
      s = bval;
    }
    // NOTE: This depends on the internal implementation.  Semantically identical code like this
    // yields an error:
    // @MatchesRegex({"a*", "b"}) String s0 = s;
    @MatchesRegex({"a*", "\\Qb\\E"}) String s1 = s;
    // :: error: (assignment)
    @MatchesRegex({"a*"}) String s2 = s;
    // :: error: (assignment)
    @StringVal({"b"}) String s3 = s;
    // :: error: (assignment)
    @MatchesRegex("b") String s4 = s;
    // :: error: (assignment)
    @MatchesRegex("^b$") String s5 = s;
  }

  void stringToRegex1(@StringVal({"(a)"}) String a) {
    // :: error: (assignment)
    @MatchesRegex("(a)") String a2 = a;
  }

  void stringToRegex2(@StringVal({"a"}) String a) {
    @MatchesRegex("(a)") String a2 = a;
  }

  void stringToRegex3(@StringVal({"a"}) String a) {
    @MatchesRegex("^a$") String a2 = a;
  }

  void regexToString(@MatchesRegex("^a$") String a) {
    // TODO: This is a false positive.  In the future, eliminate it.
    // :: error: (assignment)
    @StringVal({"a"}) String a2 = a;
  }
}
