protected Collection<String> generateSuggestedNames(PyExpression expression) {
    Collection<String> candidates =
        new LinkedHashSet<String>() {
          @Override
          public boolean add(String s) {
            if (PyNames.isReserved(s)) {
              return false;
            }
            return super.add(s);
          }
        };
    String text = expression.getText();
    final Pair<PsiElement, TextRange> selection =
        expression.getUserData(PyReplaceExpressionUtil.SELECTION_BREAKS_AST_NODE);
    if (selection != null) {
      text = selection.getSecond().substring(text);
    }
    if (expression instanceof PyCallExpression) {
      final PyExpression callee = ((PyCallExpression) expression).getCallee();
      if (callee != null) {
        text = callee.getText();
      }
    }
    if (text != null) {
      candidates.addAll(NameSuggesterUtil.generateNames(text));
    }
    final TypeEvalContext context = TypeEvalContext.userInitiated(expression.getContainingFile());
    PyType type = context.getType(expression);
    if (type != null && type != PyNoneType.INSTANCE) {
      String typeName = type.getName();
      if (typeName != null) {
        if (type.isBuiltin()) {
          typeName = typeName.substring(0, 1);
        }
        candidates.addAll(NameSuggesterUtil.generateNamesByType(typeName));
      }
    }
    final PyKeywordArgument kwArg =
        PsiTreeUtil.getParentOfType(expression, PyKeywordArgument.class);
    if (kwArg != null && kwArg.getValueExpression() == expression) {
      candidates.add(kwArg.getKeyword());
    }

    final PyArgumentList argList = PsiTreeUtil.getParentOfType(expression, PyArgumentList.class);
    if (argList != null) {
      final CallArgumentsMapping result = argList.analyzeCall(PyResolveContext.noImplicits());
      if (result.getMarkedCallee() != null) {
        final PyNamedParameter namedParameter = result.getPlainMappedParams().get(expression);
        if (namedParameter != null) {
          candidates.add(namedParameter.getName());
        }
      }
    }
    return candidates;
  }
 private static void highlightIncorrectArguments(
     ProblemsHolder holder, CallArgumentsMapping result, @NotNull TypeEvalContext context) {
   for (Map.Entry<PyExpression, EnumSet<CallArgumentsMapping.ArgFlag>> argEntry :
       result.getArgumentFlags().entrySet()) {
     EnumSet<CallArgumentsMapping.ArgFlag> flags = argEntry.getValue();
     if (!flags.isEmpty()) { // something's wrong
       PyExpression arg = argEntry.getKey();
       if (flags.contains(CallArgumentsMapping.ArgFlag.IS_DUP)) {
         holder.registerProblem(arg, PyBundle.message("INSP.duplicate.argument"));
       }
       if (flags.contains(CallArgumentsMapping.ArgFlag.IS_DUP_KWD)) {
         holder.registerProblem(arg, PyBundle.message("INSP.duplicate.doublestar.arg"));
       }
       if (flags.contains(CallArgumentsMapping.ArgFlag.IS_DUP_TUPLE)) {
         holder.registerProblem(arg, PyBundle.message("INSP.duplicate.star.arg"));
       }
       if (flags.contains(CallArgumentsMapping.ArgFlag.IS_POS_PAST_KWD)) {
         holder.registerProblem(
             arg,
             PyBundle.message("INSP.cannot.appear.past.keyword.arg"),
             ProblemHighlightType.ERROR);
       }
       if (flags.contains(CallArgumentsMapping.ArgFlag.IS_UNMAPPED)) {
         holder.registerProblem(arg, PyBundle.message("INSP.unexpected.arg"));
       }
       if (flags.contains(CallArgumentsMapping.ArgFlag.IS_TOO_LONG)) {
         final PyCallExpression.PyMarkedCallee markedCallee = result.getMarkedCallee();
         String parameterName = null;
         if (markedCallee != null) {
           final List<PyParameter> parameters =
               PyUtil.getParameters(markedCallee.getCallable(), context);
           for (int i = parameters.size() - 1; i >= 0; --i) {
             final PyParameter param = parameters.get(i);
             if (param instanceof PyNamedParameter) {
               final List<PyNamedParameter> unmappedParams = result.getUnmappedParams();
               if (!((PyNamedParameter) param).isPositionalContainer()
                   && !((PyNamedParameter) param).isKeywordContainer()
                   && param.getDefaultValue() == null
                   && !unmappedParams.contains(param)) {
                 parameterName = param.getName();
                 break;
               }
             }
           }
           holder.registerProblem(
               arg,
               parameterName != null
                   ? PyBundle.message(
                       "INSP.multiple.values.resolve.to.positional.$0", parameterName)
                   : PyBundle.message("INSP.more.args.that.pos.params"));
         }
       }
     }
   }
 }
 public static void inspectPyArgumentList(
     PyArgumentList node,
     ProblemsHolder holder,
     final TypeEvalContext context,
     int implicitOffset) {
   if (node.getParent() instanceof PyClass) return; // class Foo(object) is also an arg list
   CallArgumentsMapping result =
       node.analyzeCall(
           PyResolveContext.noImplicits().withTypeEvalContext(context), implicitOffset);
   final PyCallExpression.PyMarkedCallee callee = result.getMarkedCallee();
   if (callee != null) {
     final Callable callable = callee.getCallable();
     // Decorate functions may have different parameter lists. We don't match arguments with
     // parameters of decorators yet
     if (callable instanceof PyFunction && PyUtil.hasCustomDecorators((PyFunction) callable)) {
       return;
     }
   }
   highlightIncorrectArguments(holder, result, context);
   highlightMissingArguments(node, holder, result);
   highlightStarArgumentTypeMismatch(node, holder, context);
 }
 private static void highlightMissingArguments(
     PyArgumentList node, ProblemsHolder holder, CallArgumentsMapping result) {
   ASTNode our_node = node.getNode();
   if (our_node != null) {
     ASTNode close_paren = our_node.findChildByType(PyTokenTypes.RPAR);
     if (close_paren != null) {
       for (PyNamedParameter param : result.getUnmappedParams()) {
         holder.registerProblem(
             close_paren.getPsi(),
             PyBundle.message("INSP.parameter.$0.unfilled", param.getName()));
       }
     }
   }
 }