mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Use separate type eval context for code completion
We used to have context.allowLocalUsages() for permitting a code analysis to guess types from file-local function calls. This analysis mode came into conflict with the new structural types, since they both provided types for function parameters. Another problem is that the user used to see the types inferred from local calls in the documentation pop-up and it was not clear where did they come from. The solution is to introduce a new type eval context for code completion only named TypeEvalContext.codeCompletion() and allow file-local call based type inference only in this context.
This commit is contained in:
@@ -30,14 +30,17 @@ import org.jetbrains.annotations.Nullable;
|
||||
class TypeEvalConstraints {
|
||||
final boolean myAllowDataFlow;
|
||||
final boolean myAllowStubToAST;
|
||||
final boolean myAllowCallContext;
|
||||
@Nullable final PsiFile myOrigin;
|
||||
|
||||
/**
|
||||
* @see com.jetbrains.python.psi.types.TypeEvalContext
|
||||
*/
|
||||
TypeEvalConstraints(final boolean allowDataFlow, final boolean allowStubToAST, @Nullable final PsiFile origin) {
|
||||
TypeEvalConstraints(final boolean allowDataFlow, final boolean allowStubToAST, final boolean allowCallContext,
|
||||
@Nullable final PsiFile origin) {
|
||||
myAllowDataFlow = allowDataFlow;
|
||||
myAllowStubToAST = allowStubToAST;
|
||||
myAllowCallContext = allowCallContext;
|
||||
myOrigin = origin;
|
||||
}
|
||||
|
||||
@@ -50,6 +53,7 @@ class TypeEvalConstraints {
|
||||
|
||||
if (myAllowDataFlow != that.myAllowDataFlow) return false;
|
||||
if (myAllowStubToAST != that.myAllowStubToAST) return false;
|
||||
if (myAllowCallContext != that.myAllowCallContext) return false;
|
||||
if (myOrigin != null ? !myOrigin.equals(that.myOrigin) : that.myOrigin != null) return false;
|
||||
|
||||
return true;
|
||||
@@ -60,11 +64,12 @@ class TypeEvalConstraints {
|
||||
int result = (myAllowDataFlow ? 1 : 0);
|
||||
result = 31 * result + (myAllowStubToAST ? 1 : 0);
|
||||
result = 31 * result + (myOrigin != null ? myOrigin.hashCode() : 0);
|
||||
result = 31 * result + (myAllowCallContext ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("TypeEvalConstraints(%b, %b, %s)", myAllowDataFlow, myAllowStubToAST, myOrigin);
|
||||
return String.format("TypeEvalConstraints(%b, %b, %b, %s)", myAllowDataFlow, myAllowStubToAST, myAllowCallContext, myOrigin);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,8 +65,8 @@ public class TypeEvalContext {
|
||||
}
|
||||
};
|
||||
|
||||
private TypeEvalContext(boolean allowDataFlow, boolean allowStubToAST, @Nullable PsiFile origin) {
|
||||
myConstraints = new TypeEvalConstraints(allowDataFlow, allowStubToAST, origin);
|
||||
private TypeEvalContext(boolean allowDataFlow, boolean allowStubToAST, boolean allowCallContext, @Nullable PsiFile origin) {
|
||||
myConstraints = new TypeEvalConstraints(allowDataFlow, allowStubToAST, allowCallContext, origin);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -83,17 +83,29 @@ public class TypeEvalContext {
|
||||
return myConstraints.myAllowDataFlow || element.getContainingFile() == myConstraints.myOrigin;
|
||||
}
|
||||
|
||||
public boolean allowLocalUsages(@NotNull PsiElement element) {
|
||||
return myConstraints.myAllowStubToAST && myConstraints.myAllowDataFlow && element.getContainingFile() == myConstraints.myOrigin;
|
||||
public boolean allowCallContext(@NotNull PsiElement element) {
|
||||
return myConstraints.myAllowCallContext && element.getContainingFile() == myConstraints.myOrigin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a context for code completion.
|
||||
* <p/>
|
||||
* 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.
|
||||
*/
|
||||
public static TypeEvalContext codeCompletion(@NotNull final Project project, @Nullable final PsiFile origin) {
|
||||
return CACHE.getContext(project, new TypeEvalContext(true, true, true, origin));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the most detailed type evaluation context for user-initiated actions.
|
||||
* <p/>
|
||||
* Should be used for code completion, go to definition, find usages, refactorings, documentation.
|
||||
* Should be used go to definition, find usages, refactorings, documentation.
|
||||
* <p/>
|
||||
* For code completion see {@link TypeEvalContext#codeCompletion(Project, PsiFile)}.
|
||||
*/
|
||||
public static TypeEvalContext userInitiated(@NotNull final Project project, @Nullable final PsiFile origin) {
|
||||
return CACHE.getContext(project, new TypeEvalContext(true, true, origin));
|
||||
return CACHE.getContext(project, new TypeEvalContext(true, true, false, origin));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,20 +115,18 @@ public class TypeEvalContext {
|
||||
* Inspections should not create a new type evaluation context. They should re-use the context of the inspection session.
|
||||
*/
|
||||
public static TypeEvalContext codeAnalysis(@NotNull final Project project, @Nullable final PsiFile origin) {
|
||||
return CACHE.getContext(project, new TypeEvalContext(false, false, origin));
|
||||
return CACHE.getContext(project, new TypeEvalContext(false, false, false, origin));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the most shallow type evaluation context for code insight purposes when other more detailed contexts are not available.
|
||||
* It's use should be minimized.
|
||||
* <p/>
|
||||
* <p/>
|
||||
*
|
||||
* @param project pass project here to enable cache. Pass null if you do not have any project.
|
||||
* <strong>Always</strong> do your best to pass project here: it increases performance!
|
||||
*/
|
||||
public static TypeEvalContext codeInsightFallback(@Nullable final Project project) {
|
||||
final TypeEvalContext anchor = new TypeEvalContext(false, false, null);
|
||||
final TypeEvalContext anchor = new TypeEvalContext(false, false, false, null);
|
||||
if (project != null) {
|
||||
return CACHE.getContext(project, anchor);
|
||||
}
|
||||
@@ -129,7 +139,7 @@ public class TypeEvalContext {
|
||||
* Should be used only when normal code insight context is not enough for getting good results.
|
||||
*/
|
||||
public static TypeEvalContext deepCodeInsight(@NotNull final Project project) {
|
||||
return CACHE.getContext(project, new TypeEvalContext(false, true, null));
|
||||
return CACHE.getContext(project, new TypeEvalContext(false, true, false, null));
|
||||
}
|
||||
|
||||
public TypeEvalContext withTracing() {
|
||||
|
||||
Reference in New Issue
Block a user