PsiReference resolveFieldReference()

in src/main/com/intellij/lang/jsgraphql/ide/resolve/GraphQLReferenceService.java [203:268]


  PsiReference resolveFieldReference(@NotNull GraphQLReferenceMixin element, @NotNull GraphQLField field) {
    final String name = element.getName();
    Ref<PsiReference> reference = new Ref<>();
    if (name != null) {
      if (name.startsWith("__")) {
        // __typename or introspection fields __schema and __type which implicitly extends the query root type
        GraphQLResolveUtil.processFilesInLibrary(GraphQLBundledLibraryTypes.SPECIFICATION, element, file -> {
          file.accept(new GraphQLRecursiveVisitor() {
            @Override
            public void visitElement(@NotNull GraphQLElement schemaElement) {
              // TODO: [vepanimas] rework to use com.intellij.psi.PsiElement.processDeclarations or something similar,
              //  now it traverses the whole tree including comments, punctuation, arguments and so on,
              //  but we actually expect only field declarations in two predefined object types
              if (schemaElement instanceof GraphQLReferenceElement &&
                  Objects.equals(((GraphQLReferenceElement)schemaElement).getReferenceName(), name)) {
                reference.set(createReference(element, schemaElement));
                stopWalking();
                return;
              }
              super.visitElement(schemaElement);
            }
          });
          return reference.isNull();
        });
      }
      final GraphQLTypeScopeProvider typeScopeProvider = PsiTreeUtil.getParentOfType(field, GraphQLTypeScopeProvider.class);
      if (reference.isNull() && typeScopeProvider != null) {
        GraphQLType typeScope = typeScopeProvider.getTypeScope();
        if (typeScope != null) {
          final GraphQLType fieldType = GraphQLSchemaUtil.getUnmodified(typeScope);
          myPsiSearchHelper.processNamedElements(element, name, psiNamedElement -> {
            if (psiNamedElement.getParent() instanceof GraphQLFieldDefinition fieldDefinition) {
              if (!Objects.equals(fieldDefinition.getName(), name)) {
                // field name doesn't match, keep looking
                return true;
              }
              boolean isTypeMatch = false;
              final GraphQLTypeDefinition typeDefinition =
                PsiTreeUtil.getParentOfType(psiNamedElement, GraphQLTypeDefinition.class);
              if (typeDefinition != null) {
                final GraphQLTypeNameDefinition typeNameDefinition =
                  PsiTreeUtil.findChildOfType(typeDefinition, GraphQLTypeNameDefinition.class);
                isTypeMatch = typeNameDefinition != null &&
                              GraphQLSchemaUtil.getTypeName(fieldType).equals(typeNameDefinition.getName());
              }
              if (!isTypeMatch) {
                // check type extension
                final GraphQLTypeExtension typeExtension =
                  PsiTreeUtil.getParentOfType(psiNamedElement, GraphQLTypeExtension.class);
                if (typeExtension != null) {
                  final GraphQLTypeName typeName = PsiTreeUtil.findChildOfType(typeExtension, GraphQLTypeName.class);
                  isTypeMatch = typeName != null && GraphQLSchemaUtil.getTypeName(fieldType).equals(typeName.getName());
                }
              }
              if (isTypeMatch) {
                reference.set(createReference(element, psiNamedElement));
                return false; // done searching
              }
            }
            return true;
          });
        }
      }
    }
    return reference.get();
  }