mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PSI builder: more consistent validity checks
This commit is contained in:
@@ -569,15 +569,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
|
||||
|
||||
@SuppressWarnings({"SuspiciousMethodCalls"})
|
||||
public void doneBefore(Marker marker, Marker before) {
|
||||
// TODO: there could be not done markers after 'marker' and that's normal
|
||||
if (((StartMarker)marker).myDoneMarker != null) {
|
||||
LOG.error("Marker already done.");
|
||||
}
|
||||
|
||||
int idx = myProduction.lastIndexOf(marker);
|
||||
if (idx < 0) {
|
||||
LOG.error("Marker never been added.");
|
||||
}
|
||||
doValidityChecks(marker, before);
|
||||
|
||||
int beforeIndex = myProduction.lastIndexOf(before);
|
||||
|
||||
@@ -599,7 +591,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
|
||||
}
|
||||
|
||||
public void error(Marker marker, String message) {
|
||||
doValidityChecks(marker);
|
||||
doValidityChecks(marker, null);
|
||||
|
||||
DoneWithErrorMarker doneMarker = new DoneWithErrorMarker((StartMarker)marker, myCurrentLexeme, message);
|
||||
((StartMarker)marker).myDoneMarker = doneMarker;
|
||||
@@ -608,27 +600,18 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
|
||||
|
||||
@SuppressWarnings({"SuspiciousMethodCalls"})
|
||||
public void errorBefore(Marker marker, String message, Marker before) {
|
||||
// TODO: there could be not done markers after 'marker' and that's normal
|
||||
if (((StartMarker)marker).myDoneMarker != null) {
|
||||
LOG.error("Marker already done.");
|
||||
}
|
||||
|
||||
int idx = myProduction.lastIndexOf(marker);
|
||||
if (idx < 0) {
|
||||
LOG.error("Marker has never been added.");
|
||||
}
|
||||
doValidityChecks(marker, before);
|
||||
|
||||
int beforeIndex = myProduction.lastIndexOf(before);
|
||||
|
||||
DoneWithErrorMarker doneMarker = new DoneWithErrorMarker((StartMarker)marker, myCurrentLexeme, message);
|
||||
doneMarker.myLexemeIndex = ((StartMarker)before).myLexemeIndex;
|
||||
|
||||
((StartMarker)marker).myDoneMarker = doneMarker;
|
||||
myProduction.add(beforeIndex, doneMarker);
|
||||
}
|
||||
|
||||
public void done(final Marker marker) {
|
||||
doValidityChecks(marker);
|
||||
doValidityChecks(marker, null);
|
||||
|
||||
DoneMarker doneMarker = DONE_MARKERS.alloc();
|
||||
doneMarker.myStart = (StartMarker)marker;
|
||||
@@ -644,30 +627,41 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
|
||||
}
|
||||
|
||||
@SuppressWarnings({"UseOfSystemOutOrSystemErr", "SuspiciousMethodCalls"})
|
||||
private void doValidityChecks(final Marker marker) {
|
||||
if (myDebugMode) {
|
||||
final DoneMarker doneMarker = ((StartMarker)marker).myDoneMarker;
|
||||
if (doneMarker != null) {
|
||||
LOG.error("Marker already done.");
|
||||
}
|
||||
int idx = myProduction.lastIndexOf(marker);
|
||||
if (idx < 0) {
|
||||
LOG.error("Marker never been added.");
|
||||
}
|
||||
private void doValidityChecks(final Marker marker, @Nullable final Marker before) {
|
||||
if (!myDebugMode) return;
|
||||
|
||||
for (int i = myProduction.size() - 1; i > idx; i--) {
|
||||
Object item = myProduction.get(i);
|
||||
if (item instanceof StartMarker) {
|
||||
StartMarker otherMarker = (StartMarker)item;
|
||||
if (otherMarker.myDoneMarker == null) {
|
||||
final Throwable debugAllocOther = otherMarker.myDebugAllocationPosition;
|
||||
final Throwable debugAllocThis = ((StartMarker)marker).myDebugAllocationPosition;
|
||||
if (debugAllocOther != null) {
|
||||
debugAllocThis.printStackTrace(System.err);
|
||||
debugAllocOther.printStackTrace(System.err);
|
||||
}
|
||||
LOG.error("Another not done marker added after this one. Must be done before this.");
|
||||
final DoneMarker doneMarker = ((StartMarker)marker).myDoneMarker;
|
||||
if (doneMarker != null) {
|
||||
LOG.error("Marker already done.");
|
||||
}
|
||||
int idx = myProduction.lastIndexOf(marker);
|
||||
if (idx < 0) {
|
||||
LOG.error("Marker has never been added.");
|
||||
}
|
||||
|
||||
int endIdx = myProduction.size();
|
||||
if (before != null) {
|
||||
endIdx = myProduction.lastIndexOf(before);
|
||||
if (endIdx < 0) {
|
||||
LOG.error("'Before' marker has never been added.");
|
||||
}
|
||||
if (idx > endIdx) {
|
||||
LOG.error("'Before' marker precedes this one.");
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = endIdx - 1; i > idx; i--) {
|
||||
Object item = myProduction.get(i);
|
||||
if (item instanceof StartMarker) {
|
||||
StartMarker otherMarker = (StartMarker)item;
|
||||
if (otherMarker.myDoneMarker == null) {
|
||||
final Throwable debugAllocOther = otherMarker.myDebugAllocationPosition;
|
||||
final Throwable debugAllocThis = ((StartMarker)marker).myDebugAllocationPosition;
|
||||
if (debugAllocOther != null) {
|
||||
debugAllocThis.printStackTrace(System.err);
|
||||
debugAllocOther.printStackTrace(System.err);
|
||||
}
|
||||
LOG.error("Another not done marker added after this one. Must be done before this.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,9 +20,13 @@ import com.intellij.lexer.LexerBase;
|
||||
import com.intellij.psi.impl.DebugUtil;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.sun.tools.internal.xjc.util.NullStream;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
|
||||
public class LightPsiBuilderTest {
|
||||
@@ -140,6 +144,45 @@ public class LightPsiBuilderTest {
|
||||
" PsiElement(DIGIT)('1')\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidityChecksOnDone() throws Exception {
|
||||
doFailTest("a",
|
||||
new Parser() {
|
||||
public void parse(PsiBuilder builder) {
|
||||
final PsiBuilder.Marker first = builder.mark();
|
||||
builder.advanceLexer();
|
||||
builder.mark();
|
||||
first.done(LETTER);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidityChecksOnDoneBefore1() throws Exception {
|
||||
doFailTest("a",
|
||||
new Parser() {
|
||||
public void parse(PsiBuilder builder) {
|
||||
final PsiBuilder.Marker first = builder.mark();
|
||||
builder.advanceLexer();
|
||||
final PsiBuilder.Marker second = builder.mark();
|
||||
second.precede();
|
||||
first.doneBefore(LETTER, second);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidityChecksOnDoneBefore2() throws Exception {
|
||||
doFailTest("a",
|
||||
new Parser() {
|
||||
public void parse(PsiBuilder builder) {
|
||||
final PsiBuilder.Marker first = builder.mark();
|
||||
builder.advanceLexer();
|
||||
final PsiBuilder.Marker second = builder.mark();
|
||||
second.doneBefore(LETTER, first);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private interface Parser {
|
||||
void parse(PsiBuilder builder);
|
||||
@@ -154,6 +197,27 @@ public class LightPsiBuilderTest {
|
||||
assertEquals(expected, DebugUtil.nodeTreeToString(root, true));
|
||||
}
|
||||
|
||||
private static void doFailTest(final String text, final Parser parser) {
|
||||
final PrintStream std = System.err;
|
||||
//noinspection IOResourceOpenedButNotSafelyClosed
|
||||
System.setErr(new PrintStream(new NullStream()));
|
||||
try {
|
||||
try {
|
||||
final PsiBuilder builder = new PsiBuilderImpl(new MyTestLexer(), TokenSet.EMPTY, TokenSet.EMPTY, text);
|
||||
builder.setDebugMode(true);
|
||||
parser.parse(builder);
|
||||
fail("should fail");
|
||||
}
|
||||
catch (AssertionError e) {
|
||||
//System.out.println("caught: " + e);
|
||||
if ("should fail".equals(e.getMessage())) throw e;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
System.setErr(std);
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyTestLexer extends LexerBase {
|
||||
private CharSequence myBuffer = "";
|
||||
private int myIndex = 0;
|
||||
|
||||
Reference in New Issue
Block a user