mark syntax errors in QuickJetPsiCheckerTest

This commit is contained in:
Stepan Koltsov
2011-11-29 01:55:39 +04:00
parent 8498280b0e
commit 4fc41f4ad9
12 changed files with 128 additions and 19 deletions
@@ -2,8 +2,13 @@ package org.jetbrains.jet.checkers;
import com.google.common.collect.*; import com.google.common.collect.*;
import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.diagnostics.Diagnostic; import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.diagnostics.DiagnosticFactory;
import org.jetbrains.jet.lang.diagnostics.Severity;
import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import java.util.*; import java.util.*;
@@ -32,6 +37,15 @@ public class CheckerTestUtil {
private static final Pattern RANGE_START_OR_END_PATTERN = Pattern.compile("(<!\\w+(,\\s*\\w+)*!>)|(<!>)"); private static final Pattern RANGE_START_OR_END_PATTERN = Pattern.compile("(<!\\w+(,\\s*\\w+)*!>)|(<!>)");
private static final Pattern INDIVIDUAL_DIAGNOSTIC_PATTERN = Pattern.compile("\\w+"); private static final Pattern INDIVIDUAL_DIAGNOSTIC_PATTERN = Pattern.compile("\\w+");
public static List<Diagnostic> getDiagnosticsIncludingSyntaxErrors(BindingContext bindingContext, PsiElement root) {
ArrayList<Diagnostic> diagnostics = new ArrayList<Diagnostic>();
diagnostics.addAll(bindingContext.getDiagnostics());
for (TextRange textRange : AnalyzingUtils.getSyntaxErrorRanges(root)) {
diagnostics.add(new SyntaxErrorDiagnostic(textRange));
}
return diagnostics;
}
public interface DiagnosticDiffCallbacks { public interface DiagnosticDiffCallbacks {
void missingDiagnostic(String type, int expectedStart, int expectedEnd); void missingDiagnostic(String type, int expectedStart, int expectedEnd);
void unexpectedDiagnostic(String type, int actualStart, int actualEnd); void unexpectedDiagnostic(String type, int actualStart, int actualEnd);
@@ -144,7 +158,7 @@ public class CheckerTestUtil {
Matcher diagnosticTypeMatcher = INDIVIDUAL_DIAGNOSTIC_PATTERN.matcher(matchedText); Matcher diagnosticTypeMatcher = INDIVIDUAL_DIAGNOSTIC_PATTERN.matcher(matchedText);
DiagnosedRange range = new DiagnosedRange(effectiveOffset); DiagnosedRange range = new DiagnosedRange(effectiveOffset);
while (diagnosticTypeMatcher.find()) { while (diagnosticTypeMatcher.find()) {
range.addDiagnostic(diagnosticTypeMatcher.group()); range.addDiagnostic(diagnosticTypeMatcher.group());
} }
opened.push(range); opened.push(range);
result.add(range); result.add(range);
@@ -158,9 +172,17 @@ public class CheckerTestUtil {
return matcher.replaceAll(""); return matcher.replaceAll("");
} }
public static StringBuffer addDiagnosticMarkersToText(PsiFile psiFile, BindingContext bindingContext) { public static StringBuffer addDiagnosticMarkersToText(PsiFile psiFile, BindingContext bindingContext, List<TextRange> syntaxErrors) {
Collection<Diagnostic> diagnostics = bindingContext.getDiagnostics(); Collection<Diagnostic> diagnostics = new ArrayList<Diagnostic>();
diagnostics.addAll(bindingContext.getDiagnostics());
for (TextRange syntaxError : syntaxErrors) {
diagnostics.add(new SyntaxErrorDiagnostic(syntaxError));
}
return addDiagnosticMarkersToText(psiFile, diagnostics);
}
public static StringBuffer addDiagnosticMarkersToText(PsiFile psiFile, Collection<Diagnostic> diagnostics) {
StringBuffer result = new StringBuffer(); StringBuffer result = new StringBuffer();
String text = psiFile.getText(); String text = psiFile.getText();
if (!diagnostics.isEmpty()) { if (!diagnostics.isEmpty()) {
@@ -193,6 +215,14 @@ public class CheckerTestUtil {
} }
result.append(c); result.append(c);
} }
if (currentDescriptor != null) {
assert currentDescriptor.start == text.length();
assert currentDescriptor.end == text.length();
openDiagnosticsString(result, currentDescriptor);
opened.push(currentDescriptor);
}
while (!opened.isEmpty() && text.length() == opened.peek().end) { while (!opened.isEmpty() && text.length() == opened.peek().end) {
closeDiagnosticString(result); closeDiagnosticString(result);
opened.pop(); opened.pop();
@@ -223,6 +253,55 @@ public class CheckerTestUtil {
result.append("<!>"); result.append("<!>");
} }
private static class SyntaxErrorDiagnosticFactory implements DiagnosticFactory {
private static final SyntaxErrorDiagnosticFactory instance = new SyntaxErrorDiagnosticFactory();
@NotNull
@Override
public TextRange getTextRange(@NotNull Diagnostic diagnostic) {
return ((SyntaxErrorDiagnostic) diagnostic).textRange;
}
@NotNull
@Override
public PsiFile getPsiFile(@NotNull Diagnostic diagnostic) {
throw new IllegalStateException();
}
@NotNull
@Override
public String getName() {
return "SYNTAX";
}
}
public static class SyntaxErrorDiagnostic implements Diagnostic {
private final TextRange textRange;
public SyntaxErrorDiagnostic(TextRange textRange) {
this.textRange = textRange;
}
@NotNull
@Override
public DiagnosticFactory getFactory() {
return SyntaxErrorDiagnosticFactory.instance;
}
@NotNull
@Override
public String getMessage() {
throw new IllegalStateException();
}
@NotNull
@Override
public Severity getSeverity() {
throw new IllegalStateException();
}
}
private static List<DiagnosticDescriptor> getSortedDiagnosticDescriptors(Collection<Diagnostic> diagnostics) { private static List<DiagnosticDescriptor> getSortedDiagnosticDescriptors(Collection<Diagnostic> diagnostics) {
List<Diagnostic> list = Lists.newArrayList(diagnostics); List<Diagnostic> list = Lists.newArrayList(diagnostics);
Collections.sort(list, DIAGNOSTIC_COMPARATOR); Collections.sort(list, DIAGNOSTIC_COMPARATOR);
@@ -282,6 +361,10 @@ public class CheckerTestUtil {
public List<Diagnostic> getDiagnostics() { public List<Diagnostic> getDiagnostics() {
return diagnostics; return diagnostics;
} }
public TextRange getTextRange() {
return new TextRange(start, end);
}
} }
public static class DiagnosedRange { public static class DiagnosedRange {
@@ -4,6 +4,7 @@ import com.google.common.base.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiErrorElement; import com.intellij.psi.PsiErrorElement;
@@ -45,6 +46,22 @@ public class AnalyzingUtils {
} }
}); });
} }
public static List<TextRange> getSyntaxErrorRanges(@NotNull PsiElement root) {
final ArrayList<TextRange> r = new ArrayList<TextRange>();
root.acceptChildren(new PsiElementVisitor() {
@Override
public void visitElement(PsiElement element) {
element.acceptChildren(this);
}
@Override
public void visitErrorElement(PsiErrorElement element) {
r.add(element.getTextRange());
}
});
return r;
}
public static void throwExceptionOnErrors(BindingContext bindingContext) { public static void throwExceptionOnErrors(BindingContext bindingContext) {
for (Diagnostic diagnostic : bindingContext.getDiagnostics()) { for (Diagnostic diagnostic : bindingContext.getDiagnostics()) {
@@ -28,7 +28,7 @@ class WithPC1(a : Int) {
} }
class Foo() : <!SUPERTYPE_NOT_INITIALIZED, FINAL_SUPERTYPE!>WithPC0<!>, <!MANY_CLASSES_IN_SUPERTYPE_LIST!>this<!>() { class Foo() : <!SUPERTYPE_NOT_INITIALIZED, FINAL_SUPERTYPE!>WithPC0<!>, <!MANY_CLASSES_IN_SUPERTYPE_LIST, SYNTAX!>this<!>() {
} }
@@ -47,4 +47,4 @@ class <!PRIMARY_CONSTRUCTOR_MISSING_STATEFUL_PROPERTY!>NoCPI<!> {
var ab = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>1<!> var ab = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>1<!>
get() = 1 get() = 1
set(v) {} set(v) {}
} }
@@ -1,4 +1,4 @@
namespace return namespace <!SYNTAX!>return<!>
class A { class A {
fun outer() { fun outer() {
@@ -14,4 +14,4 @@ class A {
<!RETURN_NOT_ALLOWED!>return<!UNRESOLVED_REFERENCE!>@inner<!><!> <!RETURN_NOT_ALLOWED!>return<!UNRESOLVED_REFERENCE!>@inner<!><!>
return@outer return@outer
} }
} }
@@ -32,7 +32,7 @@ class A<E>() : C(), T {
super<<!NOT_A_SUPERTYPE!>E<!>>.bar() super<<!NOT_A_SUPERTYPE!>E<!>>.bar()
super<<!NOT_A_SUPERTYPE!>E<!>>@A.bar() super<<!NOT_A_SUPERTYPE!>E<!>>@A.bar()
super<<!NOT_A_SUPERTYPE!>Int<!>>.foo() super<<!NOT_A_SUPERTYPE!>Int<!>>.foo()
super<>.foo() super<<!SYNTAX!><!>>.foo()
super<<!NOT_A_SUPERTYPE!>fun() : Unit<!>>.foo() super<<!NOT_A_SUPERTYPE!>fun() : Unit<!>>.foo()
super<<!NOT_A_SUPERTYPE!>()<!>>.foo() super<<!NOT_A_SUPERTYPE!>()<!>>.foo()
super<T><!UNRESOLVED_REFERENCE!>@B<!>.foo() super<T><!UNRESOLVED_REFERENCE!>@B<!>.foo()
@@ -86,4 +86,4 @@ class A1 {
fun test() { fun test() {
<!SUPER_IS_NOT_AN_EXPRESSION!>super<!>.equals(null) <!SUPER_IS_NOT_AN_EXPRESSION!>super<!>.equals(null)
} }
} }
@@ -0,0 +1,5 @@
// dummy test of syntax error highlighing in tests
fun get() {
1 + 2 <!SYNTAX!>2 3 4<!>
}
@@ -0,0 +1 @@
fun f() {<!SYNTAX!><!>
@@ -4,5 +4,5 @@ import java.util.List;
fun ff(l: Any) = when(l) { fun ff(l: Any) = when(l) {
is <!CANNOT_CHECK_FOR_ERASED!>List<String><!> => 1 is <!CANNOT_CHECK_FOR_ERASED!>List<String><!> => 1
else 2 else <!SYNTAX!>2<!>
} }
@@ -3,5 +3,4 @@
fun block(f : fun() : Unit) = f() fun block(f : fun() : Unit) = f()
fun bar() = block{ <!UNRESOLVED_REFERENCE!>foo<!>() // <-- missing closing curly bracket fun bar() = block{ <!UNRESOLVED_REFERENCE!>foo<!>() // <-- missing closing curly bracket
fun foo() = block{ <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>bar()<!> } fun foo() = block{ <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>bar()<!> }<!SYNTAX!><!>
@@ -1,6 +1,7 @@
package org.jetbrains.jet.checkers; package org.jetbrains.jet.checkers;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFile;
import org.jetbrains.jet.JetLiteFixture; import org.jetbrains.jet.JetLiteFixture;
import org.jetbrains.jet.lang.diagnostics.Diagnostic; import org.jetbrains.jet.lang.diagnostics.Diagnostic;
@@ -82,12 +83,12 @@ public class CheckerTestUtilTest extends JetLiteFixture {
public void test(PsiFile psiFile) { public void test(PsiFile psiFile) {
BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(AnalyzingUtils.getInstance(ImportingStrategy.NONE), (JetFile) psiFile, AnalyzerFacade.SINGLE_DECLARATION_PROVIDER); BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(AnalyzingUtils.getInstance(ImportingStrategy.NONE), (JetFile) psiFile, AnalyzerFacade.SINGLE_DECLARATION_PROVIDER);
String expectedText = CheckerTestUtil.addDiagnosticMarkersToText(psiFile, bindingContext).toString(); String expectedText = CheckerTestUtil.addDiagnosticMarkersToText(psiFile, CheckerTestUtil.getDiagnosticsIncludingSyntaxErrors(bindingContext, psiFile)).toString();
List<CheckerTestUtil.DiagnosedRange> diagnosedRanges = Lists.newArrayList(); List<CheckerTestUtil.DiagnosedRange> diagnosedRanges = Lists.newArrayList();
CheckerTestUtil.parseDiagnosedRanges(expectedText, diagnosedRanges); CheckerTestUtil.parseDiagnosedRanges(expectedText, diagnosedRanges);
List<Diagnostic> diagnostics = Lists.newArrayList(bindingContext.getDiagnostics()); List<Diagnostic> diagnostics = CheckerTestUtil.getDiagnosticsIncludingSyntaxErrors(bindingContext, psiFile);
Collections.sort(diagnostics, CheckerTestUtil.DIAGNOSTIC_COMPARATOR); Collections.sort(diagnostics, CheckerTestUtil.DIAGNOSTIC_COMPARATOR);
makeTestData(diagnostics, diagnosedRanges); makeTestData(diagnostics, diagnosedRanges);
@@ -47,7 +47,7 @@ public class QuickJetPsiCheckerTest extends JetLiteFixture {
BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(AnalyzingUtils.getInstance(importingStrategy), jetFile, AnalyzerFacade.SINGLE_DECLARATION_PROVIDER); BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(AnalyzingUtils.getInstance(importingStrategy), jetFile, AnalyzerFacade.SINGLE_DECLARATION_PROVIDER);
CheckerTestUtil.diagnosticsDiff(diagnosedRanges, bindingContext.getDiagnostics(), new CheckerTestUtil.DiagnosticDiffCallbacks() { CheckerTestUtil.diagnosticsDiff(diagnosedRanges, CheckerTestUtil.getDiagnosticsIncludingSyntaxErrors(bindingContext, jetFile), new CheckerTestUtil.DiagnosticDiffCallbacks() {
@Override @Override
public void missingDiagnostic(String type, int expectedStart, int expectedEnd) { public void missingDiagnostic(String type, int expectedStart, int expectedEnd) {
String message = "Missing " + type + DiagnosticUtils.atLocation(myFile, new TextRange(expectedStart, expectedEnd)); String message = "Missing " + type + DiagnosticUtils.atLocation(myFile, new TextRange(expectedStart, expectedEnd));
@@ -61,14 +61,14 @@ public class QuickJetPsiCheckerTest extends JetLiteFixture {
} }
}); });
String actualText = CheckerTestUtil.addDiagnosticMarkersToText(jetFile, bindingContext).toString(); String actualText = CheckerTestUtil.addDiagnosticMarkersToText(jetFile, bindingContext, AnalyzingUtils.getSyntaxErrorRanges(jetFile)).toString();
assertEquals(expectedText, actualText); assertEquals(expectedText, actualText);
// convert(new File(myFullDataPath + "/../../checker/"), new File(myFullDataPath)); // convert(new File(myFullDataPath + "/../../checker/"), new File(myFullDataPath));
} }
// private void convert(File src, File dest) throws IOException { // private void convert(File src, File dest) throws IOException {
// File[] files = src.listFiles(); // File[] files = src.listFiles();
// for (File file : files) { // for (File file : files) {
// try { // try {
@@ -6,11 +6,12 @@ import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFile;
import org.jetbrains.jet.checkers.CheckerTestUtil; import org.jetbrains.jet.checkers.CheckerTestUtil;
import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade;
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade; import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
import java.awt.*; import java.awt.*;
@@ -18,6 +19,7 @@ import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.ClipboardOwner; import java.awt.datatransfer.ClipboardOwner;
import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable; import java.awt.datatransfer.Transferable;
import java.util.List;
/** /**
* @author abreslav * @author abreslav
@@ -30,8 +32,9 @@ public class CopyAsDiagnosticTestAction extends AnAction {
assert editor != null && psiFile != null; assert editor != null && psiFile != null;
BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile) psiFile); BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile) psiFile);
List<TextRange> syntaxError = AnalyzingUtils.getSyntaxErrorRanges(psiFile);
String result = CheckerTestUtil.addDiagnosticMarkersToText(psiFile, bindingContext).toString(); String result = CheckerTestUtil.addDiagnosticMarkersToText(psiFile, bindingContext, syntaxError).toString();
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents(new StringSelection(result), new ClipboardOwner() { clipboard.setContents(new StringSelection(result), new ClipboardOwner() {