<commit_before>/*
 * Copyright 2000-2017 JetBrains s.r.o.
 *
 * 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.intellij.codeInspection.dataFlow;

import com.intellij.codeInspection.dataFlow.StandardMethodContract.ValueConstraint;
import com.intellij.codeInspection.dataFlow.value.DfaRelationValue;
import com.intellij.codeInspection.dataFlow.value.DfaRelationValue.RelationType;
import com.intellij.codeInspection.util.OptionalUtil;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.containers.ContainerUtil;
import com.siyeh.ig.callMatcher.CallMapper;
import com.siyeh.ig.callMatcher.CallMatcher;
import com.siyeh.ig.psiutils.MethodUtils;
import com.siyeh.ig.psiutils.TypeUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import static com.intellij.codeInspection.dataFlow.ContractReturnValue.*;
import static com.intellij.codeInspection.dataFlow.MethodContract.singleConditionContract;
import static com.intellij.codeInspection.dataFlow.MethodContract.trivialContract;
import static com.intellij.codeInspection.dataFlow.StandardMethodContract.ValueConstraint.*;
import static com.intellij.codeInspection.dataFlow.StandardMethodContract.createConstraintArray;
import static com.intellij.psi.CommonClassNames.*;
import static com.siyeh.ig.callMatcher.CallMatcher.*;

/**
 * @author peter
 */
public class HardcodedContracts {
  private static final List<MethodContract> ARRAY_RANGE_CONTRACTS = ContainerUtil.immutableList(
    singleConditionContract(ContractValue.argument(1), RelationType.GT, ContractValue.argument(0).specialField(SpecialField.ARRAY_LENGTH),
                            fail()),
    singleConditionContract(ContractValue.argument(2), RelationType.GT, ContractValue.argument(0).specialField(SpecialField.ARRAY_LENGTH),
                            fail()),
    singleConditionContract(ContractValue.argument(1), RelationType.GT, ContractValue.argument(2), fail())
  );

  private static final CallMatcher QUEUE_POLL = anyOf(
    instanceCall("java.util.Queue", "poll").parameterCount(0),
    instanceCall("java.util.Deque", "pollFirst", "pollLast").parameterCount(0)
    );

  @FunctionalInterface
  interface ContractProvider {
    List<MethodContract> getContracts(PsiMethodCallExpression call, int paramCount);

    static ContractProvider of(MethodContract contract) {
      return (call, paramCount) -> Collections.singletonList(contract);
    }

    static ContractProvider of(MethodContract... contracts) {
      return (call, paramCount) -> Arrays.asList(contracts);
    }
  }

  private static final CallMapper<ContractProvider> HARDCODED_CONTRACTS = new CallMapper<ContractProvider>()
    .register(anyOf(staticCall("com.google.common.base.Preconditions", "checkNotNull"),
                    staticCall(JAVA_UTIL_OBJECTS, "requireNonNull")),
              (call, cnt) -> cnt > 0 ? failIfNull(0, cnt, true) : null)
    .register(staticCall("com.google.common.base.Preconditions", "checkArgument", "checkState"),
              (call, cnt) -> {
                if (cnt == 0) return null;
                ValueConstraint[] constraints = createConstraintArray(cnt);
                constraints[0] = FALSE_VALUE;
                return Collections.singletonList(new StandardMethodContract(constraints, fail()));
              })
    .register(instanceCall(JAVA_LANG_STRING, "charAt", "codePointAt").parameterCount(1),
              ContractProvider.of(specialFieldRangeContract(0, RelationType.LT, SpecialField.STRING_LENGTH)))
    .register(anyOf(instanceCall(JAVA_LANG_STRING, "substring", "subSequence").parameterCount(2),
                    instanceCall(JAVA_LANG_STRING, "substring").parameterCount(1)),
              (call, cnt) -> getSubstringContracts(cnt == 2))
    .register(instanceCall(JAVA_LANG_STRING, "isEmpty").parameterCount(0),
              ContractProvider.of(SpecialField.STRING_LENGTH.getEmptyContracts()))
    .register(anyOf(instanceCall(JAVA_UTIL_COLLECTION, "isEmpty").parameterCount(0),
                    instanceCall(JAVA_UTIL_MAP, "isEmpty").parameterCount(0)),
              ContractProvider.of(SpecialField.COLLECTION_SIZE.getEmptyContracts()))
    .register(instanceCall(JAVA_LANG_STRING, "equalsIgnoreCase").parameterCount(1),
              ContractProvider.of(SpecialField.STRING_LENGTH.getEqualsContracts()))
    .register(anyOf(instanceCall(JAVA_UTIL_SET, "equals").parameterTypes(JAVA_LANG_OBJECT),
                    instanceCall(JAVA_UTIL_LIST, "equals").parameterTypes(JAVA_LANG_OBJECT),
                    instanceCall(JAVA_UTIL_MAP, "equals").parameterTypes(JAVA_LANG_OBJECT)),
              ContractProvider.of(SpecialField.COLLECTION_SIZE.getEqualsContracts()))
    .register(instanceCall(JAVA_UTIL_COLLECTION, "contains").parameterCount(1),
              ContractProvider.of(singleConditionContract(
                ContractValue.qualifier().specialField(SpecialField.COLLECTION_SIZE), RelationType.EQ, ContractValue.zero(),
                returnFalse())))
    .register(instanceCall(JAVA_UTIL_MAP, "containsKey", "containsValue").parameterCount(1),
              ContractProvider.of(singleConditionContract(
                ContractValue.qualifier().specialField(SpecialField.COLLECTION_SIZE), RelationType.EQ, ContractValue.zero(), returnFalse())))
    .register(instanceCall(JAVA_UTIL_LIST, "get").parameterTypes("int"),
              ContractProvider.of(specialFieldRangeContract(0, RelationType.LT, SpecialField.COLLECTION_SIZE)))
    .register(instanceCall("java.util.SortedSet", "first", "last").parameterCount(0),
              ContractProvider.of(singleConditionContract(
                ContractValue.qualifier().specialField(SpecialField.COLLECTION_SIZE), RelationType.EQ,
                ContractValue.zero(), fail())))
    // All these methods take array as 1st parameter, from index as 2nd and to index as 3rd
    // thus ARRAY_RANGE_CONTRACTS are applicable to them
    .register(staticCall(JAVA_UTIL_ARRAYS, "binarySearch", "fill", "parallelPrefix", "parallelSort", "sort", "spliterator", "stream"),
              (call, cnt) -> cnt >= 3 ? ARRAY_RANGE_CONTRACTS : null)
    .register(staticCall("org.mockito.ArgumentMatchers", "argThat").parameterCount(1),
              ContractProvider.of(StandardMethodContract.fromText("_ -> _")))
    .register(anyOf(
      instanceCall("java.util.Queue", "peek", "poll").parameterCount(0),
      instanceCall("java.util.Deque", "peekFirst", "peekLast", "pollFirst", "pollLast").parameterCount(0)),
              (call, paramCount) -> Arrays.asList(singleConditionContract(
                ContractValue.qualifier().specialField(SpecialField.COLLECTION_SIZE), RelationType.EQ,
                ContractValue.zero(), returnNull()), trivialContract(returnAny())))
    .register(anyOf(staticCall(JAVA_LANG_MATH, "max").parameterTypes("int", "int"),
                    staticCall(JAVA_LANG_MATH, "max").parameterTypes("long", "long"),
                    staticCall(JAVA_LANG_INTEGER, "max").parameterTypes("int", "int"),
                    staticCall(JAVA_LANG_LONG, "max").parameterTypes("long", "long")),
              (call, paramCount) -> mathMinMax(true))
    .register(anyOf(staticCall(JAVA_LANG_MATH, "min").parameterTypes("int", "int"),
                    staticCall(JAVA_LANG_MATH, "min").parameterTypes("long", "long"),
                    staticCall(JAVA_LANG_INTEGER, "min").parameterTypes("int", "int"),
                    staticCall(JAVA_LANG_LONG, "min").parameterTypes("long", "long")),
              (call, paramCount) -> mathMinMax(false))
    .register(instanceCall(JAVA_LANG_STRING, "startsWith", "endsWith", "contains"),
              ContractProvider.of(
                singleConditionContract(
                  ContractValue.argument(0).specialField(SpecialField.STRING_LENGTH), RelationType.EQ,
                  ContractValue.zero(), returnTrue()),
                singleConditionContract(
                  ContractValue.qualifier().specialField(SpecialField.STRING_LENGTH), RelationType.LT,
                  ContractValue.argument(0).specialField(SpecialField.STRING_LENGTH), returnFalse())))
    .register(instanceCall(JAVA_LANG_OBJECT, "equals").parameterTypes(JAVA_LANG_OBJECT),
              (call, paramCount) -> equalsContracts(call))
    .register(anyOf(
      staticCall(JAVA_UTIL_OBJECTS, "equals").parameterCount(2),
      staticCall("com.google.common.base.Objects", "equal").parameterCount(2)),
              ContractProvider.of(
                singleConditionContract(ContractValue.argument(0), DfaRelationValue.RelationType.EQ, ContractValue.argument(1),
                                        returnTrue()),
                StandardMethodContract.fromText("null, !null -> false"),
                StandardMethodContract.fromText("!null, null -> false")
              ))
    .register(enumValues(), ContractProvider.of(StandardMethodContract.fromText("-> new")));

  public static List<MethodContract> getHardcodedContracts(@NotNull PsiMethod method, @Nullable PsiMethodCallExpression call) {
    PsiClass owner = method.getContainingClass();<commit_msg>HardcodedContracts: fixed fromText calls<commit_after>/*
 * Copyright 2000-2017 JetBrains s.r.o.
 *
 * 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.intellij.codeInspection.dataFlow;

import com.intellij.codeInspection.dataFlow.StandardMethodContract.ValueConstraint;
import com.intellij.codeInspection.dataFlow.value.DfaRelationValue;
import com.intellij.codeInspection.dataFlow.value.DfaRelationValue.RelationType;
import com.intellij.codeInspection.util.OptionalUtil;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.containers.ContainerUtil;
import com.siyeh.ig.callMatcher.CallMapper;
import com.siyeh.ig.callMatcher.CallMatcher;
import com.siyeh.ig.psiutils.MethodUtils;
import com.siyeh.ig.psiutils.TypeUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import static com.intellij.codeInspection.dataFlow.ContractReturnValue.*;
import static com.intellij.codeInspection.dataFlow.MethodContract.singleConditionContract;
import static com.intellij.codeInspection.dataFlow.MethodContract.trivialContract;
import static com.intellij.codeInspection.dataFlow.StandardMethodContract.ValueConstraint.*;
import static com.intellij.codeInspection.dataFlow.StandardMethodContract.createConstraintArray;
import static com.intellij.psi.CommonClassNames.*;
import static com.siyeh.ig.callMatcher.CallMatcher.*;

/**
 * @author peter
 */
public class HardcodedContracts {
  private static final List<MethodContract> ARRAY_RANGE_CONTRACTS = ContainerUtil.immutableList(
    singleConditionContract(ContractValue.argument(1), RelationType.GT, ContractValue.argument(0).specialField(SpecialField.ARRAY_LENGTH),
                            fail()),
    singleConditionContract(ContractValue.argument(2), RelationType.GT, ContractValue.argument(0).specialField(SpecialField.ARRAY_LENGTH),
                            fail()),
    singleConditionContract(ContractValue.argument(1), RelationType.GT, ContractValue.argument(2), fail())
  );

  private static final CallMatcher QUEUE_POLL = anyOf(
    instanceCall("java.util.Queue", "poll").parameterCount(0),
    instanceCall("java.util.Deque", "pollFirst", "pollLast").parameterCount(0)
    );

  @FunctionalInterface
  interface ContractProvider {
    List<MethodContract> getContracts(PsiMethodCallExpression call, int paramCount);

    static ContractProvider of(MethodContract contract) {
      return (call, paramCount) -> Collections.singletonList(contract);
    }

    static ContractProvider of(MethodContract... contracts) {
      return (call, paramCount) -> Arrays.asList(contracts);
    }
  }

  private static final CallMapper<ContractProvider> HARDCODED_CONTRACTS = new CallMapper<ContractProvider>()
    .register(anyOf(staticCall("com.google.common.base.Preconditions", "checkNotNull"),
                    staticCall(JAVA_UTIL_OBJECTS, "requireNonNull")),
              (call, cnt) -> cnt > 0 ? failIfNull(0, cnt, true) : null)
    .register(staticCall("com.google.common.base.Preconditions", "checkArgument", "checkState"),
              (call, cnt) -> {
                if (cnt == 0) return null;
                ValueConstraint[] constraints = createConstraintArray(cnt);
                constraints[0] = FALSE_VALUE;
                return Collections.singletonList(new StandardMethodContract(constraints, fail()));
              })
    .register(instanceCall(JAVA_LANG_STRING, "charAt", "codePointAt").parameterCount(1),
              ContractProvider.of(specialFieldRangeContract(0, RelationType.LT, SpecialField.STRING_LENGTH)))
    .register(anyOf(instanceCall(JAVA_LANG_STRING, "substring", "subSequence").parameterCount(2),
                    instanceCall(JAVA_LANG_STRING, "substring").parameterCount(1)),
              (call, cnt) -> getSubstringContracts(cnt == 2))
    .register(instanceCall(JAVA_LANG_STRING, "isEmpty").parameterCount(0),
              ContractProvider.of(SpecialField.STRING_LENGTH.getEmptyContracts()))
    .register(anyOf(instanceCall(JAVA_UTIL_COLLECTION, "isEmpty").parameterCount(0),
                    instanceCall(JAVA_UTIL_MAP, "isEmpty").parameterCount(0)),
              ContractProvider.of(SpecialField.COLLECTION_SIZE.getEmptyContracts()))
    .register(instanceCall(JAVA_LANG_STRING, "equalsIgnoreCase").parameterCount(1),
              ContractProvider.of(SpecialField.STRING_LENGTH.getEqualsContracts()))
    .register(anyOf(instanceCall(JAVA_UTIL_SET, "equals").parameterTypes(JAVA_LANG_OBJECT),
                    instanceCall(JAVA_UTIL_LIST, "equals").parameterTypes(JAVA_LANG_OBJECT),
                    instanceCall(JAVA_UTIL_MAP, "equals").parameterTypes(JAVA_LANG_OBJECT)),
              ContractProvider.of(SpecialField.COLLECTION_SIZE.getEqualsContracts()))
    .register(instanceCall(JAVA_UTIL_COLLECTION, "contains").parameterCount(1),
              ContractProvider.of(singleConditionContract(
                ContractValue.qualifier().specialField(SpecialField.COLLECTION_SIZE), RelationType.EQ, ContractValue.zero(),
                returnFalse())))
    .register(instanceCall(JAVA_UTIL_MAP, "containsKey", "containsValue").parameterCount(1),
              ContractProvider.of(singleConditionContract(
                ContractValue.qualifier().specialField(SpecialField.COLLECTION_SIZE), RelationType.EQ, ContractValue.zero(), returnFalse())))
    .register(instanceCall(JAVA_UTIL_LIST, "get").parameterTypes("int"),
              ContractProvider.of(specialFieldRangeContract(0, RelationType.LT, SpecialField.COLLECTION_SIZE)))
    .register(instanceCall("java.util.SortedSet", "first", "last").parameterCount(0),
              ContractProvider.of(singleConditionContract(
                ContractValue.qualifier().specialField(SpecialField.COLLECTION_SIZE), RelationType.EQ,
                ContractValue.zero(), fail())))
    // All these methods take array as 1st parameter, from index as 2nd and to index as 3rd
    // thus ARRAY_RANGE_CONTRACTS are applicable to them
    .register(staticCall(JAVA_UTIL_ARRAYS, "binarySearch", "fill", "parallelPrefix", "parallelSort", "sort", "spliterator", "stream"),
              (call, cnt) -> cnt >= 3 ? ARRAY_RANGE_CONTRACTS : null)
    .register(staticCall("org.mockito.ArgumentMatchers", "argThat").parameterCount(1),
              ContractProvider.of(StandardMethodContract.fromText("_->_")))
    .register(anyOf(
      instanceCall("java.util.Queue", "peek", "poll").parameterCount(0),
      instanceCall("java.util.Deque", "peekFirst", "peekLast", "pollFirst", "pollLast").parameterCount(0)),
              (call, paramCount) -> Arrays.asList(singleConditionContract(
                ContractValue.qualifier().specialField(SpecialField.COLLECTION_SIZE), RelationType.EQ,
                ContractValue.zero(), returnNull()), trivialContract(returnAny())))
    .register(anyOf(staticCall(JAVA_LANG_MATH, "max").parameterTypes("int", "int"),
                    staticCall(JAVA_LANG_MATH, "max").parameterTypes("long", "long"),
                    staticCall(JAVA_LANG_INTEGER, "max").parameterTypes("int", "int"),
                    staticCall(JAVA_LANG_LONG, "max").parameterTypes("long", "long")),
              (call, paramCount) -> mathMinMax(true))
    .register(anyOf(staticCall(JAVA_LANG_MATH, "min").parameterTypes("int", "int"),
                    staticCall(JAVA_LANG_MATH, "min").parameterTypes("long", "long"),
                    staticCall(JAVA_LANG_INTEGER, "min").parameterTypes("int", "int"),
                    staticCall(JAVA_LANG_LONG, "min").parameterTypes("long", "long")),
              (call, paramCount) -> mathMinMax(false))
    .register(instanceCall(JAVA_LANG_STRING, "startsWith", "endsWith", "contains"),
              ContractProvider.of(
                singleConditionContract(
                  ContractValue.argument(0).specialField(SpecialField.STRING_LENGTH), RelationType.EQ,
                  ContractValue.zero(), returnTrue()),
                singleConditionContract(
                  ContractValue.qualifier().specialField(SpecialField.STRING_LENGTH), RelationType.LT,
                  ContractValue.argument(0).specialField(SpecialField.STRING_LENGTH), returnFalse())))
    .register(instanceCall(JAVA_LANG_OBJECT, "equals").parameterTypes(JAVA_LANG_OBJECT),
              (call, paramCount) -> equalsContracts(call))
    .register(anyOf(
      staticCall(JAVA_UTIL_OBJECTS, "equals").parameterCount(2),
      staticCall("com.google.common.base.Objects", "equal").parameterCount(2)),
              ContractProvider.of(
                singleConditionContract(ContractValue.argument(0), DfaRelationValue.RelationType.EQ, ContractValue.argument(1),
                                        returnTrue()),
                StandardMethodContract.fromText("null,!null->false"),
                StandardMethodContract.fromText("!null,null->false")
              ))
    .register(enumValues(), ContractProvider.of(StandardMethodContract.fromText("->new")));

  public static List<MethodContract> getHardcodedContracts(@NotNull PsiMethod method, @Nullable PsiMethodCallExpression call) {
    PsiClass owner = method.getContainingClass();
{'fraction_non_alphanumeric': 0.11837005303957568, 'fraction_numerical': 0.005099959200326397, 'mean_word_length': 3.9857615052123063, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 45, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5741866', 'n_tokens_mistral': 5501, 'n_tokens_neox': 5340, 'n_words': 871}