PY-27180: Move methods to different modules according to IDEA-CR-27412

This commit is contained in:
Ilya.Kazakevich
2017-12-19 00:30:12 +03:00
parent f4d3f5a0d5
commit 3ebad657c3
5 changed files with 103 additions and 108 deletions
@@ -88,6 +88,7 @@ public class TypeEvalContext {
* It is as detailed as {@link TypeEvalContext#userInitiated(Project, PsiFile)}, but allows inferring types based on the context in which
* the analyzed code was called or may be called. Since this is basically guesswork, the results should be used only for code completion.
*/
@NotNull
public static TypeEvalContext codeCompletion(@NotNull final Project project, @Nullable final PsiFile origin) {
return getContextFromCache(project, new TypeEvalContext(true, true, true, origin));
}
@@ -0,0 +1,18 @@
/*
* Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
*/
package com.jetbrains.extensions
import com.intellij.patterns.PlatformPatterns.psiElement
import com.intellij.patterns.PsiElementPattern
import com.jetbrains.python.PythonLanguage
import com.jetbrains.python.psi.PyClass
import com.jetbrains.python.psi.PyFunction
/**
* Place right after "def" in class method. Useful to provide custom completions
*/
fun PsiElementPattern.Capture<*>.afterDefInMethod() =
withLanguage(PythonLanguage.getInstance())
.and(psiElement().inside(psiElement(PyFunction::class.java).inside(psiElement(PyClass::class.java))))
.and(psiElement().afterLeaf("def"))
@@ -0,0 +1,62 @@
/*
* Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
*/
package com.jetbrains.python.codeInsight.completion
import com.intellij.codeInsight.TailType
import com.intellij.codeInsight.completion.AutoCompletionContext
import com.intellij.codeInsight.completion.AutoCompletionDecision
import com.intellij.codeInsight.completion.CompletionParameters
import com.intellij.codeInsight.completion.CompletionResultSet
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.codeInsight.lookup.TailTypeDecorator
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil
import com.jetbrains.python.psi.PyClass
import com.jetbrains.python.psi.PyFunction
import com.jetbrains.python.psi.types.TypeEvalContext
import icons.PythonIcons
/**
* Various utils for custom completions
*/
/**
* Implementation of CompletionContributor#handleAutoCompletionPossibility
*
* auto-insert the obvious only case; else show other cases.
*/
fun autocompleteObviousCase(context: AutoCompletionContext) =
if (context.items.size == 1) {
AutoCompletionDecision.insertItem(context.items.first())!!
}
else {
AutoCompletionDecision.SHOW_LOOKUP!!
}
fun CompletionParameters.getPyClass() = (ScopeUtil.getScopeOwner(position) as? PyFunction)?.containingClass
fun CompletionParameters.getTypeEvalContext() = TypeEvalContext.codeCompletion(originalFile.project, originalFile)
/**
* Add method completion to to result.
* @param result destination
* @param pyClass if provided will check if method does not exist already
* @param builderPostprocessor function to be used to tune lookup builder
*/
fun addMethodToResult(result: CompletionResultSet,
pyClass: PyClass?,
typeEvalContext: TypeEvalContext,
methodName: String,
methodParentheses: String = "(self)",
builderPostprocessor: ((LookupElementBuilder) -> LookupElementBuilder)? = null) {
if (pyClass?.findMethodByName(methodName, false, typeEvalContext) != null) {
return
}
val item = LookupElementBuilder.create(methodName + methodParentheses)
.withIcon(PythonIcons.Python.Nodes.Cyan_dot)
result.addElement(TailTypeDecorator.withTail(builderPostprocessor?.invoke(item) ?: item, TailType.CASE_COLON))
}
@@ -1,102 +0,0 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.python.codeInsight.completion;
import com.intellij.codeInsight.TailType;
import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.codeInsight.lookup.TailTypeDecorator;
import com.intellij.openapi.util.Pair;
import com.intellij.util.ObjectUtils;
import com.intellij.util.ProcessingContext;
import com.jetbrains.python.PythonLanguage;
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyFunction;
import com.jetbrains.python.psi.types.TypeEvalContext;
import icons.PythonIcons;
import org.jetbrains.annotations.NotNull;
import static com.intellij.patterns.PlatformPatterns.psiElement;
/**
* Contributes method names to class
* User: dcheryasov
* @author Ilya.Kazakevich
*/
public abstract class PyMethodNamesCompletionContributor extends CompletionContributor {
@Override
public AutoCompletionDecision handleAutoCompletionPossibility(@NotNull AutoCompletionContext context) {
// auto-insert the obvious only case; else show other cases.
final LookupElement[] items = context.getItems();
if (items.length == 1) {
return AutoCompletionDecision.insertItem(items[0]);
}
return AutoCompletionDecision.SHOW_LOOKUP;
}
/**
* @return method_name, (arguments)
*/
@NotNull
protected abstract Iterable<Pair<String, String>> getCompletions(@NotNull final PyClass aClass,
@NotNull final TypeEvalContext context);
protected PyMethodNamesCompletionContributor() {
extend(
CompletionType.BASIC,
psiElement()
.withLanguage(PythonLanguage.getInstance())
.and(psiElement().inside(psiElement(PyFunction.class).inside(psiElement(PyClass.class))))
.and(psiElement().afterLeaf("def"))
,
new CompletionProvider<CompletionParameters>() {
@Override
protected void addCompletions(
@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result
) {
final PyFunction method =
ObjectUtils.tryCast(ScopeUtil.getScopeOwner(parameters.getPosition()), PyFunction.class);
if (method == null) {
return;
}
final PyClass pyClass = method.getContainingClass();
if (pyClass == null) {
return;
}
final TypeEvalContext typeEvalContext =
TypeEvalContext.codeCompletion(pyClass.getProject(), parameters.getOriginalFile());
for (final Pair<String, String> signature : getCompletions(pyClass, typeEvalContext)) {
final String name = signature.first;
if (pyClass.findMethodByName(name, false, typeEvalContext) != null) {
continue;
}
final String parentheses = signature.second;
final LookupElementBuilder item = LookupElementBuilder.create(name + parentheses)
.withTypeText("predefined")
.withIcon(PythonIcons.Python.Nodes.Cyan_dot);
result.addElement(TailTypeDecorator.withTail(item, TailType.CASE_COLON));
}
}
}
);
}
}
@@ -1,13 +1,29 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.jetbrains.python.codeInsight.completion
import com.intellij.openapi.util.Pair
import com.intellij.codeInsight.completion.*
import com.intellij.patterns.PlatformPatterns
import com.intellij.util.ProcessingContext
import com.jetbrains.extensions.afterDefInMethod
import com.jetbrains.python.PyNames
import com.jetbrains.python.psi.LanguageLevel
import com.jetbrains.python.psi.PyClass
import com.jetbrains.python.psi.types.TypeEvalContext
class PySpecialMethodNamesCompletionContributor : PyMethodNamesCompletionContributor() {
override fun getCompletions(aClass: PyClass, context: TypeEvalContext) =
PyNames.getBuiltinMethods(LanguageLevel.forElement(aClass)).map { Pair(it.key, it.value.signature) }
class PySpecialMethodNamesCompletionContributor : CompletionContributor() {
override fun handleAutoCompletionPossibility(context: AutoCompletionContext) = autocompleteObviousCase(context)
init {
extend(CompletionType.BASIC, PlatformPatterns.psiElement().afterDefInMethod(), MyCompletionProvider)
}
private object MyCompletionProvider : CompletionProvider<CompletionParameters>() {
override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext?, result: CompletionResultSet) {
val pyClass = parameters.getPyClass() ?: return
val typeEvalContext = parameters.getTypeEvalContext()
PyNames.getBuiltinMethods(LanguageLevel.forElement(pyClass))
?.forEach {
addMethodToResult(result, pyClass, typeEvalContext, it.key, it.value.signature) { it.withTypeText("predefined") }
}
}
}
}