Unresolved references highlighted in the editor. Resolve test added

This commit is contained in:
Andrey Breslav
2011-03-01 20:24:14 +03:00
parent d06233eed6
commit 7b7fe4dd60
20 changed files with 424 additions and 250 deletions
@@ -1,10 +1,19 @@
package org.jetbrains.jet.lang; package org.jetbrains.jet.lang;
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
/** /**
* @author abreslav * @author abreslav
*/ */
public class ErrorHandler { public class ErrorHandler {
public static final ErrorHandler DO_NOTHING = new ErrorHandler(); public static final ErrorHandler DO_NOTHING = new ErrorHandler();
public static final ErrorHandler THROW_EXCEPTION = new ErrorHandler(); public static final ErrorHandler THROW_EXCEPTION = new ErrorHandler() {
@Override
public void unresolvedReference(JetReferenceExpression referenceExpression) {
throw new IllegalStateException("Unresolved reference: " + referenceExpression.getReferencedName());
}
};
public void unresolvedReference(JetReferenceExpression referenceExpression) {
}
} }
@@ -44,4 +44,8 @@ public class JetSemanticServices {
public JetTypeInferrer getTypeInferrer(BindingTrace trace) { public JetTypeInferrer getTypeInferrer(BindingTrace trace) {
return new JetTypeInferrer(trace, this); return new JetTypeInferrer(trace, this);
} }
public ErrorHandler getErrorHandler() {
return errorHandler;
}
} }
@@ -22,7 +22,10 @@ public class JetPsiChecker implements Annotator {
if (element instanceof JetFile) { if (element instanceof JetFile) {
JetFile file = (JetFile) element; JetFile file = (JetFile) element;
JetSemanticServices semanticServices = JetSemanticServices.createSemanticServices(element.getProject(), new ErrorHandler() { JetSemanticServices semanticServices = JetSemanticServices.createSemanticServices(element.getProject(), new ErrorHandler() {
@Override
public void unresolvedReference(JetReferenceExpression referenceExpression) {
holder.createErrorAnnotation(referenceExpression, "Unresolved");
}
}); });
try { try {
final BindingContext bindingContext = new TopDownAnalyzer(semanticServices).process(semanticServices.getStandardLibrary().getLibraryScope(), file.getRootNamespace().getDeclarations()); final BindingContext bindingContext = new TopDownAnalyzer(semanticServices).process(semanticServices.getStandardLibrary().getLibraryScope(), file.getRootNamespace().getDeclarations());
@@ -20,7 +20,7 @@ public class ClassDescriptorResolver {
public ClassDescriptorResolver(JetSemanticServices semanticServices, BindingTrace trace) { public ClassDescriptorResolver(JetSemanticServices semanticServices, BindingTrace trace) {
this.semanticServices = semanticServices; this.semanticServices = semanticServices;
this.typeResolver = new TypeResolver(trace); this.typeResolver = new TypeResolver(trace, semanticServices.getErrorHandler());
this.trace = trace; this.trace = trace;
} }
@@ -11,19 +11,19 @@ public interface JetScope {
JetScope EMPTY = new JetScopeImpl() {}; JetScope EMPTY = new JetScopeImpl() {};
@Nullable @Nullable
ClassDescriptor getClass(String name); ClassDescriptor getClass(@NotNull String name);
@Nullable @Nullable
PropertyDescriptor getProperty(String name); PropertyDescriptor getProperty(@NotNull String name);
@Nullable @Nullable
ExtensionDescriptor getExtension(String name); ExtensionDescriptor getExtension(@NotNull String name);
@Nullable @Nullable
NamespaceDescriptor getNamespace(String name); NamespaceDescriptor getNamespace(@NotNull String name);
@Nullable @Nullable
TypeParameterDescriptor getTypeParameter(String name); TypeParameterDescriptor getTypeParameter(@NotNull String name);
@NotNull @NotNull
Type getThisType(); Type getThisType();
@@ -26,27 +26,27 @@ public class JetScopeAdapter implements JetScope {
} }
@Override @Override
public TypeParameterDescriptor getTypeParameter(String name) { public TypeParameterDescriptor getTypeParameter(@NotNull String name) {
return scope.getTypeParameter(name); return scope.getTypeParameter(name);
} }
@Override @Override
public NamespaceDescriptor getNamespace(String name) { public NamespaceDescriptor getNamespace(@NotNull String name) {
return scope.getNamespace(name); return scope.getNamespace(name);
} }
@Override @Override
public ClassDescriptor getClass(String name) { public ClassDescriptor getClass(@NotNull String name) {
return scope.getClass(name); return scope.getClass(name);
} }
@Override @Override
public PropertyDescriptor getProperty(String name) { public PropertyDescriptor getProperty(@NotNull String name) {
return scope.getProperty(name); return scope.getProperty(name);
} }
@Override @Override
public ExtensionDescriptor getExtension(String name) { public ExtensionDescriptor getExtension(@NotNull String name) {
return scope.getExtension(name); return scope.getExtension(name);
} }
@@ -8,27 +8,27 @@ import org.jetbrains.jet.lang.types.*;
*/ */
public abstract class JetScopeImpl implements JetScope { public abstract class JetScopeImpl implements JetScope {
@Override @Override
public ClassDescriptor getClass(String name) { public ClassDescriptor getClass(@NotNull String name) {
return null; return null;
} }
@Override @Override
public PropertyDescriptor getProperty(String name) { public PropertyDescriptor getProperty(@NotNull String name) {
return null; return null;
} }
@Override @Override
public ExtensionDescriptor getExtension(String name) { public ExtensionDescriptor getExtension(@NotNull String name) {
return null; return null;
} }
@Override @Override
public NamespaceDescriptor getNamespace(String name) { public NamespaceDescriptor getNamespace(@NotNull String name) {
return null; return null;
} }
@Override @Override
public TypeParameterDescriptor getTypeParameter(String name) { public TypeParameterDescriptor getTypeParameter(@NotNull String name) {
return null; return null;
} }
@@ -17,28 +17,28 @@ public class ScopeWithReceiver extends JetScopeImpl {
} }
@Override @Override
public ClassDescriptor getClass(String name) { public ClassDescriptor getClass(@NotNull String name) {
return super.getClass(name); // TODO return super.getClass(name); // TODO
} }
@Override @Override
public PropertyDescriptor getProperty(String name) { public PropertyDescriptor getProperty(@NotNull String name) {
return receiverTypeScope.getProperty(name); return receiverTypeScope.getProperty(name);
// TODO : extension properties // TODO : extension properties
} }
@Override @Override
public ExtensionDescriptor getExtension(String name) { public ExtensionDescriptor getExtension(@NotNull String name) {
return super.getExtension(name); // TODO return super.getExtension(name); // TODO
} }
@Override @Override
public NamespaceDescriptor getNamespace(String name) { public NamespaceDescriptor getNamespace(@NotNull String name) {
return outerScope.getNamespace(name); return outerScope.getNamespace(name);
} }
@Override @Override
public TypeParameterDescriptor getTypeParameter(String name) { public TypeParameterDescriptor getTypeParameter(@NotNull String name) {
return outerScope.getTypeParameter(name); return outerScope.getTypeParameter(name);
} }
@@ -19,7 +19,7 @@ public class SubstitutingScope implements JetScope {
} }
@Override @Override
public PropertyDescriptor getProperty(String name) { public PropertyDescriptor getProperty(@NotNull String name) {
PropertyDescriptor property = workerScope.getProperty(name); PropertyDescriptor property = workerScope.getProperty(name);
if (property == null || substitutionContext.isEmpty()) { if (property == null || substitutionContext.isEmpty()) {
return property; return property;
@@ -28,7 +28,7 @@ public class SubstitutingScope implements JetScope {
} }
@Override @Override
public ClassDescriptor getClass(String name) { public ClassDescriptor getClass(@NotNull String name) {
ClassDescriptor descriptor = workerScope.getClass(name); ClassDescriptor descriptor = workerScope.getClass(name);
if (descriptor == null) { if (descriptor == null) {
return null; return null;
@@ -37,17 +37,17 @@ public class SubstitutingScope implements JetScope {
} }
@Override @Override
public ExtensionDescriptor getExtension(String name) { public ExtensionDescriptor getExtension(@NotNull String name) {
throw new UnsupportedOperationException(); // TODO throw new UnsupportedOperationException(); // TODO
} }
@Override @Override
public NamespaceDescriptor getNamespace(String name) { public NamespaceDescriptor getNamespace(@NotNull String name) {
throw new UnsupportedOperationException(); // TODO throw new UnsupportedOperationException(); // TODO
} }
@Override @Override
public TypeParameterDescriptor getTypeParameter(String name) { public TypeParameterDescriptor getTypeParameter(@NotNull String name) {
throw new UnsupportedOperationException(); // TODO throw new UnsupportedOperationException(); // TODO
} }
@@ -2,6 +2,7 @@ package org.jetbrains.jet.lang.resolve;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.ErrorHandler;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.*;
@@ -16,9 +17,11 @@ import java.util.Set;
public class TypeResolver { public class TypeResolver {
private final BindingTrace trace; private final BindingTrace trace;
private final ErrorHandler errorHandler;
public TypeResolver(BindingTrace trace) { public TypeResolver(BindingTrace trace, ErrorHandler errorHandler) {
this.trace = trace; this.trace = trace;
this.errorHandler = errorHandler;
} }
@NotNull @NotNull
@@ -52,6 +55,7 @@ public class TypeResolver {
else if (type.getTypeArguments().isEmpty()) { else if (type.getTypeArguments().isEmpty()) {
TypeParameterDescriptor typeParameterDescriptor = scope.getTypeParameter(type.getReferencedName()); TypeParameterDescriptor typeParameterDescriptor = scope.getTypeParameter(type.getReferencedName());
if (typeParameterDescriptor != null) { if (typeParameterDescriptor != null) {
trace.recordReferenceResolution(type.getReferenceExpression(), typeParameterDescriptor);
result[0] = new TypeImpl( result[0] = new TypeImpl(
attributes, attributes,
typeParameterDescriptor.getTypeConstructor(), typeParameterDescriptor.getTypeConstructor(),
@@ -60,8 +64,13 @@ public class TypeResolver {
// TODO : joint domain // TODO : joint domain
JetStandardClasses.STUB JetStandardClasses.STUB
); );
} else {
errorHandler.unresolvedReference(type.getReferenceExpression());
} }
} }
else {
errorHandler.unresolvedReference(type.getReferenceExpression());
}
} }
@Override @Override
@@ -43,7 +43,7 @@ public class WritableScope extends JetScopeAdapter {
} }
@Override @Override
public PropertyDescriptor getProperty(String name) { public PropertyDescriptor getProperty(@NotNull String name) {
@NotNull @NotNull
Map<String, PropertyDescriptor> propertyDescriptors = getPropertyDescriptors(); Map<String, PropertyDescriptor> propertyDescriptors = getPropertyDescriptors();
PropertyDescriptor propertyDescriptor = propertyDescriptors.get(name); PropertyDescriptor propertyDescriptor = propertyDescriptors.get(name);
@@ -102,7 +102,7 @@ public class WritableScope extends JetScopeAdapter {
} }
@Override @Override
public TypeParameterDescriptor getTypeParameter(String name) { public TypeParameterDescriptor getTypeParameter(@NotNull String name) {
TypeParameterDescriptor typeParameterDescriptor = getTypeParameterDescriptors().get(name); TypeParameterDescriptor typeParameterDescriptor = getTypeParameterDescriptors().get(name);
if (typeParameterDescriptor != null) { if (typeParameterDescriptor != null) {
return typeParameterDescriptor; return typeParameterDescriptor;
@@ -130,7 +130,7 @@ public class WritableScope extends JetScopeAdapter {
} }
@Override @Override
public ClassDescriptor getClass(String name) { public ClassDescriptor getClass(@NotNull String name) {
ClassDescriptor classDescriptor = getClassDescriptors().get(name); ClassDescriptor classDescriptor = getClassDescriptors().get(name);
if (classDescriptor != null) { if (classDescriptor != null) {
return classDescriptor; return classDescriptor;
@@ -148,12 +148,12 @@ public class WritableScope extends JetScopeAdapter {
} }
@Override @Override
public NamespaceDescriptor getNamespace(String name) { public NamespaceDescriptor getNamespace(@NotNull String name) {
return super.getNamespace(name); // TODO return super.getNamespace(name); // TODO
} }
@Override @Override
public ExtensionDescriptor getExtension(String name) { public ExtensionDescriptor getExtension(@NotNull String name) {
return super.getExtension(name); // TODO return super.getExtension(name); // TODO
} }
@@ -12,27 +12,27 @@ import java.util.List;
public class ErrorType { public class ErrorType {
private static final JetScope ERROR_SCOPE = new JetScope() { private static final JetScope ERROR_SCOPE = new JetScope() {
@Override @Override
public ClassDescriptor getClass(String name) { public ClassDescriptor getClass(@NotNull String name) {
throw new UnsupportedOperationException(); // TODO throw new UnsupportedOperationException(); // TODO
} }
@Override @Override
public PropertyDescriptor getProperty(String name) { public PropertyDescriptor getProperty(@NotNull String name) {
throw new UnsupportedOperationException(); // TODO throw new UnsupportedOperationException(); // TODO
} }
@Override @Override
public ExtensionDescriptor getExtension(String name) { public ExtensionDescriptor getExtension(@NotNull String name) {
throw new UnsupportedOperationException(); // TODO throw new UnsupportedOperationException(); // TODO
} }
@Override @Override
public NamespaceDescriptor getNamespace(String name) { public NamespaceDescriptor getNamespace(@NotNull String name) {
throw new UnsupportedOperationException(); // TODO throw new UnsupportedOperationException(); // TODO
} }
@Override @Override
public TypeParameterDescriptor getTypeParameter(String name) { public TypeParameterDescriptor getTypeParameter(@NotNull String name) {
throw new UnsupportedOperationException(); // TODO throw new UnsupportedOperationException(); // TODO
} }
@@ -24,7 +24,7 @@ public class JetTypeInferrer {
public JetTypeInferrer(BindingTrace trace, JetSemanticServices semanticServices) { public JetTypeInferrer(BindingTrace trace, JetSemanticServices semanticServices) {
this.trace = trace; this.trace = trace;
this.semanticServices = semanticServices; this.semanticServices = semanticServices;
this.typeResolver = new TypeResolver(trace); this.typeResolver = new TypeResolver(trace, semanticServices.getErrorHandler());
this.classDescriptorResolver = new ClassDescriptorResolver(semanticServices, trace); this.classDescriptorResolver = new ClassDescriptorResolver(semanticServices, trace);
} }
@@ -50,9 +50,11 @@ public class JetTypeInferrer {
// TODO : other members // TODO : other members
// TODO : type substitutions??? // TODO : type substitutions???
PropertyDescriptor property = scope.getProperty(expression.getReferencedName()); PropertyDescriptor property = scope.getProperty(expression.getReferencedName());
trace.recordReferenceResolution(expression, property);
if (property != null) { if (property != null) {
trace.recordReferenceResolution(expression, property);
result[0] = property.getType(); result[0] = property.getType();
} else {
semanticServices.getErrorHandler().unresolvedReference(expression);
} }
} }
@@ -400,6 +402,8 @@ public class JetTypeInferrer {
FunctionDescriptor descriptor = result[0].getFunctionDescriptorForNamedArguments(typeArguments, valueArgumentTypes, functionLiteralArgumentType); FunctionDescriptor descriptor = result[0].getFunctionDescriptorForNamedArguments(typeArguments, valueArgumentTypes, functionLiteralArgumentType);
if (descriptor != null) { if (descriptor != null) {
trace.recordReferenceResolution(reference[0], descriptor); trace.recordReferenceResolution(reference[0], descriptor);
} else {
semanticServices.getErrorHandler().unresolvedReference(reference[0]);
} }
return descriptor; return descriptor;
} }
@@ -409,6 +413,8 @@ public class JetTypeInferrer {
FunctionDescriptor descriptor = result[0].getFunctionDescriptorForPositionedArguments(typeArguments, positionedValueArgumentTypes); FunctionDescriptor descriptor = result[0].getFunctionDescriptorForPositionedArguments(typeArguments, positionedValueArgumentTypes);
if (descriptor != null) { if (descriptor != null) {
trace.recordReferenceResolution(reference[0], descriptor); trace.recordReferenceResolution(reference[0], descriptor);
} else {
semanticServices.getErrorHandler().unresolvedReference(reference[0]);
} }
return descriptor; return descriptor;
} }
+1 -2
View File
@@ -1,2 +1 @@
val foo = 1 val x : Int
+11 -9
View File
@@ -1,17 +1,19 @@
class A { ~A~class A {
class B { ~B~class B {
} }
fun foo(a : Int) = a ~foo~fun foo(~foo.a~a : `std::Char`Char) = `foo.a`a
fun fooB() = foo(1) ~fooB~fun fooB() = `foo`foo('1')
fun foo() : Int = 1.plus(1) ~foo.1~fun foo() : Int = 1.`std::Int.plus(Int)`plus(1)
fun foo1() : B = new B() ~foo1~fun foo1() : `B`B = new `B`B()
val a : Int ~A.a~val a : `std::Int`Int
} }
class C : A { ~C~class C : `A`A {
class B : C { ~C.B~class B : `C`C {
} }
val x : `C.B`B
} }
@@ -1,109 +0,0 @@
package org.jetbrains.jet.checkers;
import com.intellij.codeHighlighting.Pass;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzerSettings;
import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl;
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.injected.editor.EditorWindow;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.vfs.VirtualFileFilter;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.testFramework.ExpectedHighlightingData;
import com.intellij.testFramework.FileTreeAccessFilter;
import com.intellij.testFramework.LightCodeInsightTestCase;
import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
/**
* @author abreslav
*/
public abstract class ExtensibleHighlightingTestCase extends LightCodeInsightTestCase {
private final FileTreeAccessFilter myJavaFilesFilter = new FileTreeAccessFilter();
@Override
protected void setUp() throws Exception {
super.setUp();
((DaemonCodeAnalyzerImpl) DaemonCodeAnalyzer.getInstance(getProject())).prepareForTest(true);
DaemonCodeAnalyzerSettings.getInstance().setImportHintEnabled(false);
}
@Override
protected void tearDown() throws Exception {
((DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(getProject())).cleanupAfterTest(true); // has to cleanup by hand since light project does not get disposed any time soon
super.tearDown();
}
@Override
protected void runTest() throws Throwable {
final Throwable[] throwable = {null};
CommandProcessor.getInstance().executeCommand(getProject(), new Runnable() {
@Override
public void run() {
try {
doRunTest();
}
catch (Throwable t) {
throwable[0] = t;
}
}
}, "", null);
if (throwable[0] != null) {
throw throwable[0];
}
}
protected void doTest(@NonNls String filePath, boolean checkWarnings, boolean checkInfos) throws Exception {
configureByFile(filePath);
doTestConfiguredFile(checkWarnings, checkInfos);
}
protected void doTestConfiguredFile(boolean checkWarnings, boolean checkInfos) {
getJavaFacade().setAssertOnFileLoadingFilter(VirtualFileFilter.NONE);
ExpectedHighlightingData expectedData = new ExpectedHighlightingData(getEditor().getDocument(),checkWarnings, checkInfos) {
@Override
protected void initAdditionalHighlightingTypes() {
// this.this.put();
}
};
PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
getFile().getText(); //to load text
myJavaFilesFilter.allowTreeAccessForFile(getVFile());
getJavaFacade().setAssertOnFileLoadingFilter(myJavaFilesFilter); // check repository work
Collection<HighlightInfo> infos = doHighlighting();
getJavaFacade().setAssertOnFileLoadingFilter(VirtualFileFilter.NONE);
expectedData.checkResult(infos, getEditor().getDocument().getText());
}
@NotNull
protected List<HighlightInfo> doHighlighting() {
PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
int[] toIgnore = doFolding() ? ArrayUtil.EMPTY_INT_ARRAY : new int[]{Pass.UPDATE_FOLDING};
Editor editor = getEditor();
PsiFile file = getFile();
if (editor instanceof EditorWindow) {
editor = ((EditorWindow)editor).getDelegate();
file = InjectedLanguageUtil.getTopLevelFile(file);
}
return CodeInsightTestFixtureImpl.instantiateAndRun(file, editor, toIgnore, false);
}
protected boolean doFolding() {
return false;
}
}
@@ -0,0 +1,150 @@
package org.jetbrains.jet.resolve;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Document;
import com.intellij.psi.PsiElement;
import org.jetbrains.jet.lang.ErrorHandler;
import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.psi.JetDeclaration;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
import org.jetbrains.jet.lang.psi.JetTypeReference;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.TopDownAnalyzer;
import org.jetbrains.jet.lang.types.*;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertSame;
/**
* @author abreslav
*/
public class ExpectedResolveData {
private final Map<String, Integer> declarationToPosition = new HashMap<String, Integer>();
private final Map<Integer, String> positionToReference = new HashMap<Integer, String>();
public ExpectedResolveData(final Document document) {
new WriteCommandAction.Simple(null) {
public void run() {
extractData(document);
}
}.execute().throwException();
}
private void extractData(Document document) {
String text = document.getText();
Pattern pattern = Pattern.compile("(~[^~]+~)|(`[^`]+`)");
while (true) {
Matcher matcher = pattern.matcher(text);
if (!matcher.find()) break;
String group = matcher.group();
String name = group.substring(1, group.length() - 1);
if (group.startsWith("~")) {
if (declarationToPosition.put(name, matcher.start()) != null) {
throw new IllegalArgumentException("Redeclaration: " + name);
}
}
else if (group.startsWith("`")) {
positionToReference.put(matcher.start(), name);
}
else {
throw new IllegalStateException();
}
document.replaceString(matcher.start(), matcher.end(), "");
text = document.getText();
}
}
public void checkResult(JetFile file) {
JetSemanticServices semanticServices = JetSemanticServices.createSemanticServices(file.getProject(), ErrorHandler.THROW_EXCEPTION);
JetStandardLibrary lib = semanticServices.getStandardLibrary();
Map<String, DeclarationDescriptor> nameToDescriptor = new HashMap<String, DeclarationDescriptor>();
nameToDescriptor.put("std::Int.plus(Int)", standardFunction(lib.getInt(), "plus", lib.getIntType()));
TopDownAnalyzer topDownAnalyzer = new TopDownAnalyzer(semanticServices);
BindingContext bindingContext = topDownAnalyzer.process(lib.getLibraryScope(), file.getRootNamespace().getDeclarations());
Map<String, JetDeclaration> nameToDeclaration = new HashMap<String, JetDeclaration>();
Map<JetDeclaration, String> declarationToName = new HashMap<JetDeclaration, String>();
for (Map.Entry<String, Integer> entry : declarationToPosition.entrySet()) {
String name = entry.getKey();
Integer position = entry.getValue();
PsiElement element = file.findElementAt(position);
JetDeclaration ancestorOfType = getAncestorOfType(JetDeclaration.class, element);
nameToDeclaration.put(name, ancestorOfType);
declarationToName.put(ancestorOfType, name);
}
for (Map.Entry<Integer, String> entry : positionToReference.entrySet()) {
Integer position = entry.getKey();
String name = entry.getValue();
PsiElement element = file.findElementAt(position);
JetDeclaration expected = nameToDeclaration.get(name);
JetReferenceExpression reference = getAncestorOfType(JetReferenceExpression.class, element);
if (expected == null && name.startsWith("std::")) {
DeclarationDescriptor expectedDescriptor = nameToDescriptor.get(name);
JetTypeReference typeReference = getAncestorOfType(JetTypeReference.class, element);
if (expectedDescriptor != null) {
DeclarationDescriptor actual = bindingContext.resolveReferenceExpression(reference);
assertSame(expectedDescriptor, actual);
continue;
}
Type actualType = bindingContext.resolveTypeReference(typeReference);
assertNotNull("Type " + name + " not resolved for reference " + name, actualType);
ClassDescriptor expectedClass = lib.getLibraryScope().getClass(name.substring(5));
assertNotNull("Expected class not found: " + name);
assertSame("Type resolution mismatch: ", expectedClass.getTypeConstructor(), actualType.getConstructor());
continue;
}
assert expected != null : "No declaration for " + name;
PsiElement actual = bindingContext.resolveToDeclarationPsiElement(reference);
String actualName = null;
if (actual != null) {
actualName = declarationToName.get(actual);
if (actualName == null) {
actualName = actual.toString();
}
}
assertSame(
"Reference `" + name + "`" + reference.getReferencedName() + " at " + reference.getTextOffset() + " is resolved into " + actualName + ".",
expected, actual);
}
}
private DeclarationDescriptor standardFunction(ClassDescriptor classDescriptor, String name, Type parameterType) {
FunctionGroup functionGroup = classDescriptor.getMemberScope(Collections.<TypeProjection>emptyList()).getFunctionGroup(name);
Collection<FunctionDescriptor> functions = functionGroup.getPossiblyApplicableFunctions(Collections.<Type>emptyList(), Collections.singletonList(parameterType));
for (FunctionDescriptor function : functions) {
if (function.getUnsubstitutedValueParameters().get(0).getType().equals(parameterType)) {
return function;
}
}
throw new IllegalArgumentException("Not found: std::" + classDescriptor.getName() + "." + name + "(" + parameterType + ")");
}
private <T> T getAncestorOfType(Class<T> type, PsiElement element) {
while (element != null && !type.isInstance(element)) {
element = element.getParent();
}
@SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"})
T result = (T) element;
return result;
}
}
@@ -0,0 +1,104 @@
package org.jetbrains.jet.resolve;
import com.intellij.codeHighlighting.Pass;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzerSettings;
import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl;
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.injected.editor.EditorWindow;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.vfs.VirtualFileFilter;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.testFramework.FileTreeAccessFilter;
import com.intellij.testFramework.LightCodeInsightTestCase;
import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetFile;
import java.util.Collection;
import java.util.List;
/**
* @author abreslav
*/
public abstract class ExtensibleResolveTestCase extends LightCodeInsightTestCase {
private final FileTreeAccessFilter myJavaFilesFilter = new FileTreeAccessFilter();
@Override
protected void setUp() throws Exception {
super.setUp();
((DaemonCodeAnalyzerImpl) DaemonCodeAnalyzer.getInstance(getProject())).prepareForTest(true);
DaemonCodeAnalyzerSettings.getInstance().setImportHintEnabled(false);
}
@Override
protected void tearDown() throws Exception {
((DaemonCodeAnalyzerImpl) DaemonCodeAnalyzer.getInstance(getProject())).cleanupAfterTest(true); // has to cleanup by hand since light project does not get disposed any time soon
super.tearDown();
}
@Override
protected void runTest() throws Throwable {
final Throwable[] throwable = {null};
CommandProcessor.getInstance().executeCommand(getProject(), new Runnable() {
@Override
public void run() {
try {
doRunTest();
} catch (Throwable t) {
throwable[0] = t;
}
}
}, "", null);
if (throwable[0] != null) {
throw throwable[0];
}
}
protected void doTest(@NonNls String filePath, boolean checkWarnings, boolean checkInfos) throws Exception {
configureByFile(filePath);
doTestConfiguredFile(checkWarnings, checkInfos);
}
protected void doTestConfiguredFile(boolean checkWarnings, boolean checkInfos) {
getJavaFacade().setAssertOnFileLoadingFilter(VirtualFileFilter.NONE);
// ExpectedHighlightingData expectedData = new ExpectedHighlightingData(getEditor().getDocument(), checkWarnings, checkInfos);
ExpectedResolveData expectedData = new ExpectedResolveData(getEditor().getDocument());
PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
getFile().getText(); //to load text
myJavaFilesFilter.allowTreeAccessForFile(getVFile());
getJavaFacade().setAssertOnFileLoadingFilter(myJavaFilesFilter); // check repository work
Collection<HighlightInfo> infos = doHighlighting();
getJavaFacade().setAssertOnFileLoadingFilter(VirtualFileFilter.NONE);
expectedData.checkResult((JetFile) getFile());
}
@NotNull
protected List<HighlightInfo> doHighlighting() {
PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
int[] toIgnore = doFolding() ? ArrayUtil.EMPTY_INT_ARRAY : new int[]{Pass.UPDATE_FOLDING};
Editor editor = getEditor();
PsiFile file = getFile();
if (editor instanceof EditorWindow) {
editor = ((EditorWindow) editor).getDelegate();
file = InjectedLanguageUtil.getTopLevelFile(file);
}
return CodeInsightTestFixtureImpl.instantiateAndRun(file, editor, toIgnore, false);
}
protected boolean doFolding() {
return false;
}
}
@@ -1,25 +1,21 @@
package org.jetbrains.jet.resolve; package org.jetbrains.jet.resolve;
import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
import com.intellij.openapi.application.PathManager; import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.util.io.FileUtil; import org.jetbrains.jet.lang.resolve.JetScope;
import org.jetbrains.jet.lang.ErrorHandler; import org.jetbrains.jet.lang.resolve.OverloadDomain;
import org.jetbrains.jet.lang.JetSemanticServices; import org.jetbrains.jet.lang.resolve.OverloadResolver;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.types.FunctionDescriptor;
import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.types.JetStandardLibrary;
import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.Type;
import org.jetbrains.jet.parsing.JetParsingTest; import org.jetbrains.jet.parsing.JetParsingTest;
import java.io.File; import java.io.File;
import java.io.FileReader;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List;
/** /**
* @author abreslav * @author abreslav
*/ */
public class JetResolveTest extends LightDaemonAnalyzerTestCase { public class JetResolveTest extends ExtensibleResolveTestCase {
private JetStandardLibrary library; private JetStandardLibrary library;
@Override @Override
@@ -38,81 +34,82 @@ public class JetResolveTest extends LightDaemonAnalyzerTestCase {
} }
public void testBasic() throws Exception { public void testBasic() throws Exception {
JetFile jetFile = JetChangeUtil.createFile(getProject(), FileUtil.loadTextAndClose(new FileReader(getTestDataPath() + "/resolve/Basic.jet"))); doTest("/resolve/Basic.jet", true, true);
List<JetDeclaration> declarations = jetFile.getRootNamespace().getDeclarations(); // JetFile jetFile = JetChangeUtil.createFile(getProject(), FileUtil.loadTextAndClose(new FileReader(getTestDataPath() + "/resolve/Basic.jet")));
BindingContext bindingContext = new TopDownAnalyzer(JetSemanticServices.createSemanticServices(library, ErrorHandler.THROW_EXCEPTION)).process(library.getLibraryScope(), declarations); // List<JetDeclaration> declarations = jetFile.getRootNamespace().getDeclarations();
// BindingContext bindingContext = new TopDownAnalyzer(JetSemanticServices.createSemanticServices(library, ErrorHandler.THROW_EXCEPTION)).process(library.getLibraryScope(), declarations);
JetClass classADecl = (JetClass) declarations.get(0); //
ClassDescriptor classA = bindingContext.getClassDescriptor(classADecl); // JetClass classADecl = (JetClass) declarations.get(0);
assertNotNull(classA); // ClassDescriptor classA = bindingContext.getClassDescriptor(classADecl);
// assertNotNull(classA);
JetScope membersOfA = classA.getMemberScope(Collections.<TypeProjection>emptyList()); //
ClassDescriptor classB = membersOfA.getClass("B"); // JetScope membersOfA = classA.getMemberScope(Collections.<TypeProjection>emptyList());
assertNotNull(classB); // ClassDescriptor classB = membersOfA.getClass("B");
// assertNotNull(classB);
{ //
FunctionGroup fooFG = membersOfA.getFunctionGroup("foo"); // {
assertFalse(fooFG.isEmpty()); // FunctionGroup fooFG = membersOfA.getFunctionGroup("foo");
} // assertFalse(fooFG.isEmpty());
// }
assertReturnType(membersOfA, "foo", library.getIntType()); //
assertReturnType(membersOfA, "foo1", new TypeImpl(classB)); // assertReturnType(membersOfA, "foo", library.getIntType());
assertReturnType(membersOfA, "fooB", library.getIntType()); // assertReturnType(membersOfA, "foo1", new TypeImpl(classB));
// assertReturnType(membersOfA, "fooB", library.getIntType());
JetFunction fooDecl = (JetFunction) classADecl.getDeclarations().get(1); //
Type expressionType = bindingContext.getExpressionType(fooDecl.getBodyExpression()); // JetFunction fooDecl = (JetFunction) classADecl.getDeclarations().get(1);
assertEquals(library.getIntType(), expressionType); // Type expressionType = bindingContext.getExpressionType(fooDecl.getBodyExpression());
// assertEquals(library.getIntType(), expressionType);
{ //
DeclarationDescriptor resolve = bindingContext.resolveReferenceExpression((JetReferenceExpression) fooDecl.getBodyExpression()); // {
assertSame(bindingContext.getFunctionDescriptor(fooDecl).getUnsubstitutedValueParameters().get(0), resolve); // DeclarationDescriptor resolve = bindingContext.resolveReferenceExpression((JetReferenceExpression) fooDecl.getBodyExpression());
} // assertSame(bindingContext.getFunctionDescriptor(fooDecl).getUnsubstitutedValueParameters().get(0), resolve);
// }
{ //
JetFunction fooBDecl = (JetFunction) classADecl.getDeclarations().get(2); // {
JetCallExpression fooBBody = (JetCallExpression) fooBDecl.getBodyExpression(); // JetFunction fooBDecl = (JetFunction) classADecl.getDeclarations().get(2);
JetReferenceExpression refToFoo = (JetReferenceExpression) fooBBody.getCalleeExpression(); // JetCallExpression fooBBody = (JetCallExpression) fooBDecl.getBodyExpression();
FunctionDescriptor mustBeFoo = (FunctionDescriptor) bindingContext.resolveReferenceExpression(refToFoo); // JetReferenceExpression refToFoo = (JetReferenceExpression) fooBBody.getCalleeExpression();
assertSame(bindingContext.getFunctionDescriptor(fooDecl), FunctionDescriptorUtil.getOriginal(mustBeFoo)); // FunctionDescriptor mustBeFoo = (FunctionDescriptor) bindingContext.resolveReferenceExpression(refToFoo);
} // assertSame(bindingContext.getFunctionDescriptor(fooDecl), FunctionDescriptorUtil.getOriginal(mustBeFoo));
// }
{ //
JetFunction fooIntDecl = (JetFunction) classADecl.getDeclarations().get(3); // {
JetCallExpression fooIntBody = (JetCallExpression) fooIntDecl.getBodyExpression(); // JetFunction fooIntDecl = (JetFunction) classADecl.getDeclarations().get(3);
JetDotQualifiedExpression qualifiedPlus = (JetDotQualifiedExpression) fooIntBody.getCalleeExpression(); // JetCallExpression fooIntBody = (JetCallExpression) fooIntDecl.getBodyExpression();
JetReferenceExpression refToPlus = (JetReferenceExpression) qualifiedPlus.getSelectorExpression(); // JetDotQualifiedExpression qualifiedPlus = (JetDotQualifiedExpression) fooIntBody.getCalleeExpression();
FunctionDescriptor mustBePlus = (FunctionDescriptor) bindingContext.resolveReferenceExpression(refToPlus); // JetReferenceExpression refToPlus = (JetReferenceExpression) qualifiedPlus.getSelectorExpression();
FunctionGroup plusGroup = library.getInt().getMemberScope(Collections.<TypeProjection>emptyList()).getFunctionGroup("plus"); // FunctionDescriptor mustBePlus = (FunctionDescriptor) bindingContext.resolveReferenceExpression(refToPlus);
Collection<FunctionDescriptor> pluses = plusGroup.getPossiblyApplicableFunctions(Collections.<Type>emptyList(), Collections.singletonList(library.getIntType())); // FunctionGroup plusGroup = library.getInt().getMemberScope(Collections.<TypeProjection>emptyList()).getFunctionGroup("plus");
FunctionDescriptor intPlus = null; // Collection<FunctionDescriptor> pluses = plusGroup.getPossiblyApplicableFunctions(Collections.<Type>emptyList(), Collections.singletonList(library.getIntType()));
for (FunctionDescriptor plus : pluses) { // FunctionDescriptor intPlus = null;
intPlus = plus; // for (FunctionDescriptor plus : pluses) {
} // intPlus = plus;
assertSame(intPlus, FunctionDescriptorUtil.getOriginal(mustBePlus)); // }
} // assertSame(intPlus, FunctionDescriptorUtil.getOriginal(mustBePlus));
// }
{ //
PropertyDescriptor a = classA.getMemberScope(Collections.<TypeProjection>emptyList()).getProperty("a"); // {
JetProperty aDecl = (JetProperty) classADecl.getDeclarations().get(5); // PropertyDescriptor a = classA.getMemberScope(Collections.<TypeProjection>emptyList()).getProperty("a");
PropertyDescriptor mustBeA = bindingContext.getPropertyDescriptor(aDecl); // JetProperty aDecl = (JetProperty) classADecl.getDeclarations().get(5);
assertSame(a, mustBeA); // PropertyDescriptor mustBeA = bindingContext.getPropertyDescriptor(aDecl);
// assertSame(a, mustBeA);
JetTypeReference propertyTypeRef = aDecl.getPropertyTypeRef(); //
Type type = bindingContext.resolveTypeReference(propertyTypeRef); // JetTypeReference propertyTypeRef = aDecl.getPropertyTypeRef();
assertEquals(library.getIntType(), type); // Type type = bindingContext.resolveTypeReference(propertyTypeRef);
} // assertEquals(library.getIntType(), type);
// }
JetClass classCDecl = (JetClass) declarations.get(1); //
ClassDescriptor classC = bindingContext.getClassDescriptor(classCDecl); // JetClass classCDecl = (JetClass) declarations.get(1);
assertNotNull(classC); // ClassDescriptor classC = bindingContext.getClassDescriptor(classCDecl);
assertEquals(1, classC.getTypeConstructor().getSupertypes().size()); // assertNotNull(classC);
assertEquals(classA.getTypeConstructor(), classC.getTypeConstructor().getSupertypes().iterator().next().getConstructor()); // assertEquals(1, classC.getTypeConstructor().getSupertypes().size());
// assertEquals(classA.getTypeConstructor(), classC.getTypeConstructor().getSupertypes().iterator().next().getConstructor());
JetScope cScope = classC.getMemberScope(Collections.<TypeProjection>emptyList()); //
ClassDescriptor classC_B = cScope.getClass("B"); // JetScope cScope = classC.getMemberScope(Collections.<TypeProjection>emptyList());
assertNotNull(classC_B); // ClassDescriptor classC_B = cScope.getClass("B");
assertNotSame(classC_B, classB); // assertNotNull(classC_B);
assertEquals(classC.getTypeConstructor(), classC_B.getTypeConstructor().getSupertypes().iterator().next().getConstructor()); // assertNotSame(classC_B, classB);
// assertEquals(classC.getTypeConstructor(), classC_B.getTypeConstructor().getSupertypes().iterator().next().getConstructor());
} }
private void assertReturnType(JetScope membersOfA, String foo, Type returnType) { private void assertReturnType(JetScope membersOfA, String foo, Type returnType) {
@@ -33,7 +33,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
public void setUp() throws Exception { public void setUp() throws Exception {
super.setUp(); super.setUp();
library = new JetStandardLibrary(getProject()); library = new JetStandardLibrary(getProject());
semanticServices = JetSemanticServices.createSemanticServices(library, ErrorHandler.THROW_EXCEPTION); semanticServices = JetSemanticServices.createSemanticServices(library, ErrorHandler.DO_NOTHING);
classDefinitions = new ClassDefinitions(); classDefinitions = new ClassDefinitions();
classDescriptorResolver = semanticServices.getClassDescriptorResolver(BindingTrace.DUMMY); classDescriptorResolver = semanticServices.getClassDescriptorResolver(BindingTrace.DUMMY);
} }
@@ -489,7 +489,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
} }
private static Type makeType(JetScope scope, String typeStr) { private static Type makeType(JetScope scope, String typeStr) {
return new TypeResolver(BindingTrace.DUMMY).resolveType(scope, JetChangeUtil.createType(getProject(), typeStr)); return new TypeResolver(BindingTrace.DUMMY, ErrorHandler.THROW_EXCEPTION).resolveType(scope, JetChangeUtil.createType(getProject(), typeStr));
} }
private class ClassDefinitions { private class ClassDefinitions {
@@ -522,7 +522,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
public JetScope BASIC_SCOPE = new JetScopeAdapter(library.getLibraryScope()) { public JetScope BASIC_SCOPE = new JetScopeAdapter(library.getLibraryScope()) {
@Override @Override
public ClassDescriptor getClass(String name) { public ClassDescriptor getClass(@NotNull String name) {
if (CLASSES.isEmpty()) { if (CLASSES.isEmpty()) {
for (String classDeclaration : CLASS_DECLARATIONS) { for (String classDeclaration : CLASS_DECLARATIONS) {
JetClass classElement = JetChangeUtil.createClass(getProject(), classDeclaration); JetClass classElement = JetChangeUtil.createClass(getProject(), classDeclaration);