diff --git a/java/idea-ui/src/com/intellij/ide/util/projectWizard/importSources/JavaSourceRootDetectionUtil.java b/java/idea-ui/src/com/intellij/ide/util/projectWizard/importSources/JavaSourceRootDetectionUtil.java index 1650d8f5a0b2..cf6466ffa24c 100644 --- a/java/idea-ui/src/com/intellij/ide/util/projectWizard/importSources/JavaSourceRootDetectionUtil.java +++ b/java/idea-ui/src/com/intellij/ide/util/projectWizard/importSources/JavaSourceRootDetectionUtil.java @@ -70,9 +70,10 @@ public class JavaSourceRootDetectionUtil { @Nullable public static String getPackageName(CharSequence text) { - Lexer lexer = JavaParserDefinition.createLexer(LanguageLevel.JDK_1_3); + Lexer lexer = JavaParserDefinition.createLexer(LanguageLevel.JDK_1_5); lexer.start(text); skipWhiteSpaceAndComments(lexer); + skipAnnotations(lexer); final IElementType firstToken = lexer.getTokenType(); if (firstToken != JavaTokenType.PACKAGE_KEYWORD) { if (JAVA_FILE_FIRST_TOKEN_SET.contains(firstToken)) { @@ -104,4 +105,54 @@ public class JavaSourceRootDetectionUtil { lexer.advance(); } } + + private static void skipAnnotations(Lexer lexer){ + while (lexer.getTokenType() == JavaTokenType.AT) { + lexer.advance(); + skipQualifiedIdentifier(lexer); + skipArguments(lexer); + skipWhiteSpaceAndComments(lexer); + } + } + + private static void skipQualifiedIdentifier(Lexer lexer) { + if (lexer.getTokenType() == JavaTokenType.IDENTIFIER) { + lexer.advance(); + skipWhiteSpaceAndComments(lexer); + while (lexer.getTokenType() == JavaTokenType.DOT) { + lexer.advance(); + skipWhiteSpaceAndComments(lexer); + if (lexer.getTokenType() != JavaTokenType.IDENTIFIER) { + break; + } + lexer.advance(); + skipWhiteSpaceAndComments(lexer); + } + skipWhiteSpaceAndComments(lexer); + } + } + + private static void skipArguments(Lexer lexer) { + skipWhiteSpaceAndComments(lexer); + if (lexer.getTokenType() == JavaTokenType.LPARENTH) { + lexer.advance(); + int depth = 1; + while (depth > 0) { + IElementType tokenType = lexer.getTokenType(); + if (tokenType == JavaTokenType.LPARENTH) { + depth++; + } + else if (tokenType == JavaTokenType.RPARENTH) { + depth--; + } + else { + if (tokenType == null) { + break; + } + } + lexer.advance(); + } + skipWhiteSpaceAndComments(lexer); + } + } } diff --git a/java/idea-ui/testSrc/com/intellij/ide/util/projectWizard/importSources/JavaSourceRootDetectionUtilTest.java b/java/idea-ui/testSrc/com/intellij/ide/util/projectWizard/importSources/JavaSourceRootDetectionUtilTest.java new file mode 100644 index 000000000000..2f543ec4fa4f --- /dev/null +++ b/java/idea-ui/testSrc/com/intellij/ide/util/projectWizard/importSources/JavaSourceRootDetectionUtilTest.java @@ -0,0 +1,65 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.ide.util.projectWizard.importSources; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * @author nik + */ +public class JavaSourceRootDetectionUtilTest { + @Test + public void simple() { + assertPackageDetected("package p; \n" + + "class A {}", "p"); + assertPackageDetected("package p; \n" + + "import java.util.Set;" + + "class A {}", "p"); + assertPackageDetected("class A {}", ""); + assertPackageDetected("import java.util.*;\n" + + "class A {}", ""); + assertPackageDetected("invalid", null); + } + + @Test + public void comments() { + assertPackageDetected("/* aa */ package p;", "p"); + assertPackageDetected("// aa\n" + + "package p;", "p"); + assertPackageDetected("/* a */ /* b */ package p;", "p"); + assertPackageDetected("package /* a */ p;", "p"); + assertPackageDetected("package p /* a */;", "p"); + } + + @Test + public void qualified() { + assertPackageDetected("package p.q;", "p.q"); + assertPackageDetected("package p . q;", "p.q"); + assertPackageDetected("package /* xxx */ p . q;", "p.q"); + assertPackageDetected("package p . /* xxx */ q;", "p.q"); + } + + @Test + public void validPackageAnnotation() { + assertPackageDetected("@Deprecated package p.q;", "p.q"); + assertPackageDetected("@java.lang.Deprecated package p.q;", "p.q"); + assertPackageDetected("@Generated(\"text\") package p.q;", "p.q"); + assertPackageDetected("@Generated( (\"text\") ) package p.q;", "p.q"); + assertPackageDetected("@Generated((\"text\"), (\"text\")) package p.q;", "p.q"); + assertPackageDetected("@Generated(\"text\")\n" + + "@Deprecated\n" + + "package p.q;", "p.q"); + assertPackageDetected("@Deprecated/*aa*/ package p.q;", "p.q"); + } + + @Test + public void invalidPackageAnnotation() { + assertPackageDetected("@Deprecatedpackage p.q;", null); + assertPackageDetected("@javax.annotation.Generated(\"text\" package p.q;", null); + } + + private static void assertPackageDetected(String text, String packageName) { + assertEquals(packageName, JavaSourceRootDetectionUtil.getPackageName(text)); + } +} diff --git a/java/java-tests/testData/ide/sourceRootDetection/packageWithAnnotation/src/pack/package-info.java b/java/java-tests/testData/ide/sourceRootDetection/packageWithAnnotation/src/pack/package-info.java new file mode 100644 index 000000000000..be9072177dcf --- /dev/null +++ b/java/java-tests/testData/ide/sourceRootDetection/packageWithAnnotation/src/pack/package-info.java @@ -0,0 +1,2 @@ +@Deprecated +package pack; diff --git a/java/java-tests/testSrc/com/intellij/java/ide/util/JavaSourceRootDetectionTest.java b/java/java-tests/testSrc/com/intellij/java/ide/util/JavaSourceRootDetectionTest.java index 831e08481e7d..e69a9a5fa1c7 100644 --- a/java/java-tests/testSrc/com/intellij/java/ide/util/JavaSourceRootDetectionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/ide/util/JavaSourceRootDetectionTest.java @@ -58,6 +58,10 @@ public class JavaSourceRootDetectionTest extends PlatformTestCase { doTest("src", ""); } + public void testPackageWithAnnotation() { + doTest("src", ""); + } + private void doTest(String... expected) { final String dirPath = JavaTestUtil.getJavaTestDataPath() + FileUtil.toSystemDependentName("/ide/sourceRootDetection/" + getTestName(true)); final File dir = new File(dirPath);