From 8c77e38c671bf5f6e1e85cb5eb6a5478f34e9d58 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Tue, 1 Mar 2011 14:27:58 +0300 Subject: [PATCH] Navigation improved a little --- .../jet/lang/annotations/JetPsiChecker.java | 38 +++--- .../jet/lang/psi/JetReferenceExpression.java | 12 +- .../lang/resolve/ClassDescriptorResolver.java | 5 +- .../jet/lang/resolve/TopDownAnalyzer.java | 16 +-- .../jet/lang/resolve/TypeResolver.java | 2 +- .../jet/lang/types/BindingTrace.java | 9 +- .../ExtensibleHighlightingTestCase.java | 109 ++++++++++++++++++ 7 files changed, 156 insertions(+), 35 deletions(-) create mode 100644 idea/tests/org/jetbrains/jet/checkers/ExtensibleHighlightingTestCase.java diff --git a/idea/src/org/jetbrains/jet/lang/annotations/JetPsiChecker.java b/idea/src/org/jetbrains/jet/lang/annotations/JetPsiChecker.java index d4c0b2cfad0..558cf64bf0a 100644 --- a/idea/src/org/jetbrains/jet/lang/annotations/JetPsiChecker.java +++ b/idea/src/org/jetbrains/jet/lang/annotations/JetPsiChecker.java @@ -2,6 +2,7 @@ package org.jetbrains.jet.lang.annotations; import com.intellij.lang.annotation.AnnotationHolder; import com.intellij.lang.annotation.Annotator; +import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.JetSemanticServices; @@ -20,24 +21,31 @@ public class JetPsiChecker implements Annotator { if (element instanceof JetFile) { JetFile file = (JetFile) element; JetSemanticServices semanticServices = new JetSemanticServices(element.getProject()); - final BindingContext bindingContext = new TopDownAnalyzer(semanticServices).process(semanticServices.getStandardLibrary().getLibraryScope(), file.getRootNamespace().getDeclarations()); - file.getRootNamespace().accept(new JetVisitor() { - @Override - public void visitClass(JetClass klass) { - for (JetDelegationSpecifier specifier : klass.getDelegationSpecifiers()) { - JetTypeReference typeReference = specifier.getTypeReference(); - Type type = bindingContext.resolveTypeReference(typeReference); - holder.createWeakWarningAnnotation(typeReference, type.toString()); + try { + final BindingContext bindingContext = new TopDownAnalyzer(semanticServices).process(semanticServices.getStandardLibrary().getLibraryScope(), file.getRootNamespace().getDeclarations()); + file.getRootNamespace().accept(new JetVisitor() { + @Override + public void visitClass(JetClass klass) { + for (JetDelegationSpecifier specifier : klass.getDelegationSpecifiers()) { + JetTypeReference typeReference = specifier.getTypeReference(); + Type type = bindingContext.resolveTypeReference(typeReference); + holder.createWeakWarningAnnotation(typeReference, type.toString()); + } } - } - @Override - public void visitNamespace(JetNamespace namespace) { - for (JetDeclaration declaration : namespace.getDeclarations()) { - declaration.accept(this); + @Override + public void visitNamespace(JetNamespace namespace) { + for (JetDeclaration declaration : namespace.getDeclarations()) { + declaration.accept(this); + } } - } - }); + }); + } + catch (Throwable e) { + // TODO + holder.createErrorAnnotation(new TextRange(0, 1), e.getClass().getCanonicalName() + ": " + e.getMessage()); + e.printStackTrace(); + } } } } diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetReferenceExpression.java b/idea/src/org/jetbrains/jet/lang/psi/JetReferenceExpression.java index c6ecda33ca0..4bbbc557137 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetReferenceExpression.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetReferenceExpression.java @@ -74,33 +74,33 @@ public class JetReferenceExpression extends JetExpression { @NotNull @Override public String getCanonicalText() { - throw new UnsupportedOperationException(); // TODO + return getReferencedName(); } @Override public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException { - throw new UnsupportedOperationException(); // TODO + throw new IncorrectOperationException(); } @Override public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException { - throw new UnsupportedOperationException(); // TODO + throw new IncorrectOperationException(); } @Override public boolean isReferenceTo(PsiElement element) { - throw new UnsupportedOperationException(); // TODO + return false; } @NotNull @Override public Object[] getVariants() { - throw new UnsupportedOperationException(); // TODO + return EMPTY_ARRAY; } @Override public boolean isSoft() { - throw new UnsupportedOperationException(); // TODO + return false; } }; } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java index 9fecc3d429d..b7850af8d59 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java @@ -139,7 +139,7 @@ public class ClassDescriptorResolver { returnType = semanticServices.getTypeInferrer().getType(parameterScope, bodyExpression, function.hasBlockBody()); } - return new FunctionDescriptorImpl( + FunctionDescriptorImpl functionDescriptor = new FunctionDescriptorImpl( function, null, AttributeResolver.INSTANCE.resolveAttributes(function.getModifierList()), @@ -148,6 +148,9 @@ public class ClassDescriptorResolver { valueParameterDescriptors, returnType ); + + trace.recordDeclarationResolution(function, functionDescriptor); + return functionDescriptor; } private List resolveValueParameters(WritableScope parameterScope, List valueParameters) { diff --git a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index 487be2e77c3..af45e4e534c 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -30,22 +30,22 @@ public class TopDownAnalyzer { this.semanticServices = semanticServices; this.classDescriptorResolver = new ClassDescriptorResolver(semanticServices, new BindingTrace() { @Override - public void recordExpressionType(JetExpression expression, Type type) { + public void recordExpressionType(@NotNull JetExpression expression, @NotNull Type type) { expressionTypes.put(expression, type); } @Override - public void recordReferenceResolution(JetReferenceExpression expression, DeclarationDescriptor descriptor) { + public void recordReferenceResolution(@NotNull JetReferenceExpression expression, @NotNull DeclarationDescriptor descriptor) { resolutionResults.put(expression, descriptor); } @Override - public void recordTypeResolution(JetTypeReference typeReference, Type type) { + public void recordTypeResolution(@NotNull JetTypeReference typeReference, @NotNull Type type) { types.put(typeReference, type); } @Override - public void recordDeclarationResolution(JetDeclaration declaration, DeclarationDescriptor descriptor) { + public void recordDeclarationResolution(@NotNull JetDeclaration declaration, @NotNull DeclarationDescriptor descriptor) { descriptorToDeclarations.put(descriptor, declaration); } }); @@ -245,22 +245,22 @@ public class TopDownAnalyzer { private void resolveExpression(@NotNull JetScope scope, JetExpression expression, boolean preferBlock) { semanticServices.getTypeInferrer(new BindingTrace() { @Override - public void recordExpressionType(JetExpression expression, Type type) { + public void recordExpressionType(@NotNull JetExpression expression, @NotNull Type type) { expressionTypes.put(expression, type); } @Override - public void recordReferenceResolution(JetReferenceExpression expression, DeclarationDescriptor descriptor) { + public void recordReferenceResolution(@NotNull JetReferenceExpression expression, @NotNull DeclarationDescriptor descriptor) { resolutionResults.put(expression, descriptor); } @Override - public void recordTypeResolution(JetTypeReference typeReference, Type type) { + public void recordTypeResolution(@NotNull JetTypeReference typeReference, @NotNull Type type) { types.put(typeReference, type); } @Override - public void recordDeclarationResolution(JetDeclaration declaration, DeclarationDescriptor descriptor) { + public void recordDeclarationResolution(@NotNull JetDeclaration declaration, @NotNull DeclarationDescriptor descriptor) { throw new IllegalStateException(); } }).getType(scope, expression, preferBlock); diff --git a/idea/src/org/jetbrains/jet/lang/resolve/TypeResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/TypeResolver.java index 5313ddbc896..d20c05abecc 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/TypeResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/TypeResolver.java @@ -37,8 +37,8 @@ public class TypeResolver { @Override public void visitUserType(JetUserType type) { ClassDescriptor classDescriptor = resolveClass(scope, type); - trace.recordReferenceResolution(type.getReferenceExpression(), classDescriptor); if (classDescriptor != null) { + trace.recordReferenceResolution(type.getReferenceExpression(), classDescriptor); TypeConstructor typeConstructor = classDescriptor.getTypeConstructor(); List arguments = resolveTypeProjections(scope, typeConstructor, type.getTypeArguments()); result[0] = new TypeImpl( diff --git a/idea/src/org/jetbrains/jet/lang/types/BindingTrace.java b/idea/src/org/jetbrains/jet/lang/types/BindingTrace.java index 306ff9bc1cb..d1284a3cfc1 100644 --- a/idea/src/org/jetbrains/jet/lang/types/BindingTrace.java +++ b/idea/src/org/jetbrains/jet/lang/types/BindingTrace.java @@ -1,5 +1,6 @@ package org.jetbrains.jet.lang.types; +import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.psi.JetDeclaration; import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetReferenceExpression; @@ -11,18 +12,18 @@ import org.jetbrains.jet.lang.psi.JetTypeReference; public class BindingTrace { public static final BindingTrace DUMMY = new BindingTrace(); - public void recordExpressionType(JetExpression expression, Type type) { + public void recordExpressionType(@NotNull JetExpression expression, @NotNull Type type) { } - public void recordReferenceResolution(JetReferenceExpression expression, DeclarationDescriptor descriptor) { + public void recordReferenceResolution(@NotNull JetReferenceExpression expression, @NotNull DeclarationDescriptor descriptor) { } - public void recordDeclarationResolution(JetDeclaration declaration, DeclarationDescriptor descriptor) { + public void recordDeclarationResolution(@NotNull JetDeclaration declaration, @NotNull DeclarationDescriptor descriptor) { } - public void recordTypeResolution(JetTypeReference typeReference, Type type) { + public void recordTypeResolution(@NotNull JetTypeReference typeReference, @NotNull Type type) { } } diff --git a/idea/tests/org/jetbrains/jet/checkers/ExtensibleHighlightingTestCase.java b/idea/tests/org/jetbrains/jet/checkers/ExtensibleHighlightingTestCase.java new file mode 100644 index 00000000000..ace0c66c258 --- /dev/null +++ b/idea/tests/org/jetbrains/jet/checkers/ExtensibleHighlightingTestCase.java @@ -0,0 +1,109 @@ +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 infos = doHighlighting(); + + getJavaFacade().setAssertOnFileLoadingFilter(VirtualFileFilter.NONE); + + expectedData.checkResult(infos, getEditor().getDocument().getText()); + } + + @NotNull + protected List 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; + } +}