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 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()));
       }
     }
   }
 }
  @Nullable
  public Ref<PyType> getParameterType(
      @NotNull PyNamedParameter param, @NotNull PyFunction func, @NotNull TypeEvalContext context) {
    final PyAnnotation annotation = param.getAnnotation();
    if (annotation != null) {
      // XXX: Requires switching from stub to AST
      final PyExpression value = annotation.getValue();
      if (value != null) {
        final PyType type = getType(value, new Context(context));
        if (type != null) {
          final PyType optionalType = getOptionalTypeFromDefaultNone(param, type, context);
          return Ref.create(optionalType != null ? optionalType : type);
        }
      }
    }

    final String paramComment = param.getTypeCommentAnnotation();
    if (paramComment != null) {
      return Ref.create(getStringBasedType(paramComment, param, new Context(context)));
    }

    final String comment = func.getTypeCommentAnnotation();
    if (comment != null) {
      final PyTypeParser.ParseResult result =
          PyTypeParser.parsePep484FunctionTypeComment(param, comment);
      final PyCallableType functionType = as(result.getType(), PyCallableType.class);
      if (functionType != null) {
        final List<PyCallableParameter> paramTypes = functionType.getParameters(context);
        // Function annotation of kind (...) -> Type
        if (paramTypes == null) {
          return Ref.create();
        }
        final PyParameter[] funcParams = func.getParameterList().getParameters();
        final int startOffset = omitFirstParamInTypeComment(func) ? 1 : 0;
        for (int paramIndex = 0; paramIndex < funcParams.length; paramIndex++) {
          if (funcParams[paramIndex] == param) {
            final int typeIndex = paramIndex - startOffset;
            if (typeIndex >= 0 && typeIndex < paramTypes.size()) {
              return Ref.create(paramTypes.get(typeIndex).getType(context));
            }
            break;
          }
        }
      }
    }
    return null;
  }
 @Nullable
 private static PyType getOptionalTypeFromDefaultNone(
     @NotNull PyNamedParameter param, @NotNull PyType type, @NotNull TypeEvalContext context) {
   final PyExpression defaultValue = param.getDefaultValue();
   if (defaultValue != null) {
     final PyType defaultType = context.getType(defaultValue);
     if (defaultType instanceof PyNoneType) {
       return PyUnionType.union(type, defaultType);
     }
   }
   return null;
 }
  private static Pair<String, String> getTypeAndDescription(
      @Nullable final String docString, @NotNull final PyNamedParameter followed) {
    StructuredDocString structuredDocString = DocStringUtil.parse(docString);
    String type = null;
    String desc = null;
    if (structuredDocString != null) {
      final String name = followed.getName();
      type = structuredDocString.getParamType(name);

      desc = structuredDocString.getParamDescription(name);
    }

    return Pair.create(type, desc);
  }
 @Override
 public void visitPyDecoratorList(final PyDecoratorList node) {
   PyDecorator[] decorators = node.getDecorators();
   for (PyDecorator deco : decorators) {
     if (deco.hasArgumentList()) continue;
     final PyCallExpression.PyMarkedCallee markedCallee =
         deco.resolveCallee(resolveWithoutImplicits());
     if (markedCallee != null && !markedCallee.isImplicitlyResolved()) {
       final Callable callable = markedCallee.getCallable();
       int firstParamOffset = markedCallee.getImplicitOffset();
       final List<PyParameter> params = PyUtil.getParameters(callable, myTypeEvalContext);
       final PyNamedParameter allegedFirstParam =
           params.size() < firstParamOffset
               ? null
               : params.get(firstParamOffset - 1).getAsNamed();
       if (allegedFirstParam == null || allegedFirstParam.isKeywordContainer()) {
         // no parameters left to pass function implicitly, or wrong param type
         registerProblem(
             deco,
             PyBundle.message(
                 "INSP.func.$0.lacks.first.arg",
                 callable.getName())); // TODO: better names for anon lambdas
       } else { // possible unfilled params
         for (int i = firstParamOffset; i < params.size(); i += 1) {
           final PyParameter parameter = params.get(i);
           if (parameter instanceof PySingleStarParameter) continue;
           final PyNamedParameter par = parameter.getAsNamed();
           // param tuples, non-starred or non-default won't do
           if (par == null
               || (!par.isKeywordContainer()
                   && !par.isPositionalContainer()
                   && !par.hasDefaultValue())) {
             String parameterName = par != null ? par.getName() : "(...)";
             registerProblem(
                 deco, PyBundle.message("INSP.parameter.$0.unfilled", parameterName));
           }
         }
       }
     }
     // else: this case is handled by arglist visitor
   }
 }