@Override
    public boolean equals(Object o) {
      if (this == o) return true;
      if (o == null || getClass() != o.getClass()) return false;

      AllowedValues a2 = (AllowedValues) o;
      if (canBeOred != a2.canBeOred) {
        return false;
      }
      Set<PsiAnnotationMemberValue> v1 =
          new THashSet<PsiAnnotationMemberValue>(Arrays.asList(values));
      Set<PsiAnnotationMemberValue> v2 =
          new THashSet<PsiAnnotationMemberValue>(Arrays.asList(a2.values));
      if (v1.size() != v2.size()) {
        return false;
      }
      for (PsiAnnotationMemberValue value : v1) {
        for (PsiAnnotationMemberValue value2 : v2) {
          if (same(value, value2, value.getManager())) {
            v2.remove(value2);
            break;
          }
        }
      }
      return v2.isEmpty();
    }
  private static void processCallerMethod(
      JavaChangeInfo changeInfo,
      PsiMethod caller,
      PsiMethod baseMethod,
      boolean toInsertParams,
      boolean toInsertThrows)
      throws IncorrectOperationException {
    LOG.assertTrue(toInsertParams || toInsertThrows);
    if (toInsertParams) {
      List<PsiParameter> newParameters = new ArrayList<PsiParameter>();
      ContainerUtil.addAll(newParameters, caller.getParameterList().getParameters());
      final JavaParameterInfo[] primaryNewParms = changeInfo.getNewParameters();
      PsiSubstitutor substitutor =
          baseMethod == null
              ? PsiSubstitutor.EMPTY
              : ChangeSignatureProcessor.calculateSubstitutor(caller, baseMethod);
      for (JavaParameterInfo info : primaryNewParms) {
        if (info.getOldIndex() < 0)
          newParameters.add(createNewParameter(changeInfo, info, substitutor));
      }
      PsiParameter[] arrayed = newParameters.toArray(new PsiParameter[newParameters.size()]);
      boolean[] toRemoveParm = new boolean[arrayed.length];
      Arrays.fill(toRemoveParm, false);
      resolveParameterVsFieldsConflicts(arrayed, caller, caller.getParameterList(), toRemoveParm);
    }

    if (toInsertThrows) {
      List<PsiJavaCodeReferenceElement> newThrowns = new ArrayList<PsiJavaCodeReferenceElement>();
      final PsiReferenceList throwsList = caller.getThrowsList();
      ContainerUtil.addAll(newThrowns, throwsList.getReferenceElements());
      final ThrownExceptionInfo[] primaryNewExns = changeInfo.getNewExceptions();
      for (ThrownExceptionInfo thrownExceptionInfo : primaryNewExns) {
        if (thrownExceptionInfo.getOldIndex() < 0) {
          final PsiClassType type =
              (PsiClassType) thrownExceptionInfo.createType(caller, caller.getManager());
          final PsiJavaCodeReferenceElement ref =
              JavaPsiFacade.getInstance(caller.getProject())
                  .getElementFactory()
                  .createReferenceElementByType(type);
          newThrowns.add(ref);
        }
      }
      PsiJavaCodeReferenceElement[] arrayed =
          newThrowns.toArray(new PsiJavaCodeReferenceElement[newThrowns.size()]);
      boolean[] toRemoveParm = new boolean[arrayed.length];
      Arrays.fill(toRemoveParm, false);
      ChangeSignatureUtil.synchronizeList(
          throwsList, Arrays.asList(arrayed), ThrowsList.INSTANCE, toRemoveParm);
    }
  }
示例#3
0
 @NotNull
 @Override
 public PsiClass[] findClassByShortName(
     @NotNull String name, @NotNull final GlobalSearchScope scope) {
   PsiClass[] allClasses = getCachedClassesByName(name);
   if (allClasses.length == 0) return allClasses;
   if (allClasses.length == 1) {
     return PsiSearchScopeUtil.isInScope(scope, allClasses[0]) ? allClasses : PsiClass.EMPTY_ARRAY;
   }
   PsiClass[] array =
       ContainerUtil.findAllAsArray(
           allClasses,
           new Condition<PsiClass>() {
             @Override
             public boolean value(PsiClass aClass) {
               return PsiSearchScopeUtil.isInScope(scope, aClass);
             }
           });
   Arrays.sort(
       array,
       new Comparator<PsiClass>() {
         @Override
         public int compare(PsiClass o1, PsiClass o2) {
           VirtualFile file1 = o1.getContainingFile().getVirtualFile();
           VirtualFile file2 = o2.getContainingFile().getVirtualFile();
           if (file1 == null) return file2 == null ? 0 : -1;
           if (file2 == null) return 1;
           return scope.compare(file2, file1);
         }
       });
   return array;
 }
示例#4
0
 @NotNull
 public static PsiElement[] findSuperElements(@NotNull PsiElement element) {
   if (element instanceof PsiClass) {
     PsiClass aClass = (PsiClass) element;
     List<PsiClass> allSupers = new ArrayList<>(Arrays.asList(aClass.getSupers()));
     for (Iterator<PsiClass> iterator = allSupers.iterator(); iterator.hasNext(); ) {
       PsiClass superClass = iterator.next();
       if (CommonClassNames.JAVA_LANG_OBJECT.equals(superClass.getQualifiedName()))
         iterator.remove();
     }
     return allSupers.toArray(new PsiClass[allSupers.size()]);
   }
   if (element instanceof PsiMethod) {
     PsiMethod method = (PsiMethod) element;
     if (method.isConstructor()) {
       PsiMethod constructorInSuper = PsiSuperMethodUtil.findConstructorInSuper(method);
       if (constructorInSuper != null) {
         return new PsiMethod[] {constructorInSuper};
       }
     } else {
       PsiMethod[] superMethods = method.findSuperMethods(false);
       if (superMethods.length == 0) {
         PsiMethod superMethod = getSiblingInheritedViaSubClass(method);
         if (superMethod != null) {
           superMethods = new PsiMethod[] {superMethod};
         }
       }
       return superMethods;
     }
   }
   return PsiElement.EMPTY_ARRAY;
 }
    public MultiMap<PsiElement, String> findConflicts(Ref<UsageInfo[]> refUsages) {
      MultiMap<PsiElement, String> conflictDescriptions = new MultiMap<PsiElement, String>();
      addMethodConflicts(conflictDescriptions);
      Set<UsageInfo> usagesSet = new HashSet<UsageInfo>(Arrays.asList(refUsages.get()));
      RenameUtil.removeConflictUsages(usagesSet);
      if (myChangeInfo.isVisibilityChanged()) {
        try {
          addInaccessibilityDescriptions(usagesSet, conflictDescriptions);
        } catch (IncorrectOperationException e) {
          LOG.error(e);
        }
      }

      for (UsageInfo usageInfo : usagesSet) {
        if (usageInfo instanceof OverriderUsageInfo) {
          final PsiMethod method = (PsiMethod) usageInfo.getElement();
          final PsiMethod baseMethod = ((OverriderUsageInfo) usageInfo).getBaseMethod();
          final int delta =
              baseMethod.getParameterList().getParametersCount()
                  - method.getParameterList().getParametersCount();
          if (delta > 0) {
            final boolean[] toRemove = myChangeInfo.toRemoveParm();
            if (toRemove[
                toRemove.length - 1]) { // todo check if implicit parameter is not the last one
              conflictDescriptions.putValue(
                  baseMethod, "Implicit last parameter should not be deleted");
            }
          }
        }
      }

      return conflictDescriptions;
    }
示例#6
0
  @Override
  @Nullable
  public Collection<PsiImportStatementBase> findRedundantImports(final PsiJavaFile file) {
    final PsiImportList importList = file.getImportList();
    if (importList == null) return null;
    final PsiImportStatementBase[] imports = importList.getAllImportStatements();
    if (imports.length == 0) return null;

    Set<PsiImportStatementBase> allImports =
        new THashSet<PsiImportStatementBase>(Arrays.asList(imports));
    final Collection<PsiImportStatementBase> redundant;
    if (FileTypeUtils.isInServerPageFile(file)) {
      // remove only duplicate imports
      redundant = ContainerUtil.newIdentityTroveSet();
      ContainerUtil.addAll(redundant, imports);
      redundant.removeAll(allImports);
      for (PsiImportStatementBase importStatement : imports) {
        if (importStatement instanceof JspxImportStatement
            && importStatement.isForeignFileImport()) {
          redundant.remove(importStatement);
        }
      }
    } else {
      redundant = allImports;
      final List<PsiFile> roots = file.getViewProvider().getAllFiles();
      for (PsiElement root : roots) {
        root.accept(
            new JavaRecursiveElementWalkingVisitor() {
              @Override
              public void visitReferenceElement(PsiJavaCodeReferenceElement reference) {
                if (!reference.isQualified()) {
                  final JavaResolveResult resolveResult = reference.advancedResolve(false);
                  if (!inTheSamePackage(file, resolveResult.getElement())) {
                    final PsiElement resolveScope = resolveResult.getCurrentFileResolveScope();
                    if (resolveScope instanceof PsiImportStatementBase) {
                      final PsiImportStatementBase importStatementBase =
                          (PsiImportStatementBase) resolveScope;
                      redundant.remove(importStatementBase);
                    }
                  }
                }
                super.visitReferenceElement(reference);
              }

              private boolean inTheSamePackage(PsiJavaFile file, PsiElement element) {
                if (element instanceof PsiClass
                    && ((PsiClass) element).getContainingClass() == null) {
                  final PsiFile containingFile = element.getContainingFile();
                  if (containingFile instanceof PsiJavaFile) {
                    return Comparing.strEqual(
                        file.getPackageName(), ((PsiJavaFile) containingFile).getPackageName());
                  }
                }
                return false;
              }
            });
      }
    }
    return redundant;
  }
 public static void addExpandingReflectedMethods(List<PsiMethod> result, PsiMethod method) {
   if (method instanceof GrMethod) {
     final GrReflectedMethod[] reflectedMethods = ((GrMethod) method).getReflectedMethods();
     if (reflectedMethods.length > 0) {
       result.addAll(Arrays.asList(reflectedMethods));
       return;
     }
   }
   result.add(method);
 }
  @NotNull
  private static List<PsiClass> getInnerClassesForResolve(
      @NotNull final GrTypeDefinition grType,
      @Nullable final PsiElement lastParent,
      @NotNull final PsiElement place) {
    if (lastParent instanceof GrReferenceList
        || PsiTreeUtil.getParentOfType(place, GrReferenceList.class) != null) {
      return Arrays.asList(grType.getInnerClasses());
    }

    List<PsiClass> classes =
        RecursionManager.doPreventingRecursion(
            grType,
            true,
            new Computable<List<PsiClass>>() {
              @Override
              public List<PsiClass> compute() {
                List<PsiClass> result = new ArrayList<PsiClass>();
                for (CandidateInfo info :
                    CollectClassMembersUtil.getAllInnerClasses(grType, false).values()) {
                  final PsiClass inner = (PsiClass) info.getElement();
                  final PsiClass containingClass = inner.getContainingClass();
                  assert containingClass != null;

                  if (lastParent == null
                      || !containingClass.isInterface()
                      || PsiTreeUtil.isAncestor(containingClass, place, false)) {
                    ContainerUtil.addIfNotNull(result, inner);
                  }
                }
                return result;
              }
            });

    if (classes == null) {
      return Arrays.asList(grType.getInnerClasses());
    }

    return classes;
  }
  @Override
  public List<RefEntity> getChildren() {
    List<RefEntity> superChildren = super.getChildren();
    if (myParameters == null) return superChildren;
    if (superChildren == null || superChildren.isEmpty())
      return Arrays.<RefEntity>asList(myParameters);

    List<RefEntity> allChildren =
        new ArrayList<RefEntity>(superChildren.size() + myParameters.length);
    allChildren.addAll(superChildren);
    Collections.addAll(allChildren, myParameters);
    return allChildren;
  }
  private static void getImplementListsInner(
      GrTypeDefinition grType, List<PsiClassType> result, Set<PsiClass> visited) {
    if (!visited.add(grType)) return;

    final PsiClassType[] implementsTypes = getReferenceListTypes(grType.getImplementsClause());
    List<PsiClassType> fromDelegates = getImplementsFromDelegate(grType, visited);
    if (fromDelegates != null) {
      result.addAll(fromDelegates);
    }
    result.addAll(Arrays.asList(implementsTypes));

    if (!grType.isInterface()
        && !ContainerUtil.or(implementsTypes, IS_GROOVY_OBJECT)
        && !ContainerUtil.or(getReferenceListTypes(grType.getExtendsClause()), IS_GROOVY_OBJECT)) {
      result.add(getGroovyObjectType(grType));
    }
  }
  @Nullable
  private Ref<? extends PyType> getYieldStatementType(@NotNull final TypeEvalContext context) {
    Ref<PyType> elementType = null;
    final PyBuiltinCache cache = PyBuiltinCache.getInstance(this);
    final PyStatementList statements = getStatementList();
    final Set<PyType> types = new LinkedHashSet<>();
    statements.accept(
        new PyRecursiveElementVisitor() {
          @Override
          public void visitPyYieldExpression(PyYieldExpression node) {
            final PyExpression expr = node.getExpression();
            final PyType type = expr != null ? context.getType(expr) : null;
            if (node.isDelegating() && type instanceof PyCollectionType) {
              final PyCollectionType collectionType = (PyCollectionType) type;
              // TODO: Select the parameter types that matches T in Iterable[T]
              final List<PyType> elementTypes = collectionType.getElementTypes(context);
              types.add(elementTypes.isEmpty() ? null : elementTypes.get(0));
            } else {
              types.add(type);
            }
          }

          @Override
          public void visitPyFunction(PyFunction node) {
            // Ignore nested functions
          }
        });
    final int n = types.size();
    if (n == 1) {
      elementType = Ref.create(types.iterator().next());
    } else if (n > 0) {
      elementType = Ref.create(PyUnionType.union(types));
    }
    if (elementType != null) {
      final PyClass generator = cache.getClass(PyNames.FAKE_GENERATOR);
      if (generator != null) {
        final List<PyType> parameters =
            Arrays.asList(elementType.get(), null, getReturnStatementType(context));
        return Ref.create(new PyCollectionTypeImpl(generator, false, parameters));
      }
    }
    if (!types.isEmpty()) {
      return Ref.create(null);
    }
    return null;
  }
 private static void resolveParameterVsFieldsConflicts(
     final PsiParameter[] newParms,
     final PsiMethod method,
     final PsiParameterList list,
     boolean[] toRemoveParm)
     throws IncorrectOperationException {
   List<FieldConflictsResolver> conflictResolvers = new ArrayList<FieldConflictsResolver>();
   for (PsiParameter parameter : newParms) {
     conflictResolvers.add(new FieldConflictsResolver(parameter.getName(), method.getBody()));
   }
   ChangeSignatureUtil.synchronizeList(
       list, Arrays.asList(newParms), ParameterList.INSTANCE, toRemoveParm);
   JavaCodeStyleManager.getInstance(list.getProject()).shortenClassReferences(list);
   for (FieldConflictsResolver fieldConflictsResolver : conflictResolvers) {
     fieldConflictsResolver.fix();
   }
 }
 private void getFilesRecursively(
     VirtualFile file, boolean compileTimeOnly, Set<VirtualFile> result) {
   if (result.contains(file)) return;
   PsiFile psiFile = myPsiManager.findFile(file);
   if (psiFile == null) return;
   VirtualFile[] includes =
       compileTimeOnly
           ? myCachedValuesManager.getParameterizedCachedValue(
               psiFile, COMPILE_TIME_KEY, COMPILE_TIME_PROVIDER, false, psiFile)
           : myCachedValuesManager.getParameterizedCachedValue(
               psiFile, RUNTIME_KEY, RUNTIME_PROVIDER, false, psiFile);
   if (includes.length != 0) {
     result.addAll(Arrays.asList(includes));
     for (VirtualFile include : includes) {
       getFilesRecursively(include, compileTimeOnly, result);
     }
   }
 }
示例#14
0
  private static void sortVariableNameSuggestions(
      String[] names,
      final VariableKind variableKind,
      @Nullable final String propertyName,
      @Nullable final PsiType type) {
    if (names.length <= 1) {
      return;
    }

    if (LOG.isDebugEnabled()) {
      LOG.debug("sorting names:" + variableKind);
      if (propertyName != null) {
        LOG.debug("propertyName:" + propertyName);
      }
      if (type != null) {
        LOG.debug("type:" + type);
      }
      for (String name : names) {
        int count =
            JavaStatisticsManager.getVariableNameUseCount(name, variableKind, propertyName, type);
        LOG.debug(name + " : " + count);
      }
    }

    Comparator<String> comparator =
        new Comparator<String>() {
          @Override
          public int compare(String s1, String s2) {
            int count1 =
                JavaStatisticsManager.getVariableNameUseCount(s1, variableKind, propertyName, type);
            int count2 =
                JavaStatisticsManager.getVariableNameUseCount(s2, variableKind, propertyName, type);
            return count2 - count1;
          }
        };
    Arrays.sort(names, comparator);
  }
示例#15
0
/**
 * @author Hani Suleiman
 * @since Jul 20, 2005
 */
public class TestNGUtil {
  private static final Logger LOGGER = Logger.getInstance("TestNG Runner");

  public static final String TESTNG_GROUP_NAME = "TestNG";

  public static boolean hasDocTagsSupport = hasDocTagsSupport();

  private static boolean hasDocTagsSupport() {
    String testngJarPath = PathUtil.getJarPathForClass(Test.class);
    String version =
        JarUtil.getJarAttribute(new File(testngJarPath), Attributes.Name.IMPLEMENTATION_VERSION);
    return version != null && StringUtil.compareVersionNumbers(version, "5.12") <= 0;
  }

  public static final String TEST_ANNOTATION_FQN = Test.class.getName();
  public static final String FACTORY_ANNOTATION_FQN = Factory.class.getName();

  @SuppressWarnings("deprecation")
  public static final String[] CONFIG_ANNOTATIONS_FQN = {
    Configuration.class.getName(),
    Factory.class.getName(),
    ObjectFactory.class.getName(),
    DataProvider.class.getName(),
    BeforeClass.class.getName(),
    BeforeGroups.class.getName(),
    BeforeMethod.class.getName(),
    BeforeSuite.class.getName(),
    BeforeTest.class.getName(),
    AfterClass.class.getName(),
    AfterGroups.class.getName(),
    AfterMethod.class.getName(),
    AfterSuite.class.getName(),
    AfterTest.class.getName()
  };

  @SuppressWarnings("deprecation")
  public static final String[] CONFIG_ANNOTATIONS_FQN_NO_TEST_LEVEL = {
    Configuration.class.getName(),
    Factory.class.getName(),
    ObjectFactory.class.getName(),
    BeforeClass.class.getName(),
    BeforeGroups.class.getName(),
    BeforeSuite.class.getName(),
    BeforeTest.class.getName(),
    AfterClass.class.getName(),
    AfterGroups.class.getName(),
    AfterSuite.class.getName(),
    AfterTest.class.getName()
  };

  @NonNls
  private static final String[] CONFIG_JAVADOC_TAGS = {
    "testng.configuration",
    "testng.before-class",
    "testng.before-groups",
    "testng.before-method",
    "testng.before-suite",
    "testng.before-test",
    "testng.after-class",
    "testng.after-groups",
    "testng.after-method",
    "testng.after-suite",
    "testng.after-test"
  };

  private static final List<String> JUNIT_ANNOTATIONS =
      Arrays.asList(
          "org.junit.Test",
          "org.junit.Before",
          "org.junit.BeforeClass",
          "org.junit.After",
          "org.junit.AfterClass");

  @NonNls private static final String SUITE_TAG_NAME = "suite";

  public static boolean hasConfig(PsiModifierListOwner element) {
    return hasConfig(element, CONFIG_ANNOTATIONS_FQN);
  }

  public static boolean hasConfig(PsiModifierListOwner element, String[] configAnnotationsFqn) {
    if (element instanceof PsiClass) {
      for (PsiMethod method : ((PsiClass) element).getAllMethods()) {
        if (isConfigMethod(method, configAnnotationsFqn)) return true;
      }
    } else {
      if (!(element instanceof PsiMethod)) return false;
      return isConfigMethod((PsiMethod) element, configAnnotationsFqn);
    }
    return false;
  }

  private static boolean isConfigMethod(PsiMethod method, String[] configAnnotationsFqn) {
    for (String fqn : configAnnotationsFqn) {
      if (AnnotationUtil.isAnnotated(method, fqn, false)) return true;
    }

    if (hasDocTagsSupport) {
      final PsiDocComment comment = method.getDocComment();
      if (comment != null) {
        for (String javadocTag : CONFIG_JAVADOC_TAGS) {
          if (comment.findTagByName(javadocTag) != null) return true;
        }
      }
    }
    return false;
  }

  public static String getConfigAnnotation(PsiMethod method) {
    if (method != null) {
      for (String fqn : CONFIG_ANNOTATIONS_FQN) {
        if (AnnotationUtil.isAnnotated(method, fqn, false)) return fqn;
      }
    }
    return null;
  }

  public static boolean isTestNGAnnotation(PsiAnnotation annotation) {
    String qName = annotation.getQualifiedName();
    if (qName != null) {
      if (qName.equals(TEST_ANNOTATION_FQN)) return true;
      for (String qn : CONFIG_ANNOTATIONS_FQN) {
        if (qName.equals(qn)) return true;
      }
      if (qName.equals(TEST_ANNOTATION_FQN)) return true;
      for (String qn : CONFIG_ANNOTATIONS_FQN) {
        if (qName.equals(qn)) return true;
      }
    }
    return false;
  }

  public static boolean hasTest(PsiModifierListOwner element) {
    return CachedValuesManager.getCachedValue(
        element,
        () ->
            CachedValueProvider.Result.create(
                hasTest(element, true), PsiModificationTracker.MODIFICATION_COUNT));
  }

  public static boolean hasTest(PsiModifierListOwner element, boolean checkDisabled) {
    return hasTest(element, true, checkDisabled, hasDocTagsSupport);
  }

  public static boolean hasTest(
      PsiModifierListOwner element,
      boolean checkHierarchy,
      boolean checkDisabled,
      boolean checkJavadoc) {
    // LanguageLevel effectiveLanguageLevel = element.getManager().getEffectiveLanguageLevel();
    // boolean is15 = effectiveLanguageLevel != LanguageLevel.JDK_1_4 && effectiveLanguageLevel !=
    // LanguageLevel.JDK_1_3;
    boolean hasAnnotation =
        AnnotationUtil.isAnnotated(element, TEST_ANNOTATION_FQN, checkHierarchy, true);
    if (hasAnnotation) {
      if (checkDisabled) {
        PsiAnnotation annotation =
            AnnotationUtil.findAnnotation(element, true, TEST_ANNOTATION_FQN);
        if (annotation != null) {
          if (isDisabled(annotation)) return false;
        }
      }
      return true;
    }
    if (element instanceof PsiDocCommentOwner
        && checkJavadoc
        && getTextJavaDoc((PsiDocCommentOwner) element) != null) return true;
    // now we check all methods for the test annotation
    if (element instanceof PsiClass) {
      PsiClass psiClass = (PsiClass) element;
      for (PsiMethod method : psiClass.getAllMethods()) {
        PsiAnnotation annotation = AnnotationUtil.findAnnotation(method, true, TEST_ANNOTATION_FQN);
        if (annotation != null) {
          if (checkDisabled) {
            if (isDisabled(annotation)) continue;
          }
          return true;
        }
        if (AnnotationUtil.isAnnotated(method, FACTORY_ANNOTATION_FQN, false, true)) return true;
        if (checkJavadoc && getTextJavaDoc(method) != null) return true;
      }
      return false;
    } else if (element instanceof PsiMethod) {
      // even if it has a global test, we ignore private and static methods
      if (element.hasModifierProperty(PsiModifier.PRIVATE)
          || element.hasModifierProperty(PsiModifier.STATIC)) {
        return false;
      }

      // if it's a method, we check if the class it's in has a global @Test annotation
      PsiClass psiClass = ((PsiMethod) element).getContainingClass();
      if (psiClass != null) {
        final PsiAnnotation annotation =
            checkHierarchy
                ? AnnotationUtil.findAnnotationInHierarchy(
                    psiClass, Collections.singleton(TEST_ANNOTATION_FQN))
                : AnnotationUtil.findAnnotation(psiClass, true, TEST_ANNOTATION_FQN);
        if (annotation != null) {
          if (checkDisabled && isDisabled(annotation)) return false;
          return !hasConfig(element);
        } else if (checkJavadoc && getTextJavaDoc(psiClass) != null) return true;
      }
    }
    return false;
  }

  public static boolean isDisabled(PsiAnnotation annotation) {
    final PsiAnnotationMemberValue attributeValue =
        annotation.findDeclaredAttributeValue("enabled");
    return attributeValue != null && attributeValue.textMatches("false");
  }

  private static PsiDocTag getTextJavaDoc(@NotNull final PsiDocCommentOwner element) {
    final PsiDocComment docComment = element.getDocComment();
    if (docComment != null) {
      return docComment.findTagByName("testng.test");
    }
    return null;
  }

  /** Ignore these, they cause an NPE inside of AnnotationUtil */
  private static boolean isBrokenPsiClass(PsiClass psiClass) {
    return (psiClass == null
        || psiClass instanceof PsiAnonymousClass
        || psiClass instanceof PsiSyntheticClass);
  }

  /**
   * Filter the specified collection of classes to return only ones that contain any of the
   * specified values in the specified annotation parameter. For example, this method can be used to
   * return all classes that contain all tesng annotations that are in the groups 'foo' or 'bar'.
   */
  public static Map<PsiClass, Collection<PsiMethod>> filterAnnotations(
      String parameter, Set<String> values, Collection<PsiClass> classes) {
    Map<PsiClass, Collection<PsiMethod>> results = new HashMap<>();
    Set<String> test = new HashSet<>(1);
    test.add(TEST_ANNOTATION_FQN);
    ContainerUtil.addAll(test, CONFIG_ANNOTATIONS_FQN);
    for (PsiClass psiClass : classes) {
      if (isBrokenPsiClass(psiClass)) continue;

      PsiAnnotation annotation;
      try {
        annotation = AnnotationUtil.findAnnotation(psiClass, test);
      } catch (Exception e) {
        LOGGER.error(
            "Exception trying to findAnnotation on "
                + psiClass.getClass().getName()
                + ".\n\n"
                + e.getMessage());
        annotation = null;
      }
      if (annotation != null) {
        if (isAnnotatedWithParameter(annotation, parameter, values)) {
          results.put(psiClass, new LinkedHashSet<>());
        }
      } else {
        Collection<String> matches =
            extractAnnotationValuesFromJavaDoc(getTextJavaDoc(psiClass), parameter);
        for (String s : matches) {
          if (values.contains(s)) {
            results.put(psiClass, new LinkedHashSet<>());
            break;
          }
        }
      }

      // we already have the class, no need to look through its methods
      PsiMethod[] methods = psiClass.getMethods();
      for (PsiMethod method : methods) {
        if (method != null) {
          annotation = AnnotationUtil.findAnnotation(method, test);
          if (annotation != null) {
            if (isAnnotatedWithParameter(annotation, parameter, values)) {
              if (results.get(psiClass) == null) results.put(psiClass, new LinkedHashSet<>());
              results.get(psiClass).add(method);
            }
          } else {
            Collection<String> matches =
                extractAnnotationValuesFromJavaDoc(getTextJavaDoc(psiClass), parameter);
            for (String s : matches) {
              if (values.contains(s)) {
                results.get(psiClass).add(method);
              }
            }
          }
        }
      }
    }
    return results;
  }

  public static boolean isAnnotatedWithParameter(
      PsiAnnotation annotation, String parameter, Set<String> values) {
    final PsiAnnotationMemberValue attributeValue =
        annotation.findDeclaredAttributeValue(parameter);
    if (attributeValue != null) {
      Collection<String> matches = extractValuesFromParameter(attributeValue);
      for (String s : matches) {
        if (values.contains(s)) {
          return true;
        }
      }
    }
    return false;
  }

  public static Set<String> getAnnotationValues(String parameter, PsiClass... classes) {
    Map<String, Collection<String>> results = new HashMap<>();
    final HashSet<String> set = new HashSet<>();
    results.put(parameter, set);
    collectAnnotationValues(results, null, classes);
    return set;
  }

  /** @return were javadoc params used */
  public static void collectAnnotationValues(
      final Map<String, Collection<String>> results, PsiMethod[] psiMethods, PsiClass... classes) {
    final Set<String> test = new HashSet<>(1);
    test.add(TEST_ANNOTATION_FQN);
    ContainerUtil.addAll(test, CONFIG_ANNOTATIONS_FQN);
    if (psiMethods != null) {
      for (final PsiMethod psiMethod : psiMethods) {
        ApplicationManager.getApplication()
            .runReadAction(
                () ->
                    appendAnnotationAttributeValues(
                        results, AnnotationUtil.findAnnotation(psiMethod, test), psiMethod));
      }
    } else {
      for (final PsiClass psiClass : classes) {
        ApplicationManager.getApplication()
            .runReadAction(
                () -> {
                  if (psiClass != null && hasTest(psiClass)) {
                    appendAnnotationAttributeValues(
                        results, AnnotationUtil.findAnnotation(psiClass, test), psiClass);
                    PsiMethod[] methods = psiClass.getMethods();
                    for (PsiMethod method : methods) {
                      if (method != null) {
                        appendAnnotationAttributeValues(
                            results, AnnotationUtil.findAnnotation(method, test), method);
                      }
                    }
                  }
                });
      }
    }
  }

  private static void appendAnnotationAttributeValues(
      final Map<String, Collection<String>> results,
      final PsiAnnotation annotation,
      final PsiDocCommentOwner commentOwner) {
    for (String parameter : results.keySet()) {
      final Collection<String> values = results.get(parameter);
      if (annotation != null) {
        final PsiAnnotationMemberValue value = annotation.findDeclaredAttributeValue(parameter);
        if (value != null) {
          values.addAll(extractValuesFromParameter(value));
        }
      } else {
        values.addAll(extractAnnotationValuesFromJavaDoc(getTextJavaDoc(commentOwner), parameter));
      }
    }
  }

  private static Collection<String> extractAnnotationValuesFromJavaDoc(
      PsiDocTag tag, String parameter) {
    if (tag == null) return Collections.emptyList();
    Collection<String> results = new ArrayList<>();
    Matcher matcher =
        Pattern.compile("\\@testng.test(?:.*)" + parameter + "\\s*=\\s*\"(.*?)\".*")
            .matcher(tag.getText());
    if (matcher.matches()) {
      String[] groups = matcher.group(1).split("[,\\s]");
      for (String group : groups) {
        final String trimmed = group.trim();
        if (trimmed.length() > 0) {
          results.add(trimmed);
        }
      }
    }
    return results;
  }

  private static Collection<String> extractValuesFromParameter(PsiAnnotationMemberValue value) {
    Collection<String> results = new ArrayList<>();
    if (value instanceof PsiArrayInitializerMemberValue) {
      for (PsiElement child : value.getChildren()) {
        if (child instanceof PsiLiteralExpression) {
          results.add((String) ((PsiLiteralExpression) child).getValue());
        }
      }
    } else {
      if (value instanceof PsiLiteralExpression) {
        results.add((String) ((PsiLiteralExpression) value).getValue());
      }
    }
    return results;
  }

  @Nullable
  public static PsiClass[] getAllTestClasses(final TestClassFilter filter, boolean sync) {
    final PsiClass[][] holder = new PsiClass[1][];
    final Runnable process =
        () -> {
          final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();

          final Collection<PsiClass> set = new LinkedHashSet<>();
          final PsiManager manager = PsiManager.getInstance(filter.getProject());
          final GlobalSearchScope projectScope =
              GlobalSearchScope.projectScope(manager.getProject());
          final GlobalSearchScope scope = projectScope.intersectWith(filter.getScope());
          for (final PsiClass psiClass : AllClassesSearch.search(scope, manager.getProject())) {
            if (filter.isAccepted(psiClass)) {
              if (indicator != null) {
                indicator.setText2(
                    "Found test class " + ReadAction.compute(psiClass::getQualifiedName));
              }
              set.add(psiClass);
            }
          }
          holder[0] = set.toArray(new PsiClass[set.size()]);
        };
    if (sync) {
      ProgressManager.getInstance()
          .runProcessWithProgressSynchronously(
              process, "Searching For Tests...", true, filter.getProject());
    } else {
      process.run();
    }
    return holder[0];
  }

  public static PsiAnnotation[] getTestNGAnnotations(PsiElement element) {
    PsiElement[] annotations =
        PsiTreeUtil.collectElements(
            element,
            new PsiElementFilter() {
              public boolean isAccepted(PsiElement element) {
                if (!(element instanceof PsiAnnotation)) return false;
                String name = ((PsiAnnotation) element).getQualifiedName();
                if (null == name) return false;
                if (name.startsWith("org.testng.annotations")) {
                  return true;
                }
                return false;
              }
            });
    PsiAnnotation[] array = new PsiAnnotation[annotations.length];
    System.arraycopy(annotations, 0, array, 0, annotations.length);
    return array;
  }

  public static boolean isTestNGClass(PsiClass psiClass) {
    return hasTest(psiClass, true, false, false);
  }

  public static boolean checkTestNGInClasspath(PsiElement psiElement) {
    final Project project = psiElement.getProject();
    final PsiManager manager = PsiManager.getInstance(project);
    if (JavaPsiFacade.getInstance(manager.getProject())
            .findClass(TestNG.class.getName(), psiElement.getResolveScope())
        == null) {
      if (!ApplicationManager.getApplication().isUnitTestMode()) {
        if (Messages.showOkCancelDialog(
                psiElement.getProject(),
                "TestNG will be added to module classpath",
                "Unable to convert.",
                Messages.getWarningIcon())
            != Messages.OK) {
          return false;
        }
      }
      final Module module = ModuleUtilCore.findModuleForPsiElement(psiElement);
      if (module == null) return false;
      String url =
          VfsUtil.getUrlForLibraryRoot(new File(PathUtil.getJarPathForClass(Assert.class)));
      ModuleRootModificationUtil.addModuleLibrary(module, url);
    }
    return true;
  }

  public static boolean containsJunitAnnotions(PsiClass psiClass) {
    if (psiClass != null) {
      for (PsiMethod method : psiClass.getMethods()) {
        if (containsJunitAnnotions(method)) {
          return true;
        }
      }
    }
    return false;
  }

  public static boolean containsJunitAnnotions(PsiMethod method) {
    return method != null && AnnotationUtil.isAnnotated(method, JUNIT_ANNOTATIONS);
  }

  public static boolean inheritsJUnitTestCase(PsiClass psiClass) {
    PsiClass current = psiClass;
    while (current != null) {
      PsiClass[] supers = current.getSupers();
      if (supers.length > 0) {
        PsiClass parent = supers[0];
        if ("junit.framework.TestCase".equals(parent.getQualifiedName())) return true;
        current = parent;
        // handle typo where class extends itself
        if (current == psiClass) return false;
      } else {
        current = null;
      }
    }
    return false;
  }

  public static boolean inheritsITestListener(@NotNull PsiClass psiClass) {
    final Project project = psiClass.getProject();
    final PsiClass aListenerClass =
        JavaPsiFacade.getInstance(project)
            .findClass(ITestNGListener.class.getName(), GlobalSearchScope.allScope(project));
    return aListenerClass != null && psiClass.isInheritor(aListenerClass, true);
  }

  public static boolean isTestngXML(final VirtualFile virtualFile) {
    if ("xml".equalsIgnoreCase(virtualFile.getExtension())
        && virtualFile.isInLocalFileSystem()
        && virtualFile.isValid()) {
      final String result = NanoXmlUtil.parseHeader(virtualFile).getRootTagLocalName();
      if (result != null && result.equals(SUITE_TAG_NAME)) {
        return true;
      }
    }
    return false;
  }

  public static PsiClass getProviderClass(final PsiElement element, final PsiClass topLevelClass) {
    final PsiAnnotation annotation = PsiTreeUtil.getParentOfType(element, PsiAnnotation.class);
    if (annotation != null) {
      final PsiAnnotationMemberValue value =
          annotation.findDeclaredAttributeValue("dataProviderClass");
      if (value instanceof PsiClassObjectAccessExpression) {
        final PsiTypeElement operand = ((PsiClassObjectAccessExpression) value).getOperand();
        final PsiClass psiClass = PsiUtil.resolveClassInType(operand.getType());
        if (psiClass != null) {
          return psiClass;
        }
      }
    }
    return topLevelClass;
  }
}
 @Override
 public int hashCode() {
   int result = values != null ? Arrays.hashCode(values) : 0;
   result = 31 * result + (canBeOred ? 1 : 0);
   return result;
 }
 public List<PsiExpression> getChildren(PsiExpressionList psiExpressionList) {
   return Arrays.asList(psiExpressionList.getExpressions());
 }
 @Nullable
 public String extractDeprecationMessage() {
   PyStatementList statementList = getStatementList();
   return extractDeprecationMessage(Arrays.asList(statementList.getStatements()));
 }
  // This methods works equally well for primary usages as well as for propagated callers' usages
  private static void fixActualArgumentsList(
      PsiExpressionList list,
      JavaChangeInfo changeInfo,
      boolean toInsertDefaultValue,
      PsiSubstitutor substitutor)
      throws IncorrectOperationException {
    final PsiElementFactory factory =
        JavaPsiFacade.getInstance(list.getProject()).getElementFactory();
    if (changeInfo.isParameterSetOrOrderChanged()) {
      if (changeInfo instanceof JavaChangeInfoImpl
          && ((JavaChangeInfoImpl) changeInfo).isPropagationEnabled) {
        final ParameterInfoImpl[] createdParmsInfo =
            ((JavaChangeInfoImpl) changeInfo).getCreatedParmsInfoWithoutVarargs();
        for (ParameterInfoImpl info : createdParmsInfo) {
          PsiExpression newArg;
          if (toInsertDefaultValue) {
            newArg = createDefaultValue(changeInfo, factory, info, list);
          } else {
            newArg = factory.createExpressionFromText(info.getName(), list);
          }
          JavaCodeStyleManager.getInstance(list.getProject())
              .shortenClassReferences(list.add(newArg));
        }
      } else {
        final PsiExpression[] args = list.getExpressions();
        final int nonVarargCount = getNonVarargCount(changeInfo, args);
        final int varargCount = args.length - nonVarargCount;
        if (varargCount < 0) return;
        PsiExpression[] newVarargInitializers = null;

        final int newArgsLength;
        final int newNonVarargCount;
        final JavaParameterInfo[] newParms = changeInfo.getNewParameters();
        if (changeInfo.isArrayToVarargs()) {
          newNonVarargCount = newParms.length - 1;
          final JavaParameterInfo lastNewParm = newParms[newParms.length - 1];
          final PsiExpression arrayToConvert = args[lastNewParm.getOldIndex()];
          if (arrayToConvert instanceof PsiNewExpression) {
            final PsiNewExpression expression = (PsiNewExpression) arrayToConvert;
            final PsiArrayInitializerExpression arrayInitializer = expression.getArrayInitializer();
            if (arrayInitializer != null) {
              newVarargInitializers = arrayInitializer.getInitializers();
            }
          }
          newArgsLength =
              newVarargInitializers == null
                  ? newParms.length
                  : newNonVarargCount + newVarargInitializers.length;
        } else if (changeInfo.isRetainsVarargs()) {
          newNonVarargCount = newParms.length - 1;
          newArgsLength = newNonVarargCount + varargCount;
        } else if (changeInfo.isObtainsVarags()) {
          newNonVarargCount = newParms.length - 1;
          newArgsLength = newNonVarargCount;
        } else {
          newNonVarargCount = newParms.length;
          newArgsLength = newParms.length;
        }

        String[] oldVarargs = null;
        if (changeInfo.wasVararg() && !changeInfo.isRetainsVarargs()) {
          oldVarargs = new String[varargCount];
          for (int i = nonVarargCount; i < args.length; i++) {
            oldVarargs[i - nonVarargCount] = args[i].getText();
          }
        }

        final PsiExpression[] newArgs = new PsiExpression[newArgsLength];
        for (int i = 0; i < newNonVarargCount; i++) {
          if (newParms[i].getOldIndex() == nonVarargCount && oldVarargs != null) {
            PsiType type = newParms[i].createType(changeInfo.getMethod(), list.getManager());
            if (type instanceof PsiArrayType) {
              type = substitutor.substitute(type);
              type = TypeConversionUtil.erasure(type);
              String typeText = type.getCanonicalText();
              if (type instanceof PsiEllipsisType) {
                typeText = typeText.replace("...", "[]");
              }
              String text = "new " + typeText + "{" + StringUtil.join(oldVarargs, ",") + "}";
              newArgs[i] = factory.createExpressionFromText(text, changeInfo.getMethod());
              continue;
            }
          }
          newArgs[i] =
              createActualArgument(changeInfo, list, newParms[i], toInsertDefaultValue, args);
        }
        if (changeInfo.isArrayToVarargs()) {
          if (newVarargInitializers == null) {
            newArgs[newNonVarargCount] =
                createActualArgument(
                    changeInfo, list, newParms[newNonVarargCount], toInsertDefaultValue, args);
          } else {
            System.arraycopy(
                newVarargInitializers, 0, newArgs, newNonVarargCount, newVarargInitializers.length);
          }
        } else {
          final int newVarargCount = newArgsLength - newNonVarargCount;
          LOG.assertTrue(newVarargCount == 0 || newVarargCount == varargCount);
          for (int i = newNonVarargCount; i < newArgsLength; i++) {
            final int oldIndex = newParms[newNonVarargCount].getOldIndex();
            if (oldIndex >= 0 && oldIndex != nonVarargCount) {
              newArgs[i] =
                  createActualArgument(
                      changeInfo, list, newParms[newNonVarargCount], toInsertDefaultValue, args);
            } else {
              System.arraycopy(args, nonVarargCount, newArgs, newNonVarargCount, newVarargCount);
              break;
            }
          }
        }
        ChangeSignatureUtil.synchronizeList(
            list, Arrays.asList(newArgs), ExpressionList.INSTANCE, changeInfo.toRemoveParm());
      }
    }
  }
 public List<PsiParameter> getChildren(PsiParameterList psiParameterList) {
   return Arrays.asList(psiParameterList.getParameters());
 }
 public List<PsiJavaCodeReferenceElement> getChildren(PsiReferenceList throwsList) {
   return Arrays.asList(throwsList.getReferenceElements());
 }