void (final Set<? super PsiTypeParameter> used, @NotNull final GroovyPsiElement element) { element.accept(new GroovyRecursiveElementVisitor() { @Override public void visitCodeReferenceElement(@NotNull GrCodeReferenceElement reference) { super.visitCodeReferenceElement(reference); if (reference.getQualifier() == null) { final PsiElement resolved = reference.resolve(); if (resolved instanceof PsiTypeParameter typeParameter) { if (PsiTreeUtil.isAncestor(typeParameter.getOwner(), element, false)) { used.add(typeParameter); } } } } @Override public void visitExpression(@NotNull final GrExpression expression) { super.visitExpression(expression); final PsiType type = expression.getType(); if (type != null) { final TypeParameterSearcher searcher = new TypeParameterSearcher(); type.accept(searcher); for (PsiTypeParameter typeParam : searcher.myTypeParams) { if (PsiTreeUtil.isAncestor(typeParam.getOwner(), element, false)) { used.add(typeParam); } } } } static class TypeParameterSearcher extends PsiTypeVisitor<Boolean> { private final Set<PsiTypeParameter> myTypeParams = new HashSet<>(); @Override public Boolean visitType(@NotNull final PsiType type) { return false; } @Override public Boolean visitArrayType(@NotNull final PsiArrayType arrayType) { return arrayType.getComponentType().accept(this); } @Override public Boolean visitClassType(@NotNull final PsiClassType classType) { final PsiClass aClass = classType.resolve(); if (aClass instanceof PsiTypeParameter) { myTypeParams.add((PsiTypeParameter)aClass); } final PsiType[] types = classType.getParameters(); for (final PsiType psiType : types) { psiType.accept(this); } return false; } @Override public Boolean visitWildcardType(@NotNull final PsiWildcardType wildcardType) { final PsiType bound = wildcardType.getBound(); if (bound != null) { bound.accept(this); } return false; } } }); }