private static boolean typeElementsAreEquivalent(
     PsiTypeElement typeElement1, PsiTypeElement typeElement2) {
   if (typeElement1 == null) {
     return typeElement2 == null;
   } else if (typeElement2 == null) {
     return false;
   }
   final PsiType type1 = typeElement1.getType();
   final PsiType type2 = typeElement2.getType();
   return typesAreEquivalent(type1, type2);
 }
 private static void checkMethodReference(
     PsiMethodReferenceExpression expression,
     InspectionManager inspectionManager,
     List<ProblemDescriptor> problems) {
   final PsiTypeElement qualifierTypeElement = expression.getQualifierType();
   if (qualifierTypeElement != null) {
     final PsiType psiType = qualifierTypeElement.getType();
     if (psiType instanceof PsiClassType && !(((PsiClassType) psiType).isRaw())) {
       final JavaResolveResult result = expression.advancedResolve(false);
       final PsiElement element = result.getElement();
       if (element instanceof PsiTypeParameterListOwner) {
         final PsiMethodReferenceExpression copy =
             createMethodReference(expression, qualifierTypeElement);
         final JavaResolveResult simplifiedResolve = copy.advancedResolve(false);
         final PsiElement candidate = simplifiedResolve.getElement();
         if (candidate == element) {
           final PsiJavaCodeReferenceElement referenceElement =
               qualifierTypeElement.getInnermostComponentReferenceElement();
           LOG.assertTrue(referenceElement != null, qualifierTypeElement);
           final PsiReferenceParameterList parameterList = referenceElement.getParameterList();
           LOG.assertTrue(parameterList != null);
           final ProblemDescriptor descriptor =
               inspectionManager.createProblemDescriptor(
                   parameterList,
                   InspectionsBundle.message("inspection.redundant.type.problem.descriptor"),
                   new MyMethodReferenceFixAction(),
                   ProblemHighlightType.LIKE_UNUSED_SYMBOL,
                   false);
           problems.add(descriptor);
         }
       }
     }
   }
 }
  private int substituteToTypeParameters(
      PsiTypeElement typeElement,
      PsiTypeElement inplaceTypeElement,
      PsiType[] paramVals,
      PsiTypeParameter[] params,
      TemplateBuilder builder,
      PsiSubstitutor rawingSubstitutor,
      boolean toplevel) {
    PsiType type = inplaceTypeElement.getType();
    List<PsiType> types = new ArrayList<>();
    for (int i = 0; i < paramVals.length; i++) {
      PsiType val = paramVals[i];
      if (val == null) return SUBSTITUTED_NONE;
      if (type.equals(val)) {
        types.add(myFactory.createType(params[i]));
      }
    }

    if (!types.isEmpty()) {
      Project project = typeElement.getProject();
      PsiType substituted = rawingSubstitutor.substitute(type);
      if (!CommonClassNames.JAVA_LANG_OBJECT.equals(substituted.getCanonicalText())
          && (toplevel || substituted.equals(type))) {
        types.add(substituted);
      }

      builder.replaceElement(
          typeElement,
          new TypeExpression(project, types.toArray(PsiType.createArray(types.size()))));
      return toplevel ? SUBSTITUTED_IN_REF : SUBSTITUTED_IN_PARAMETERS;
    }

    boolean substituted = false;
    PsiJavaCodeReferenceElement ref = typeElement.getInnermostComponentReferenceElement();
    PsiJavaCodeReferenceElement inplaceRef =
        inplaceTypeElement.getInnermostComponentReferenceElement();
    if (ref != null) {
      LOG.assertTrue(inplaceRef != null);
      PsiTypeElement[] innerTypeElements = ref.getParameterList().getTypeParameterElements();
      PsiTypeElement[] inplaceInnerTypeElements =
          inplaceRef.getParameterList().getTypeParameterElements();
      for (int i = 0; i < innerTypeElements.length; i++) {
        substituted |=
            substituteToTypeParameters(
                    innerTypeElements[i],
                    inplaceInnerTypeElements[i],
                    paramVals,
                    params,
                    builder,
                    rawingSubstitutor,
                    false)
                != SUBSTITUTED_NONE;
      }
    }

    return substituted ? SUBSTITUTED_IN_PARAMETERS : SUBSTITUTED_NONE;
  }
 private static PsiMethodReferenceExpression createMethodReference(
     PsiMethodReferenceExpression expression, PsiTypeElement typeElement) {
   final PsiType type = typeElement.getType();
   final PsiElementFactory elementFactory =
       JavaPsiFacade.getElementFactory(expression.getProject());
   final PsiMethodReferenceExpression copy = (PsiMethodReferenceExpression) expression.copy();
   copy.getQualifierType()
       .replace(elementFactory.createTypeElement(((PsiClassType) type).rawType()));
   return copy;
 }
 private static boolean typecastExpressionsAreEquivalent(
     @NotNull PsiTypeCastExpression typecastExp1, @NotNull PsiTypeCastExpression typecastExp2) {
   final PsiTypeElement typeElement1 = typecastExp1.getCastType();
   final PsiTypeElement typeElement2 = typecastExp2.getCastType();
   if (typeElement1 == null && typeElement2 == null) {
     return true;
   }
   if (typeElement1 == null || typeElement2 == null) {
     return false;
   }
   final PsiType type1 = typeElement1.getType();
   final PsiType type2 = typeElement2.getType();
   if (!typesAreEquivalent(type1, type2)) {
     return false;
   }
   final PsiExpression operand1 = typecastExp1.getOperand();
   final PsiExpression operand2 = typecastExp2.getOperand();
   return expressionsAreEquivalent(operand1, operand2);
 }
 private static boolean instanceofExpressionsAreEquivalent(
     PsiInstanceOfExpression instanceOfExpression1,
     PsiInstanceOfExpression instanceOfExpression2) {
   final PsiExpression operand1 = instanceOfExpression1.getOperand();
   final PsiExpression operand2 = instanceOfExpression2.getOperand();
   if (!expressionsAreEquivalent(operand1, operand2)) {
     return false;
   }
   final PsiTypeElement typeElement1 = instanceOfExpression1.getCheckType();
   final PsiTypeElement typeElement2 = instanceOfExpression2.getCheckType();
   if (typeElement1 == null) {
     return typeElement2 == null;
   } else if (typeElement2 == null) {
     return false;
   }
   final PsiType type1 = typeElement1.getType();
   final PsiType type2 = typeElement2.getType();
   return typesAreEquivalent(type1, type2);
 }
 @Nullable
 public static HighlightInfo checkValidAnnotationType(final PsiTypeElement typeElement) {
   PsiType type = typeElement.getType();
   if (type.accept(AnnotationReturnTypeVisitor.INSTANCE).booleanValue()) {
     return null;
   }
   String description = JavaErrorMessages.message("annotation.invalid.annotation.member.type");
   return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
       .range(typeElement)
       .descriptionAndTooltip(description)
       .create();
 }
  @Nullable
  public static List<String> findTestDataFiles(@NotNull DataContext context) {
    final PsiMethod method = findTargetMethod(context);
    if (method == null) {
      return null;
    }
    final String name = method.getName();

    if (name.startsWith("test")) {
      String testDataPath =
          TestDataLineMarkerProvider.getTestDataBasePath(method.getContainingClass());
      final TestDataReferenceCollector collector =
          new TestDataReferenceCollector(testDataPath, name.substring(4));
      return collector.collectTestDataReferences(method);
    }

    final Location<?> location = Location.DATA_KEY.getData(context);
    if (location instanceof PsiMemberParameterizedLocation) {
      PsiClass containingClass = ((PsiMemberParameterizedLocation) location).getContainingClass();
      if (containingClass == null) {
        containingClass =
            PsiTreeUtil.getParentOfType(location.getPsiElement(), PsiClass.class, false);
      }
      if (containingClass != null) {
        final PsiAnnotation annotation =
            AnnotationUtil.findAnnotationInHierarchy(
                containingClass, Collections.singleton(JUnitUtil.RUN_WITH));
        if (annotation != null) {
          final PsiAnnotationMemberValue memberValue = annotation.findAttributeValue("value");
          if (memberValue instanceof PsiClassObjectAccessExpression) {
            final PsiTypeElement operand =
                ((PsiClassObjectAccessExpression) memberValue).getOperand();
            if (operand.getType().equalsToText(Parameterized.class.getName())) {
              final String testDataPath =
                  TestDataLineMarkerProvider.getTestDataBasePath(containingClass);
              final String paramSetName =
                  ((PsiMemberParameterizedLocation) location).getParamSetName();
              final String baseFileName =
                  StringUtil.trimEnd(StringUtil.trimStart(paramSetName, "["), "]");
              final ProjectFileIndex fileIndex =
                  ProjectRootManager.getInstance(containingClass.getProject()).getFileIndex();
              return TestDataGuessByExistingFilesUtil.suggestTestDataFiles(
                  fileIndex, baseFileName, testDataPath, containingClass);
            }
          }
        }
      }
    }

    return null;
  }
 @Override
 protected final void doFix(Project project, ProblemDescriptor descriptor)
     throws IncorrectOperationException {
   final PsiElement element = descriptor.getPsiElement();
   final PsiTypeElement castTypeElement;
   final PsiReferenceExpression reference;
   if (element instanceof PsiTypeCastExpression) {
     final PsiTypeCastExpression typeCastExpression = (PsiTypeCastExpression) element;
     castTypeElement = typeCastExpression.getCastType();
     final PsiExpression operand = typeCastExpression.getOperand();
     if (!(operand instanceof PsiReferenceExpression)) {
       return;
     }
     reference = (PsiReferenceExpression) operand;
   } else if (element instanceof PsiMethodCallExpression) {
     final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression) element;
     final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
     final PsiExpression qualifier = methodExpression.getQualifierExpression();
     if (!(qualifier instanceof PsiClassObjectAccessExpression)) {
       return;
     }
     final PsiClassObjectAccessExpression classObjectAccessExpression =
         (PsiClassObjectAccessExpression) qualifier;
     castTypeElement = classObjectAccessExpression.getOperand();
     final PsiExpressionList argumentList = methodCallExpression.getArgumentList();
     final PsiExpression[] arguments = argumentList.getExpressions();
     if (arguments.length != 1) {
       return;
     }
     final PsiExpression argument = arguments[0];
     if (!(argument instanceof PsiReferenceExpression)) {
       return;
     }
     reference = (PsiReferenceExpression) argument;
   } else {
     return;
   }
   if (castTypeElement == null) {
     return;
   }
   final PsiInstanceOfExpression conflictingInstanceof =
       InstanceOfUtils.getConflictingInstanceof(castTypeElement.getType(), reference, element);
   final PsiTypeElement instanceofTypeElement = conflictingInstanceof.getCheckType();
   if (instanceofTypeElement == null) {
     return;
   }
   final PsiElement newElement = replace(castTypeElement, instanceofTypeElement);
   final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project);
   codeStyleManager.shortenClassReferences(newElement);
 }
 @Nullable
 public static HighlightInfo checkCyclicMemberType(PsiTypeElement typeElement, PsiClass aClass) {
   LOG.assertTrue(aClass.isAnnotationType());
   PsiType type = typeElement.getType();
   final Set<PsiClass> checked = new HashSet<PsiClass>();
   if (cyclicDependencies(aClass, type, checked, aClass.getManager())) {
     String description = JavaErrorMessages.message("annotation.cyclic.element.type");
     return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
         .range(typeElement)
         .descriptionAndTooltip(description)
         .create();
   }
   return null;
 }
 @Override
 public void visitMethodCallExpression(PsiMethodCallExpression expression) {
   super.visitMethodCallExpression(expression);
   final PsiReferenceExpression methodExpression = expression.getMethodExpression();
   final String methodName = methodExpression.getReferenceName();
   if (!"cast".equals(methodName)) {
     return;
   }
   final PsiMethod method = expression.resolveMethod();
   if (method == null) {
     return;
   }
   final PsiClass containingClass = method.getContainingClass();
   if (containingClass == null) {
     return;
   }
   final String qualifiedName = containingClass.getQualifiedName();
   if (!"java.lang.Class".equals(qualifiedName)) {
     return;
   }
   final PsiExpression qualifier = methodExpression.getQualifierExpression();
   if (!(qualifier instanceof PsiClassObjectAccessExpression)) {
     return;
   }
   final PsiClassObjectAccessExpression classObjectAccessExpression =
       (PsiClassObjectAccessExpression) qualifier;
   final PsiTypeElement operand = classObjectAccessExpression.getOperand();
   final PsiType castType = operand.getType();
   if (!(castType instanceof PsiClassType)) {
     return;
   }
   final PsiExpressionList argumentList = expression.getArgumentList();
   final PsiExpression[] arguments = argumentList.getExpressions();
   if (arguments.length != 1) {
     return;
   }
   final PsiExpression argument = arguments[0];
   if (!(argument instanceof PsiReferenceExpression)) {
     return;
   }
   final PsiReferenceExpression referenceExpression = (PsiReferenceExpression) argument;
   final PsiInstanceOfExpression conflictingInstanceof =
       InstanceOfUtils.getConflictingInstanceof(castType, referenceExpression, expression);
   if (conflictingInstanceof == null) {
     return;
   }
   final PsiTypeElement instanceofTypeElement = conflictingInstanceof.getCheckType();
   registerError(expression, referenceExpression, operand, instanceofTypeElement);
 }
Esempio n. 12
0
 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 void visitReferenceParameterList(PsiReferenceParameterList referenceParameterList) {
   super.visitReferenceParameterList(referenceParameterList);
   final PsiTypeElement[] typeParameterElements =
       referenceParameterList.getTypeParameterElements();
   if (typeParameterElements.length == 1) {
     final PsiTypeElement typeParameterElement = typeParameterElements[0];
     final PsiType type = typeParameterElement.getType();
     if (type instanceof PsiDiamondType) {
       final PsiNewExpression newExpression =
           PsiTreeUtil.getParentOfType(referenceParameterList, PsiNewExpression.class);
       if (newExpression != null) {
         final List<PsiType> types =
             PsiDiamondTypeImpl.resolveInferredTypesNoCheck(newExpression, newExpression)
                 .getInferredTypes();
         if (!types.isEmpty()) {
           registerError(referenceParameterList);
         }
       }
     }
   }
 }
 @Override
 public void visitTypeCastExpression(@NotNull PsiTypeCastExpression expression) {
   super.visitTypeCastExpression(expression);
   final PsiTypeElement castType = expression.getCastType();
   if (castType == null) {
     return;
   }
   final PsiType type = castType.getType();
   final PsiExpression operand = expression.getOperand();
   if (!(operand instanceof PsiReferenceExpression)) {
     return;
   }
   final PsiReferenceExpression referenceExpression = (PsiReferenceExpression) operand;
   final PsiInstanceOfExpression conflictingInstanceof =
       InstanceOfUtils.getConflictingInstanceof(type, referenceExpression, expression);
   if (conflictingInstanceof == null) {
     return;
   }
   final PsiTypeElement instanceofTypeElement = conflictingInstanceof.getCheckType();
   if (instanceofTypeElement == null) {
     return;
   }
   registerError(expression, referenceExpression, castType, instanceofTypeElement);
 }
 private void checkTypeElement(PsiTypeElement typeElement) {
   if (typeElement == null || !TypeUtils.isOptional(typeElement.getType())) {
     return;
   }
   registerError(typeElement, typeElement);
 }
  public void setupTypeElement(
      PsiTypeElement typeElement,
      ExpectedTypeInfo[] infos,
      PsiSubstitutor substitutor,
      TemplateBuilder builder,
      @Nullable PsiElement context,
      PsiClass targetClass) {
    LOG.assertTrue(typeElement.isValid());
    ApplicationManager.getApplication().assertWriteAccessAllowed();

    PsiManager manager = typeElement.getManager();
    GlobalSearchScope scope = typeElement.getResolveScope();
    Project project = manager.getProject();

    if (infos.length == 1 && substitutor != null && substitutor != PsiSubstitutor.EMPTY) {
      ExpectedTypeInfo info = infos[0];
      Map<PsiTypeParameter, PsiType> map = substitutor.getSubstitutionMap();
      PsiType[] vals = map.values().toArray(PsiType.createArray(map.size()));
      PsiTypeParameter[] params = map.keySet().toArray(new PsiTypeParameter[map.size()]);

      List<PsiType> types = matchingTypeParameters(vals, params, info);
      if (!types.isEmpty()) {
        ContainerUtil.addAll(
            types,
            ExpectedTypesProvider.processExpectedTypes(
                infos, new MyTypeVisitor(manager, scope), project));
        builder.replaceElement(
            typeElement,
            new TypeExpression(project, types.toArray(PsiType.createArray(types.size()))));
        return;
      } else {
        PsiElementFactory factory =
            JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
        PsiType type = info.getType();
        PsiType defaultType = info.getDefaultType();
        try {
          PsiTypeElement inplaceTypeElement =
              ((PsiVariable)
                      factory.createVariableDeclarationStatement("foo", type, null)
                          .getDeclaredElements()[0])
                  .getTypeElement();

          PsiSubstitutor rawingSubstitutor = getRawingSubstitutor(context, targetClass);
          int substitionResult =
              substituteToTypeParameters(
                  typeElement, inplaceTypeElement, vals, params, builder, rawingSubstitutor, true);
          if (substitionResult != SUBSTITUTED_NONE) {
            if (substitionResult == SUBSTITUTED_IN_PARAMETERS) {
              PsiJavaCodeReferenceElement refElement =
                  typeElement.getInnermostComponentReferenceElement();
              LOG.assertTrue(refElement != null && refElement.getReferenceNameElement() != null);
              type = getComponentType(type);
              LOG.assertTrue(type != null);
              defaultType = getComponentType(defaultType);
              LOG.assertTrue(defaultType != null);
              ExpectedTypeInfo info1 =
                  ExpectedTypesProvider.createInfo(
                      ((PsiClassType) defaultType).rawType(),
                      ExpectedTypeInfo.TYPE_STRICTLY,
                      ((PsiClassType) defaultType).rawType(),
                      info.getTailType());
              MyTypeVisitor visitor = new MyTypeVisitor(manager, scope);
              builder.replaceElement(
                  refElement.getReferenceNameElement(),
                  new TypeExpression(
                      project,
                      ExpectedTypesProvider.processExpectedTypes(
                          new ExpectedTypeInfo[] {info1}, visitor, project)));
            }

            return;
          }
        } catch (IncorrectOperationException e) {
          LOG.error(e);
        }
      }
    }

    PsiType[] types =
        infos.length == 0
            ? new PsiType[] {typeElement.getType()}
            : ExpectedTypesProvider.processExpectedTypes(
                infos, new MyTypeVisitor(manager, scope), project);
    builder.replaceElement(typeElement, new TypeExpression(project, types));
  }
  @Nullable
  public static HighlightInfo checkApplicability(
      @NotNull PsiAnnotation annotation,
      @NotNull LanguageLevel languageLevel,
      @NotNull PsiFile containingFile) {
    if (ANY_ANNOTATION_ALLOWED.accepts(annotation)) {
      return null;
    }

    PsiJavaCodeReferenceElement nameRef = annotation.getNameReferenceElement();
    if (nameRef == null) return null;

    PsiAnnotationOwner owner = annotation.getOwner();
    PsiAnnotation.TargetType[] targets = PsiImplUtil.getTargetsForLocation(owner);
    if (owner == null || targets.length == 0) {
      String message = JavaErrorMessages.message("annotation.not.allowed.here");
      return annotationError(annotation, message);
    }

    if (!(owner instanceof PsiModifierList)) {
      HighlightInfo info =
          HighlightUtil.checkTypeAnnotationFeature(annotation, languageLevel, containingFile);
      if (info != null) return info;
    }

    PsiAnnotation.TargetType applicable = PsiImplUtil.findApplicableTarget(annotation, targets);
    if (applicable == PsiAnnotation.TargetType.UNKNOWN) return null;

    if (applicable == null) {
      String target = JavaErrorMessages.message("annotation.target." + targets[0]);
      String message =
          JavaErrorMessages.message("annotation.not.applicable", nameRef.getText(), target);
      return annotationError(annotation, message);
    }

    if (applicable == PsiAnnotation.TargetType.TYPE_USE) {
      if (owner instanceof PsiClassReferenceType) {
        PsiJavaCodeReferenceElement ref = ((PsiClassReferenceType) owner).getReference();
        HighlightInfo info = checkReferenceTarget(annotation, ref);
        if (info != null) return info;
      } else if (owner instanceof PsiModifierList) {
        PsiElement nextElement =
            PsiTreeUtil.skipSiblingsForward(
                (PsiModifierList) owner,
                PsiComment.class,
                PsiWhiteSpace.class,
                PsiTypeParameterList.class);
        if (nextElement instanceof PsiTypeElement) {
          PsiTypeElement typeElement = (PsiTypeElement) nextElement;
          PsiType type = typeElement.getType();
          if (PsiType.VOID.equals(type)) {
            String message = JavaErrorMessages.message("annotation.not.allowed.void");
            return annotationError(annotation, message);
          }
          if (!(type instanceof PsiPrimitiveType)) {
            PsiJavaCodeReferenceElement ref =
                getOutermostReferenceElement(typeElement.getInnermostComponentReferenceElement());
            HighlightInfo info = checkReferenceTarget(annotation, ref);
            if (info != null) return info;
          }
        }
      } else if (owner instanceof PsiTypeElement) {
        PsiElement context =
            PsiTreeUtil.skipParentsOfType((PsiTypeElement) owner, PsiTypeElement.class);
        if (context instanceof PsiClassObjectAccessExpression) {
          String message = JavaErrorMessages.message("annotation.not.allowed.class");
          return annotationError(annotation, message);
        }
      }
    }

    return null;
  }
Esempio n. 18
0
  @Override
  public void beforeCompletion(@NotNull final CompletionInitializationContext context) {
    final PsiFile file = context.getFile();

    if (file instanceof PsiJavaFile) {
      if (context.getInvocationCount() > 0) {
        autoImport(file, context.getStartOffset() - 1, context.getEditor());

        PsiElement leaf = file.findElementAt(context.getStartOffset() - 1);
        if (leaf != null) leaf = PsiTreeUtil.prevVisibleLeaf(leaf);

        PsiVariable variable = PsiTreeUtil.getParentOfType(leaf, PsiVariable.class);
        if (variable != null) {
          PsiTypeElement typeElement = variable.getTypeElement();
          if (typeElement != null) {
            PsiType type = typeElement.getType();
            if (type instanceof PsiClassType && ((PsiClassType) type).resolve() == null) {
              autoImportReference(
                  file, context.getEditor(), typeElement.getInnermostComponentReferenceElement());
            }
          }
        }
      }

      JavaCompletionUtil.initOffsets(file, context.getOffsetMap());

      if (context.getCompletionType() == CompletionType.BASIC) {
        if (semicolonNeeded(context.getEditor(), file, context.getStartOffset())) {
          context.setDummyIdentifier(CompletionInitializationContext.DUMMY_IDENTIFIER.trim() + ";");
          return;
        }

        final PsiJavaCodeReferenceElement ref =
            PsiTreeUtil.findElementOfClassAtOffset(
                file, context.getStartOffset(), PsiJavaCodeReferenceElement.class, false);
        if (ref != null && !(ref instanceof PsiReferenceExpression)) {
          if (ref.getParent() instanceof PsiTypeElement) {
            context.setDummyIdentifier(
                CompletionInitializationContext.DUMMY_IDENTIFIER.trim() + ";");
          }

          if (JavaSmartCompletionContributor.AFTER_NEW.accepts(ref)) {
            final PsiReferenceParameterList paramList = ref.getParameterList();
            if (paramList != null && paramList.getTextLength() > 0) {
              context
                  .getOffsetMap()
                  .addOffset(
                      ConstructorInsertHandler.PARAM_LIST_START,
                      paramList.getTextRange().getStartOffset());
              context
                  .getOffsetMap()
                  .addOffset(
                      ConstructorInsertHandler.PARAM_LIST_END,
                      paramList.getTextRange().getEndOffset());
            }
          }

          return;
        }

        final PsiElement element = file.findElementAt(context.getStartOffset());

        if (psiElement().inside(PsiAnnotation.class).accepts(element)) {
          return;
        }

        context.setDummyIdentifier(CompletionInitializationContext.DUMMY_IDENTIFIER_TRIMMED);
      }
    }
  }
  @Override
  public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {
    if (!MinecraftSettings.Companion.getInstance().isShowEventListenerGutterIcons()) {
      return;
    }

    // Since we want to line up with the method declaration, not the annotation
    // declaration, we need to target identifiers, not just PsiMethods.
    if (!(element instanceof PsiIdentifier && (element.getParent() instanceof PsiMethod))) {
      return;
    }
    // The PsiIdentifier is going to be a method of course!
    PsiMethod method = (PsiMethod) element.getParent();
    if (method.hasModifierProperty(PsiModifier.ABSTRACT)) {
      // I don't think any implementation allows for abstract
      return;
    }
    PsiModifierList modifierList = method.getModifierList();
    Module module = ModuleUtilCore.findModuleForPsiElement(element);
    if (module == null) {
      return;
    }
    MinecraftModule instance = MinecraftModule.getInstance(module);
    if (instance == null) {
      return;
    }
    // Since each platform has their own valid listener annotations,
    // some platforms may have multiple allowed annotations for various cases
    final Collection<AbstractModuleType<?>> moduleTypes = instance.getTypes();
    boolean contains = false;
    for (AbstractModuleType<?> moduleType : moduleTypes) {
      final List<String> listenerAnnotations = moduleType.getListenerAnnotations();
      for (String listenerAnnotation : listenerAnnotations) {
        if (modifierList.findAnnotation(listenerAnnotation) != null) {
          contains = true;
          break;
        }
      }
    }
    if (!contains) {
      return;
    }

    final PsiParameter[] parameters = method.getParameterList().getParameters();
    if (parameters.length < 1) {
      return;
    }
    final PsiParameter eventParameter = parameters[0];
    if (eventParameter == null) {
      // Listeners must have at least a single parameter
      return;
    }
    // Get the type of the parameter so we can start resolving it
    PsiTypeElement psiEventElement = eventParameter.getTypeElement();
    if (psiEventElement == null) {
      return;
    }
    final PsiType type = psiEventElement.getType();
    // Validate that it is a class reference type, I don't know if this will work with
    // other JVM languages such as Kotlin or Scala, but it might!
    if (!(type instanceof PsiClassReferenceType)) {
      return;
    }
    // And again, make sure that we can at least resolve the type, otherwise it's not a valid
    // class reference.
    final PsiClass eventClass = ((PsiClassReferenceType) type).resolve();
    if (eventClass == null) {
      return;
    }

    if (instance.isEventClassValid(eventClass, method)) {
      return;
    }

    if (!instance.isStaticListenerSupported(eventClass, method)
        && method.hasModifierProperty(PsiModifier.STATIC)) {
      if (method.getNameIdentifier() != null) {
        holder.createErrorAnnotation(
            method.getNameIdentifier(), "Event listener method must not be static");
      }
    }

    if (!isSuperEventListenerAllowed(eventClass, method, instance)) {
      holder.createErrorAnnotation(
          eventParameter, instance.writeErrorMessageForEvent(eventClass, method));
    }
  }
 @Override
 public void visitClassObjectAccessExpression(PsiClassObjectAccessExpression expression) {
   super.visitClassObjectAccessExpression(expression);
   PsiElement parent = expression.getParent();
   if (parent instanceof PsiReferenceExpression) {
     final PsiReferenceExpression referenceExpression = (PsiReferenceExpression) parent;
     if (!expression.equals(referenceExpression.getQualifierExpression())) {
       return;
     }
     @NonNls final String name = referenceExpression.getReferenceName();
     if (!"getName".equals(name)) {
       return;
     }
     final PsiElement grandParent = referenceExpression.getParent();
     if (!(grandParent instanceof PsiMethodCallExpression)) {
       return;
     }
     final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression) grandParent;
     final PsiExpressionList list = methodCallExpression.getArgumentList();
     if (list.getExpressions().length != 0) {
       return;
     }
     parent = methodCallExpression.getParent();
   }
   if (!(parent instanceof PsiExpressionList)) {
     return;
   }
   final PsiElement grandParent = parent.getParent();
   if (!(grandParent instanceof PsiMethodCallExpression)) {
     return;
   }
   final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression) grandParent;
   final PsiExpressionList argumentList = methodCallExpression.getArgumentList();
   final PsiExpression[] expressions = argumentList.getExpressions();
   if (expressions.length != 1) {
     return;
   }
   final PsiClass containingClass = PsiTreeUtil.getParentOfType(expression, PsiClass.class);
   if (containingClass == null) {
     return;
   }
   final String containingClassName = containingClass.getName();
   if (containingClassName == null) {
     return;
   }
   final PsiMethod method = methodCallExpression.resolveMethod();
   if (method == null) {
     return;
   }
   final PsiClass aClass = method.getContainingClass();
   if (aClass == null) {
     return;
   }
   final String className = aClass.getQualifiedName();
   final int index = loggerFactoryClassNames.indexOf(className);
   if (index < 0) {
     return;
   }
   final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
   final String referenceName = methodExpression.getReferenceName();
   final String loggerFactoryMethodName = loggerFactoryMethodNames.get(index);
   if (!loggerFactoryMethodName.equals(referenceName)) {
     return;
   }
   final PsiTypeElement operand = expression.getOperand();
   final PsiType type = operand.getType();
   if (!(type instanceof PsiClassType)) {
     return;
   }
   final PsiClassType classType = (PsiClassType) type;
   final PsiClass initializerClass = classType.resolve();
   if (initializerClass == null) {
     return;
   }
   if (containingClass.equals(initializerClass)) {
     return;
   }
   registerError(expression, containingClassName);
 }