diff options
author | Tor Norbye <tnorbye@google.com> | 2013-04-24 10:43:41 -0700 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2013-04-24 10:43:41 -0700 |
commit | b17587c84879dd2ea42495f1fbdadbc806b9475b (patch) | |
tree | b4d9014f69cb8289627ddc75339a6b0b3fe1bc5e /java/java-psi-impl/src/com | |
parent | b569bc6aa78f6eacf72e8b90622d300e1a9db25f (diff) | |
download | idea-b17587c84879dd2ea42495f1fbdadbc806b9475b.tar.gz |
Snapshot e242282deb41c328afbe971fc167e47ddfb26df9 from master branch of git://git.jetbrains.org/idea/community.git
Change-Id: Ifdc1818cde7b63f6d7bf42801f18c7f1557b8d85
Diffstat (limited to 'java/java-psi-impl/src/com')
5 files changed, 313 insertions, 31 deletions
diff --git a/java/java-psi-impl/src/com/intellij/externalSystem/JavaProjectData.java b/java/java-psi-impl/src/com/intellij/externalSystem/JavaProjectData.java new file mode 100644 index 000000000000..d1f5bfa9503a --- /dev/null +++ b/java/java-psi-impl/src/com/intellij/externalSystem/JavaProjectData.java @@ -0,0 +1,163 @@ +/* + * 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.intellij.externalSystem; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.externalSystem.model.Key; +import com.intellij.openapi.externalSystem.model.ProjectSystemId; +import com.intellij.openapi.externalSystem.model.project.AbstractProjectEntityData; +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; +import com.intellij.openapi.projectRoots.JavaSdkVersion; +import com.intellij.pom.java.LanguageLevel; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author Denis Zhdanov + * @since 4/12/13 12:27 PM + */ +public class JavaProjectData extends AbstractProjectEntityData { + + @NotNull public static final Key<JavaProjectData> KEY = Key.create(JavaProjectData.class); + + private static final Logger LOG = Logger.getInstance("#" + JavaProjectData.class.getName()); + + private static final long serialVersionUID = 1L; + + private static final LanguageLevel DEFAULT_LANGUAGE_LEVEL = LanguageLevel.JDK_1_6; + private static final JavaSdkVersion DEFAULT_JDK_VERSION = JavaSdkVersion.JDK_1_6; + private static final Pattern JDK_VERSION_PATTERN = Pattern.compile(".*1\\.(\\d+).*"); + + @NotNull private JavaSdkVersion myJdkVersion = DEFAULT_JDK_VERSION; + @NotNull private LanguageLevel myLanguageLevel = DEFAULT_LANGUAGE_LEVEL; + + @NotNull private String myCompileOutputPath; + + public JavaProjectData(@NotNull ProjectSystemId owner, @NotNull String compileOutputPath) { + super(owner); + myCompileOutputPath = compileOutputPath; + } + + @NotNull + public String getCompileOutputPath() { + return myCompileOutputPath; + } + + public void setCompileOutputPath(@NotNull String compileOutputPath) { + myCompileOutputPath = ExternalSystemApiUtil.toCanonicalPath(compileOutputPath); + } + + @NotNull + public JavaSdkVersion getJdkVersion() { + return myJdkVersion; + } + + public void setJdkVersion(@NotNull JavaSdkVersion jdkVersion) { + myJdkVersion = jdkVersion; + } + + public void setJdkVersion(@Nullable String jdk) { + if (jdk == null) { + return; + } + try { + int version = Integer.parseInt(jdk.trim()); + if (applyJdkVersion(version)) { + return; + } + } + catch (NumberFormatException e) { + // Ignore. + } + + Matcher matcher = JDK_VERSION_PATTERN.matcher(jdk); + if (!matcher.matches()) { + return; + } + String versionAsString = matcher.group(1); + try { + applyJdkVersion(Integer.parseInt(versionAsString)); + } + catch (NumberFormatException e) { + // Ignore. + } + } + + public boolean applyJdkVersion(int version) { + if (version < 0 || version >= JavaSdkVersion.values().length) { + LOG.warn(String.format( + "Unsupported jdk version detected (%d). Expected to get number from range [0; %d]", version, JavaSdkVersion.values().length + )); + return false; + } + for (JavaSdkVersion sdkVersion : JavaSdkVersion.values()) { + if (sdkVersion.ordinal() == version) { + myJdkVersion = sdkVersion; + return true; + } + } + assert false : version + ", max value: " + JavaSdkVersion.values().length; + return false; + } + + @NotNull + public LanguageLevel getLanguageLevel() { + return myLanguageLevel; + } + + public void setLanguageLevel(@NotNull LanguageLevel level) { + myLanguageLevel = level; + } + + public void setLanguageLevel(@Nullable String languageLevel) { + LanguageLevel level = LanguageLevel.parse(languageLevel); + if (level != null) { + myLanguageLevel = level; + } + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + myJdkVersion.hashCode(); + result = 31 * result + myLanguageLevel.hashCode(); + result = 31 * result + myCompileOutputPath.hashCode(); + return result; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + + JavaProjectData project = (JavaProjectData)o; + + if (!myCompileOutputPath.equals(project.myCompileOutputPath)) return false; + if (myJdkVersion != project.myJdkVersion) return false; + if (myLanguageLevel != project.myLanguageLevel) return false; + + return true; + } + + @Override + public String toString() { + return "java project"; + } +} diff --git a/java/java-psi-impl/src/com/intellij/externalSystem/JavaProjectDataService.java b/java/java-psi-impl/src/com/intellij/externalSystem/JavaProjectDataService.java new file mode 100644 index 000000000000..05132a8b7734 --- /dev/null +++ b/java/java-psi-impl/src/com/intellij/externalSystem/JavaProjectDataService.java @@ -0,0 +1,114 @@ +/* + * 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.intellij.externalSystem; + +import com.intellij.openapi.externalSystem.model.DataNode; +import com.intellij.openapi.externalSystem.model.Key; +import com.intellij.openapi.externalSystem.model.ProjectSystemId; +import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataService; +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.JavaSdk; +import com.intellij.openapi.projectRoots.JavaSdkVersion; +import com.intellij.openapi.projectRoots.ProjectJdkTable; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.roots.LanguageLevelProjectExtension; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.pom.java.LanguageLevel; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.List; + +/** + * @author Denis Zhdanov + * @since 4/15/13 12:09 PM + */ +public class JavaProjectDataService implements ProjectDataService<JavaProjectData> { + + @NotNull + @Override + public Key<JavaProjectData> getTargetDataKey() { + return JavaProjectData.KEY; + } + + @Override + public void importData(@NotNull Collection<DataNode<JavaProjectData>> toImport, @NotNull Project project, boolean synchronous) { + if (toImport.size() != 1) { + throw new IllegalArgumentException(String.format("Expected to get a single project but got %d: %s", toImport.size(), toImport)); + } + JavaProjectData projectData = toImport.iterator().next().getData(); + + // JDK. + JavaSdkVersion version = projectData.getJdkVersion(); + JavaSdk javaSdk = JavaSdk.getInstance(); + ProjectRootManager rootManager = ProjectRootManager.getInstance(project); + Sdk sdk = rootManager.getProjectSdk(); + if (sdk instanceof JavaSdk) { + JavaSdkVersion currentVersion = javaSdk.getVersion(sdk); + if (currentVersion == null || !currentVersion.isAtLeast(version)) { + Sdk newJdk = findJdk(version); + if (newJdk != null) { + rootManager.setProjectSdk(sdk); + LanguageLevel level = version.getMaxLanguageLevel(); + LanguageLevelProjectExtension ext = LanguageLevelProjectExtension.getInstance(project); + if (level.compareTo(ext.getLanguageLevel()) < 0) { + ext.setLanguageLevel(level); + } + } + } + } + // Language level. + setLanguageLevel(projectData.getLanguageLevel(), project, synchronous); + } + + @Nullable + private static Sdk findJdk(@NotNull JavaSdkVersion version) { + JavaSdk javaSdk = JavaSdk.getInstance(); + List<Sdk> javaSdks = ProjectJdkTable.getInstance().getSdksOfType(javaSdk); + Sdk candidate = null; + for (Sdk sdk : javaSdks) { + JavaSdkVersion v = javaSdk.getVersion(sdk); + if (v == version) { + return sdk; + } + else if (candidate == null && v != null && version.getMaxLanguageLevel().isAtLeast(version.getMaxLanguageLevel())) { + candidate = sdk; + } + } + return candidate; + } + + @Override + public void removeData(@NotNull Collection<DataNode<JavaProjectData>> toRemove, @NotNull Project project, boolean synchronous) { + } + + @SuppressWarnings("MethodMayBeStatic") + public void setLanguageLevel(@NotNull final LanguageLevel languageLevel, @NotNull Project project, boolean synchronous) { + final LanguageLevelProjectExtension languageLevelExtension = LanguageLevelProjectExtension.getInstance(project); + if (languageLevelExtension.getLanguageLevel().isAtLeast(languageLevel)) { + return; + } + ExternalSystemApiUtil.executeProjectChangeAction(project, ProjectSystemId.IDE, synchronous, new Runnable() { + @Override + public void run() { + languageLevelExtension.setLanguageLevel(languageLevel); + } + }); + } + +} diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiElementFactoryImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiElementFactoryImpl.java index 27bf4b56426f..d0f86c7f8faa 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiElementFactoryImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiElementFactoryImpl.java @@ -21,7 +21,6 @@ import com.intellij.lang.java.parser.JavaParserUtil; import com.intellij.lexer.JavaLexer; import com.intellij.lexer.Lexer; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; @@ -200,7 +199,7 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps throw new IncorrectOperationException("Cannot create field with type \"null\"."); } - final String text = StringUtil.join("class _Dummy_ { private ", type.getCanonicalText(), " ", name, "; }"); + final String text = "class _Dummy_ { private " + type.getCanonicalText() + " " + name + "; }"; final PsiJavaFile aFile = createDummyJavaFile(text); final PsiClass[] classes = aFile.getClasses(); if (classes.length < 1) { @@ -225,7 +224,7 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps } final String canonicalText = returnType.getCanonicalText(); - final PsiJavaFile aFile = createDummyJavaFile(StringUtil.join("class _Dummy_ { public " + canonicalText, " ", name, "() {} }")); + final PsiJavaFile aFile = createDummyJavaFile("class _Dummy_ { public " + canonicalText + " " + name + "() {} }"); final PsiClass[] classes = aFile.getClasses(); if (classes.length < 1) { throw new IncorrectOperationException("Class was not created. Method name: " + name + "; return type: " + canonicalText); @@ -248,7 +247,7 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps @NotNull @Override public PsiMethod createConstructor(@NotNull @NonNls final String name) { - final PsiJavaFile aFile = createDummyJavaFile(StringUtil.join("class ", name, " { public ", name, "() {} }")); + final PsiJavaFile aFile = createDummyJavaFile("class " + name + " { public " + name + "() {} }"); final PsiMethod method = aFile.getClasses()[0].getMethods()[0]; return (PsiMethod)CodeStyleManager.getInstance(myManager.getProject()).reformat(method); } @@ -274,7 +273,7 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps throw new IncorrectOperationException("Cannot create parameter with type \"null\"."); } - final String text = StringUtil.join(type.getCanonicalText() + " " + name); + final String text = type.getCanonicalText() + " " + name; PsiParameter parameter = createParameterFromText(text, null); final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(myManager.getProject()); PsiUtil.setModifierProperty(parameter, PsiModifier.FINAL, @@ -429,7 +428,7 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps @NotNull @Override public PsiPackageStatement createPackageStatement(@NotNull final String name) throws IncorrectOperationException { - final PsiJavaFile aFile = createDummyJavaFile(StringUtil.join("package ", name, ";")); + final PsiJavaFile aFile = createDummyJavaFile("package " + name + ";"); final PsiPackageStatement stmt = aFile.getPackageStatement(); if (stmt == null) { throw new IncorrectOperationException("Incorrect package name: " + name); @@ -448,7 +447,7 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps throw new IncorrectOperationException("Cannot create import statement for local class."); } - final PsiJavaFile aFile = createDummyJavaFile(StringUtil.join("import static ", aClass.getQualifiedName(), ".", memberName, ";")); + final PsiJavaFile aFile = createDummyJavaFile("import static " + aClass.getQualifiedName() + "." + memberName + ";"); final PsiImportStatementBase statement = extractImport(aFile, true); return (PsiImportStaticStatement)CodeStyleManager.getInstance(myManager.getProject()).reformat(statement); } @@ -548,7 +547,7 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps throw new IncorrectOperationException("Cannot create import statement for local class."); } - final PsiJavaFile aFile = createDummyJavaFile(StringUtil.join("import ", aClass.getQualifiedName(), ";")); + final PsiJavaFile aFile = createDummyJavaFile("import " + aClass.getQualifiedName() + ";"); final PsiImportStatementBase statement = extractImport(aFile, false); return (PsiImportStatement)CodeStyleManager.getInstance(myManager.getProject()).reformat(statement); } @@ -563,7 +562,7 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps throw new IncorrectOperationException("Incorrect package name: \"" + packageName + "\"."); } - final PsiJavaFile aFile = createDummyJavaFile(StringUtil.join("import ", packageName, ".*;")); + final PsiJavaFile aFile = createDummyJavaFile("import " + packageName + ".*;"); final PsiImportStatementBase statement = extractImport(aFile, false); return (PsiImportStatement)CodeStyleManager.getInstance(myManager.getProject()).reformat(statement); } @@ -580,7 +579,7 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps throw new IncorrectOperationException("Cannot create variable with type \"null\"."); } - final String text = "X " + (initializer != null ? " = x" : "") + " = x"; + final String text = "X " + name + (initializer != null ? " = x" : "") + ";"; final PsiDeclarationStatement statement = (PsiDeclarationStatement)createStatementFromText(text, null); final PsiVariable variable = (PsiVariable)statement.getDeclaredElements()[0]; @@ -719,7 +718,7 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps throw new IncorrectOperationException("Unexpected type:" + exceptionType); } - final String text = StringUtil.join("catch (", exceptionType.getCanonicalText(), " ", exceptionName, ") {}"); + final String text = "catch (" + exceptionType.getCanonicalText() + " " + exceptionName + ") {}"; final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, CATCH_SECTION, level(context)), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); if (!(element instanceof PsiCatchSection)) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiTypeElementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiTypeElementImpl.java index 4c837556371a..cc46b4bd5cd0 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiTypeElementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiTypeElementImpl.java @@ -16,11 +16,13 @@ package com.intellij.psi.impl.source; import com.intellij.lang.ASTNode; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.*; import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.impl.source.codeStyle.CodeEditUtil; -import com.intellij.psi.impl.source.tree.*; +import com.intellij.psi.impl.source.tree.CompositePsiElement; +import com.intellij.psi.impl.source.tree.ElementType; +import com.intellij.psi.impl.source.tree.JavaElementType; +import com.intellij.psi.impl.source.tree.TreeElement; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; @@ -36,8 +38,6 @@ import org.jetbrains.annotations.Nullable; import java.util.List; public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeElement { - private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.PsiTypeElementImpl"); - private volatile PsiType myCachedType = null; @SuppressWarnings({"UnusedDeclaration"}) @@ -120,22 +120,16 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl if (PsiUtil.isJavaToken(child, JavaTokenType.QUEST)) { assert type == null : this; - PsiElement next = PsiTreeUtil.skipSiblingsForward(child, PsiComment.class, PsiWhiteSpace.class); - if (next == null) { - type = PsiWildcardType.createUnbounded(getManager()); + PsiElement boundKind = PsiTreeUtil.skipSiblingsForward(child, PsiComment.class, PsiWhiteSpace.class); + PsiElement boundType = PsiTreeUtil.skipSiblingsForward(boundKind, PsiComment.class, PsiWhiteSpace.class); + if (PsiUtil.isJavaToken(boundKind, JavaTokenType.EXTENDS_KEYWORD) && boundType instanceof PsiTypeElement) { + type = PsiWildcardType.createExtends(getManager(), ((PsiTypeElement)boundType).getType()); + } + else if (PsiUtil.isJavaToken(boundKind, JavaTokenType.SUPER_KEYWORD) && boundType instanceof PsiTypeElement) { + type = PsiWildcardType.createSuper(getManager(), ((PsiTypeElement)boundType).getType()); } else { - PsiElement bound = PsiTreeUtil.skipSiblingsForward(next, PsiComment.class, PsiWhiteSpace.class); - if (PsiUtil.isJavaToken(next, JavaTokenType.EXTENDS_KEYWORD) && bound instanceof PsiTypeElement) { - type = PsiWildcardType.createExtends(getManager(), ((PsiTypeElement)bound).getType()); - } - else if (PsiUtil.isJavaToken(next, JavaTokenType.SUPER_KEYWORD) && bound instanceof PsiTypeElement) { - type = PsiWildcardType.createSuper(getManager(), ((PsiTypeElement)bound).getType()); - } - else { - LOG.error("next=" + next + " bound=" + bound + ": " + this); - type = PsiWildcardType.createUnbounded(getManager()); - } + type = PsiWildcardType.createUnbounded(getManager()); } PsiAnnotation[] array = ContainerUtil.copyAndClear(annotations, PsiAnnotation.ARRAY_FACTORY, true); type = ((PsiWildcardType)type).annotate(array); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ClassElement.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ClassElement.java index 8b33ab278903..712b32ca6d5b 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ClassElement.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ClassElement.java @@ -26,6 +26,7 @@ import com.intellij.psi.impl.source.tree.*; import com.intellij.psi.tree.ChildRoleBase; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; +import com.intellij.psi.util.PsiUtil; import com.intellij.util.CharTable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -134,12 +135,17 @@ public class ClassElement extends CompositeElement implements Constants { } } else if (psiClass.isInterface()) { + final boolean level8OrHigher = PsiUtil.isLanguageLevel8OrHigher(psiClass); for (ASTNode child = first; child != afterLast; child = next) { next = child.getTreeNext(); - if (child.getElementType() == JavaElementType.METHOD || child.getElementType() == JavaElementType.FIELD) { + final IElementType childElementType = child.getElementType(); + if (childElementType == JavaElementType.METHOD || childElementType == JavaElementType.FIELD) { CompositeElement modifierList = (CompositeElement)((CompositeElement)child).findChildByRole(ChildRole.MODIFIER_LIST); + final TokenSet removeModifiersBitSet = level8OrHigher && childElementType == JavaElementType.METHOD + ? MODIFIERS_TO_REMOVE_IN_INTERFACE_BIT_SET_18_METHOD + : MODIFIERS_TO_REMOVE_IN_INTERFACE_BIT_SET; while (true) { - ASTNode modifier = modifierList.findChildByType(MODIFIERS_TO_REMOVE_IN_INTERFACE_BIT_SET); + ASTNode modifier = modifierList.findChildByType(removeModifiersBitSet); if (modifier == null) break; modifierList.deleteChildInternal(modifier); } @@ -233,6 +239,12 @@ public class ClassElement extends CompositeElement implements Constants { NATIVE_KEYWORD ); + private static final TokenSet MODIFIERS_TO_REMOVE_IN_INTERFACE_BIT_SET_18_METHOD = TokenSet.create( + PUBLIC_KEYWORD, ABSTRACT_KEYWORD, + FINAL_KEYWORD, + NATIVE_KEYWORD + ); + private static final TokenSet MODIFIERS_TO_REMOVE_IN_ENUM_BIT_SET = TokenSet.create( PUBLIC_KEYWORD, FINAL_KEYWORD ); |