<commit_before>/*
 * Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
 */
package com.intellij.codeInsight;

import com.intellij.codeInspection.dataFlow.CommonDataflow;
import com.intellij.codeInspection.dataFlow.DfaFactType;
import com.intellij.codeInspection.dataFlow.TypeConstraint;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.psi.javadoc.PsiDocTag;
import com.intellij.psi.javadoc.PsiDocToken;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.search.searches.FunctionalExpressionSearch;
import com.intellij.psi.util.*;
import com.intellij.util.BitUtil;
import com.intellij.util.Processor;
import com.intellij.util.ThreeState;
import com.intellij.util.containers.ContainerUtil;
import com.siyeh.ig.psiutils.MethodUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.*;

public class JavaTargetElementEvaluator extends TargetElementEvaluatorEx2 implements TargetElementUtilExtender{
  public static final int NEW_AS_CONSTRUCTOR = 0x04;
  public static final int THIS_ACCEPTED = 0x10;
  public static final int SUPER_ACCEPTED = 0x20;
  public static final int USE_DFA = 0x40;

  @Override
  public int getAllAdditionalFlags() {
    return NEW_AS_CONSTRUCTOR | THIS_ACCEPTED | SUPER_ACCEPTED | USE_DFA;
  }

  /**
   * Accepts THIS or SUPER or USE_DFA but not NEW_AS_CONSTRUCTOR.
   */
  @Override
  public int getAdditionalDefinitionSearchFlags() {
    return THIS_ACCEPTED | SUPER_ACCEPTED | USE_DFA;
  }

  /**
   * Accepts NEW_AS_CONSTRUCTOR but not THIS or SUPER.
   */
  @Override
  public int getAdditionalReferenceSearchFlags() {
    return NEW_AS_CONSTRUCTOR;
  }

  @Nullable
  @Override
  public PsiElement adjustTargetElement(Editor editor, int offset, int flags, @NotNull PsiElement targetElement) {
    if (targetElement instanceof PsiKeyword) {
      if (targetElement.getParent() instanceof PsiThisExpression) {
        if (!BitUtil.isSet(flags, THIS_ACCEPTED)) return null;
        PsiType type = ((PsiThisExpression)targetElement.getParent()).getType();
        if (!(type instanceof PsiClassType)) return null;
        return ((PsiClassType)type).resolve();
      }

      if (targetElement.getParent() instanceof PsiSuperExpression) {
        if (!BitUtil.isSet(flags, SUPER_ACCEPTED)) return null;
        PsiType type = ((PsiSuperExpression)targetElement.getParent()).getType();
        if (!(type instanceof PsiClassType)) return null;
        return ((PsiClassType)type).resolve();
      }
    }
    if (targetElement instanceof PsiMethod && BitUtil.isSet(flags, USE_DFA)) {
      PsiElement realMethod = findOverridingMethod(editor, offset, (PsiMethod)targetElement);
      if (realMethod != null) return realMethod;
    }
    return super.adjustTargetElement(editor, offset, flags, targetElement);
  }

  @Nullable
  private static PsiElement findOverridingMethod(Editor editor, int offset, PsiMethod method) {
    PsiClass qualifierClass = method.getContainingClass();
    if (qualifierClass == null || !PsiUtil.canBeOverridden(method)) return null;
    PsiReference reference = TargetElementUtil.findReference(editor, offset);
    if (!(reference instanceof PsiReferenceExpression) || !reference.isReferenceTo(method)) return null;
    PsiExpression qualifier = ((PsiReferenceExpression)reference).getQualifierExpression();
    if (qualifier == null) return null;
    TypeConstraint constraint = CommonDataflow.getExpressionFact(qualifier, DfaFactType.TYPE_CONSTRAINT);
    if (constraint == null) return null;
    return MethodUtils.findSpecificMethod(method, constraint.getPsiType());
  }

  @Override
  public boolean isAcceptableNamedParent(@NotNull PsiElement parent) {
    return !(parent instanceof PsiDocTag);
  }

  @Override
  @NotNull
  public ThreeState isAcceptableReferencedElement(@NotNull final PsiElement element, final PsiElement referenceOrReferencedElement) {
    if (isEnumConstantReference(element, referenceOrReferencedElement)) return ThreeState.NO;
    if (element instanceof PsiDocToken) return ThreeState.NO;
    return super.isAcceptableReferencedElement(element, referenceOrReferencedElement);
  }

  private static boolean isEnumConstantReference(final PsiElement element, final PsiElement referenceOrReferencedElement) {
    return element != null &&
           element.getParent() instanceof PsiEnumConstant &&
           referenceOrReferencedElement instanceof PsiMethod &&
           ((PsiMethod)referenceOrReferencedElement).isConstructor();
  }

  @Nullable
  @Override
  public PsiElement getElementByReference(@NotNull PsiReference ref, int flags) {<commit_msg>JavaTargetElementEvaluator#findOverridingMethod: run DFA only if method class has subclasses<commit_after>/*
 * Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
 */
package com.intellij.codeInsight;

import com.intellij.codeInspection.dataFlow.CommonDataflow;
import com.intellij.codeInspection.dataFlow.DfaFactType;
import com.intellij.codeInspection.dataFlow.TypeConstraint;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.psi.javadoc.PsiDocTag;
import com.intellij.psi.javadoc.PsiDocToken;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.search.searches.DirectClassInheritorsSearch;
import com.intellij.psi.search.searches.FunctionalExpressionSearch;
import com.intellij.psi.util.*;
import com.intellij.util.BitUtil;
import com.intellij.util.Processor;
import com.intellij.util.ThreeState;
import com.intellij.util.containers.ContainerUtil;
import com.siyeh.ig.psiutils.MethodUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.*;

public class JavaTargetElementEvaluator extends TargetElementEvaluatorEx2 implements TargetElementUtilExtender{
  public static final int NEW_AS_CONSTRUCTOR = 0x04;
  public static final int THIS_ACCEPTED = 0x10;
  public static final int SUPER_ACCEPTED = 0x20;
  public static final int USE_DFA = 0x40;

  @Override
  public int getAllAdditionalFlags() {
    return NEW_AS_CONSTRUCTOR | THIS_ACCEPTED | SUPER_ACCEPTED | USE_DFA;
  }

  /**
   * Accepts THIS or SUPER or USE_DFA but not NEW_AS_CONSTRUCTOR.
   */
  @Override
  public int getAdditionalDefinitionSearchFlags() {
    return THIS_ACCEPTED | SUPER_ACCEPTED | USE_DFA;
  }

  /**
   * Accepts NEW_AS_CONSTRUCTOR but not THIS or SUPER.
   */
  @Override
  public int getAdditionalReferenceSearchFlags() {
    return NEW_AS_CONSTRUCTOR;
  }

  @Nullable
  @Override
  public PsiElement adjustTargetElement(Editor editor, int offset, int flags, @NotNull PsiElement targetElement) {
    if (targetElement instanceof PsiKeyword) {
      if (targetElement.getParent() instanceof PsiThisExpression) {
        if (!BitUtil.isSet(flags, THIS_ACCEPTED)) return null;
        PsiType type = ((PsiThisExpression)targetElement.getParent()).getType();
        if (!(type instanceof PsiClassType)) return null;
        return ((PsiClassType)type).resolve();
      }

      if (targetElement.getParent() instanceof PsiSuperExpression) {
        if (!BitUtil.isSet(flags, SUPER_ACCEPTED)) return null;
        PsiType type = ((PsiSuperExpression)targetElement.getParent()).getType();
        if (!(type instanceof PsiClassType)) return null;
        return ((PsiClassType)type).resolve();
      }
    }
    if (targetElement instanceof PsiMethod && BitUtil.isSet(flags, USE_DFA)) {
      PsiElement realMethod = findOverridingMethod(editor, offset, (PsiMethod)targetElement);
      if (realMethod != null) return realMethod;
    }
    return super.adjustTargetElement(editor, offset, flags, targetElement);
  }

  @Nullable
  private static PsiElement findOverridingMethod(Editor editor, int offset, PsiMethod method) {
    PsiClass qualifierClass = method.getContainingClass();
    if (qualifierClass == null || !PsiUtil.canBeOverridden(method)) return null;
    PsiReference reference = TargetElementUtil.findReference(editor, offset);
    if (!(reference instanceof PsiReferenceExpression) || !reference.isReferenceTo(method)) return null;
    PsiExpression qualifier = ((PsiReferenceExpression)reference).getQualifierExpression();
    if (qualifier == null) return null;
    if (DirectClassInheritorsSearch.search(qualifierClass, qualifier.getResolveScope(), false).findFirst() == null) {
      return null;
    }
    TypeConstraint constraint = CommonDataflow.getExpressionFact(qualifier, DfaFactType.TYPE_CONSTRAINT);
    if (constraint == null) return null;
    return MethodUtils.findSpecificMethod(method, constraint.getPsiType());
  }

  @Override
  public boolean isAcceptableNamedParent(@NotNull PsiElement parent) {
    return !(parent instanceof PsiDocTag);
  }

  @Override
  @NotNull
  public ThreeState isAcceptableReferencedElement(@NotNull final PsiElement element, final PsiElement referenceOrReferencedElement) {
    if (isEnumConstantReference(element, referenceOrReferencedElement)) return ThreeState.NO;
    if (element instanceof PsiDocToken) return ThreeState.NO;
    return super.isAcceptableReferencedElement(element, referenceOrReferencedElement);
  }

  private static boolean isEnumConstantReference(final PsiElement element, final PsiElement referenceOrReferencedElement) {
    return element != null &&
           element.getParent() instanceof PsiEnumConstant &&
           referenceOrReferencedElement instanceof PsiMethod &&
           ((PsiMethod)referenceOrReferencedElement).isConstructor();
  }

  @Nullable
  @Override
  public PsiElement getElementByReference(@NotNull PsiReference ref, int flags) {
{'fraction_non_alphanumeric': 0.0880305852367415, 'fraction_numerical': 0.004509361827271836, 'mean_word_length': 4.9835777126099705, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6818624', 'n_tokens_mistral': 3019, 'n_tokens_neox': 2917, 'n_words': 681}