Copy Current File As Diagnostic Test action added

Testing framework with error type support added
This commit is contained in:
Andrey Breslav
2011-09-15 22:12:13 +04:00
parent 4b720733c0
commit e5304aba66
13 changed files with 1024 additions and 40 deletions
@@ -4,7 +4,6 @@ import com.intellij.lang.ASTNode;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
@@ -42,8 +41,14 @@ public class DiagnosticUtils {
return closestPsiElement.getContainingFile();
}
@NotNull
public static String atLocation(@NotNull PsiFile file, @NotNull TextRange textRange) {
Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file);
Document document = file.getViewProvider().getDocument();//PsiDocumentManager.getInstance(file.getProject()).getDocument(file);
return atLocation(file, textRange, document);
}
@NotNull
public static String atLocation(PsiFile file, TextRange textRange, Document document) {
int offset = textRange.getStartOffset();
VirtualFile virtualFile = file.getVirtualFile();
String pathSuffix = virtualFile == null ? "" : " in " + virtualFile.getPath();
@@ -355,6 +355,7 @@ public class CallResolver {
if (error) {
failedCandidates.add(candidate);
checkTypesWithNoCallee(temporaryTrace, scope, task.getTypeArguments(), task.getValueArguments(), task.getFunctionLiteralArguments());
continue;
}
+5
View File
@@ -19,6 +19,11 @@
<keyboard-shortcut keymap="$default" first-keystroke="control shift Q"/>
<add-to-group group-id="CodeMenu" anchor="last"/>
</action>
<action id="CopyAsDiagnosticTest" class="org.jetbrains.jet.plugin.actions.CopyAsDiagnosticTestAction"
text="Copy Current File As Diagnostic Test">
<keyboard-shortcut keymap="$default" first-keystroke="control alt shift T"/>
<add-to-group group-id="CodeMenu" anchor="last"/>
</action>
<action id="ToggleJetErrorReporting" class="org.jetbrains.jet.plugin.actions.ToggleErrorReportingAction"
text="Toggle Error Reporting">
<keyboard-shortcut keymap="$default" first-keystroke="control alt shift E"/>
@@ -0,0 +1,302 @@
package org.jetbrains.jet.checkers;
import com.google.common.collect.*;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiFile;
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.resolve.BindingContext;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author abreslav
*/
public class CheckerTestUtil {
public static final Comparator<Diagnostic> DIAGNOSTIC_COMPARATOR = new Comparator<Diagnostic>() {
@Override
public int compare(Diagnostic o1, Diagnostic o2) {
TextRange range1 = getTextRange(o1);
TextRange range2 = getTextRange(o2);
int startOffset1 = range1.getStartOffset();
int startOffset2 = range2.getStartOffset();
if (startOffset1 != startOffset2) {
// Start early -- go first
return startOffset1 - range2.getStartOffset();
}
// start at the same offset, the one who end later is the outer, i.e. goes first
return range2.getEndOffset() - range1.getEndOffset();
}
};
private static final Pattern RANGE_START_OR_END_PATTERN = Pattern.compile("(<!\\w+(,\\s*\\w+)*!>)|(<!>)");
private static final Pattern INDIVIDUAL_DIAGNOSTIC_PATTERN = Pattern.compile("\\w+");
public interface DiagnosticDiffCallbacks {
void missingDiagnostic(String type, int expectedStart, int expectedEnd);
void unexpectedDiagnostic(String type, int actualStart, int actualEnd);
}
public static void diagnosticsDiff(List<DiagnosedRange> expected, Collection<Diagnostic> actual, DiagnosticDiffCallbacks callbacks) {
Iterator<DiagnosedRange> expectedDiagnostics = expected.iterator();
List<DiagnosticDescriptor> sortedDiagnosticDescriptors = getSortedDiagnosticDescriptors(actual);
Iterator<DiagnosticDescriptor> actualDiagnostics = sortedDiagnosticDescriptors.iterator();
DiagnosedRange currentExpected = safeAdvance(expectedDiagnostics);
DiagnosticDescriptor currentActual = safeAdvance(actualDiagnostics);
while (currentExpected != null || currentActual != null) {
if (currentExpected != null) {
if (currentActual == null) {
missingDiagnostics(callbacks, currentExpected);
currentExpected = safeAdvance(expectedDiagnostics);
}
else {
int expectedStart = currentExpected.getStart();
int actualStart = currentActual.getStart();
int expectedEnd = currentExpected.getEnd();
int actualEnd = currentActual.getEnd();
if (expectedStart < actualStart) {
missingDiagnostics(callbacks, currentExpected);
currentExpected = safeAdvance(expectedDiagnostics);
}
else if (expectedStart > actualStart) {
unexpectedDiagnostics(currentActual.getDiagnostics(), callbacks);
currentActual = safeAdvance(actualDiagnostics);
}
else if (expectedEnd > actualEnd) {
assert expectedStart == actualStart;
missingDiagnostics(callbacks, currentExpected);
currentExpected = safeAdvance(expectedDiagnostics);
}
else if (expectedEnd < actualEnd) {
assert expectedStart == actualStart;
unexpectedDiagnostics(currentActual.getDiagnostics(), callbacks);
currentActual = safeAdvance(actualDiagnostics);
}
else {
assert expectedStart == actualStart && expectedEnd == actualEnd;
Multiset<String> actualDiagnosticTypes = currentActual.getDiagnosticTypeStrings();
Multiset<String> expectedDiagnosticTypes = currentExpected.getDiagnostics();
if (!actualDiagnosticTypes.equals(expectedDiagnosticTypes)) {
Multiset<String> expectedCopy = HashMultiset.create(expectedDiagnosticTypes);
expectedCopy.removeAll(actualDiagnosticTypes);
Multiset<String> actualCopy = HashMultiset.create(actualDiagnosticTypes);
actualCopy.removeAll(expectedDiagnosticTypes);
for (String type : expectedCopy) {
callbacks.missingDiagnostic(type, expectedStart, expectedEnd);
}
for (String type : actualCopy) {
callbacks.unexpectedDiagnostic(type, actualStart, actualEnd);
}
}
currentExpected = safeAdvance(expectedDiagnostics);
currentActual = safeAdvance(actualDiagnostics);
}
}
}
else {
if (currentActual != null) {
unexpectedDiagnostics(currentActual.getDiagnostics(), callbacks);
currentActual = safeAdvance(actualDiagnostics);
}
else {
break;
}
}
// assert expectedDiagnostics.hasNext() || actualDiagnostics.hasNext();
}
}
private static void unexpectedDiagnostics(List<Diagnostic> actual, DiagnosticDiffCallbacks callbacks) {
for (Diagnostic diagnostic : actual) {
TextRange textRange = getTextRange(diagnostic);
callbacks.unexpectedDiagnostic(diagnostic.getFactory().getName(), textRange.getStartOffset(), textRange.getEndOffset());
}
}
private static void missingDiagnostics(DiagnosticDiffCallbacks callbacks, DiagnosedRange currentExpected) {
for (String type : currentExpected.getDiagnostics()) {
callbacks.missingDiagnostic(type, currentExpected.getStart(), currentExpected.getEnd());
}
}
private static <T> T safeAdvance(Iterator<T> iterator) {
return iterator.hasNext() ? iterator.next() : null;
}
public static String parseDiagnosedRanges(String text, List<DiagnosedRange> result) {
Matcher matcher = RANGE_START_OR_END_PATTERN.matcher(text);
Stack<DiagnosedRange> opened = new Stack<DiagnosedRange>();
int offsetCompensation = 0;
while (matcher.find()) {
int effectiveOffset = matcher.start() - offsetCompensation;
String matchedText = matcher.group();
if ("<!>".equals(matchedText)) {
opened.pop().setEnd(effectiveOffset);
}
else {
Matcher diagnosticTypeMatcher = INDIVIDUAL_DIAGNOSTIC_PATTERN.matcher(matchedText);
DiagnosedRange range = new DiagnosedRange(effectiveOffset);
while (diagnosticTypeMatcher.find()) {
range.addDiagnostic(diagnosticTypeMatcher.group());
}
opened.push(range);
result.add(range);
}
offsetCompensation += matchedText.length();
}
matcher.reset();
return matcher.replaceAll("");
}
public static StringBuffer addDiagnosticMarkersToText(PsiFile psiFile, BindingContext bindingContext) {
Collection<Diagnostic> diagnostics = bindingContext.getDiagnostics();
StringBuffer result = new StringBuffer();
String text = psiFile.getText();
if (!diagnostics.isEmpty()) {
List<DiagnosticDescriptor> diagnosticDescriptors = getSortedDiagnosticDescriptors(diagnostics);
Stack<DiagnosticDescriptor> opened = new Stack<DiagnosticDescriptor>();
ListIterator<DiagnosticDescriptor> iterator = diagnosticDescriptors.listIterator();
DiagnosticDescriptor currentDescriptor = iterator.next();
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
while (!opened.isEmpty() && i == opened.peek().end) {
closeDiagnosticString(result);
opened.pop();
}
if (currentDescriptor != null && i == currentDescriptor.start) {
openDiagnosticsString(result, currentDescriptor);
opened.push(currentDescriptor);
if (iterator.hasNext()) {
currentDescriptor = iterator.next();
}
else {
currentDescriptor = null;
}
}
result.append(c);
}
}
else {
result.append(text);
}
return result;
}
private static void openDiagnosticsString(StringBuffer result, DiagnosticDescriptor currentDescriptor) {
result.append("<!");
for (Iterator<Diagnostic> iterator = currentDescriptor.diagnostics.iterator(); iterator.hasNext(); ) {
Diagnostic diagnostic = iterator.next();
result.append(diagnostic.getFactory().getName());
if (iterator.hasNext()) {
result.append(", ");
}
}
result.append("!>");
}
private static void closeDiagnosticString(StringBuffer result) {
result.append("<!>");
}
private static List<DiagnosticDescriptor> getSortedDiagnosticDescriptors(Collection<Diagnostic> diagnostics) {
List<Diagnostic> list = Lists.newArrayList(diagnostics);
Collections.sort(list, DIAGNOSTIC_COMPARATOR);
List<DiagnosticDescriptor> diagnosticDescriptors = Lists.newArrayList();
DiagnosticDescriptor currentDiagnosticDescriptor = null;
for (Iterator<Diagnostic> iterator = list.iterator(); iterator.hasNext(); ) {
Diagnostic diagnostic = iterator.next();
TextRange textRange = getTextRange(diagnostic);
if (currentDiagnosticDescriptor != null && currentDiagnosticDescriptor.equalRange(textRange)) {
currentDiagnosticDescriptor.diagnostics.add(diagnostic);
}
else {
currentDiagnosticDescriptor = new DiagnosticDescriptor(textRange.getStartOffset(), textRange.getEndOffset(), diagnostic);
diagnosticDescriptors.add(currentDiagnosticDescriptor);
}
}
return diagnosticDescriptors;
}
private static TextRange getTextRange(Diagnostic currentDiagnostic) {
return currentDiagnostic.getFactory().getTextRange(currentDiagnostic);
}
private static class DiagnosticDescriptor {
private final int start;
private final int end;
private final List<Diagnostic> diagnostics = Lists.newArrayList();
DiagnosticDescriptor(int start, int end, Diagnostic diagnostic) {
this.start = start;
this.end = end;
this.diagnostics.add(diagnostic);
}
public boolean equalRange(TextRange textRange) {
return start == textRange.getStartOffset() && end == textRange.getEndOffset();
}
public Multiset<String> getDiagnosticTypeStrings() {
Multiset<String> actualDiagnosticTypes = HashMultiset.create();
for (Diagnostic diagnostic : diagnostics) {
actualDiagnosticTypes.add(diagnostic.getFactory().getName());
}
return actualDiagnosticTypes;
}
public int getStart() {
return start;
}
public int getEnd() {
return end;
}
public List<Diagnostic> getDiagnostics() {
return diagnostics;
}
}
public static class DiagnosedRange {
private final int start;
private int end;
private final Multiset<String> diagnostics = HashMultiset.create();
private DiagnosedRange(int start) {
this.start = start;
}
public int getStart() {
return start;
}
public int getEnd() {
return end;
}
public Multiset<String> getDiagnostics() {
return diagnostics;
}
public void setEnd(int end) {
this.end = end;
}
public void addDiagnostic(String diagnostic) {
diagnostics.add(diagnostic);
}
}
}
@@ -0,0 +1,50 @@
package org.jetbrains.jet.plugin.actions;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiFile;
import org.jetbrains.jet.checkers.CheckerTestUtil;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.plugin.AnalyzerFacade;
import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.ClipboardOwner;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
/**
* @author abreslav
*/
public class CopyAsDiagnosticTestAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent e) {
Editor editor = e.getData(PlatformDataKeys.EDITOR);
PsiFile psiFile = e.getData(LangDataKeys.PSI_FILE);
assert editor != null && psiFile != null;
BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache((JetFile) psiFile);
String result = CheckerTestUtil.addDiagnosticMarkersToText(psiFile, bindingContext).toString();
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents(new StringSelection(result), new ClipboardOwner() {
@Override
public void lostOwnership(Clipboard clipboard, Transferable contents) {}
});
}
@Override
public void update(AnActionEvent e) {
Editor editor = e.getData(PlatformDataKeys.EDITOR);
PsiFile psiFile = e.getData(LangDataKeys.PSI_FILE);
e.getPresentation().setEnabled(editor != null && psiFile instanceof JetFile && ApplicationManager.getApplication().isInternal());
}
}
+15
View File
@@ -0,0 +1,15 @@
fun foo(u : Unit) : Int = 1
fun test() : Int {
foo(1)
val a : fun() : Unit = {
foo(1)
}
return 1 - "1"
}
class A() {
val x : Int = foo1(xx)
}
fun foo1() {}
@@ -0,0 +1,241 @@
namespace abstract
class MyClass() {
//properties
val <!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>a<!>: Int
val a1: Int = 1
<!ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS!>abstract<!> val a2: Int
<!ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS!>abstract<!> val a3: Int = 1
var <!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>b<!>: Int private set
var b1: Int = 0; private set
<!ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS!>abstract<!> var b2: Int private set
<!ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS!>abstract<!> var b3: Int = 0; private set
var <!MUST_BE_INITIALIZED!>c<!>: Int set(v: Int) { $c = v }
var c1: Int = 0; set(v: Int) { $c1 = v }
<!ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS!>abstract<!> var c2: Int set(v: Int) { $c2 = v }
<!ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS!>abstract<!> var c3: Int = 0; set(v: Int) { $c3 = v }
val e: Int get() = a
val e1: Int = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>0<!>; get() = a
<!ABSTRACT_PROPERTY_IN_NN_ABSTRACT_CLASS!>abstract<!> val e2: Int get() = a
<!ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS!>abstract<!> val e3: Int = 0; get() = a
//methods
fun <!NON_ABSTRACT_FUNCTION_WITH_NO_BODY!>f<!>()
fun g() {}
<!ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS!>abstract<!> fun h()
<!ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS, ABSTRACT_FUNCTION_WITH_BODY!>abstract<!> fun j() {}
//property accessors
var i: Int <!ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS!>abstract<!> get <!ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS!>abstract<!> set
var i1: Int = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>0<!>; <!ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS!>abstract<!> get <!ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS!>abstract<!> set
var j: Int get() = i; <!ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS!>abstract<!> set
var j1: Int = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>0<!>; get() = i; <!ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS!>abstract<!> set
var <!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>k<!>: Int <!ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS!>abstract<!> set
var k1: Int = 0; <!ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS!>abstract<!> set
var l: Int <!ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS!>abstract<!> get <!ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS!>abstract<!> set
var l1: Int = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>0<!>; <!ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS!>abstract<!> get <!ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS!>abstract<!> set
var n: Int <!ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS!>abstract<!> get <!ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS, ABSTRACT_FUNCTION_WITH_BODY!>abstract<!> set(v: Int) {}
}
abstract class MyAbstractClass() {
//properties
val <!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>a<!>: Int
val a1: Int = 1
abstract val a2: Int
abstract val a3: Int = <!ABSTRACT_PROPERTY_WITH_INITIALIZER!>1<!>
var <!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>b<!>: Int private set
var b1: Int = 0; private set
abstract var b2: Int private set
abstract var b3: Int = <!ABSTRACT_PROPERTY_WITH_INITIALIZER!>0<!>; private set
var <!MUST_BE_INITIALIZED!>c<!>: Int set(v: Int) { $c = v }
var c1: Int = 0; set(v: Int) { $c1 = v }
abstract var c2: Int <!ABSTRACT_PROPERTY_WITH_SETTER!>set(v: Int) { $c2 = v }<!>
abstract var c3: Int = <!ABSTRACT_PROPERTY_WITH_INITIALIZER!>0<!>; <!ABSTRACT_PROPERTY_WITH_SETTER!>set(v: Int) { $c3 = v }<!>
val e: Int get() = a
val e1: Int = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>0<!>; get() = a
abstract val e2: Int <!ABSTRACT_PROPERTY_WITH_GETTER!>get() = a<!>
abstract val e3: Int = <!ABSTRACT_PROPERTY_WITH_INITIALIZER!>0<!>; <!ABSTRACT_PROPERTY_WITH_GETTER!>get() = a<!>
//methods
fun <!NON_ABSTRACT_FUNCTION_WITH_NO_BODY!>f<!>()
fun g() {}
abstract fun h()
<!ABSTRACT_FUNCTION_WITH_BODY!>abstract<!> fun j() {}
//property accessors
var i: Int abstract get abstract set
var i1: Int = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>0<!>; abstract get abstract set
var j: Int get() = i; abstract set
var j1: Int get() = i; abstract set
var <!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>k<!>: Int abstract set
var k1: Int = 0; abstract set
var l: Int abstract get abstract set
var l1: Int = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>0<!>; abstract get abstract set
var n: Int abstract get <!ABSTRACT_FUNCTION_WITH_BODY!>abstract<!> set(v: Int) {}
}
trait MyTrait {
//properties
val a: Int
val a1: Int = <!PROPERTY_INITIALIZER_IN_TRAIT!>1<!>
<!REDUNDANT_ABSTRACT!>abstract<!> val a2: Int
<!REDUNDANT_ABSTRACT!>abstract<!> val a3: Int = <!ABSTRACT_PROPERTY_WITH_INITIALIZER!>1<!>
var b: Int private set
var b1: Int = <!PROPERTY_INITIALIZER_IN_TRAIT!>0<!>; private set
<!REDUNDANT_ABSTRACT!>abstract<!> var b2: Int private set
<!REDUNDANT_ABSTRACT!>abstract<!> var b3: Int = <!ABSTRACT_PROPERTY_WITH_INITIALIZER!>0<!>; private set
var <!BACKING_FIELD_IN_TRAIT!>c<!>: Int set(v: Int) { $c = v }
var <!BACKING_FIELD_IN_TRAIT!>c1<!>: Int = <!PROPERTY_INITIALIZER_IN_TRAIT!>0<!>; set(v: Int) { $c1 = v }
<!REDUNDANT_ABSTRACT!>abstract<!> var c2: Int <!ABSTRACT_PROPERTY_WITH_SETTER!>set(v: Int) { $c2 = v }<!>
<!REDUNDANT_ABSTRACT!>abstract<!> var c3: Int = <!ABSTRACT_PROPERTY_WITH_INITIALIZER!>0<!>; <!ABSTRACT_PROPERTY_WITH_SETTER!>set(v: Int) { $c3 = v }<!>
val e: Int get() = a
val e1: Int = <!PROPERTY_INITIALIZER_IN_TRAIT!>0<!>; get() = a
<!REDUNDANT_ABSTRACT!>abstract<!> val e2: Int <!ABSTRACT_PROPERTY_WITH_GETTER!>get() = a<!>
<!REDUNDANT_ABSTRACT!>abstract<!> val e3: Int = <!ABSTRACT_PROPERTY_WITH_INITIALIZER!>0<!>; <!ABSTRACT_PROPERTY_WITH_GETTER!>get() = a<!>
//methods
fun f()
fun g() {}
<!REDUNDANT_ABSTRACT!>abstract<!> fun h()
<!REDUNDANT_ABSTRACT, ABSTRACT_FUNCTION_WITH_BODY!>abstract<!> fun j() {}
//property accessors
var i: Int abstract get abstract set
var i1: Int = <!PROPERTY_INITIALIZER_IN_TRAIT!>0<!>; abstract get abstract set
var j: Int get() = i; abstract set
var j1: Int = <!PROPERTY_INITIALIZER_IN_TRAIT!>0<!>; get() = i; abstract set
var k: Int abstract set
var k1: Int = <!PROPERTY_INITIALIZER_IN_TRAIT!>0<!>; abstract set
var l: Int abstract get abstract set
var l1: Int = <!PROPERTY_INITIALIZER_IN_TRAIT!>0<!>; abstract get abstract set
var n: Int abstract get <!ABSTRACT_FUNCTION_WITH_BODY!>abstract<!> set(v: Int) {}
}
enum class MyEnum() {
//properties
val <!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>a<!>: Int
val a1: Int = 1
abstract val a2: Int
abstract val a3: Int = <!ABSTRACT_PROPERTY_WITH_INITIALIZER!>1<!>
var <!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>b<!>: Int private set
var b1: Int = 0; private set
abstract var b2: Int private set
abstract var b3: Int = <!ABSTRACT_PROPERTY_WITH_INITIALIZER!>0<!>; private set
var <!MUST_BE_INITIALIZED!>c<!>: Int set(v: Int) { $c = v }
var c1: Int = 0; set(v: Int) { $c1 = v }
abstract var c2: Int <!ABSTRACT_PROPERTY_WITH_SETTER!>set(v: Int) { $c2 = v }<!>
abstract var c3: Int = <!ABSTRACT_PROPERTY_WITH_INITIALIZER!>0<!>; <!ABSTRACT_PROPERTY_WITH_SETTER!>set(v: Int) { $c3 = v }<!>
val e: Int get() = a
val e1: Int = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>0<!>; get() = a
abstract val e2: Int <!ABSTRACT_PROPERTY_WITH_GETTER!>get() = a<!>
abstract val e3: Int = <!ABSTRACT_PROPERTY_WITH_INITIALIZER!>0<!>; <!ABSTRACT_PROPERTY_WITH_GETTER!>get() = a<!>
//methods
fun <!NON_ABSTRACT_FUNCTION_WITH_NO_BODY!>f<!>()
fun g() {}
abstract fun h()
<!ABSTRACT_FUNCTION_WITH_BODY!>abstract<!> fun j() {}
//property accessors
var i: Int abstract get abstract set
var i1: Int = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>0<!>; abstract get abstract set
var j: Int get() = i; abstract set
var j1: Int = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>0<!>; get() = i; abstract set
var <!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>k<!>: Int abstract set
var k1: Int = 0; abstract set
var l: Int abstract get abstract set
var l1: Int = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>0<!>; abstract get abstract set
var n: Int abstract get <!ABSTRACT_FUNCTION_WITH_BODY!>abstract<!> set(v: Int) {}
}
abstract enum class MyAbstractEnum() {}
namespace MyNamespace {
//properties
val <!MUST_BE_INITIALIZED!>a<!>: Int
val a1: Int = 1
<!ABSTRACT_PROPERTY_NOT_IN_CLASS!>abstract<!> val a2: Int
<!ABSTRACT_PROPERTY_NOT_IN_CLASS!>abstract<!> val a3: Int = 1
var <!MUST_BE_INITIALIZED!>b<!>: Int private set
var b1: Int = 0; private set
<!ABSTRACT_PROPERTY_NOT_IN_CLASS!>abstract<!> var b2: Int private set
<!ABSTRACT_PROPERTY_NOT_IN_CLASS!>abstract<!> var b3: Int = 0; private set
var <!MUST_BE_INITIALIZED!>c<!>: Int set(v: Int) { $c = v }
var c1: Int = 0; set(v: Int) { $c1 = v }
<!ABSTRACT_PROPERTY_NOT_IN_CLASS!>abstract<!> var c2: Int set(v: Int) { $c2 = v }
<!ABSTRACT_PROPERTY_NOT_IN_CLASS!>abstract<!> var c3: Int = 0; set(v: Int) { $c3 = v }
val e: Int get() = a
val e1: Int = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>0<!>; get() = a
<!ABSTRACT_PROPERTY_NOT_IN_CLASS!>abstract<!> val e2: Int get() = a
<!ABSTRACT_PROPERTY_NOT_IN_CLASS!>abstract<!> val e3: Int = 0; get() = a
//methods
fun <!NON_MEMBER_FUNCTION_NO_BODY!>f<!>()
fun g() {}
<!NON_MEMBER_ABSTRACT_FUNCTION!>abstract<!> fun h()
<!NON_MEMBER_ABSTRACT_FUNCTION!>abstract<!> fun j() {}
//property accessors
var i: Int <!NON_MEMBER_ABSTRACT_ACCESSOR!>abstract<!> get <!NON_MEMBER_ABSTRACT_ACCESSOR!>abstract<!> set
var i1: Int = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>0<!>; <!NON_MEMBER_ABSTRACT_ACCESSOR!>abstract<!> get <!NON_MEMBER_ABSTRACT_ACCESSOR!>abstract<!> set
var j: Int get() = i; <!NON_MEMBER_ABSTRACT_ACCESSOR!>abstract<!> set
var j1: Int = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>0<!>; get() = i; <!NON_MEMBER_ABSTRACT_ACCESSOR!>abstract<!> set
var <!MUST_BE_INITIALIZED!>k<!>: Int <!NON_MEMBER_ABSTRACT_ACCESSOR!>abstract<!> set
var k1: Int = 0; <!NON_MEMBER_ABSTRACT_ACCESSOR!>abstract<!> set
var l: Int <!NON_MEMBER_ABSTRACT_ACCESSOR!>abstract<!> get <!NON_MEMBER_ABSTRACT_ACCESSOR!>abstract<!> set
var l1: Int = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>0<!>; <!NON_MEMBER_ABSTRACT_ACCESSOR!>abstract<!> get <!NON_MEMBER_ABSTRACT_ACCESSOR!>abstract<!> set
var n: Int <!NON_MEMBER_ABSTRACT_ACCESSOR!>abstract<!> get <!NON_MEMBER_ABSTRACT_ACCESSOR!>abstract<!> set(v: Int) {}
}
//creating an instance
abstract class B1(
val i: Int,
val s: String
) {
}
class B2() : B1(1, "r") {}
abstract class B3(i: Int) {
this(): this(1)
}
fun foo(a: B3) {
val a = <!CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS!>B3()<!>
val b = <!CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS!>B1(2, "s")<!>
}
@@ -0,0 +1,15 @@
fun foo(u : Unit) : Int = 1
fun test() : Int {
foo(<!TYPE_MISMATCH!>1<!>)
val a : fun() : Unit = {
foo(<!TYPE_MISMATCH!>1<!>)
}
return 1 <!NONE_APPLICABLE!>-<!> "1"
}
class A() {
val x : Int = <!TYPE_MISMATCH!>foo1(<!TOO_MANY_ARGUMENTS, UNRESOLVED_REFERENCE!>xx<!>)<!>
}
fun foo1() {}
@@ -0,0 +1,189 @@
package org.jetbrains.jet;
import com.intellij.ide.startup.impl.StartupManagerImpl;
import com.intellij.lang.*;
import com.intellij.lang.impl.PsiBuilderFactoryImpl;
import com.intellij.mock.*;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl;
import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
import com.intellij.openapi.fileTypes.FileTypeFactory;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.options.SchemesManagerFactory;
import com.intellij.openapi.progress.impl.ProgressManagerImpl;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiCachedValuesFactory;
import com.intellij.psi.impl.PsiFileFactoryImpl;
import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry;
import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistryImpl;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.testFramework.LightVirtualFile;
import com.intellij.testFramework.MockSchemesManagerFactory;
import com.intellij.testFramework.PlatformLiteFixture;
import com.intellij.testFramework.TestDataFile;
import com.intellij.util.CachedValuesManagerImpl;
import com.intellij.util.Function;
import com.intellij.util.messages.MessageBus;
import com.intellij.util.messages.MessageBusFactory;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.jet.lang.parsing.JetParserDefinition;
import org.picocontainer.MutablePicoContainer;
import org.picocontainer.PicoContainer;
import org.picocontainer.PicoInitializationException;
import org.picocontainer.PicoIntrospectionException;
import org.picocontainer.defaults.AbstractComponentAdapter;
import java.io.File;
import java.io.IOException;
/**
* @author abreslav
*/
public class JetLiteFixture extends PlatformLiteFixture {
protected String myFileExt;
@NonNls
protected final String myFullDataPath;
protected PsiFile myFile;
private MockPsiManager myPsiManager;
private PsiFileFactoryImpl myFileFactory;
protected Language myLanguage;
protected final ParserDefinition[] myDefinitions;
public JetLiteFixture(@NonNls String dataPath) {
myFileExt = "jet";
myFullDataPath = getTestDataPath() + "/" + dataPath;
myDefinitions = new ParserDefinition[] {new JetParserDefinition()};
}
protected String getTestDataPath() {
return JetTestCaseBase.getTestDataPathBase();
}
@Override
protected void setUp() throws Exception {
super.setUp();
initApplication();
getApplication().getPicoContainer().registerComponent(new AbstractComponentAdapter("com.intellij.openapi.progress.ProgressManager", Object.class) {
@Override
public Object getComponentInstance(PicoContainer container) throws PicoInitializationException, PicoIntrospectionException {
return new ProgressManagerImpl(getApplication());
}
@Override
public void verify(PicoContainer container) throws PicoIntrospectionException {
}
});
myProject = disposeOnTearDown(new MockProjectEx());
myPsiManager = new MockPsiManager(myProject);
myFileFactory = new PsiFileFactoryImpl(myPsiManager);
final MutablePicoContainer appContainer = getApplication().getPicoContainer();
registerComponentInstance(appContainer, MessageBus.class, MessageBusFactory.newMessageBus(getApplication()));
registerComponentInstance(appContainer, SchemesManagerFactory.class, new MockSchemesManagerFactory());
final MockEditorFactory editorFactory = new MockEditorFactory();
registerComponentInstance(appContainer, EditorFactory.class, editorFactory);
registerComponentInstance(appContainer, FileDocumentManager.class, new MockFileDocumentManagerImpl(new Function<CharSequence, Document>() {
@Override
public Document fun(CharSequence charSequence) {
return editorFactory.createDocument(charSequence);
}
}, FileDocumentManagerImpl.DOCUMENT_KEY));
registerComponentInstance(appContainer, PsiDocumentManager.class, new MockPsiDocumentManager());
myLanguage = myLanguage == null && myDefinitions != null && myDefinitions.length > 0
? myDefinitions[0].getFileNodeType().getLanguage()
: myLanguage;
registerComponentInstance(appContainer, FileTypeManager.class, new MockFileTypeManager(new MockLanguageFileType(myLanguage, myFileExt)));
registerApplicationService(PsiBuilderFactory.class, new PsiBuilderFactoryImpl());
registerApplicationService(DefaultASTFactory.class, new DefaultASTFactoryImpl());
registerApplicationService(ReferenceProvidersRegistry.class, new ReferenceProvidersRegistryImpl());
myProject.registerService(CachedValuesManager.class, new CachedValuesManagerImpl(myProject, new PsiCachedValuesFactory(myPsiManager)));
myProject.registerService(PsiManager.class, myPsiManager);
myProject.registerService(StartupManager.class, new StartupManagerImpl(myProject));
myProject.registerService(PsiFileFactory.class, new PsiFileFactoryImpl(myPsiManager));
registerExtensionPoint(FileTypeFactory.FILE_TYPE_FACTORY_EP, FileTypeFactory.class);
for (ParserDefinition definition : myDefinitions) {
addExplicitExtension(LanguageParserDefinitions.INSTANCE, definition.getFileNodeType().getLanguage(), definition);
}
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
myFile = null;
myProject = null;
myPsiManager = null;
}
protected String loadFile(@NonNls @TestDataFile String name) throws IOException {
return doLoadFile(myFullDataPath, name);
}
private static String doLoadFile(String myFullDataPath, String name) throws IOException {
String fullName = myFullDataPath + File.separatorChar + name;
String text = FileUtil.loadFile(new File(fullName), CharsetToolkit.UTF8).trim();
text = StringUtil.convertLineSeparators(text);
return text;
}
protected PsiFile createPsiFile(String name, String text) {
return createFile(name + "." + myFileExt, text);
}
protected PsiFile createFile(@NonNls String name, String text) {
LightVirtualFile virtualFile = new LightVirtualFile(name, myLanguage, text);
virtualFile.setCharset(CharsetToolkit.UTF8_CHARSET);
return myFileFactory.trySetupPsiForFile(virtualFile, myLanguage, true, false);
}
protected static void ensureParsed(PsiFile file) {
file.accept(new PsiElementVisitor() {
@Override
public void visitElement(PsiElement element) {
element.acceptChildren(this);
}
});
}
protected <T> void registerApplicationService(final Class<T> aClass, T object) {
getApplication().registerService(aClass, object);
Disposer.register(myProject, new Disposable() {
@Override
public void dispose() {
getApplication().getPicoContainer().unregisterComponent(aClass.getName());
}
});
}
protected <T> void addExplicitExtension(final LanguageExtension<T> instance, final Language language, final T object) {
instance.addExplicitExtension(language, object);
Disposer.register(myProject, new Disposable() {
@Override
public void dispose() {
instance.removeExplicitExtension(language, object);
}
});
}
protected void prepareForTest(String name) throws IOException {
String text = loadFile(name + "." + myFileExt);
createAndCheckPsiFile(name, text);
}
protected void createAndCheckPsiFile(String name, String text) {
myFile = createPsiFile(name, text);
ensureParsed(myFile);
assertEquals("light virtual file text mismatch", text, ((LightVirtualFile) myFile.getVirtualFile()).getContent().toString());
assertEquals("virtual file text mismatch", text, LoadTextUtil.loadText(myFile.getVirtualFile()));
assertEquals("doc text mismatch", text, myFile.getViewProvider().getDocument().getText());
assertEquals("psi text mismatch", text, myFile.getText());
}
}
@@ -43,11 +43,11 @@ public abstract class JetTestCaseBase extends LightDaemonAnalyzerTestCase {
return getTestDataPathBase();
}
protected static String getTestDataPathBase() {
public static String getTestDataPathBase() {
return getHomeDirectory() + "/idea/testData";
}
private static String getHomeDirectory() {
public static String getHomeDirectory() {
return new File(PathManager.getResourceRoot(JetTestCaseBase.class, "/org/jetbrains/jet/JetTestCaseBase.class")).getParentFile().getParentFile().getParent();
}
@@ -0,0 +1,125 @@
package org.jetbrains.jet.checkers;
import com.google.common.collect.Lists;
import com.intellij.psi.PsiFile;
import org.jetbrains.jet.JetLiteFixture;
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
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.ImportingStrategy;
import java.util.Collections;
import java.util.List;
/**
* @author abreslav
*/
public class CheckerTestUtilTest extends JetLiteFixture {
public CheckerTestUtilTest() {
super("checkerTestUtil");
}
protected void doTest(TheTest theTest) throws Exception {
prepareForTest("test");
theTest.test(myFile);
}
public void testEquals() throws Exception {
doTest(new TheTest() {
@Override
protected void makeTestData(List<Diagnostic> diagnostics, List<CheckerTestUtil.DiagnosedRange> diagnosedRanges) {
}
});
}
public void testMissing() throws Exception {
doTest(new TheTest("Missing TYPE_MISMATCH at 56 to 57") {
@Override
protected void makeTestData(List<Diagnostic> diagnostics, List<CheckerTestUtil.DiagnosedRange> diagnosedRanges) {
diagnostics.remove(0);
}
});
}
public void testUnexpected() throws Exception {
doTest(new TheTest("Unexpected TYPE_MISMATCH at 56 to 57") {
@Override
protected void makeTestData(List<Diagnostic> diagnostics, List<CheckerTestUtil.DiagnosedRange> diagnosedRanges) {
diagnosedRanges.remove(0);
}
});
}
public void testBoth() throws Exception {
doTest(new TheTest("Unexpected TYPE_MISMATCH at 56 to 57", "Missing UNRESOLVED_REFERENCE at 166 to 168") {
@Override
protected void makeTestData(List<Diagnostic> diagnostics, List<CheckerTestUtil.DiagnosedRange> diagnosedRanges) {
diagnosedRanges.remove(0);
diagnostics.remove(diagnostics.size() - 1);
}
});
}
public void testMissingInTheMiddle() throws Exception {
doTest(new TheTest("Unexpected NONE_APPLICABLE at 122 to 123", "Missing TYPE_MISMATCH at 161 to 169") {
@Override
protected void makeTestData(List<Diagnostic> diagnostics, List<CheckerTestUtil.DiagnosedRange> diagnosedRanges) {
diagnosedRanges.remove(2);
diagnostics.remove(diagnostics.size() - 3);
}
});
}
private static abstract class TheTest {
private final String[] expected;
protected TheTest(String... expectedMessages) {
this.expected = expectedMessages;
}
public void test(PsiFile psiFile) {
BindingContext bindingContext = AnalyzingUtils.getInstance(ImportingStrategy.NONE).analyzeFileWithCache((JetFile) psiFile);
String expectedText = CheckerTestUtil.addDiagnosticMarkersToText(psiFile, bindingContext).toString();
List<CheckerTestUtil.DiagnosedRange> diagnosedRanges = Lists.newArrayList();
CheckerTestUtil.parseDiagnosedRanges(expectedText, diagnosedRanges);
List<Diagnostic> diagnostics = Lists.newArrayList(bindingContext.getDiagnostics());
Collections.sort(diagnostics, CheckerTestUtil.DIAGNOSTIC_COMPARATOR);
makeTestData(diagnostics, diagnosedRanges);
final List<String> expectedMessages = Lists.newArrayList(expected);
final List<String> actualMessages = Lists.newArrayList();
CheckerTestUtil.diagnosticsDiff(diagnosedRanges, diagnostics, new CheckerTestUtil.DiagnosticDiffCallbacks() {
@Override
public void missingDiagnostic(String type, int expectedStart, int expectedEnd) {
String message = "Missing " + type + " at " + expectedStart + " to " + expectedEnd;
actualMessages.add(message);
}
@Override
public void unexpectedDiagnostic(String type, int actualStart, int actualEnd) {
String message = "Unexpected " + type + " at " + actualStart + " to " + actualEnd;
actualMessages.add(message);
}
});
assertEquals(listToString(expectedMessages), listToString(actualMessages));
}
private String listToString(List<String> expectedMessages) {
StringBuilder stringBuilder = new StringBuilder();
for (String expectedMessage : expectedMessages) {
stringBuilder.append(expectedMessage).append("\n");
}
return stringBuilder.toString();
}
protected abstract void makeTestData(List<Diagnostic> diagnostics, List<CheckerTestUtil.DiagnosedRange> diagnosedRanges);
}
}
@@ -0,0 +1,72 @@
package org.jetbrains.jet.checkers;
import com.google.common.collect.Lists;
import com.intellij.openapi.util.TextRange;
import junit.framework.Test;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.JetLiteFixture;
import org.jetbrains.jet.JetTestCaseBase;
import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils;
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.ImportingStrategy;
import java.util.List;
/**
* @author abreslav
*/
public class QuickJetPsiCheckerTest extends JetLiteFixture {
private String name;
public QuickJetPsiCheckerTest(@NonNls String dataPath, String name) {
super(dataPath);
this.name = name;
}
@Override
public String getName() {
return "test" + name;
}
@Override
public void runTest() throws Exception {
String expectedText = loadFile(name + ".jet");
List<CheckerTestUtil.DiagnosedRange> diagnosedRanges = Lists.newArrayList();
String clearText = CheckerTestUtil.parseDiagnosedRanges(expectedText, diagnosedRanges);
createAndCheckPsiFile(name, clearText);
JetFile jetFile = (JetFile) myFile;
BindingContext bindingContext = AnalyzingUtils.getInstance(ImportingStrategy.NONE).analyzeFileWithCache(jetFile);
CheckerTestUtil.diagnosticsDiff(diagnosedRanges, bindingContext.getDiagnostics(), new CheckerTestUtil.DiagnosticDiffCallbacks() {
@Override
public void missingDiagnostic(String type, int expectedStart, int expectedEnd) {
String message = "Missing " + type + DiagnosticUtils.atLocation(myFile, new TextRange(expectedStart, expectedEnd));
System.err.println(message);
}
@Override
public void unexpectedDiagnostic(String type, int actualStart, int actualEnd) {
String message = "Unexpected " + type + DiagnosticUtils.atLocation(myFile, new TextRange(actualStart, actualEnd));
System.err.println(message);
}
});
String actualText = CheckerTestUtil.addDiagnosticMarkersToText(jetFile, bindingContext).toString();
assertEquals(expectedText, actualText);
}
public static Test suite() {
return JetTestCaseBase.suiteForDirectory(JetTestCaseBase.getTestDataPathBase(), "/checkerWithErrorTypes/quick", true, new JetTestCaseBase.NamedTestFactory() {
@NotNull
@Override
public Test createTest(@NotNull String dataPath, @NotNull String name) {
return new QuickJetPsiCheckerTest(dataPath, name);
}
});
}
}
@@ -143,42 +143,6 @@ public class JetResolveTest extends ExtensibleResolveTestCase {
doTest(path, true, false);
}
// public void testBasic() throws Exception {
// doTest("/resolve/Basic.jet", true, true);
// }
//
// public void testResolveToJava() throws Exception {
// doTest("/resolve/ResolveToJava.jet", true, true);
// }
//
// public void testResolveOfInfixExpressions() throws Exception {
// doTest("/resolve/ResolveOfInfixExpressions.jet", true, true);
// }
//
// public void testProjections() throws Exception {
// doTest("/resolve/Projections.jet", true, true);
// }
//
// public void testPrimaryConstructors() throws Exception {
// doTest("/resolve/PrimaryConstructors.jet", true, true);
// }
//
// public void testClassifiers() throws Exception {
// doTest("/resolve/Classifiers.jet", true, true);
// }
//
// public void testConstructorsAndInitializers() throws Exception {
// doTest("/resolve/ConstructorsAndInitializers.jet", true, true);
// }
//
// public void testNamespaces() throws Exception {
// doTest("/resolve/Namespaces.jet", true, true);
// }
//
// public void testTryCatch() throws Exception {
// doTest("/resolve/TryCatch.jet", true, true);
// }
public static Test suite() {
return JetTestCaseBase.suiteForDirectory(getHomeDirectory() + "/idea/testData/", "/resolve/", true, new JetTestCaseBase.NamedTestFactory() {
@NotNull