public void visitJSFunctionDeclaration()

in flex/src/com/intellij/lang/javascript/inspections/actionscript/ActionScriptAnnotatingVisitor.java [306:466]


  public void visitJSFunctionDeclaration(final @NotNull JSFunction node) {
    super.visitJSFunctionDeclaration(node);

    checkPackageElement(node);

    final ASTNode nameIdentifier = node.findNameIdentifier();
    if (nameIdentifier == null) return;
    PsiElement parent = node.getParent();

    if (parent instanceof JSFile) {
      parent = JSResolveUtil.getClassReferenceForXmlFromContext(parent);
      final String name = node.getName();

      if (parent instanceof JSClass &&
          name != null &&
          name.equals(((JSClass)parent).getName()) &&
          !isNative(node) &&
          FlexSupportLoader.isFlexMxmFile(parent.getContainingFile())) {
        myHolder.newAnnotation(HighlightSeverity.ERROR,
                               FlexBundle.message("javascript.validation.message.constructor.in.mxml.is.not.allowed")
        ).range(nameIdentifier)
        .withFix(new RemoveASTNodeFix("javascript.fix.remove.constructor", node)).create();
      }
    }

    if (parent instanceof JSClass clazz && !node.isConstructor()) {
      final JSAttributeList attributeList = node.getAttributeList();

      if (attributeList == null ||
          !attributeList.hasModifier(JSAttributeList.ModifierType.STATIC) &&
          (attributeList.getAccessType() != JSAttributeList.AccessType.PRIVATE ||
           attributeList.hasModifier(JSAttributeList.ModifierType.OVERRIDE)
          )) {
        final String qName = clazz.getQualifiedName();
        final boolean hasOverride = attributeList != null && attributeList.hasModifier(JSAttributeList.ModifierType.OVERRIDE);

        final Ref<JSFunction> set = new Ref<>();
        boolean b = JSResolveUtil.iterateOverrides(node, null, new JSOverrideHandler() {
          @Override
          public boolean process(final @NotNull List<? extends JSPsiElementBase> elements, final PsiElement scope, final @Nullable String className) {
            if (Objects.equals(qName, className)) return true;
            JSFunction value = (JSFunction)elements.iterator().next();
            set.set(value);

            DialectOptionHolder holder= myHighlighter.getDialectOptionsHolder();
            if ("Object".equals(className)) {
              if (hasOverride && !attributeList.hasModifier(JSAttributeList.ModifierType.NATIVE)) { /*native modifier is written always*/
                final ASTNode astNode = attributeList.getNode().findChildByType(JSTokenTypes.OVERRIDE_KEYWORD);

                myHolder.newAnnotation(HighlightSeverity.ERROR,
                                       JavaScriptBundle.message("javascript.validation.message.function.override.for.object.method"))
                  .range(astNode)
                  .withFix(new RemoveASTNodeFix("javascript.fix.remove.override.modifier", astNode.getPsi()))
                  .create();
              }
              return false;
            }
            else if (!hasOverride && holder.isECMA4) {
              myHolder.newAnnotation(HighlightSeverity.ERROR, JavaScriptBundle.message(
                "javascript.validation.message.function.override.without.override.modifier", className))
                .range(nameIdentifier)
                .withFix(new AddOverrideIntentionAction(node))
                .create();
            }
            else {
              JSAttributeList attrList = value.getAttributeList();
              JSAttributeList parentAttrList = ((JSAttributeListOwner)scope).getAttributeList();

              if (attrList != null && attrList.hasModifier(JSAttributeList.ModifierType.FINAL) ||
                  parentAttrList != null && parentAttrList.hasModifier(JSAttributeList.ModifierType.FINAL)
                ) {
                myHolder.newAnnotation(HighlightSeverity.ERROR,
                                       JavaScriptBundle.message("javascript.validation.message.can.not.override.final.method", className))
                  .range(attributeList.getNode().findChildByType(JSTokenTypes.OVERRIDE_KEYWORD))
                  .create();
              }
            }
            if (clazz.isInterface()) {
              myHolder.newAnnotation(HighlightSeverity.ERROR, JavaScriptBundle.message(
                "javascript.validation.message.function.override.for.interface", className)).range(nameIdentifier).create();
            }
            return false;
          }
        }, true);

        if (b && hasOverride) {
          final ASTNode astNode = attributeList.getNode().findChildByType(JSTokenTypes.OVERRIDE_KEYWORD);
          myHolder.newAnnotation(HighlightSeverity.ERROR,
                                 JavaScriptBundle.message("javascript.validation.message.function.override.without.parent.method"))
            .range(astNode)
            .withFix(new RemoveASTNodeFix("javascript.fix.remove.override.modifier", astNode.getPsi()))
            .create();
        }

        if (!b && hasOverride) {
          final JSFunction override = set.get();
          final JSAttributeList overrideAttrList = override.getAttributeList();
          String overrideNs = null;

          if (attributeList.getAccessType() != overrideAttrList.getAccessType() ||
              (overrideNs = ActionScriptPsiImplUtil.getNamespaceValue(overrideAttrList)) != null &&
              !overrideNs.equals(ActionScriptPsiImplUtil.getNamespaceValue(attributeList))) {
            String newVisibility;
            ModCommandAction fix;
            if (overrideNs != null) {
              newVisibility = overrideNs;
              fix = JSFixFactory.getInstance().createChangeVisibilityFix(node, null ,overrideNs);
            }
            else {
              newVisibility = JSFormatUtil.formatVisibility(overrideAttrList.getAccessType());
              fix = JSFixFactory.getInstance().createChangeVisibilityFix(node, overrideAttrList.getAccessType() ,null);
            }
            myHolder.newAnnotation(HighlightSeverity.ERROR, JavaScriptBundle
              .message("javascript.validation.message.function.override.incompatible.access.modifier", newVisibility))
              .range(findElementForAccessModifierError(node, attributeList))
              .withFix(fix)
              .create();
          }

          final SignatureMatchResult incompatibleSignature = checkCompatibleSignature(node, override);

          if (incompatibleSignature == SignatureMatchResult.PARAMETERS_DIFFERS) {
            final JSParameterList nodeParameterList = node.getParameterList();
            final JSParameterList overrideParameterList = override.getParameterList();

            myHolder.newAnnotation(HighlightSeverity.ERROR,
                                   JavaScriptBundle.message("javascript.validation.message.function.override.incompatible.signature",
                                                            overrideParameterList != null ? overrideParameterList.getText() : "()"
                                   ))
              .range(nodeParameterList != null ? nodeParameterList.getNode() : node.findNameIdentifier())
              .withFix(new JSChangeSignatureFix(node, overrideParameterList, false) {
                @Override
                public @NotNull String getText() {
                  return JavaScriptBundle.message("javascript.fix.message.change.parameters.to.expected");
                }
              })
              .withFix(new JSChangeSignatureFix(override, nodeParameterList))
              .create();
          }
          else if (incompatibleSignature == SignatureMatchResult.RETURN_TYPE_DIFFERS) {
            PsiElement returnTypeExpr = node.getReturnTypeElement();
            JSType type = override.getReturnType();
            final String baseReturnType = type != null ? type.getResolvedTypeText() : null;
            String msg = JavaScriptBundle
              .message("javascript.validation.message.function.override.incompatible.signature2", StringUtil.notNullize(baseReturnType));
            myHolder.newAnnotation(HighlightSeverity.ERROR, msg)
              .range(returnTypeExpr != null ? returnTypeExpr.getNode() : node.findNameIdentifier())
              .withFix(new JSChangeTypeFix(node, baseReturnType, "javascript.fix.message.change.return.type.to.expected"))
              .withFix(createChangeBaseMethodSignatureFix(override, node))
              .create();
          }
          else if (incompatibleSignature == SignatureMatchResult.FUNCTION_KIND_DIFFERS) {
            String msg = JavaScriptBundle
              .message("javascript.validation.message.function.override.incompatible.signature3", override.getKind().toString());
            myHolder.newAnnotation(HighlightSeverity.ERROR, msg).range(node.findNameIdentifier())
              .create();
          }
        }
      }
    }
  }