diff --git a/java/java-psi-impl/src/com/intellij/lang/java/parser/FileParser.java b/java/java-psi-impl/src/com/intellij/lang/java/parser/FileParser.java index eeee97774d96..6b9f154ebe93 100644 --- a/java/java-psi-impl/src/com/intellij/lang/java/parser/FileParser.java +++ b/java/java-psi-impl/src/com/intellij/lang/java/parser/FileParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -55,19 +55,14 @@ public class FileParser { @NotNull final String errorMessageKey) { parsePackageStatement(builder); - final Pair impListInfo = parseImportList(builder, importListStoppers); + Pair impListInfo = parseImportList(builder, importListStoppers); Boolean firstDeclarationOk = null; PsiBuilder.Marker firstDeclaration = null; PsiBuilder.Marker invalidElements = null; while (!builder.eof()) { if (builder.getTokenType() == JavaTokenType.SEMICOLON) { - if (invalidElements != null) { - invalidElements.error(error(bundle, errorMessageKey)); - invalidElements = null; - } builder.advanceLexer(); - if (firstDeclarationOk == null) firstDeclarationOk = false; continue; } @@ -124,7 +119,7 @@ public class FileParser { final PsiBuilder.Marker ref = myParser.getReferenceParser().parseJavaCodeReference(builder, true, false, false, false); if (ref == null) { - statement.rollbackTo(); + statement.error(JavaErrorMessages.message("expected.class.or.interface")); return null; } @@ -136,13 +131,21 @@ public class FileParser { @NotNull public Pair parseImportList(final PsiBuilder builder, final TokenSet stoppers) { - final PsiBuilder.Marker list = builder.mark(); + PsiBuilder.Marker list = builder.mark(); - final boolean isEmpty = builder.getTokenType() != JavaTokenType.IMPORT_KEYWORD; + IElementType tokenType = builder.getTokenType(); + boolean isEmpty = tokenType != JavaTokenType.IMPORT_KEYWORD && tokenType != JavaTokenType.SEMICOLON; if (!isEmpty) { PsiBuilder.Marker invalidElements = null; while (!builder.eof()) { - if (stoppers.contains(builder.getTokenType())) break; + tokenType = builder.getTokenType(); + if (stoppers.contains(tokenType)) { + break; + } + else if (tokenType == JavaTokenType.SEMICOLON) { + builder.advanceLexer(); + continue; + } final PsiBuilder.Marker statement = parseImportStatement(builder); if (statement != null) { diff --git a/java/java-tests/testData/psi/parser-partial/files/ExtraSemicolons.txt b/java/java-tests/testData/psi/parser-partial/files/ExtraSemicolons.txt new file mode 100644 index 000000000000..d7618538bd15 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/files/ExtraSemicolons.txt @@ -0,0 +1,37 @@ +PsiJavaFile:ExtraSemicolons.java + PsiPackageStatement:p + PsiKeyword:package('package') + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:p + PsiIdentifier:p('p') + PsiReferenceParameterList + + PsiJavaToken:SEMICOLON(';') + PsiImportList + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace('\n') + PsiImportStatement + PsiKeyword:import('import') + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:a + PsiIdentifier:a('a') + PsiReferenceParameterList + + PsiJavaToken:SEMICOLON(';') + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace('\n') + PsiClass:C + PsiModifierList: + + PsiKeyword:class('class') + PsiWhiteSpace(' ') + PsiIdentifier:C('C') + PsiTypeParameterList + + PsiReferenceList + + PsiReferenceList + + PsiJavaToken:LBRACE('{') + PsiJavaToken:RBRACE('}') + PsiJavaToken:SEMICOLON(';') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/files/UnclosedPackage0.txt b/java/java-tests/testData/psi/parser-partial/files/UnclosedPackage0.txt index cc9866bf1040..bd210adf7e67 100644 --- a/java/java-tests/testData/psi/parser-partial/files/UnclosedPackage0.txt +++ b/java/java-tests/testData/psi/parser-partial/files/UnclosedPackage0.txt @@ -1,5 +1,5 @@ PsiJavaFile:UnclosedPackage0.java - PsiImportList - PsiErrorElement:'class' or 'interface' expected - PsiKeyword:package('package') \ No newline at end of file + PsiKeyword:package('package') + PsiImportList + \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/FileParserTest.java b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/FileParserTest.java index 52766f5d2c8e..8b3969273225 100644 --- a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/FileParserTest.java +++ b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/FileParserTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -19,7 +19,6 @@ import com.intellij.lang.PsiBuilder; import com.intellij.lang.java.parser.JavaParser; import com.intellij.lang.java.parser.JavaParsingTestCase; - public class FileParserTest extends JavaParsingTestCase { public FileParserTest() { super("parser-partial/files"); @@ -41,6 +40,10 @@ public class FileParserTest extends JavaParsingTestCase { public void testUnclosedImport2() { doParserTest("import java.awt."); } public void testUnclosedImport3() { doParserTest("import static a"); } + public void testExtraSemicolons() { doParserTest("package p;;\n" + + "import a;;\n" + + "class C{};"); } + public void testFileWithClass() { doParserTest("package a;\n" + "import b;\n" + "public class C { }\n" + diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessarySemicolonInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessarySemicolonInspection.java index 05b38609a4df..5c014906557f 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessarySemicolonInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessarySemicolonInspection.java @@ -20,6 +20,7 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; @@ -93,29 +94,27 @@ public class UnnecessarySemicolonInspection extends BaseInspection { } } - private static class UnnecessarySemicolonVisitor - extends BaseInspectionVisitor { - - /** - * Finds semicolons between the top level classes in a java file. - */ + private static class UnnecessarySemicolonVisitor extends BaseInspectionVisitor { @Override public void visitFile(PsiFile file) { - final PsiElement firstChild = file.getFirstChild(); - PsiElement sibling = skipForwardWhiteSpacesAndComments(firstChild); - while (sibling != null) { - if (sibling instanceof PsiJavaToken) { - final PsiJavaToken token = (PsiJavaToken)sibling; - final IElementType tokenType = token.getTokenType(); - if (tokenType.equals(JavaTokenType.SEMICOLON)) { - registerError(sibling); - } - } - sibling = skipForwardWhiteSpacesAndComments(sibling); - } + findTopLevelSemicolons(file); super.visitFile(file); } + @Override + public void visitImportList(PsiImportList list) { + findTopLevelSemicolons(list); + super.visitImportList(list); + } + + private void findTopLevelSemicolons(PsiElement element) { + for (PsiElement sibling = element.getFirstChild(); sibling != null; sibling = skipForwardWhiteSpacesAndComments(sibling)) { + if (PsiUtil.isJavaToken(sibling, JavaTokenType.SEMICOLON)) { + registerError(sibling); + } + } + } + @Override public void visitClass(@NotNull PsiClass aClass) { super.visitClass(aClass); diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessary_semicolon/UnnecessarySemicolonInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessary_semicolon/UnnecessarySemicolonInspection.java index 13d978b455d1..25ae055fe781 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessary_semicolon/UnnecessarySemicolonInspection.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessary_semicolon/UnnecessarySemicolonInspection.java @@ -1,6 +1,21 @@ +/* + * Copyright 2000-2013 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 com.siyeh.igtest.style.unnecessary_semicolon;; -; +import java.util.List;; public class UnnecessarySemicolonInspection { int i;