Extracted VariablesHighlightingVisitor from JetPsiChecker.

This commit is contained in:
Evgeny Gerashchenko
2012-03-29 14:30:33 +04:00
parent 3328dda81a
commit e92d8fcda7
2 changed files with 103 additions and 79 deletions
@@ -19,7 +19,6 @@ package org.jetbrains.jet.plugin.highlighter;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.lang.ASTNode;
import com.intellij.lang.annotation.Annotation; import com.intellij.lang.annotation.Annotation;
import com.intellij.lang.annotation.AnnotationHolder; import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.Annotator; import com.intellij.lang.annotation.Annotator;
@@ -31,13 +30,9 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference; import com.intellij.psi.PsiReference;
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.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.diagnostics.*; import org.jetbrains.jet.lang.diagnostics.*;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade; import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
import org.jetbrains.jet.plugin.quickfix.JetIntentionActionFactory; import org.jetbrains.jet.plugin.quickfix.JetIntentionActionFactory;
import org.jetbrains.jet.plugin.quickfix.QuickFixes; import org.jetbrains.jet.plugin.quickfix.QuickFixes;
@@ -46,13 +41,10 @@ import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
/** /**
* @author abreslav * @author abreslav
*/ */
public class JetPsiChecker implements Annotator { public class JetPsiChecker implements Annotator {
private static volatile boolean errorReportingEnabled = true; private static volatile boolean errorReportingEnabled = true;
public static void setErrorReportingEnabled(boolean value) { public static void setErrorReportingEnabled(boolean value) {
@@ -66,16 +58,15 @@ public class JetPsiChecker implements Annotator {
@Override @Override
public void annotate(@NotNull PsiElement element, @NotNull final AnnotationHolder holder) { public void annotate(@NotNull PsiElement element, @NotNull final AnnotationHolder holder) {
if (element instanceof JetFile) { if (element instanceof JetFile) {
JetFile file = (JetFile) element; JetFile file = (JetFile)element;
try { try {
final BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file); BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file);
if (errorReportingEnabled) { if (errorReportingEnabled) {
Collection<Diagnostic> diagnostics = Sets.newLinkedHashSet(bindingContext.getDiagnostics()); Collection<Diagnostic> diagnostics = Sets.newLinkedHashSet(bindingContext.getDiagnostics());
Set<PsiElement> redeclarations = Sets.newHashSet(); Set<PsiElement> redeclarations = Sets.newHashSet();
for (Diagnostic diagnostic : diagnostics) { for (Diagnostic diagnostic : diagnostics) {
// This is needed because we have the same context for all files // This is needed because we have the same context for all files
if (diagnostic.getPsiFile() != file) continue; if (diagnostic.getPsiFile() != file) continue;
@@ -84,58 +75,7 @@ public class JetPsiChecker implements Annotator {
} }
file.acceptChildren(new BackingFieldHighlightingVisitor(holder, bindingContext)); file.acceptChildren(new BackingFieldHighlightingVisitor(holder, bindingContext));
file.acceptChildren(new VariablesHighlightingVisitor(holder, bindingContext));
file.acceptChildren(new JetVisitorVoid() {
@Override
public void visitSimpleNameExpression(@NotNull JetSimpleNameExpression expression) {
DeclarationDescriptor target = bindingContext.get(REFERENCE_TARGET, expression);
if (target instanceof ValueParameterDescriptor) {
ValueParameterDescriptor parameterDescriptor = (ValueParameterDescriptor) target;
if (bindingContext.get(AUTO_CREATED_IT, parameterDescriptor)) {
holder.createInfoAnnotation(expression, "Automatically declared based on the expected type").setTextAttributes(JetHighlightingColors.FUNCTION_LITERAL_DEFAULT_PARAMETER);
}
}
markVariableAsWrappedIfNeeded(expression.getNode(), target);
super.visitSimpleNameExpression(expression);
}
private void markVariableAsWrappedIfNeeded(@NotNull ASTNode node, DeclarationDescriptor target) {
if (target instanceof VariableDescriptor) {
VariableDescriptor variableDescriptor = (VariableDescriptor) target;
if (bindingContext.get(MUST_BE_WRAPPED_IN_A_REF, variableDescriptor)) {
holder.createInfoAnnotation(node, "Wrapped into a ref-object to be modifier when captured in a closure").setTextAttributes(
JetHighlightingColors.WRAPPED_INTO_REF);
}
}
}
@Override
public void visitProperty(@NotNull JetProperty property) {
DeclarationDescriptor declarationDescriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, property);
PsiElement nameIdentifier = property.getNameIdentifier();
if (nameIdentifier != null) {
markVariableAsWrappedIfNeeded(nameIdentifier.getNode(), declarationDescriptor);
}
super.visitProperty(property);
}
@Override
public void visitExpression(@NotNull JetExpression expression) {
JetType autoCast = bindingContext.get(AUTOCAST, expression);
if (autoCast != null) {
holder.createInfoAnnotation(expression, "Automatically cast to " + autoCast).setTextAttributes(
JetHighlightingColors.AUTO_CASTED_VALUE);
}
expression.acceptChildren(this);
}
@Override
public void visitJetElement(@NotNull JetElement element) {
element.acceptChildren(this);
}
});
} }
catch (ProcessCanceledException e) { catch (ProcessCanceledException e) {
throw e; throw e;
@@ -153,26 +93,24 @@ public class JetPsiChecker implements Annotator {
} }
} }
private void registerDiagnosticAnnotations( private static void registerDiagnosticAnnotations(@NotNull Diagnostic diagnostic,
@NotNull Diagnostic diagnostic, @NotNull Set<PsiElement> redeclarations,
@NotNull Set<PsiElement> redeclarations, @NotNull final AnnotationHolder holder) {
@NotNull final AnnotationHolder holder
) {
List<TextRange> textRanges = diagnostic.getTextRanges(); List<TextRange> textRanges = diagnostic.getTextRanges();
if (diagnostic.getSeverity() == Severity.ERROR) { if (diagnostic.getSeverity() == Severity.ERROR) {
if (diagnostic.getFactory() == Errors.UNRESOLVED_IDE_TEMPLATE) { if (diagnostic.getFactory() == Errors.UNRESOLVED_IDE_TEMPLATE) {
return; return;
} }
if (diagnostic instanceof UnresolvedReferenceDiagnostic) { if (diagnostic instanceof UnresolvedReferenceDiagnostic) {
UnresolvedReferenceDiagnostic unresolvedReferenceDiagnostic = (UnresolvedReferenceDiagnostic) diagnostic; UnresolvedReferenceDiagnostic unresolvedReferenceDiagnostic = (UnresolvedReferenceDiagnostic)diagnostic;
JetReferenceExpression referenceExpression = unresolvedReferenceDiagnostic.getPsiElement(); JetReferenceExpression referenceExpression = unresolvedReferenceDiagnostic.getPsiElement();
PsiReference reference = referenceExpression.getReference(); PsiReference reference = referenceExpression.getReference();
if (reference instanceof MultiRangeReference) { if (reference instanceof MultiRangeReference) {
MultiRangeReference mrr = (MultiRangeReference) reference; MultiRangeReference mrr = (MultiRangeReference)reference;
for (TextRange range : mrr.getRanges()) { for (TextRange range : mrr.getRanges()) {
Annotation annotation = holder.createErrorAnnotation( Annotation annotation = holder.createErrorAnnotation(
range.shiftRight(referenceExpression.getTextOffset()), range.shiftRight(referenceExpression.getTextOffset()),
diagnostic.getMessage()); diagnostic.getMessage());
registerQuickFix(annotation, diagnostic); registerQuickFix(annotation, diagnostic);
@@ -191,7 +129,7 @@ public class JetPsiChecker implements Annotator {
} }
if (diagnostic instanceof RedeclarationDiagnostic) { if (diagnostic instanceof RedeclarationDiagnostic) {
RedeclarationDiagnostic redeclarationDiagnostic = (RedeclarationDiagnostic) diagnostic; RedeclarationDiagnostic redeclarationDiagnostic = (RedeclarationDiagnostic)diagnostic;
registerQuickFix(markRedeclaration(redeclarations, redeclarationDiagnostic, holder), diagnostic); registerQuickFix(markRedeclaration(redeclarations, redeclarationDiagnostic, holder), diagnostic);
return; return;
} }
@@ -218,10 +156,7 @@ public class JetPsiChecker implements Annotator {
* Add a quick fix if and return modified annotation. * Add a quick fix if and return modified annotation.
*/ */
@Nullable @Nullable
private Annotation registerQuickFix( private static Annotation registerQuickFix(@Nullable Annotation annotation, @NotNull Diagnostic diagnostic) {
@Nullable Annotation annotation,
@NotNull Diagnostic diagnostic) {
if (annotation == null) { if (annotation == null) {
return null; return null;
} }
@@ -246,7 +181,7 @@ public class JetPsiChecker implements Annotator {
} }
@NotNull @NotNull
private String getMessage(@NotNull Diagnostic diagnostic) { private static String getMessage(@NotNull Diagnostic diagnostic) {
if (ApplicationManager.getApplication().isInternal() || ApplicationManager.getApplication().isUnitTestMode()) { if (ApplicationManager.getApplication().isInternal() || ApplicationManager.getApplication().isUnitTestMode()) {
return "[" + diagnostic.getFactory().getName() + "] " + diagnostic.getMessage(); return "[" + diagnostic.getFactory().getName() + "] " + diagnostic.getMessage();
} }
@@ -254,7 +189,9 @@ public class JetPsiChecker implements Annotator {
} }
@Nullable @Nullable
private Annotation markRedeclaration(@NotNull Set<PsiElement> redeclarations, @NotNull RedeclarationDiagnostic diagnostic, @NotNull AnnotationHolder holder) { private static Annotation markRedeclaration(@NotNull Set<PsiElement> redeclarations,
@NotNull RedeclarationDiagnostic diagnostic,
@NotNull AnnotationHolder holder) {
if (!redeclarations.add(diagnostic.getPsiElement())) return null; if (!redeclarations.add(diagnostic.getPsiElement())) return null;
List<TextRange> textRanges = diagnostic.getTextRanges(); List<TextRange> textRanges = diagnostic.getTextRanges();
if (textRanges.isEmpty()) return null; if (textRanges.isEmpty()) return null;
@@ -0,0 +1,87 @@
/*
* Copyright 2010-2012 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 org.jetbrains.jet.plugin.highlighter;
import com.intellij.lang.ASTNode;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.JetType;
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
class VariablesHighlightingVisitor extends AfterAnalysisHighlightingVisitor {
VariablesHighlightingVisitor(AnnotationHolder holder, BindingContext bindingContext) {
super(holder, bindingContext);
}
@Override
public void visitSimpleNameExpression(@NotNull JetSimpleNameExpression expression) {
DeclarationDescriptor target = bindingContext.get(REFERENCE_TARGET, expression);
if (target instanceof ValueParameterDescriptor) {
ValueParameterDescriptor parameterDescriptor = (ValueParameterDescriptor) target;
if (Boolean.TRUE.equals(bindingContext.get(AUTO_CREATED_IT, parameterDescriptor))) {
holder.createInfoAnnotation(expression, "Automatically declared based on the expected type").setTextAttributes(
JetHighlightingColors.FUNCTION_LITERAL_DEFAULT_PARAMETER);
}
}
markVariableAsWrappedIfNeeded(expression.getNode(), target);
super.visitSimpleNameExpression(expression);
}
private void markVariableAsWrappedIfNeeded(@NotNull ASTNode node, DeclarationDescriptor target) {
if (target instanceof VariableDescriptor) {
VariableDescriptor variableDescriptor = (VariableDescriptor) target;
if (Boolean.TRUE.equals(bindingContext.get(MUST_BE_WRAPPED_IN_A_REF, variableDescriptor))) {
holder.createInfoAnnotation(node, "Wrapped into a ref-object to be modifier when captured in a closure").setTextAttributes(
JetHighlightingColors.WRAPPED_INTO_REF);
}
}
}
@Override
public void visitProperty(@NotNull JetProperty property) {
DeclarationDescriptor declarationDescriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, property);
PsiElement nameIdentifier = property.getNameIdentifier();
if (nameIdentifier != null) {
markVariableAsWrappedIfNeeded(nameIdentifier.getNode(), declarationDescriptor);
}
super.visitProperty(property);
}
@Override
public void visitExpression(@NotNull JetExpression expression) {
JetType autoCast = bindingContext.get(AUTOCAST, expression);
if (autoCast != null) {
holder.createInfoAnnotation(expression, "Automatically cast to " + autoCast).setTextAttributes(
JetHighlightingColors.AUTO_CASTED_VALUE);
}
expression.acceptChildren(this);
}
@Override
public void visitJetElement(@NotNull JetElement element) {
element.acceptChildren(this);
}
}