diff --git a/build/scripts/layouts.gant b/build/scripts/layouts.gant index e866606c5852..c32d10a8ced1 100644 --- a/build/scripts/layouts.gant +++ b/build/scripts/layouts.gant @@ -664,8 +664,9 @@ def setPluginVersionAndSince(String moduleName, String version) { if (file.isFile()) { def text = file.text if (!text.contains("")) { - def nextMajorVersion = Integer.parseInt(version.substring(0, version.indexOf('.'))) + 1 - file.text = text.replace("", "\n ${version}\n \n") + def dotIndex = version.indexOf('.') + def untilBuild = dotIndex > 0 ? (Integer.parseInt(version.substring(0, dotIndex)) + 1).toString() + ".0" : version + file.text = text.replace("", "\n ${version}\n \n") } } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java index f563f316422b..5448aff23bb9 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java @@ -740,7 +740,7 @@ public class GenericsHighlightUtil { if (type instanceof PsiClassType && ((PsiClassType)type).resolve() == aClass) return null; } - if (PsiUtil.isCompileTimeConstant(field)) return null; + if (PsiUtil.isCompileTimeConstant((PsiVariable)field)) return null; String description = JavaErrorMessages.message( "illegal.to.access.static.member.from.enum.constructor.or.instance.initializer", diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java index 830678b58b1e..0dbd868f5144 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java @@ -292,7 +292,7 @@ public class HighlightClassUtil { } PsiField field = (PsiField)keyword.getParent().getParent(); - if (PsiUtilCore.hasErrorElementChild(field) || PsiUtil.isCompileTimeConstant(field)) { + if (PsiUtilCore.hasErrorElementChild(field) || PsiUtil.isCompileTimeConstant((PsiVariable)field)) { return null; } diff --git a/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java b/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java index 905bba345c72..bd39b5f96f47 100644 --- a/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java +++ b/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java @@ -21,7 +21,7 @@ import com.intellij.codeInsight.ExternalAnnotationsManager; import com.intellij.codeInsight.InferredAnnotationsManager; import com.intellij.codeInsight.documentation.DocumentationManagerProtocol; import com.intellij.codeInsight.documentation.DocumentationManagerUtil; -import com.intellij.javadoc.JavadocConfiguration; +import com.intellij.javadoc.JavadocGeneratorRunProfile; import com.intellij.lang.ASTNode; import com.intellij.lang.LangBundle; import com.intellij.openapi.diagnostic.Logger; @@ -233,7 +233,7 @@ public class JavaDocInfoGenerator { myProject = project; myElement = element; - Sdk jdk = JavadocConfiguration.getSdk(myProject); + Sdk jdk = JavadocGeneratorRunProfile.getSdk(myProject); mySdkVersion = jdk == null ? null : JavaSdk.getInstance().getVersion(jdk); } diff --git a/java/java-impl/src/com/intellij/javadoc/JavadocConfigurable.java b/java/java-impl/src/com/intellij/javadoc/JavadocConfigurable.java index d0d6ad8ff11b..0f51d477408c 100644 --- a/java/java-impl/src/com/intellij/javadoc/JavadocConfigurable.java +++ b/java/java-impl/src/com/intellij/javadoc/JavadocConfigurable.java @@ -16,6 +16,9 @@ package com.intellij.javadoc; import com.intellij.openapi.options.Configurable; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.roots.JavadocOrderRootType; import com.intellij.psi.PsiKeyword; import javax.swing.*; @@ -24,14 +27,21 @@ import java.io.File; public final class JavadocConfigurable implements Configurable { private JavadocGenerationPanel myPanel; private final JavadocConfiguration myConfiguration; + private final Project myProject; - public JavadocConfigurable(JavadocConfiguration configuration) { + public JavadocConfigurable(JavadocConfiguration configuration, Project project) { myConfiguration = configuration; + myProject = project; + } + + public static boolean sdkHasJavadocUrls(Project project) { + Sdk sdk = JavadocGeneratorRunProfile.getSdk(project); + return sdk != null && sdk.getRootProvider().getFiles(JavadocOrderRootType.getInstance()).length > 0; } public JComponent createComponent() { myPanel = new JavadocGenerationPanel(); - myPanel.myLinkToJdkDocs.setEnabled(myConfiguration.sdkHasJavadocUrls()); + myPanel.myLinkToJdkDocs.setEnabled(sdkHasJavadocUrls(myProject)); return myPanel.myPanel; } diff --git a/java/java-impl/src/com/intellij/javadoc/JavadocConfiguration.java b/java/java-impl/src/com/intellij/javadoc/JavadocConfiguration.java index ae35f7e616d5..5ac31e88f656 100644 --- a/java/java-impl/src/com/intellij/javadoc/JavadocConfiguration.java +++ b/java/java-impl/src/com/intellij/javadoc/JavadocConfiguration.java @@ -15,57 +15,21 @@ */ package com.intellij.javadoc; -import com.intellij.analysis.AnalysisScope; -import com.intellij.execution.CantRunException; -import com.intellij.execution.ExecutionException; -import com.intellij.execution.Executor; -import com.intellij.execution.configurations.*; -import com.intellij.execution.filters.RegexpFilter; -import com.intellij.execution.process.OSProcessHandler; -import com.intellij.execution.process.ProcessAdapter; -import com.intellij.execution.process.ProcessEvent; -import com.intellij.execution.process.ProcessTerminatedListener; -import com.intellij.execution.runners.ExecutionEnvironment; -import com.intellij.ide.BrowserUtil; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleUtilCore; -import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.projectRoots.JavaSdk; -import com.intellij.openapi.projectRoots.JavaSdkType; -import com.intellij.openapi.projectRoots.JavaSdkVersion; -import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.projectRoots.ex.PathUtilEx; -import com.intellij.openapi.roots.*; -import com.intellij.openapi.util.*; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.VfsUtil; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.*; -import com.intellij.util.PathsList; -import com.intellij.util.containers.HashSet; +import com.intellij.openapi.util.DefaultJDOMExternalizer; +import com.intellij.openapi.util.InvalidDataException; +import com.intellij.openapi.util.JDOMExternalizable; +import com.intellij.openapi.util.WriteExternalException; +import com.intellij.psi.PsiKeyword; import org.jdom.Element; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes; -import javax.swing.*; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.Collection; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; +import java.lang.reflect.Field; /** * @author Eugene Zhuravlev * Date: Apr 24, 2004 */ -public class JavadocConfiguration implements ModuleRunProfile, JDOMExternalizable{ +public class JavadocConfiguration implements JDOMExternalizable { public String OUTPUT_DIRECTORY; public String OPTION_SCOPE = PsiKeyword.PROTECTED; public boolean OPTION_HIERARCHY = true; @@ -81,46 +45,10 @@ public class JavadocConfiguration implements ModuleRunProfile, JDOMExternalizabl public String HEAP_SIZE; public String LOCALE; public boolean OPEN_IN_BROWSER = true; - - private final Project myProject; - private AnalysisScope myGenerationScope; - private static final Logger LOGGER = Logger.getInstance("#" + JavadocConfiguration.class.getName()); public boolean OPTION_INCLUDE_LIBS = false; public boolean OPTION_LINK_TO_JDK_DOCS = false; - public void setGenerationScope(AnalysisScope generationScope) { - myGenerationScope = generationScope; - } - - public JavadocConfiguration(Project project) { - myProject = project; - } - - public RunProfileState getState(@NotNull final Executor executor, @NotNull final ExecutionEnvironment env) throws ExecutionException { - return new MyJavaCommandLineState(myProject, myGenerationScope, env); - } - - public String getName() { - return JavadocBundle.message("javadoc.settings.title"); - } - - public void checkConfiguration() throws RuntimeConfigurationException { - if (myGenerationScope == null) { - throw new RuntimeConfigurationError(JavadocBundle.message("javadoc.settings.not.specified")); - } - } - - public JavadocConfigurable createConfigurable() { - return new JavadocConfigurable(this); - } - - public Icon getIcon() { - return null; - } - - @NotNull - public Module[] getModules() { - return Module.EMPTY_ARRAY; + public JavadocConfiguration() { } public void readExternal(Element element) throws InvalidDataException { @@ -128,280 +56,12 @@ public class JavadocConfiguration implements ModuleRunProfile, JDOMExternalizabl } public void writeExternal(Element element) throws WriteExternalException { - DefaultJDOMExternalizer.writeExternal(this, element); - } - - public boolean sdkHasJavadocUrls() { - Sdk sdk = getSdk(myProject); - return sdk != null && sdk.getRootProvider().getFiles(JavadocOrderRootType.getInstance()).length > 0; - } - - public static Sdk getSdk(@NotNull Project project) { - return PathUtilEx.getAnyJdk(project); - } - - private class MyJavaCommandLineState extends CommandLineState { - private final AnalysisScope myGenerationOptions; - private final Project myProject; - @NonNls private static final String INDEX_HTML = "index.html"; - - public MyJavaCommandLineState(Project project, AnalysisScope generationOptions, ExecutionEnvironment env) { - super(env); - myGenerationOptions = generationOptions; - myProject = project; - addConsoleFilters(new RegexpFilter(project, "$FILE_PATH$:$LINE$:[^\\^]+\\^"), - new RegexpFilter(project, "$FILE_PATH$:$LINE$: warning - .+$")); - } - - protected GeneralCommandLine createCommandLine() throws ExecutionException { - final GeneralCommandLine cmdLine = new GeneralCommandLine(); - final Sdk jdk = getSdk(myProject); - setupExeParams(jdk, cmdLine); - setupProgramParameters(jdk, cmdLine); - return cmdLine; - } - - private void setupExeParams(final Sdk jdk, GeneralCommandLine cmdLine) throws ExecutionException { - final String jdkPath = jdk != null && jdk.getSdkType() instanceof JavaSdkType ? ((JavaSdkType)jdk.getSdkType()).getBinPath(jdk) : null; - if (jdkPath == null) { - throw new CantRunException(JavadocBundle.message("javadoc.generate.no.jdk.path")); + DefaultJDOMExternalizer.writeExternal(this, element, new DefaultJDOMExternalizer.JDOMFilter() { + @Override + public boolean isAccept(@NotNull Field field) { + return !field.getName().equals("OPTION_LINK_TO_JDK_DOCS") || OPTION_LINK_TO_JDK_DOCS; } - JavaSdkVersion version = JavaSdk.getInstance().getVersion(jdk); - if (HEAP_SIZE != null && HEAP_SIZE.trim().length() != 0) { - if (version == null || version.isAtLeast(JavaSdkVersion.JDK_1_2)) { - cmdLine.getParametersList().prepend("-J-Xmx" + HEAP_SIZE + "m"); - } - else { - cmdLine.getParametersList().prepend("-J-mx" + HEAP_SIZE + "m"); - } - } - cmdLine.setWorkDirectory((File)null); - @NonNls final String javadocExecutableName = File.separator + (SystemInfo.isWindows ? "javadoc.exe" : "javadoc"); - @NonNls String exePath = jdkPath.replace('/', File.separatorChar) + javadocExecutableName; - if (new File(exePath).exists()) { - cmdLine.setExePath(exePath); - } else { //try to use wrapper jdk - exePath = new File(jdkPath).getParent().replace('/', File.separatorChar) + javadocExecutableName; - if (!new File(exePath).exists()){ - final File parent = new File(System.getProperty("java.home")).getParentFile(); //try system jre - exePath = parent.getPath() + File.separator + "bin" + javadocExecutableName; - if (!new File(exePath).exists()){ - throw new CantRunException(JavadocBundle.message("javadoc.generate.no.jdk.path")); - } - } - cmdLine.setExePath(exePath); - } - } - - private void setupProgramParameters(final Sdk jdk, final GeneralCommandLine cmdLine) throws CantRunException { - @NonNls final ParametersList parameters = cmdLine.getParametersList(); - - if (LOCALE != null && LOCALE.length() > 0) { - parameters.add("-locale"); - parameters.add(LOCALE); - } - - if (OPTION_SCOPE != null) { - parameters.add("-" + OPTION_SCOPE); - } - - if (!OPTION_HIERARCHY) { - parameters.add("-notree"); - } - - if (!OPTION_NAVIGATOR) { - parameters.add("-nonavbar"); - } - - if (!OPTION_INDEX) { - parameters.add("-noindex"); - } - else if (OPTION_SEPARATE_INDEX) { - parameters.add("-splitindex"); - } - - if (OPTION_DOCUMENT_TAG_USE) { - parameters.add("-use"); - } - - if (OPTION_DOCUMENT_TAG_AUTHOR) { - parameters.add("-author"); - } - - if (OPTION_DOCUMENT_TAG_VERSION) { - parameters.add("-version"); - } - - if (!OPTION_DOCUMENT_TAG_DEPRECATED) { - parameters.add("-nodeprecated"); - } - else if (!OPTION_DEPRECATED_LIST) { - parameters.add("-nodeprecatedlist"); - } - - parameters.addParametersString(OTHER_OPTIONS); - - final Set modules = new LinkedHashSet(); - try { - final File sourcePathTempFile = FileUtil.createTempFile("javadoc", "args.txt", true); - parameters.add("@" + sourcePathTempFile.getCanonicalPath()); - final PrintWriter writer = new PrintWriter(new FileWriter(sourcePathTempFile)); - try { - final Collection packages = new HashSet(); - final Collection sources = new HashSet(); - final Runnable findRunnable = new Runnable() { - public void run() { - final int scopeType = myGenerationOptions.getScopeType(); - final boolean usePackageNotation = scopeType == AnalysisScope.MODULE || - scopeType == AnalysisScope.MODULES || - scopeType == AnalysisScope.PROJECT || - scopeType == AnalysisScope.DIRECTORY; - myGenerationOptions.accept(new MyContentIterator(myProject, packages, sources, modules, usePackageNotation)); - } - }; - if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(findRunnable, "Search for sources to generate javadoc in...", true, myProject)) { - return; - } - if (packages.size() + sources.size() == 0) { - throw new CantRunException(JavadocBundle.message("javadoc.generate.no.classes.in.selected.packages.error")); - } - for (String aPackage : packages) { - writer.println(aPackage); - } - //http://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#runningjavadoc - for (String source : sources) { - writer.println(StringUtil.wrapWithDoubleQuote(source)); - } - writer.println("-sourcepath"); - OrderEnumerator enumerator = OrderEnumerator.orderEntries(myProject); - if (!OPTION_INCLUDE_LIBS) { - enumerator = enumerator.withoutSdk().withoutLibraries(); - } - final PathsList pathsList = enumerator.getSourcePathsList(); - final List files = pathsList.getRootDirs(); - final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(myProject).getFileIndex(); - final StringBuilder sourcePath = new StringBuilder(); - boolean start = true; - for (VirtualFile file : files) { - if (!myGenerationOptions.isIncludeTestSource() && fileIndex.isInTestSourceContent(file)) continue; - if (start) { - start = false; - } - else { - sourcePath.append(File.pathSeparator); - } - sourcePath.append(file.getPath()); - } - writer.println(StringUtil.wrapWithDoubleQuote(sourcePath.toString())); - } - finally { - writer.close(); - } - } - catch (IOException e) { - LOGGER.error(e); - } - - if (OPTION_LINK_TO_JDK_DOCS) { - VirtualFile[] docUrls = jdk.getRootProvider().getFiles(JavadocOrderRootType.getInstance()); - for (VirtualFile docUrl : docUrls) { - parameters.add("-link"); - parameters.add(VfsUtil.toUri(docUrl).toString()); - } - } - - final PathsList classPath; - final OrderEnumerator orderEnumerator = ProjectRootManager.getInstance(myProject).orderEntries(modules); - if (jdk.getSdkType() instanceof JavaSdk) { - classPath = orderEnumerator.withoutSdk().withoutModuleSourceEntries().getPathsList(); - } - else { - //libraries are included into jdk - classPath = orderEnumerator.withoutModuleSourceEntries().getPathsList(); - } - final String classPathString = classPath.getPathsString(); - if (classPathString.length() > 0) { - parameters.add("-classpath"); - parameters.add(classPathString); - } - - if (OUTPUT_DIRECTORY != null) { - parameters.add("-d"); - parameters.add(OUTPUT_DIRECTORY.replace('/', File.separatorChar)); - } - - } - - @NotNull - protected OSProcessHandler startProcess() throws ExecutionException { - final OSProcessHandler handler = JavaCommandLineStateUtil.startProcess(createCommandLine()); - ProcessTerminatedListener.attach(handler, myProject, JavadocBundle.message("javadoc.generate.exited")); - handler.addProcessListener(new ProcessAdapter() { - public void processTerminated(ProcessEvent event) { - if (OPEN_IN_BROWSER) { - File url = new File(OUTPUT_DIRECTORY, INDEX_HTML); - if (url.exists() && event.getExitCode() == 0) { - BrowserUtil.browse(url); - } - } - } - }); - return handler; - } - } - - private static class MyContentIterator extends PsiRecursiveElementWalkingVisitor { - private final PsiManager myPsiManager; - private final Collection myPackages; - private final Collection mySourceFiles; - private final Set myModules; - private final boolean myUsePackageNotation; - - public MyContentIterator(Project project, - Collection packages, - Collection sources, - Set modules, - boolean canUsePackageNotation) { - myModules = modules; - myUsePackageNotation = canUsePackageNotation; - myPsiManager = PsiManager.getInstance(project); - myPackages = packages; - mySourceFiles = sources; - } - - @Override - public void visitFile(PsiFile file) { - final VirtualFile fileOrDir = file.getVirtualFile(); - if (fileOrDir == null) return; - if (!fileOrDir.isInLocalFileSystem()) return; - final Module module = ModuleUtilCore.findModuleForFile(fileOrDir, myPsiManager.getProject()); - if (module != null) { - myModules.add(module); - } - if (file instanceof PsiJavaFile) { - final PsiJavaFile javaFile = (PsiJavaFile)file; - final String packageName = javaFile.getPackageName(); - if (containsPackagePrefix(module, packageName) || (packageName.length() == 0 && !(javaFile instanceof ServerPageFile)) || !myUsePackageNotation) { - mySourceFiles.add(FileUtil.toSystemIndependentName(fileOrDir.getPath())); - } - else { - myPackages.add(packageName); - } - } - } - - private static boolean containsPackagePrefix(Module module, String packageFQName) { - if (module == null) return false; - for (ContentEntry contentEntry : ModuleRootManager.getInstance(module).getContentEntries()) { - for (SourceFolder sourceFolder : contentEntry.getSourceFolders(JavaModuleSourceRootTypes.SOURCES)) { - final String packagePrefix = sourceFolder.getPackagePrefix(); - final int prefixLength = packagePrefix.length(); - if (prefixLength > 0 && packageFQName.startsWith(packagePrefix)) { - return true; - } - } - } - return false; - } + }); } } + diff --git a/java/java-impl/src/com/intellij/javadoc/JavadocGenerationManager.java b/java/java-impl/src/com/intellij/javadoc/JavadocGenerationManager.java index 3589918fe4a1..b1a5ef4984ef 100644 --- a/java/java-impl/src/com/intellij/javadoc/JavadocGenerationManager.java +++ b/java/java-impl/src/com/intellij/javadoc/JavadocGenerationManager.java @@ -20,7 +20,6 @@ import com.intellij.analysis.AnalysisScope; import com.intellij.execution.ExecutionException; import com.intellij.execution.executors.DefaultRunExecutor; import com.intellij.execution.runners.ExecutionEnvironmentBuilder; -import com.intellij.execution.runners.ExecutionUtil; import com.intellij.execution.util.ExecutionErrorDialog; import com.intellij.openapi.components.*; import com.intellij.openapi.diagnostic.Logger; @@ -48,7 +47,7 @@ public final class JavadocGenerationManager implements PersistentStateComponent< JavadocGenerationManager(Project project) { myProject = project; - myConfiguration = new JavadocConfiguration(project); + myConfiguration = new JavadocConfiguration(); } @Override @@ -78,9 +77,9 @@ public final class JavadocGenerationManager implements PersistentStateComponent< } public void generateJavadoc(AnalysisScope scope) { - myConfiguration.setGenerationScope(scope); try { - ExecutionEnvironmentBuilder.create(myProject, DefaultRunExecutor.getRunExecutorInstance(), myConfiguration).buildAndExecute(); + JavadocGeneratorRunProfile profile = new JavadocGeneratorRunProfile(myProject, scope, myConfiguration); + ExecutionEnvironmentBuilder.create(myProject, DefaultRunExecutor.getRunExecutorInstance(), profile).buildAndExecute(); } catch (ExecutionException e) { ExecutionErrorDialog.show(e, CommonBundle.getErrorTitle(), myProject); diff --git a/java/java-impl/src/com/intellij/javadoc/JavadocGeneratorRunProfile.java b/java/java-impl/src/com/intellij/javadoc/JavadocGeneratorRunProfile.java new file mode 100644 index 000000000000..b18a5b38ef6f --- /dev/null +++ b/java/java-impl/src/com/intellij/javadoc/JavadocGeneratorRunProfile.java @@ -0,0 +1,373 @@ +/* + * Copyright 2000-2015 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.javadoc; + +import com.intellij.analysis.AnalysisScope; +import com.intellij.execution.CantRunException; +import com.intellij.execution.ExecutionException; +import com.intellij.execution.Executor; +import com.intellij.execution.configurations.*; +import com.intellij.execution.filters.RegexpFilter; +import com.intellij.execution.process.OSProcessHandler; +import com.intellij.execution.process.ProcessAdapter; +import com.intellij.execution.process.ProcessEvent; +import com.intellij.execution.process.ProcessTerminatedListener; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.ide.BrowserUtil; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleUtilCore; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.JavaSdk; +import com.intellij.openapi.projectRoots.JavaSdkType; +import com.intellij.openapi.projectRoots.JavaSdkVersion; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.projectRoots.ex.PathUtilEx; +import com.intellij.openapi.roots.*; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.*; +import com.intellij.util.PathsList; +import com.intellij.util.containers.HashSet; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes; + +import javax.swing.*; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +/** + * @author nik + */ +public class JavadocGeneratorRunProfile implements ModuleRunProfile { + private static final Logger LOGGER = Logger.getInstance("#" + JavadocConfiguration.class.getName()); + private final Project myProject; + private final AnalysisScope myGenerationScope; + private final JavadocConfiguration myConfiguration; + + public JavadocGeneratorRunProfile(Project project, AnalysisScope generationScope, JavadocConfiguration configuration) { + myProject = project; + myGenerationScope = generationScope; + myConfiguration = configuration; + } + + public static Sdk getSdk(@NotNull Project project) { + return PathUtilEx.getAnyJdk(project); + } + + public RunProfileState getState(@NotNull final Executor executor, @NotNull final ExecutionEnvironment env) throws ExecutionException { + return new MyJavaCommandLineState(myConfiguration, myProject, myGenerationScope, env); + } + + public String getName() { + return JavadocBundle.message("javadoc.settings.title"); + } + + public Icon getIcon() { + return null; + } + + @NotNull + public Module[] getModules() { + return Module.EMPTY_ARRAY; + } + + private static class MyJavaCommandLineState extends CommandLineState { + private final AnalysisScope myGenerationOptions; + private final Project myProject; + @NonNls private static final String INDEX_HTML = "index.html"; + private JavadocConfiguration myConfiguration; + + public MyJavaCommandLineState(final JavadocConfiguration configuration, + Project project, + AnalysisScope generationOptions, + ExecutionEnvironment env) { + super(env); + myGenerationOptions = generationOptions; + myProject = project; + addConsoleFilters(new RegexpFilter(project, "$FILE_PATH$:$LINE$:[^\\^]+\\^"), + new RegexpFilter(project, "$FILE_PATH$:$LINE$: warning - .+$")); + this.myConfiguration = configuration; + } + + protected GeneralCommandLine createCommandLine() throws ExecutionException { + final GeneralCommandLine cmdLine = new GeneralCommandLine(); + final Sdk jdk = getSdk(myProject); + setupExeParams(jdk, cmdLine); + setupProgramParameters(jdk, cmdLine); + return cmdLine; + } + + private void setupExeParams(final Sdk jdk, GeneralCommandLine cmdLine) throws ExecutionException { + final String jdkPath = + jdk != null && jdk.getSdkType() instanceof JavaSdkType ? ((JavaSdkType)jdk.getSdkType()).getBinPath(jdk) : null; + if (jdkPath == null) { + throw new CantRunException(JavadocBundle.message("javadoc.generate.no.jdk.path")); + } + JavaSdkVersion version = JavaSdk.getInstance().getVersion(jdk); + if (myConfiguration.HEAP_SIZE != null && myConfiguration.HEAP_SIZE.trim().length() != 0) { + if (version == null || version.isAtLeast(JavaSdkVersion.JDK_1_2)) { + cmdLine.getParametersList().prepend("-J-Xmx" + myConfiguration.HEAP_SIZE + "m"); + } + else { + cmdLine.getParametersList().prepend("-J-mx" + myConfiguration.HEAP_SIZE + "m"); + } + } + cmdLine.setWorkDirectory((File)null); + @NonNls final String javadocExecutableName = File.separator + (SystemInfo.isWindows ? "javadoc.exe" : "javadoc"); + @NonNls String exePath = jdkPath.replace('/', File.separatorChar) + javadocExecutableName; + if (new File(exePath).exists()) { + cmdLine.setExePath(exePath); + } + else { //try to use wrapper jdk + exePath = new File(jdkPath).getParent().replace('/', File.separatorChar) + javadocExecutableName; + if (!new File(exePath).exists()) { + final File parent = new File(System.getProperty("java.home")).getParentFile(); //try system jre + exePath = parent.getPath() + File.separator + "bin" + javadocExecutableName; + if (!new File(exePath).exists()) { + throw new CantRunException(JavadocBundle.message("javadoc.generate.no.jdk.path")); + } + } + cmdLine.setExePath(exePath); + } + } + + private void setupProgramParameters(final Sdk jdk, final GeneralCommandLine cmdLine) throws CantRunException { + @NonNls final ParametersList parameters = cmdLine.getParametersList(); + + if (myConfiguration.LOCALE != null && myConfiguration.LOCALE.length() > 0) { + parameters.add("-locale"); + parameters.add(myConfiguration.LOCALE); + } + + if (myConfiguration.OPTION_SCOPE != null) { + parameters.add("-" + myConfiguration.OPTION_SCOPE); + } + + if (!myConfiguration.OPTION_HIERARCHY) { + parameters.add("-notree"); + } + + if (!myConfiguration.OPTION_NAVIGATOR) { + parameters.add("-nonavbar"); + } + + if (!myConfiguration.OPTION_INDEX) { + parameters.add("-noindex"); + } + else if (myConfiguration.OPTION_SEPARATE_INDEX) { + parameters.add("-splitindex"); + } + + if (myConfiguration.OPTION_DOCUMENT_TAG_USE) { + parameters.add("-use"); + } + + if (myConfiguration.OPTION_DOCUMENT_TAG_AUTHOR) { + parameters.add("-author"); + } + + if (myConfiguration.OPTION_DOCUMENT_TAG_VERSION) { + parameters.add("-version"); + } + + if (!myConfiguration.OPTION_DOCUMENT_TAG_DEPRECATED) { + parameters.add("-nodeprecated"); + } + else if (!myConfiguration.OPTION_DEPRECATED_LIST) { + parameters.add("-nodeprecatedlist"); + } + + parameters.addParametersString(myConfiguration.OTHER_OPTIONS); + + final Set modules = new LinkedHashSet(); + try { + final File sourcePathTempFile = FileUtil.createTempFile("javadoc", "args.txt", true); + parameters.add("@" + sourcePathTempFile.getCanonicalPath()); + final PrintWriter writer = new PrintWriter(new FileWriter(sourcePathTempFile)); + try { + final Collection packages = new HashSet(); + final Collection sources = new HashSet(); + final Runnable findRunnable = new Runnable() { + public void run() { + final int scopeType = myGenerationOptions.getScopeType(); + final boolean usePackageNotation = scopeType == AnalysisScope.MODULE || + scopeType == AnalysisScope.MODULES || + scopeType == AnalysisScope.PROJECT || + scopeType == AnalysisScope.DIRECTORY; + myGenerationOptions.accept(new MyContentIterator(myProject, packages, sources, modules, usePackageNotation)); + } + }; + if (!ProgressManager + .getInstance() + .runProcessWithProgressSynchronously(findRunnable, "Search for sources to generate javadoc in...", true, myProject)) { + return; + } + if (packages.size() + sources.size() == 0) { + throw new CantRunException(JavadocBundle.message("javadoc.generate.no.classes.in.selected.packages.error")); + } + for (String aPackage : packages) { + writer.println(aPackage); + } + //http://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#runningjavadoc + for (String source : sources) { + writer.println(StringUtil.wrapWithDoubleQuote(source)); + } + writer.println("-sourcepath"); + OrderEnumerator enumerator = OrderEnumerator.orderEntries(myProject); + if (!myConfiguration.OPTION_INCLUDE_LIBS) { + enumerator = enumerator.withoutSdk().withoutLibraries(); + } + final PathsList pathsList = enumerator.getSourcePathsList(); + final List files = pathsList.getRootDirs(); + final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(myProject).getFileIndex(); + final StringBuilder sourcePath = new StringBuilder(); + boolean start = true; + for (VirtualFile file : files) { + if (!myGenerationOptions.isIncludeTestSource() && fileIndex.isInTestSourceContent(file)) continue; + if (start) { + start = false; + } + else { + sourcePath.append(File.pathSeparator); + } + sourcePath.append(file.getPath()); + } + writer.println(StringUtil.wrapWithDoubleQuote(sourcePath.toString())); + } + finally { + writer.close(); + } + } + catch (IOException e) { + LOGGER.error(e); + } + + if (myConfiguration.OPTION_LINK_TO_JDK_DOCS) { + VirtualFile[] docUrls = jdk.getRootProvider().getFiles(JavadocOrderRootType.getInstance()); + for (VirtualFile docUrl : docUrls) { + parameters.add("-link"); + parameters.add(VfsUtil.toUri(docUrl).toString()); + } + } + + final PathsList classPath; + final OrderEnumerator orderEnumerator = ProjectRootManager.getInstance(myProject).orderEntries(modules); + if (jdk.getSdkType() instanceof JavaSdk) { + classPath = orderEnumerator.withoutSdk().withoutModuleSourceEntries().getPathsList(); + } + else { + //libraries are included into jdk + classPath = orderEnumerator.withoutModuleSourceEntries().getPathsList(); + } + final String classPathString = classPath.getPathsString(); + if (classPathString.length() > 0) { + parameters.add("-classpath"); + parameters.add(classPathString); + } + + if (myConfiguration.OUTPUT_DIRECTORY != null) { + parameters.add("-d"); + parameters.add(myConfiguration.OUTPUT_DIRECTORY.replace('/', File.separatorChar)); + } + } + + @NotNull + protected OSProcessHandler startProcess() throws ExecutionException { + final OSProcessHandler handler = JavaCommandLineStateUtil.startProcess(createCommandLine()); + ProcessTerminatedListener.attach(handler, myProject, JavadocBundle.message("javadoc.generate.exited")); + handler.addProcessListener(new ProcessAdapter() { + public void processTerminated(ProcessEvent event) { + if (myConfiguration.OPEN_IN_BROWSER) { + File url = new File(myConfiguration.OUTPUT_DIRECTORY, INDEX_HTML); + if (url.exists() && event.getExitCode() == 0) { + BrowserUtil.browse(url); + } + } + } + }); + return handler; + } + } + + private static class MyContentIterator extends PsiRecursiveElementWalkingVisitor { + private final PsiManager myPsiManager; + private final Collection myPackages; + private final Collection mySourceFiles; + private final Set myModules; + private final boolean myUsePackageNotation; + + public MyContentIterator(Project project, + Collection packages, + Collection sources, + Set modules, + boolean canUsePackageNotation) { + myModules = modules; + myUsePackageNotation = canUsePackageNotation; + myPsiManager = PsiManager.getInstance(project); + myPackages = packages; + mySourceFiles = sources; + } + + @Override + public void visitFile(PsiFile file) { + final VirtualFile fileOrDir = file.getVirtualFile(); + if (fileOrDir == null) return; + if (!fileOrDir.isInLocalFileSystem()) return; + final Module module = ModuleUtilCore.findModuleForFile(fileOrDir, myPsiManager.getProject()); + if (module != null) { + myModules.add(module); + } + if (file instanceof PsiJavaFile) { + final PsiJavaFile javaFile = (PsiJavaFile)file; + final String packageName = javaFile.getPackageName(); + if (containsPackagePrefix(module, packageName) || + (packageName.length() == 0 && !(javaFile instanceof ServerPageFile)) || + !myUsePackageNotation) { + mySourceFiles.add(FileUtil.toSystemIndependentName(fileOrDir.getPath())); + } + else { + myPackages.add(packageName); + } + } + } + + private static boolean containsPackagePrefix(Module module, String packageFQName) { + if (module == null) return false; + for (ContentEntry contentEntry : ModuleRootManager.getInstance(module).getContentEntries()) { + for (SourceFolder sourceFolder : contentEntry.getSourceFolders(JavaModuleSourceRootTypes.SOURCES)) { + final String packagePrefix = sourceFolder.getPackagePrefix(); + final int prefixLength = packagePrefix.length(); + if (prefixLength > 0 && packageFQName.startsWith(packagePrefix)) { + return true; + } + } + } + return false; + } + } +} diff --git a/java/java-impl/src/com/intellij/javadoc/actions/GenerateJavadocAction.java b/java/java-impl/src/com/intellij/javadoc/actions/GenerateJavadocAction.java index 068f527c0170..9f097a117c4b 100644 --- a/java/java-impl/src/com/intellij/javadoc/actions/GenerateJavadocAction.java +++ b/java/java-impl/src/com/intellij/javadoc/actions/GenerateJavadocAction.java @@ -44,7 +44,7 @@ public final class GenerateJavadocAction extends BaseAnalysisAction{ @Override protected JComponent getAdditionalActionSettings(Project project, final BaseAnalysisActionDialog dialog) { - myConfigurable = JavadocGenerationManager.getInstance(project).getConfiguration().createConfigurable(); + myConfigurable = new JavadocConfigurable(JavadocGenerationManager.getInstance(project).getConfiguration(), project); final JComponent component = myConfigurable.createComponent(); myConfigurable.reset(); myConfigurable.getOutputDirField().getDocument().addDocumentListener(new DocumentAdapter() { diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldDialog.java b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldDialog.java index 6f1cd002c9c5..e71e6c3317ae 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldDialog.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -16,6 +16,7 @@ package com.intellij.refactoring.introduceField; import com.intellij.codeInsight.completion.JavaCompletionUtil; +import com.intellij.openapi.editor.Editor; import com.intellij.openapi.help.HelpManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; @@ -32,6 +33,8 @@ import com.intellij.refactoring.ui.*; import com.intellij.refactoring.util.CommonRefactoringUtil; import com.intellij.refactoring.util.RefactoringMessageUtil; import com.intellij.util.ArrayUtil; +import com.intellij.util.ui.update.Activatable; +import com.intellij.util.ui.update.UiNotifyConnector; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -147,7 +150,7 @@ class IntroduceFieldDialog extends DialogWrapper { gbConstraints.gridx = 0; gbConstraints.gridy = 0; - JLabel type = new JLabel(getTypeLabel()); + final JLabel type = new JLabel(getTypeLabel()); panel.add(type, gbConstraints); @@ -163,7 +166,7 @@ class IntroduceFieldDialog extends DialogWrapper { gbConstraints.weighty = 1; gbConstraints.gridx = 0; gbConstraints.gridy = 1; - JLabel namePrompt = new JLabel(RefactoringBundle.message("name.prompt")); + final JLabel namePrompt = new JLabel(RefactoringBundle.message("name.prompt")); panel.add(namePrompt, gbConstraints); gbConstraints.insets = new Insets(4, 0, 4, 4); @@ -180,10 +183,24 @@ class IntroduceFieldDialog extends DialogWrapper { }); namePrompt.setLabelFor(myNameField.getFocusableComponent()); - myNameSuggestionsManager = new NameSuggestionsManager(myTypeSelector, myNameField, - createGenerator(myWillBeDeclaredStatic, myLocalVariable, myInitializerExpression, myIsInvokedOnDeclaration, myEnteredName, - myParentClass, myProject)); - myNameSuggestionsManager.setLabelsFor(type, namePrompt); + // We delay initialization of name field till dialog is shown, so that it will be executed in a different command and won't + // be tied to any document changes performed in current command (and won't prevent undo for them later) + new UiNotifyConnector.Once(panel, new Activatable.Adapter() { + @Override + public void showNotify() { + myNameSuggestionsManager = new NameSuggestionsManager(myTypeSelector, myNameField, + createGenerator(myWillBeDeclaredStatic, myLocalVariable, + myInitializerExpression, myIsInvokedOnDeclaration, + myEnteredName, myParentClass, myProject)); + myNameSuggestionsManager.setLabelsFor(type, namePrompt); + + Editor editor = myNameField.getEditor(); + if (editor != null) { + editor.getSelectionModel().setSelection(0, editor.getDocument().getTextLength()); + } + } + }); + return panel; } diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationReplacementUtil.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationReplacementUtil.java index 0611af494c47..15d7b115352e 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationReplacementUtil.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationReplacementUtil.java @@ -39,17 +39,17 @@ public class TypeMigrationReplacementUtil { private TypeMigrationReplacementUtil() { } - public static void replaceExpression(PsiExpression expression, final Project project, Object conversion) { + public static PsiElement replaceExpression(PsiExpression expression, final Project project, Object conversion) { if (conversion instanceof TypeConversionDescriptorBase) { try { - ((TypeConversionDescriptorBase)conversion).replace(expression); + return ((TypeConversionDescriptorBase)conversion).replace(expression); } catch (IncorrectOperationException e) { LOG.error(e); } } else if (conversion instanceof String) { String replacement = (String)conversion; try { - expression.replace( + return expression.replace( JavaPsiFacade.getInstance(project).getElementFactory().createExpressionFromText(replacement, expression)); } catch (IncorrectOperationException e) { @@ -66,7 +66,7 @@ public class TypeMigrationReplacementUtil { if (conversion instanceof PsiMethod) { if (resolved instanceof PsiMethod) { try { - expression.replace( + return expression.replace( JavaPsiFacade.getInstance(project).getElementFactory().createExpressionFromText(newref, expression)); } catch (IncorrectOperationException e) { @@ -75,7 +75,7 @@ public class TypeMigrationReplacementUtil { } else { try { - expression.replace(JavaPsiFacade.getInstance(project).getElementFactory().createExpressionFromText( + return expression.replace(JavaPsiFacade.getInstance(project).getElementFactory().createExpressionFromText( newref + "()", expression)); } catch (IncorrectOperationException e) { @@ -86,7 +86,7 @@ public class TypeMigrationReplacementUtil { else if (conversion instanceof PsiField) { if (resolved instanceof PsiField) { try { - expression.replace( + return expression.replace( JavaPsiFacade.getInstance(project).getElementFactory().createExpressionFromText(newref, expression)); } catch (IncorrectOperationException e) { @@ -98,7 +98,7 @@ public class TypeMigrationReplacementUtil { if (parent instanceof PsiMethodCallExpression) { try { - parent.replace( + return parent.replace( JavaPsiFacade.getInstance(project).getElementFactory().createExpressionFromText(newref, expression)); } catch (IncorrectOperationException e) { @@ -108,6 +108,7 @@ public class TypeMigrationReplacementUtil { } } } + return expression; } static void migratePsiMemberType(final PsiElement element, final Project project, PsiType migratedType) { diff --git a/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java b/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java index 306c43e5b15c..54cade32e37a 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java @@ -636,13 +636,16 @@ public final class PsiUtil extends PsiUtilCore { return containingClass1 == null && containingClass2 == null; } + /** + * @deprecated use more generic {@link #isCompileTimeConstant(PsiVariable)} instead + */ public static boolean isCompileTimeConstant(@NotNull final PsiField field) { return isCompileTimeConstant((PsiVariable)field); } - /** - * JLS 15.28 - */ + /** + * JLS 15.28 + */ public static boolean isCompileTimeConstant(@NotNull final PsiVariable field) { return field.hasModifierProperty(PsiModifier.FINAL) && (TypeConversionUtil.isPrimitiveAndNotNull(field.getType()) || field.getType().equalsToText(JAVA_LANG_STRING)) diff --git a/java/java-tests/testData/codeInsight/template/postfix/templates/for/iterSameAsFor.java b/java/java-tests/testData/codeInsight/template/postfix/templates/for/iterSameAsFor.java new file mode 100644 index 000000000000..6487ce37be7c --- /dev/null +++ b/java/java-tests/testData/codeInsight/template/postfix/templates/for/iterSameAsFor.java @@ -0,0 +1,8 @@ +import java.util.ArrayList; + +class Test { + public static void main(String[] args) { + ArrayList list = new ArrayList(); + list.iter + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/template/postfix/templates/for/iterSameAsFor_after.java b/java/java-tests/testData/codeInsight/template/postfix/templates/for/iterSameAsFor_after.java new file mode 100644 index 000000000000..b9ddd87e080a --- /dev/null +++ b/java/java-tests/testData/codeInsight/template/postfix/templates/for/iterSameAsFor_after.java @@ -0,0 +1,10 @@ +import java.util.ArrayList; + +class Test { + public static void main(String[] args) { + ArrayList list = new ArrayList(); + for (Object o : list) { + + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/template/postfix/templates/ForeachTemplateTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/template/postfix/templates/ForeachTemplateTest.java index ff29755dd05e..6d57c28e1396 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/template/postfix/templates/ForeachTemplateTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/template/postfix/templates/ForeachTemplateTest.java @@ -37,6 +37,10 @@ public class ForeachTemplateTest extends PostfixTemplateTestCase { public void testInAnonymousRunnable() { doTest(); } + + public void testIterSameAsFor() { + doTest(); + } public void testFinalLocals() { CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); diff --git a/java/typeMigration/src/META-INF/TypeMigration.xml b/java/typeMigration/src/META-INF/TypeMigration.xml index 9a0c0e187dfa..082c3ba802d5 100644 --- a/java/typeMigration/src/META-INF/TypeMigration.xml +++ b/java/typeMigration/src/META-INF/TypeMigration.xml @@ -12,6 +12,7 @@ + com.intellij.refactoring.typeMigration.intentions.ConvertFieldToAtomicIntention Java/Concurrency diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/inspections/GuavaInspection.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/inspections/GuavaInspection.java index 7a31db0f2d95..914a17cb6bf0 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/inspections/GuavaInspection.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/inspections/GuavaInspection.java @@ -15,21 +15,31 @@ */ package com.intellij.refactoring.typeMigration.inspections; +import com.intellij.codeInsight.FileModificationService; import com.intellij.codeInsight.daemon.impl.quickfix.VariableTypeFix; import com.intellij.codeInspection.*; +import com.intellij.openapi.command.undo.UndoUtil; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.AtomicNotNullLazyValue; import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; -import com.intellij.refactoring.typeMigration.TypeMigrationVariableTypeFixProvider; +import com.intellij.refactoring.typeMigration.*; import com.intellij.refactoring.typeMigration.rules.TypeConversionRule; import com.intellij.refactoring.typeMigration.rules.guava.BaseGuavaTypeConversionRule; +import com.intellij.refactoring.typeMigration.rules.guava.GuavaFluentIterableConversionRule; import com.intellij.refactoring.typeMigration.rules.guava.GuavaFunctionConversionRule; +import com.intellij.refactoring.typeMigration.rules.guava.GuavaOptionalConversionRule; +import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.hash.HashMap; +import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; @@ -43,6 +53,7 @@ public class GuavaInspection extends BaseJavaLocalInspectionTool { private final static Logger LOG = Logger.getInstance(GuavaInspection.class); private final static String PROBLEM_DESCRIPTION_FOR_VARIABLE = "Guava's functional primitives can be replaced by Java API"; + private final static String PROBLEM_DESCRIPTION_FOR_METHOD_CHAIN = "Guava's FluentIterable method chain can be replaced by Java API"; @NotNull @Override @@ -93,6 +104,54 @@ public class GuavaInspection extends BaseJavaLocalInspectionTool { } } + @Override + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + if (!isFluentIterableFromCall(expression)) return; + + final PsiMethodCallExpression chain = findGuavaMethodChain(expression); + + PsiClassType initialType = (PsiClassType)expression.getType(); + LOG.assertTrue(initialType != null); + PsiClass resolvedClass = initialType.resolve(); + PsiClass target; + if (resolvedClass == null || (target = myGuavaClassConversions.getValue().get(resolvedClass.getQualifiedName())) == null) { + return; + } + PsiClassType targetType = addTypeParameters(initialType, initialType.resolveGenerics(), target); + + holder.registerProblem(chain, PROBLEM_DESCRIPTION_FOR_METHOD_CHAIN, new MigrateFluentIterableChainQuickFix(chain, initialType, targetType)); + } + + private boolean isFluentIterableFromCall(PsiMethodCallExpression expression) { + PsiMethod method = expression.resolveMethod(); + if (method == null || !"from".equals(method.getName())) { + return false; + } + PsiClass aClass = method.getContainingClass(); + return aClass != null && GuavaFluentIterableConversionRule.FLUENT_ITERABLE.equals(aClass.getQualifiedName()); + } + + private PsiMethodCallExpression findGuavaMethodChain(PsiMethodCallExpression expression) { + PsiMethodCallExpression chain = expression; + while (true) { + final PsiMethodCallExpression current = PsiTreeUtil.getParentOfType(chain, PsiMethodCallExpression.class); + if (current != null && current.getMethodExpression().getQualifierExpression() == chain) { + final PsiMethod method = current.resolveMethod(); + if (method == null) { + return chain; + } + final PsiClass containingClass = method.getContainingClass(); + if (containingClass == null || ! (GuavaFluentIterableConversionRule.FLUENT_ITERABLE.equals(containingClass.getQualifiedName()) + || GuavaOptionalConversionRule.GUAVA_OPTIONAL.equals(containingClass.getQualifiedName()))) { + return chain; + } + } else { + return chain; + } + chain = current; + } + } + private PsiClassType addTypeParameters(PsiType currentType, PsiClassType.ClassResolveResult currentTypeResolveResult, PsiClass targetClass) { final Map substitutionMap = currentTypeResolveResult.getSubstitutor().getSubstitutionMap(); final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(holder.getProject()); @@ -110,4 +169,58 @@ public class GuavaInspection extends BaseJavaLocalInspectionTool { } }; } + + public static class MigrateFluentIterableChainQuickFix extends LocalQuickFixAndIntentionActionOnPsiElement { + private final PsiClassType myInitialType; + private final PsiClassType myTargetType; + + private MigrateFluentIterableChainQuickFix(@Nullable PsiElement element, PsiClassType initialType, PsiClassType targetType) { + super(element); + myInitialType = initialType; + myTargetType = targetType; + } + + @Override + public void invoke(@NotNull Project project, + @NotNull PsiFile file, + @Nullable("is null when called from inspection") Editor editor, + @NotNull PsiElement startElement, + @NotNull PsiElement endElement) { + + if (!FileModificationService.getInstance().prepareFileForWrite(file)) return; + try { + final PsiMethodCallExpression expr = (PsiMethodCallExpression)startElement; + final TypeMigrationRules rules = new TypeMigrationRules(myInitialType); + rules.setMigrationRootType(myTargetType); + rules.setBoundScope(GlobalSearchScope.fileScope(file)); + final TypeConversionDescriptorBase conversion = + rules.findConversion(myInitialType, myTargetType, expr.resolveMethod(), expr, new TypeMigrationLabeler(rules)); + LOG.assertTrue(conversion != null); + final PsiElement replacedExpression = TypeMigrationReplacementUtil.replaceExpression(expr, project, conversion); + JavaCodeStyleManager.getInstance(project).shortenClassReferences(replacedExpression); + UndoUtil.markPsiFileForUndo(file); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } + + @Override + public boolean startInWriteAction() { + return true; + } + + @NotNull + @Override + public String getText() { + return getFamilyName(); + } + + @Nls + @NotNull + @Override + public String getFamilyName() { + return "Replace FluentIterable method chain by Java API"; + } + } } \ No newline at end of file diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/BaseGuavaTypeConversionRule.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/BaseGuavaTypeConversionRule.java index 8daec6de5c7d..8984ccc0f4a4 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/BaseGuavaTypeConversionRule.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/BaseGuavaTypeConversionRule.java @@ -45,10 +45,10 @@ public abstract class BaseGuavaTypeConversionRule extends TypeConversionRule { protected void fillSimpleDescriptors(Map descriptorsMap) {}; @Nullable - protected TypeConversionDescriptorBase findConversionForMethod(@NotNull PsiType from, - @NotNull PsiType to, + protected TypeConversionDescriptorBase findConversionForMethod(PsiType from, + PsiType to, @NotNull PsiMethod method, - String methodName, + @NotNull String methodName, PsiExpression context, TypeMigrationLabeler labeler) { return null; @@ -62,12 +62,12 @@ public abstract class BaseGuavaTypeConversionRule extends TypeConversionRule { @Nullable @Override - public final TypeConversionDescriptorBase findConversion(PsiType from, - PsiType to, - PsiMember member, - PsiExpression context, - TypeMigrationLabeler labeler) { - if (!canConvert(from, to)) { + public final TypeConversionDescriptorBase findConversion(@Nullable PsiType from, + @Nullable PsiType to, + PsiMember member, + PsiExpression context, + TypeMigrationLabeler labeler) { + if (from != null && to != null && !canConvert(from, to)) { return null; } if (member instanceof PsiMethod) { diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaFluentIterableConversionRule.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaFluentIterableConversionRule.java index 3a75c0202116..386c6ebcfe6b 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaFluentIterableConversionRule.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaFluentIterableConversionRule.java @@ -16,10 +16,12 @@ package com.intellij.refactoring.typeMigration.rules.guava; import com.intellij.codeInspection.java18StreamApi.StreamApiConstants; +import com.intellij.openapi.util.NotNullLazyValue; import com.intellij.psi.*; import com.intellij.refactoring.typeMigration.TypeConversionDescriptor; import com.intellij.refactoring.typeMigration.TypeConversionDescriptorBase; import com.intellij.refactoring.typeMigration.TypeMigrationLabeler; +import com.intellij.refactoring.typeMigration.rules.TypeConversionRule; import com.intellij.util.IncorrectOperationException; import com.intellij.util.SmartList; import com.intellij.util.containers.hash.HashMap; @@ -27,7 +29,6 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Collections; import java.util.List; import java.util.Map; @@ -106,11 +107,11 @@ public class GuavaFluentIterableConversionRule extends BaseGuavaTypeConversionRu protected TypeConversionDescriptorBase findConversionForMethod(@NotNull PsiType from, @NotNull PsiType to, @NotNull PsiMethod method, - String methodName, + @NotNull String methodName, PsiExpression context, TypeMigrationLabeler labeler) { if (context instanceof PsiMethodCallExpression) { - return buildCompoundDescriptor((PsiMethodCallExpression)context, to); + return buildCompoundDescriptor((PsiMethodCallExpression)context, to, labeler); } final TypeConversionDescriptorFactory base = DESCRIPTORS_MAP.get(methodName); if (base != null) { @@ -126,8 +127,23 @@ public class GuavaFluentIterableConversionRule extends BaseGuavaTypeConversionRu } @Nullable - private GuavaChainedConversionDescriptor buildCompoundDescriptor(PsiMethodCallExpression expression, PsiType to) { - List methodDescriptors = new SmartList(); + private static GuavaChainedConversionDescriptor buildCompoundDescriptor(PsiMethodCallExpression expression, + PsiType to, + TypeMigrationLabeler labeler) { + List methodDescriptors = new SmartList(); + + NotNullLazyValue optionalDescriptor = new NotNullLazyValue() { + @NotNull + @Override + protected TypeConversionRule compute() { + for (TypeConversionRule rule : TypeConversionRule.EP_NAME.getExtensions()) { + if (rule instanceof GuavaOptionalConversionRule) { + return rule; + } + } + throw new RuntimeException("GuavaOptionalConversionRule extension is not found"); + } + }; PsiMethodCallExpression current = expression; while (true) { @@ -137,15 +153,26 @@ public class GuavaFluentIterableConversionRule extends BaseGuavaTypeConversionRu } final String methodName = method.getName(); final PsiClass containingClass = method.getContainingClass(); - //TODO for optional too - if (containingClass == null || !FLUENT_ITERABLE.equals(containingClass.getQualifiedName())) { + if (containingClass == null) { break; } - final TypeConversionDescriptorFactory descriptorFactory = DESCRIPTORS_MAP.get(methodName); - if (descriptorFactory == null) { - return null; + TypeConversionDescriptorBase descriptor; + if (FLUENT_ITERABLE.equals(containingClass.getQualifiedName())) { + final TypeConversionDescriptorFactory descriptorFactory = DESCRIPTORS_MAP.get(methodName); + if (descriptorFactory == null) { + return null; + } + descriptor = descriptorFactory.create(); } - methodDescriptors.add(descriptorFactory.create()); + else if (GuavaOptionalConversionRule.GUAVA_OPTIONAL.equals(containingClass.getQualifiedName())) { + descriptor = optionalDescriptor.getValue().findConversion(null, null, method, current.getMethodExpression(), labeler); + if (descriptor == null) { + return null; + } + } else { + break; + } + methodDescriptors.add(descriptor); final PsiExpression qualifier = current.getMethodExpression().getQualifierExpression(); if (qualifier instanceof PsiMethodCallExpression) { current = (PsiMethodCallExpression)qualifier; @@ -172,10 +199,10 @@ public class GuavaFluentIterableConversionRule extends BaseGuavaTypeConversionRu } private static class GuavaChainedConversionDescriptor extends TypeConversionDescriptorBase { - private final List myMethodDescriptors; + private final List myMethodDescriptors; private final PsiType myToType; - private GuavaChainedConversionDescriptor(List descriptors, PsiType to) { + private GuavaChainedConversionDescriptor(List descriptors, PsiType to) { myMethodDescriptors = descriptors; myToType = to; } @@ -184,15 +211,21 @@ public class GuavaFluentIterableConversionRule extends BaseGuavaTypeConversionRu public PsiExpression replace(PsiExpression expression) throws IncorrectOperationException { PsiMethodCallExpression toReturn = null; PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression) expression; - for (TypeConversionDescriptor descriptor : myMethodDescriptors) { + final SmartPointerManager smartPointerManager = SmartPointerManager.getInstance(expression.getProject()); + + for (TypeConversionDescriptorBase descriptor : myMethodDescriptors) { + final PsiExpression oldQualifier = methodCallExpression.getMethodExpression().getQualifierExpression(); + final SmartPsiElementPointer qualifierRef = oldQualifier == null + ? null + : smartPointerManager.createSmartPsiElementPointer(oldQualifier); final PsiMethodCallExpression replaced = (PsiMethodCallExpression)descriptor.replace(methodCallExpression); if (toReturn == null) { toReturn = replaced; } - final PsiExpression qualifier = replaced.getMethodExpression().getQualifierExpression(); - if (qualifier instanceof PsiMethodCallExpression) { - methodCallExpression = (PsiMethodCallExpression)qualifier; + final PsiExpression newQualifier = qualifierRef == null ? null : qualifierRef.getElement(); + if (newQualifier instanceof PsiMethodCallExpression) { + methodCallExpression = (PsiMethodCallExpression)newQualifier; } else { return toReturn; } diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaOptionalConversionRule.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaOptionalConversionRule.java index cc8968f8f51e..9363797e757d 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaOptionalConversionRule.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaOptionalConversionRule.java @@ -36,10 +36,10 @@ public class GuavaOptionalConversionRule extends BaseGuavaTypeConversionRule { @Nullable @Override - protected TypeConversionDescriptorBase findConversionForMethod(@NotNull PsiType from, - @NotNull PsiType to, + protected TypeConversionDescriptorBase findConversionForMethod(@Nullable PsiType from, + @Nullable PsiType to, @NotNull PsiMethod method, - String methodName, + @NotNull String methodName, PsiExpression context, TypeMigrationLabeler labeler) { if ("or".equals(methodName)) { @@ -53,9 +53,7 @@ public class GuavaOptionalConversionRule extends BaseGuavaTypeConversionRule { if (aClass != null) { final String qName = aClass.getQualifiedName(); String pattern = - GUAVA_OPTIONAL.equals(qName) ? "java.util.Optional.ofNullable($expr$.get())" : "com.google.common.bas.Supplier".equals(qName) - ? "java.util.Optional.ofNullable($expr$)" - : "java.util.Optional.ofNullable($expr$)"; + GUAVA_OPTIONAL.equals(qName) ? "java.util.Optional.ofNullable($expr$.get())" : "java.util.Optional.ofNullable($expr$)"; return new TypeConversionDescriptor("$expr$", pattern); } return null; @@ -73,10 +71,15 @@ public class GuavaOptionalConversionRule extends BaseGuavaTypeConversionRule { if (aClass != null) { final String qName = aClass.getQualifiedName(); if (GUAVA_OPTIONAL.equals(qName)) { - return new TypeConversionDescriptor("$val$.or($other$)", "java.util.Optional.ofNullable($val$.orElseGet($other$::get))", to); + TypeConversionDescriptor descriptor = + new TypeConversionDescriptor("$val$.or($other$)", "java.util.Optional.ofNullable($val$.orElseGet($other$::get))"); + if (to != null) { + descriptor.withConversionType(to); + } + return descriptor; } - String pattern = "com.google.common.bas.Supplier".equals(qName) ? "$val$.orElseGet($other$::get)" : "$val$.orElse($other$)"; - return new TypeConversionDescriptor("$val$.or($other$)", pattern); + String pattern = GuavaSupplierConversionRule.GUAVA_SUPPLIER.equals(qName) ? "$val$.orElseGet($other$)" : "$val$.orElse($other$)"; + return new LambdaParametersTypeConversionDescription("$val$.or($other$)", pattern); } return null; } diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaSupplierConversionRule.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaSupplierConversionRule.java new file mode 100644 index 000000000000..dc9df00e3250 --- /dev/null +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaSupplierConversionRule.java @@ -0,0 +1,46 @@ +/* + * Copyright 2000-2015 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.refactoring.typeMigration.rules.guava; + +import com.intellij.refactoring.typeMigration.TypeConversionDescriptor; +import com.intellij.refactoring.typeMigration.TypeConversionDescriptorBase; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; + +/** + * @author Dmitry Batkovich + */ +public class GuavaSupplierConversionRule extends BaseGuavaTypeConversionRule { + public final static String GUAVA_SUPPLIER = "com.google.common.base.Supplier"; + + @Override + protected void fillSimpleDescriptors(Map descriptorsMap) { + descriptorsMap.put("get", new TypeConversionDescriptor("$val$.get()", "$val$.get()")); + } + + @NotNull + @Override + public String ruleFromClass() { + return GUAVA_SUPPLIER; + } + + @NotNull + @Override + public String ruleToClass() { + return "java.util.function.Supplier"; + } +} diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/LambdaParametersTypeConversionDescription.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/LambdaParametersTypeConversionDescription.java index c70598eeb77d..c64472df85a3 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/LambdaParametersTypeConversionDescription.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/LambdaParametersTypeConversionDescription.java @@ -27,10 +27,6 @@ import org.jetbrains.annotations.NonNls; public class LambdaParametersTypeConversionDescription extends TypeConversionDescriptor { private static final Logger LOG = Logger.getInstance(LambdaParametersTypeConversionDescription.class); - public LambdaParametersTypeConversionDescription(@NonNls String stringToReplace, @NonNls String replaceByString, PsiType conversionType) { - super(stringToReplace, replaceByString, conversionType); - } - public LambdaParametersTypeConversionDescription(@NonNls String stringToReplace, @NonNls String replaceByString) { super(stringToReplace, replaceByString); } @@ -52,7 +48,16 @@ public class LambdaParametersTypeConversionDescription extends TypeConversionDes } private static PsiExpression addApplyReference(final PsiExpression expression) { - return (PsiExpression)expression.replace(JavaPsiFacade.getElementFactory(expression.getProject()).createExpressionFromText(expression.getText() + "::apply", null)); + boolean isSupplier = false; + PsiType type = expression.getType(); + if (type instanceof PsiClassType) { + PsiClass resolvedClass = ((PsiClassType)type).resolve(); + if (resolvedClass != null && GuavaSupplierConversionRule.GUAVA_SUPPLIER.equals(resolvedClass.getQualifiedName())) { + isSupplier = true; + } + } + return (PsiExpression)expression.replace( + JavaPsiFacade.getElementFactory(expression.getProject()).createExpressionFromText(expression.getText() + "::" + (isSupplier ? "get" : "apply"), null)); } public static PsiExpression convertParameter(PsiExpression expression) { diff --git a/java/typeMigration/test/com/intellij/codeInsight/inspections/GuavaInspectionTest.java b/java/typeMigration/test/com/intellij/codeInsight/inspections/GuavaInspectionTest.java index 8afd272fb25a..886a3c356356 100644 --- a/java/typeMigration/test/com/intellij/codeInsight/inspections/GuavaInspectionTest.java +++ b/java/typeMigration/test/com/intellij/codeInsight/inspections/GuavaInspectionTest.java @@ -63,7 +63,7 @@ public class GuavaInspectionTest extends JavaCodeInsightFixtureTestCase { doTest(); } - public void _testFluentIterableChainWithoutVariable() { + public void testFluentIterableChainWithoutVariable() { doTest(); } @@ -71,19 +71,23 @@ public class GuavaInspectionTest extends JavaCodeInsightFixtureTestCase { doTest(); } + public void testFluentIterableChainWithOptional() { + doTest(); + } + private void doTest() { myFixture.configureByFile(getTestName(true) + ".java"); myFixture.enableInspections(new GuavaInspection()); boolean actionFound = false; myFixture.doHighlighting(); for (IntentionAction action : myFixture.getAvailableIntentions()) { - if (action instanceof VariableTypeFix) { + if (action instanceof VariableTypeFix || action instanceof GuavaInspection.MigrateFluentIterableChainQuickFix) { myFixture.launchAction(action); actionFound = true; break; } } - assertTrue(actionFound); + assertTrue("Quick fix isn't found", actionFound); myFixture.checkResultByFile(getTestName(true) + "_after.java"); } } diff --git a/java/typeMigration/testData/inspections/guava/fluentIterableChainWithOptional.java b/java/typeMigration/testData/inspections/guava/fluentIterableChainWithOptional.java new file mode 100644 index 000000000000..5bc29c381651 --- /dev/null +++ b/java/typeMigration/testData/inspections/guava/fluentIterableChainWithOptional.java @@ -0,0 +1,10 @@ +import java.util.*; +import com.google.common.collect.FluentIterable; + +class A { + void m1() { + ArrayList strings = new ArrayList(); + String str = FluentIterable.from(strings).transform(s -> s + s).limit(10).firstMatch(s -> s.isEmpty()).orNull(); + System.out.println("s: " + str); + } +} \ No newline at end of file diff --git a/java/typeMigration/testData/inspections/guava/fluentIterableChainWithOptional_after.java b/java/typeMigration/testData/inspections/guava/fluentIterableChainWithOptional_after.java new file mode 100644 index 000000000000..e55604989080 --- /dev/null +++ b/java/typeMigration/testData/inspections/guava/fluentIterableChainWithOptional_after.java @@ -0,0 +1,10 @@ +import java.util.*; +import com.google.common.collect.FluentIterable; + +class A { + void m1() { + ArrayList strings = new ArrayList(); + String str = strings.stream().map(s -> s + s).limit(10).filter(s -> s.isEmpty()).findFirst().orElse(null); + System.out.println("s: " + str); + } +} \ No newline at end of file diff --git a/java/typeMigration/testData/inspections/guava/fluentIterableChainWithoutVariable.java b/java/typeMigration/testData/inspections/guava/fluentIterableChainWithoutVariable.java new file mode 100644 index 000000000000..a66738c7885d --- /dev/null +++ b/java/typeMigration/testData/inspections/guava/fluentIterableChainWithoutVariable.java @@ -0,0 +1,25 @@ +/* + * Copyright 2000-2015 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. + */ +import java.util.*; +import com.google.common.collect.FluentIterable; + +class A { + int m1() { + ArrayList strings = new ArrayList(); + int size = FluentIterable.from(strings).transform(s -> s + s).limit(10).size(); + return size + } +} \ No newline at end of file diff --git a/java/typeMigration/testData/inspections/guava/fluentIterableChainWithoutVariable_after.java b/java/typeMigration/testData/inspections/guava/fluentIterableChainWithoutVariable_after.java new file mode 100644 index 000000000000..fd41604f6a9f --- /dev/null +++ b/java/typeMigration/testData/inspections/guava/fluentIterableChainWithoutVariable_after.java @@ -0,0 +1,27 @@ +/* + * Copyright 2000-2015 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. + */ +import java.util.*; +import java.util.stream.Collectors; + +import com.google.common.collect.FluentIterable; + +class A { + int m1() { + ArrayList strings = new ArrayList(); + int size = strings.stream().map(s -> s + s).limit(10).collect(Collectors.toList()).size(); + return size + } +} \ No newline at end of file diff --git a/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildSession.java b/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildSession.java index b0470155ff36..c4fa71e86864 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildSession.java +++ b/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildSession.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -22,6 +22,7 @@ import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream; import com.intellij.openapi.util.io.FileSystemUtil; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.concurrency.Semaphore; import com.intellij.util.concurrency.SequentialTaskExecutor; import com.intellij.util.io.DataOutputStream; import io.netty.channel.Channel; @@ -49,7 +50,6 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; import static org.jetbrains.jps.api.CmdlineRemoteProto.Message.ControllerMessage.ParametersMessage.TargetTypeBuildScope; @@ -64,7 +64,7 @@ final class BuildSession implements Runnable, CanceledStatus { private final Channel myChannel; @Nullable private final PreloadedData myPreloadedData; - private volatile boolean myCanceled = false; + private volatile boolean myCanceled; private final String myProjectPath; @Nullable private CmdlineRemoteProto.Message.ControllerMessage.FSEvent myInitialFSDelta; @@ -345,7 +345,7 @@ final class BuildSession implements Runnable, CanceledStatus { } public void processFSEvent(final CmdlineRemoteProto.Message.ControllerMessage.FSEvent event) { - myEventsProcessor.submit(new Runnable() { + myEventsProcessor.execute(new Runnable() { @Override public void run() { try { @@ -646,23 +646,21 @@ final class BuildSession implements Runnable, CanceledStatus { } private static class EventsProcessor extends SequentialTaskExecutor { - private final AtomicBoolean myProcessingEnabled = new AtomicBoolean(false); + private final Semaphore myProcessingEnabled = new Semaphore(); - EventsProcessor() { + private EventsProcessor() { super(SharedThreadPool.getInstance()); + myProcessingEnabled.down(); + execute(new Runnable() { + @Override + public void run() { + myProcessingEnabled.waitFor(); + } + }); } - public void startProcessing() { - if (!myProcessingEnabled.getAndSet(true)) { - super.processQueue(); - } - } - - @Override - protected void processQueue() { - if (myProcessingEnabled.get()) { - super.processQueue(); - } + private void startProcessing() { + myProcessingEnabled.up(); } } diff --git a/platform/built-in-server/src/org/jetbrains/ide/ActivateApplicationHttpService.java b/platform/built-in-server/src/org/jetbrains/ide/ActivateApplicationHttpService.java new file mode 100644 index 000000000000..e1cadcfbe3a2 --- /dev/null +++ b/platform/built-in-server/src/org/jetbrains/ide/ActivateApplicationHttpService.java @@ -0,0 +1,57 @@ +package org.jetbrains.ide; + +import com.intellij.openapi.wm.IdeFocusManager; +import com.intellij.openapi.wm.IdeFrame; +import com.intellij.ui.AppIcon; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.QueryStringDecoder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.io.IOException; + +/** + * @author Konstantin Bulenkov + */ +public class ActivateApplicationHttpService extends RestService { + @NotNull + @Override + protected String getServiceName() { + return "show"; + } + + @Override + protected boolean isMethodSupported(@NotNull HttpMethod method) { + return method == HttpMethod.GET; + } + + @Nullable + @Override + public String execute(@NotNull QueryStringDecoder urlDecoder, @NotNull FullHttpRequest request, @NotNull ChannelHandlerContext context) + throws IOException { + final IdeFrame frame = IdeFocusManager.findInstance().getLastFocusedFrame(); + if (frame instanceof Window) { + sendOk(request, context); + Runnable runnable = new Runnable() { + public void run() { + Window window = (Window)frame; + window.toFront(); + window.requestFocusInWindow(); + + AppIcon.getInstance().requestFocus(frame); + + } + }; + //noinspection SSBasedInspection + SwingUtilities.invokeLater(runnable); + return "Success"; + } + sendStatus(HttpResponseStatus.NOT_FOUND, false, context.channel()); + return "Can't find IDE Frame"; + } +} diff --git a/platform/built-in-server/testSrc/RestApiTest.kt b/platform/built-in-server/testSrc/RestApiTest.kt index f399816c1be9..5116c6425b47 100644 --- a/platform/built-in-server/testSrc/RestApiTest.kt +++ b/platform/built-in-server/testSrc/RestApiTest.kt @@ -1,13 +1,10 @@ package org.jetbrains.ide import com.google.gson.stream.JsonWriter -import com.intellij.openapi.vfs.CharsetToolkit import io.netty.handler.codec.http.HttpResponseStatus import org.assertj.core.api.Assertions.assertThat import org.jetbrains.ide.TestManager.TestDescriptor import org.junit.Test -import java.io.BufferedOutputStream -import java.io.OutputStreamWriter import java.net.HttpURLConnection import java.net.URL @@ -72,13 +69,13 @@ private class RestApiTest : BuiltInServerTestCase() { connection = URL("$serviceUrl").openConnection() as HttpURLConnection connection.requestMethod = "POST" connection.doOutput = true - val writer = JsonWriter(OutputStreamWriter(BufferedOutputStream(connection.outputStream), CharsetToolkit.UTF8_CHARSET)) - writer.beginObject() - writer.name("file").value(manager.filePath) - writer.name("line").value(line) - writer.name("column").value(column) - writer.endObject() - writer.close() + JsonWriter(connection.outputStream.bufferedWriter()).use { + it.beginObject() + it.name("file").value(manager.filePath) + it.name("line").value(line) + it.name("column").value(column) + it.endObject() + } assertThat(HttpResponseStatus.valueOf(connection.responseCode)).isEqualTo(expectedStatus) } } diff --git a/platform/configuration-store-impl/src/FileBasedStorage.kt b/platform/configuration-store-impl/src/FileBasedStorage.kt index 3d799134b6bc..27f1e106e14f 100644 --- a/platform/configuration-store-impl/src/FileBasedStorage.kt +++ b/platform/configuration-store-impl/src/FileBasedStorage.kt @@ -27,6 +27,7 @@ import com.intellij.openapi.components.StoragePathMacros import com.intellij.openapi.components.TrackingPathMacroSubstitutor import com.intellij.openapi.components.impl.stores.StorageUtil import com.intellij.openapi.components.store.ReadOnlyModificationException +import com.intellij.openapi.diagnostic.debug import com.intellij.openapi.fileEditor.impl.LoadTextUtil import com.intellij.openapi.util.JDOMUtil import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream @@ -113,9 +114,7 @@ open class FileBasedStorage(file: File, try { val file = getVirtualFile() if (file == null || file.isDirectory || !file.isValid) { - if (LOG.isDebugEnabled) { - LOG.debug("Document was not loaded for $fileSpec file is ${if (file == null) "null" else "directory"}") - } + LOG.debug { "Document was not loaded for $fileSpec file is ${if (file == null) "null" else "directory"}" } } else if (file.length == 0L) { processReadException(null) @@ -194,10 +193,7 @@ private fun isEqualContent(result: VirtualFile, lineSeparator: LineSeparator, co } private fun doWrite(requestor: Any, file: VirtualFile, content: Any, lineSeparator: LineSeparator, prependXmlProlog: Boolean) { - if (LOG.isDebugEnabled) { - LOG.debug("Save ${file.presentableUrl}") - } - + LOG.debug { "Save ${file.presentableUrl}" } val token = WriteAction.start() try { val out = file.getOutputStream(requestor) diff --git a/platform/configuration-store-impl/src/StateMap.kt b/platform/configuration-store-impl/src/StateMap.kt index 1ea0b98b8097..403e0f4ef31c 100644 --- a/platform/configuration-store-impl/src/StateMap.kt +++ b/platform/configuration-store-impl/src/StateMap.kt @@ -32,6 +32,9 @@ import java.util.* import java.util.concurrent.atomic.AtomicReferenceArray class StateMap private constructor(private val names: Array, private val states: AtomicReferenceArray) { + override fun toString(): String = + if (this == EMPTY) "EMPTY" else states.toString(); + companion object { private val XML_FORMAT = Format.getRawFormat().setTextMode(Format.TextMode.TRIM).setOmitEncoding(true).setOmitDeclaration(true) diff --git a/platform/configuration-store-impl/src/StoreAwareProjectManager.kt b/platform/configuration-store-impl/src/StoreAwareProjectManager.kt index b180c871612b..2f1ad5d405ae 100644 --- a/platform/configuration-store-impl/src/StoreAwareProjectManager.kt +++ b/platform/configuration-store-impl/src/StoreAwareProjectManager.kt @@ -24,6 +24,7 @@ import com.intellij.openapi.components.ComponentManager import com.intellij.openapi.components.StateStorage import com.intellij.openapi.components.impl.stores.* import com.intellij.openapi.components.stateStore +import com.intellij.openapi.diagnostic.debug import com.intellij.openapi.module.Module import com.intellij.openapi.progress.ProgressManager import com.intellij.openapi.project.Project @@ -117,9 +118,7 @@ class StoreAwareProjectManager(virtualFileManager: VirtualFileManager, progressM private fun isReloadUnblocked(): Boolean { val count = reloadBlockCount.get() - if (LOG.isDebugEnabled) { - LOG.debug("[RELOAD] myReloadBlockCount = $count") - } + LOG.debug { "[RELOAD] myReloadBlockCount = $count" } return count == 0 } diff --git a/platform/configuration-store-impl/src/XmlElementStorage.kt b/platform/configuration-store-impl/src/XmlElementStorage.kt index e50f262475ac..d0125c08bc4a 100644 --- a/platform/configuration-store-impl/src/XmlElementStorage.kt +++ b/platform/configuration-store-impl/src/XmlElementStorage.kt @@ -19,13 +19,13 @@ import com.intellij.openapi.components.RoamingType import com.intellij.openapi.components.StateStorage import com.intellij.openapi.components.TrackingPathMacroSubstitutor import com.intellij.openapi.components.impl.stores.FileStorageCoreUtil +import com.intellij.openapi.diagnostic.debug import com.intellij.openapi.util.JDOMUtil import com.intellij.util.containers.ContainerUtil import com.intellij.util.containers.SmartHashSet import gnu.trove.THashMap import org.jdom.Attribute import org.jdom.Element -import java.io.IOException abstract class XmlElementStorage protected constructor(protected val fileSpec: String, protected val rootElementName: String, @@ -87,16 +87,12 @@ abstract class XmlElementStorage protected constructor(protected val fileSpec: S val oldData = storageDataRef.get() val newData = getStorageData(true) if (oldData == null) { - if (LOG.isDebugEnabled) { - LOG.debug("analyzeExternalChangesAndUpdateIfNeed: old data null, load new for ${toString()}") - } + LOG.debug { "analyzeExternalChangesAndUpdateIfNeed: old data null, load new for ${toString()}" } componentNames.addAll(newData.keys()) } else { val changedComponentNames = oldData.getChangedComponentNames(newData) - if (LOG.isDebugEnabled) { - LOG.debug("analyzeExternalChangesAndUpdateIfNeed: changedComponentNames $changedComponentNames for ${toString()}") - } + LOG debug { "analyzeExternalChangesAndUpdateIfNeed: changedComponentNames $changedComponentNames for ${toString()}" } if (!ContainerUtil.isEmpty(changedComponentNames)) { componentNames.addAll(changedComponentNames) } diff --git a/platform/core-api/src/com/intellij/openapi/components/PersistentStateComponent.java b/platform/core-api/src/com/intellij/openapi/components/PersistentStateComponent.java index 64d3cfaf8a32..df8eed4d1255 100644 --- a/platform/core-api/src/com/intellij/openapi/components/PersistentStateComponent.java +++ b/platform/core-api/src/com/intellij/openapi/components/PersistentStateComponent.java @@ -24,7 +24,8 @@ import org.jetbrains.annotations.Nullable; * See IntelliJ Platform SDK DevGuide * for detailed description. * - * Implementation must be thread-safe - a component should expect these methods to be called at any moment of its lifecycle. + * In general, implementation should be thread-safe, because "loadState" is called from the same thread where component is initialized. + * If component used only from one thread (e.g. EDT), thread-safe implementation is not required. */ public interface PersistentStateComponent { /** diff --git a/platform/core-impl/src/com/intellij/codeInsight/CodeInsightUtilCore.java b/platform/core-impl/src/com/intellij/codeInsight/CodeInsightUtilCore.java index fef3b5703a43..2181e43f96f6 100644 --- a/platform/core-impl/src/com/intellij/codeInsight/CodeInsightUtilCore.java +++ b/platform/core-impl/src/com/intellij/codeInsight/CodeInsightUtilCore.java @@ -28,6 +28,9 @@ import com.intellij.util.ReflectionUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Arrays; +import java.util.List; + public abstract class CodeInsightUtilCore extends FileModificationService { public static T findElementInRange(@NotNull PsiFile file, int startOffset, @@ -78,7 +81,12 @@ public abstract class CodeInsightUtilCore extends FileModificationService { } public static boolean parseStringCharacters(@NotNull String chars, @NotNull StringBuilder outChars, @Nullable int[] sourceOffsets) { + return parseStringCharacters(chars, outChars, sourceOffsets, '"', '\''); + } + + public static boolean parseStringCharacters(@NotNull String chars, @NotNull StringBuilder outChars, @Nullable int[] sourceOffsets, Character... endChars) { assert sourceOffsets == null || sourceOffsets.length == chars.length()+1; + List endCharList = Arrays.asList(endChars); if (chars.indexOf('\\') < 0) { outChars.append(chars); if (sourceOffsets != null) { @@ -123,14 +131,6 @@ public abstract class CodeInsightUtilCore extends FileModificationService { outChars.append('\r'); break; - case'"': - outChars.append('"'); - break; - - case'\'': - outChars.append('\''); - break; - case'\\': outChars.append('\\'); break; @@ -193,7 +193,11 @@ public abstract class CodeInsightUtilCore extends FileModificationService { break; default: - return false; + if (endCharList.contains(c)) { + outChars.append(c); + } else { + return false; + } } if (sourceOffsets != null) { sourceOffsets[outChars.length()-outOffset] = index; diff --git a/platform/icons/src/xml/browsers/edge16.png b/platform/icons/src/xml/browsers/edge16.png new file mode 100644 index 000000000000..80ea90842c97 Binary files /dev/null and b/platform/icons/src/xml/browsers/edge16.png differ diff --git a/platform/icons/src/xml/browsers/edge16@2x.png b/platform/icons/src/xml/browsers/edge16@2x.png new file mode 100644 index 000000000000..de81b85536d4 Binary files /dev/null and b/platform/icons/src/xml/browsers/edge16@2x.png differ diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleRegex.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleRegex.java index 8eae08363699..420a15b026db 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleRegex.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleRegex.java @@ -35,7 +35,7 @@ public class ToggleRegex extends EditorHeaderToggleAction { FindModel findModel = session.getFindModel(); findModel.setRegularExpressions(selected); if (selected) { - findModel.setWholeWordsOnly(true); + findModel.setWholeWordsOnly(false); } FindSettings.getInstance().setLocalRegularExpressions(selected); } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java index 01df71fb6b58..480dfca26df7 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java @@ -1221,7 +1221,16 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } else if (isSetting(value)) { String text = getSettingText((OptionDescription)value); - append(text); + SimpleTextAttributes attrs = SimpleTextAttributes.REGULAR_ATTRIBUTES; + if (value instanceof Changeable && ((Changeable)value).hasChanged()) { + if (selected) { + attrs = SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES; + } else { + SimpleTextAttributes base = SimpleTextAttributes.LINK_BOLD_ATTRIBUTES; + attrs = base.derive(SimpleTextAttributes.STYLE_BOLD, base.getFgColor(), null, null); + } + } + append(text, attrs); final String id = ((OptionDescription)value).getConfigurableId(); final String name = myConfigurables.get(id); if (name != null) { diff --git a/platform/platform-api/src/com/intellij/ui/Changeable.java b/platform/platform-api/src/com/intellij/ui/Changeable.java new file mode 100644 index 000000000000..dab15fb58817 --- /dev/null +++ b/platform/platform-api/src/com/intellij/ui/Changeable.java @@ -0,0 +1,26 @@ +/* + * Copyright 2000-2015 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.ui; + +/** + * This markup interface is used to provide meta-information to element renderers + * + * @author Konstantin Bulenkov + * @since 15.0 + */ +public interface Changeable { + boolean hasChanged(); +} diff --git a/platform/platform-impl/src/com/intellij/ide/ui/RegistryBooleanOptionDescriptor.java b/platform/platform-impl/src/com/intellij/ide/ui/RegistryBooleanOptionDescriptor.java index 7ee208c19dff..61abb041ef3e 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/RegistryBooleanOptionDescriptor.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/RegistryBooleanOptionDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -17,11 +17,12 @@ package com.intellij.ide.ui; import com.intellij.ide.ui.search.BooleanOptionDescription; import com.intellij.openapi.util.registry.Registry; +import com.intellij.ui.Changeable; /** * @author Konstantin Bulenkov */ -public class RegistryBooleanOptionDescriptor extends BooleanOptionDescription { +public class RegistryBooleanOptionDescriptor extends BooleanOptionDescription implements Changeable { private final String myKey; public RegistryBooleanOptionDescriptor(String option, String registryKey) { @@ -38,4 +39,9 @@ public class RegistryBooleanOptionDescriptor extends BooleanOptionDescription { public void setOptionState(boolean enabled) { Registry.get(myKey).setValue(enabled); } + + @Override + public boolean hasChanged() { + return Registry.get(myKey).isChangedFromDefault(); + } } diff --git a/platform/platform-impl/src/com/intellij/ide/ui/RegistryOptionsTopHitProvider.java b/platform/platform-impl/src/com/intellij/ide/ui/RegistryOptionsTopHitProvider.java index fa4a04e4771e..e84e1aadd408 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/RegistryOptionsTopHitProvider.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/RegistryOptionsTopHitProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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,7 +55,12 @@ public class RegistryOptionsTopHitProvider extends OptionsTopHitProvider { for (RegistryValue value : Registry.getAll()) { if (value.isBoolean()) { final String key = value.getKey(); - result.add(new RegistryBooleanOptionDescriptor(key, key)); + RegistryBooleanOptionDescriptor optionDescriptor = new RegistryBooleanOptionDescriptor(key, key); + if (value.isChangedFromDefault()) { + result.add(0, optionDescriptor); + } else { + result.add(optionDescriptor); + } } } return result; diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageBase.kt b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageBase.kt index 03f9840274fb..6e2168a4554a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageBase.kt +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageBase.kt @@ -17,14 +17,13 @@ package com.intellij.openapi.components.impl.stores import com.intellij.openapi.components.StateStorage import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.diagnostic.debug import org.jdom.Element import java.util.concurrent.atomic.AtomicReference -abstract class StateStorageBase : StateStorage { - companion object { - private val LOG: Logger = Logger.getInstance(StateStorageBase::class.java) - } +private val LOG: Logger = Logger.getInstance(StateStorageBase::class.java) +abstract class StateStorageBase : StateStorage { private var mySavingDisabled = false protected val storageDataRef: AtomicReference = AtomicReference() @@ -45,13 +44,11 @@ abstract class StateStorageBase : StateStorage { protected abstract fun hasState(storageData: T, componentName: String): Boolean - override fun hasState(componentName: String, reloadData: Boolean): Boolean { + override final fun hasState(componentName: String, reloadData: Boolean): Boolean { return hasState(getStorageData(reloadData), componentName) } - public fun getStorageData(): T = getStorageData(false) - - protected fun getStorageData(reload: Boolean): T { + protected fun getStorageData(reload: Boolean = false): T { val storageData = storageDataRef.get() if (storageData != null && !reload) { return storageData @@ -69,23 +66,17 @@ abstract class StateStorageBase : StateStorage { protected abstract fun loadData(): T public fun disableSaving() { - if (LOG.isDebugEnabled()) { - LOG.debug("Disabled saving for " + toString()) - } + LOG.debug { "Disabled saving for ${toString()}" } mySavingDisabled = true } public fun enableSaving() { - if (LOG.isDebugEnabled()) { - LOG.debug("Enabled saving " + toString()) - } + LOG.debug { "Enabled saving ${toString()}" } mySavingDisabled = false } protected fun checkIsSavingDisabled(): Boolean { - if (mySavingDisabled && LOG.isDebugEnabled()) { - LOG.debug("Saving disabled for " + toString()) - } + LOG.debug { "Saving disabled for ${toString()}" } return mySavingDisabled } } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/diagnostic/util.kt b/platform/platform-impl/src/com/intellij/openapi/diagnostic/util.kt new file mode 100644 index 000000000000..71ffc357970f --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/diagnostic/util.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2000-2015 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.openapi.diagnostic + +inline fun Logger.debug(lazyMessage: () -> String) { + if (isDebugEnabled) { + debug(lazyMessage()) + } +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ComplementaryFontsRegistry.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ComplementaryFontsRegistry.java index b295643c0cd9..7e5f99c602c9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ComplementaryFontsRegistry.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ComplementaryFontsRegistry.java @@ -15,13 +15,13 @@ */ package com.intellij.openapi.editor.impl; +import com.intellij.Patches; import com.intellij.ide.ui.AntialiasingType; import com.intellij.ide.ui.UISettings; import com.intellij.ide.ui.UISettingsListener; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.colors.FontPreferences; import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.SystemInfo; import gnu.trove.TIntHashSet; import org.intellij.lang.annotations.JdkConstants; import org.jetbrains.annotations.NonNls; @@ -111,7 +111,7 @@ public class ComplementaryFontsRegistry { if (ApplicationManager.getApplication().isUnitTestMode()) { ourFontNames.add("Monospaced"); } else { - if (SystemInfo.isMac) { + if (Patches.JDK_MAC_FONT_STYLE_BUG) { fillStyledFontMap(); } String[] fontNames = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(); @@ -199,7 +199,7 @@ public class ComplementaryFontsRegistry { @Nullable private static FontInfo doGetFontAbleToDisplay(char c, int size, @JdkConstants.FontStyle int style, @NotNull String defaultFontFamily) { synchronized (lock) { - if (SystemInfo.isMac && style > 0 && style < 4) { + if (Patches.JDK_MAC_FONT_STYLE_BUG && style > 0 && style < 4) { Pair[] replacement = ourStyledFontMap.get(defaultFontFamily); if (replacement != null) { defaultFontFamily = replacement[style].first; diff --git a/platform/platform-impl/src/com/intellij/ui/messages/SheetController.java b/platform/platform-impl/src/com/intellij/ui/messages/SheetController.java index 7c3240ac26db..3511604c6631 100755 --- a/platform/platform-impl/src/com/intellij/ui/messages/SheetController.java +++ b/platform/platform-impl/src/com/intellij/ui/messages/SheetController.java @@ -367,7 +367,7 @@ public class SheetController { } private static String handleBreaks(final String message) { - return message.replaceAll("(\r\n|\n)", "
"); + return message == null ? "" : message.replaceAll("(\r\n|\n)", "
"); } private void shiftButtonsToTheBottom(int shiftDistance) { diff --git a/platform/platform-resources/src/META-INF/XmlPlugin.xml b/platform/platform-resources/src/META-INF/XmlPlugin.xml index c33f9ef75e3d..b7ce21f6e5cf 100644 --- a/platform/platform-resources/src/META-INF/XmlPlugin.xml +++ b/platform/platform-resources/src/META-INF/XmlPlugin.xml @@ -11,9 +11,9 @@ - - com.intellij.javaee.DefaultHtmlDoctypeInitialConfigurator - + + + com.intellij.codeInsight.editorActions.XmlTagNameSynchronizer diff --git a/platform/platform-resources/src/META-INF/built-in-server.xml b/platform/platform-resources/src/META-INF/built-in-server.xml index 165a37cd25a1..63a623f6086a 100644 --- a/platform/platform-resources/src/META-INF/built-in-server.xml +++ b/platform/platform-resources/src/META-INF/built-in-server.xml @@ -27,6 +27,7 @@ + diff --git a/platform/util/src/com/intellij/Patches.java b/platform/util/src/com/intellij/Patches.java index 1c9294a4615f..dfbbce137097 100644 --- a/platform/util/src/com/intellij/Patches.java +++ b/platform/util/src/com/intellij/Patches.java @@ -129,4 +129,10 @@ public class Patches { * See JDK-8042123 */ public static final boolean JDK_BUG_ID_8042123 = !SystemInfo.isJavaVersionAtLeast("1.8.0_40"); + + /** + * Older JDK versions could mistakenly use derived italics font, when genuine italics font was available in the system. + * The issue was fixed in JDK 1.8.0_60 as part of JDK-8064833. + */ + public static final boolean JDK_MAC_FONT_STYLE_BUG = SystemInfo.isMac && !SystemInfo.isJavaVersionAtLeast("1.8.0_60"); } diff --git a/platform/util/src/com/intellij/icons/AllIcons.java b/platform/util/src/com/intellij/icons/AllIcons.java index 46fb5fab897d..1eb40d1b1c2b 100644 --- a/platform/util/src/com/intellij/icons/AllIcons.java +++ b/platform/util/src/com/intellij/icons/AllIcons.java @@ -1224,6 +1224,7 @@ public class AllIcons { public static final Icon Canary16 = IconLoader.getIcon("/xml/browsers/canary16.png"); // 16x16 public static final Icon Chrome16 = IconLoader.getIcon("/xml/browsers/chrome16.png"); // 16x16 public static final Icon Chromium16 = IconLoader.getIcon("/xml/browsers/chromium16.png"); // 16x16 + public static final Icon Edge16 = IconLoader.getIcon("/xml/browsers/edge16.png"); // 16x16 public static final Icon Explorer16 = IconLoader.getIcon("/xml/browsers/explorer16.png"); // 16x16 public static final Icon Firefox16 = IconLoader.getIcon("/xml/browsers/firefox16.png"); // 16x16 public static final Icon Nwjs16 = IconLoader.getIcon("/xml/browsers/nwjs16.png"); // 16x16 diff --git a/platform/util/src/com/intellij/openapi/util/BuildNumber.java b/platform/util/src/com/intellij/openapi/util/BuildNumber.java index c720b7fbda95..c2b68b44c3c2 100644 --- a/platform/util/src/com/intellij/openapi/util/BuildNumber.java +++ b/platform/util/src/com/intellij/openapi/util/BuildNumber.java @@ -181,11 +181,6 @@ public class BuildNumber implements Comparable { @Override public int compareTo(@NotNull BuildNumber o) { - //if both are snapshots then IDEA and plugin are built from sources, - //in that case comparing baselines doesn't make sense, - //so we treat those builds equal - if (isSnapshot() && o.isSnapshot()) return 0; - if (myBaselineVersion == o.myBaselineVersion) return myBuildNumber - o.myBuildNumber; return myBaselineVersion - o.myBaselineVersion; } @@ -210,8 +205,6 @@ public class BuildNumber implements Comparable { BuildNumber that = (BuildNumber)o; - if (isSnapshot() && ((BuildNumber)o).isSnapshot()) return true; - if (myBaselineVersion != that.myBaselineVersion) return false; if (myBuildNumber != that.myBuildNumber) return false; if (!myProductCode.equals(that.myProductCode)) return false; @@ -222,9 +215,6 @@ public class BuildNumber implements Comparable { @Override public int hashCode() { - if (isSnapshot()) { - return 0; - } int result = myProductCode.hashCode(); result = 31 * result + myBaselineVersion; result = 31 * result + myBuildNumber; diff --git a/platform/util/src/com/intellij/util/CompressionUtil.java b/platform/util/src/com/intellij/util/CompressionUtil.java index fe2fa15d45c3..ee36d99ea042 100644 --- a/platform/util/src/com/intellij/util/CompressionUtil.java +++ b/platform/util/src/com/intellij/util/CompressionUtil.java @@ -63,12 +63,12 @@ public class CompressionUtil { public static final boolean DUMP_COMPRESSION_STATS = SystemProperties.getBooleanProperty("idea.dump.compression.stats", false); public static int writeCompressedWithoutOriginalBufferLength(@NotNull DataOutput out, @NotNull byte[] bytes, int length) throws IOException { - long started = System.nanoTime(); + long started = DUMP_COMPRESSION_STATS ? System.nanoTime() : 0; final byte[] compressedOutputBuffer = spareBufferLocal.getBuffer(Snappy.maxCompressedLength(length)); int compressedSize = Snappy.compress(bytes, 0, length, compressedOutputBuffer, 0); - final long time = System.nanoTime() - started; + final long time = (DUMP_COMPRESSION_STATS ? System.nanoTime() : 0) - started; mySizeAfterCompression.addAndGet(compressedSize); mySizeBeforeCompression.addAndGet(length); int requests = myCompressionRequests.incrementAndGet(); @@ -92,11 +92,11 @@ public class CompressionUtil { in.readFully(bytes, 0, size); int decompressedRequests = myDecompressionRequests.incrementAndGet(); - long started = System.nanoTime(); + long started = DUMP_COMPRESSION_STATS ? System.nanoTime() : 0; byte[] decompressedResult = Snappy.uncompress(bytes, 0, size); - long doneTime = System.nanoTime() - started; + long doneTime = (DUMP_COMPRESSION_STATS ? System.nanoTime() : 0) - started; long decompressedSize = myDecompressedSize.addAndGet(size); long decompressedTime = myDecompressionTime.addAndGet(doneTime); if (DUMP_COMPRESSION_STATS && decompressedRequests % 1000 == 0) { diff --git a/platform/util/src/com/intellij/util/io/CompressedAppendableFile.java b/platform/util/src/com/intellij/util/io/CompressedAppendableFile.java index 32e1faed15b4..052a63d2a8b6 100644 --- a/platform/util/src/com/intellij/util/io/CompressedAppendableFile.java +++ b/platform/util/src/com/intellij/util/io/CompressedAppendableFile.java @@ -22,7 +22,6 @@ import com.intellij.util.CompressionUtil; import com.intellij.util.SystemProperties; import com.intellij.util.containers.SLRUMap; import gnu.trove.TLongArrayList; -import org.iq80.snappy.CorruptionException; import org.jetbrains.annotations.NotNull; import java.io.*; @@ -201,11 +200,13 @@ public class CompressedAppendableFile { } catch (IOException ignore) {} } - assert false; + assert false:"data corruption detected:"+chunkNumber + "," + myChunkTableLength; return ArrayUtil.EMPTY_BYTE_ARRAY; } - catch (CorruptionException e) { + catch (RuntimeException e) { // CorruptedException, ArrayIndexOutofBounds, etc throw new IOException(e); + } catch(AssertionError ae) { + throw new IOException(ae); } } diff --git a/platform/util/src/com/intellij/util/io/PersistentHashMapValueStorage.java b/platform/util/src/com/intellij/util/io/PersistentHashMapValueStorage.java index 20b168a81fd4..ab1a59128a99 100644 --- a/platform/util/src/com/intellij/util/io/PersistentHashMapValueStorage.java +++ b/platform/util/src/com/intellij/util/io/PersistentHashMapValueStorage.java @@ -354,7 +354,7 @@ public class PersistentHashMapValueStorage { forceAppender(myPath); checkCancellation(); - long startedTime = System.nanoTime(); + long startedTime = ourDumpChunkRemovalTime ? System.nanoTime() : 0; long chunk = tailChunkAddress; int chunkCount = 0; @@ -426,7 +426,7 @@ public class PersistentHashMapValueStorage { if (chunkCount > 1 && !myCompactionMode) { checkCancellation(); - long endCompactionTime = System.nanoTime(); + long endCompactionTime = ourDumpChunkRemovalTime ? System.nanoTime() : 0; long diff = endCompactionTime - startedTime; myChunksRemovalTime += diff; diff --git a/platform/util/testSrc/com/intellij/openapi/util/BuildNumberTest.java b/platform/util/testSrc/com/intellij/openapi/util/BuildNumberTest.java index f2e3e0bebfaa..c5690842a29d 100644 --- a/platform/util/testSrc/com/intellij/openapi/util/BuildNumberTest.java +++ b/platform/util/testSrc/com/intellij/openapi/util/BuildNumberTest.java @@ -41,7 +41,7 @@ public class BuildNumberTest { assertTrue(BuildNumber.fromString("90.SNAPSHOT").compareTo(BuildNumber.fromString("90.12345")) > 0); assertTrue(BuildNumber.fromString("IU-90.SNAPSHOT").compareTo(BuildNumber.fromString("RM-90.12345")) > 0); assertTrue(BuildNumber.fromString("IU-90.SNAPSHOT").compareTo(BuildNumber.fromString("RM-100.12345")) < 0); - assertTrue(BuildNumber.fromString("IU-90.SNAPSHOT").compareTo(BuildNumber.fromString("RM-100.SNAPSHOT")) == 0); + assertTrue(BuildNumber.fromString("IU-90.SNAPSHOT").compareTo(BuildNumber.fromString("RM-100.SNAPSHOT")) < 0); assertTrue(BuildNumber.fromString("IU-90.SNAPSHOT").compareTo(BuildNumber.fromString("RM-90.SNAPSHOT")) == 0); } } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/abstraction/MagicNumberInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/abstraction/MagicNumberInspectionBase.java index a664d01a92dc..222c5715c602 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/abstraction/MagicNumberInspectionBase.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/abstraction/MagicNumberInspectionBase.java @@ -93,7 +93,7 @@ public class MagicNumberInspectionBase extends BaseInspection { return; } final PsiField field = PsiTreeUtil.getParentOfType(expression, PsiField.class); - if (field != null && PsiUtil.isCompileTimeConstant(field)) { + if (field != null && PsiUtil.isCompileTimeConstant((PsiVariable)field)) { return; } final PsiElement parent = expression.getParent(); diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/IteratorHasNextCallsIteratorNextInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/IteratorHasNextCallsIteratorNextInspection.java index ea55c8778593..ba62d217d304 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/IteratorHasNextCallsIteratorNextInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/IteratorHasNextCallsIteratorNextInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2015 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,7 +23,6 @@ import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.psiutils.IteratorUtils; import com.siyeh.ig.psiutils.MethodUtils; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; public class IteratorHasNextCallsIteratorNextInspection @@ -48,15 +47,12 @@ public class IteratorHasNextCallsIteratorNextInspection return new IteratorHasNextCallsIteratorNext(); } - private static class IteratorHasNextCallsIteratorNext - extends BaseInspectionVisitor { + private static class IteratorHasNextCallsIteratorNext extends BaseInspectionVisitor { @Override public void visitMethod(@NotNull PsiMethod method) { // note: no call to super - @NonNls final String name = method.getName(); - if (!MethodUtils.methodMatches(method, CommonClassNames.JAVA_UTIL_ITERATOR, null, - HardcodedMethodConstants.HAS_NEXT)) { + if (!MethodUtils.methodMatches(method, CommonClassNames.JAVA_UTIL_ITERATOR, null, HardcodedMethodConstants.HAS_NEXT)) { return; } if (!IteratorUtils.containsCallToIteratorNext(method, null, true)) { diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/IfMayBeConditionalInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/IfMayBeConditionalInspection.java index f75617403e5c..04724eb4d929 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/IfMayBeConditionalInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/IfMayBeConditionalInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2012 Bas Leijdekkers + * Copyright 2008-2015 Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -190,6 +190,9 @@ public class IfMayBeConditionalInspection extends BaseInspection { @Override public void visitIfStatement(PsiIfStatement statement) { super.visitIfStatement(statement); + if (ControlFlowUtils.isElseIf(statement)) { + return; + } final PsiStatement thenBranch = statement.getThenBranch(); final PsiStatement elseBranch = statement.getElseBranch(); final PsiStatement thenStatement = ControlFlowUtils.stripBraces(thenBranch); diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/FieldMayBeStaticInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/FieldMayBeStaticInspection.java index 40b06c127967..fcdcdbfa22fe 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/FieldMayBeStaticInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/FieldMayBeStaticInspection.java @@ -77,11 +77,11 @@ public class FieldMayBeStaticInspection extends BaseInspection { if (containingClass != null && !containingClass.hasModifierProperty(PsiModifier.STATIC) && containingClass.getContainingClass() != null - && !PsiUtil.isCompileTimeConstant(field)) { + && !PsiUtil.isCompileTimeConstant((PsiVariable)field)) { // inner class cannot have static declarations return; } - if (containingClass instanceof PsiAnonymousClass && !PsiUtil.isCompileTimeConstant(field)) { + if (containingClass instanceof PsiAnonymousClass && !PsiUtil.isCompileTimeConstant((PsiVariable)field)) { return; } if (!canBeStatic(initializer)) { diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/IteratorUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/IteratorUtils.java index 4f4cb93b62e2..f2e1e9ab5e15 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/IteratorUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/IteratorUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2011 Bas Leijdekkers + * Copyright 2003-2015 Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -96,9 +96,8 @@ public class IteratorUtils { } } else { - if (!MethodCallUtils.isCallToMethod(expression, - CommonClassNames.JAVA_UTIL_ITERATOR, null, - HardcodedMethodConstants.NEXT)) { + if (!MethodCallUtils.isCallToMethod(expression, CommonClassNames.JAVA_UTIL_ITERATOR, null, HardcodedMethodConstants.NEXT) + && !MethodCallUtils.isCallToMethod(expression, "java.util.ListIterator", null, "previous")) { return; } } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/if_may_be_conditional/IfMayBeConditional.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/if_may_be_conditional/IfMayBeConditional.java index 1109243d24a2..4f8524d2600a 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/if_may_be_conditional/IfMayBeConditional.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/if_may_be_conditional/IfMayBeConditional.java @@ -9,11 +9,11 @@ public class IfMayBeConditional { void foo2(int a, int b) { int c = 0; - if (a < b) { c += a - b; } else { c += b; } + if (a < b) { c += a - b; } else { c += b; } } void foo3(int i, StringBuilder sb) { - if (i == 0) { + if (i == 0) { sb.append("type.getConstructor()", 0, 1); } else { @@ -22,7 +22,7 @@ public class IfMayBeConditional { } int foo4(int a, int b) { - if (a < b) return a; + if (a < b) return a; else return b; } @@ -42,4 +42,17 @@ public class IfMayBeConditional { i = b < c ? b : c; } } + + void largeIf(boolean a, boolean b, boolean c) { + final String value; + if (a) { + value = "a"; + } else if (b) { + value = "b"; + } else if (c) { + value = "c"; + } else { + value = "d"; + } + } } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/if_may_be_conditional/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/if_may_be_conditional/expected.xml deleted file mode 100644 index 3ecb05a6e414..000000000000 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/if_may_be_conditional/expected.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - IfMayBeConditional.java - 12 - If statement could be replaced with simple conditional expression - <code>if</code> could be replaced with simple conditional expression #loc - - - - IfMayBeConditional.java - 16 - 'if' statement could be replaced with simple conditional expression - <code>if</code> could be replaced with simple conditional expression #loc - - - - IfMayBeConditional.java - 25 - 'if' statement could be replaced with conditional expression - <code>if</code> could be replaced with conditional expression #loc - - \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/IteratorHasNextCallsIteratorNextInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/IteratorHasNextCallsIteratorNextInspectionTest.java new file mode 100644 index 000000000000..bd09bdcc14bb --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/IteratorHasNextCallsIteratorNextInspectionTest.java @@ -0,0 +1,70 @@ +/* + * Copyright 2000-2015 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.ig.bugs; + +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.Nullable; + +/** + * @author Bas Leijdekkers + */ +public class IteratorHasNextCallsIteratorNextInspectionTest extends LightInspectionTestCase { + + public void testHasNextCallsNext() { + doTest("import java.util.*;" + + "class MyIterator implements Iterator {" + + " private Iterator iterator;" + + " public MyIterator(Iterator iterator) {" + + " this.iterator = iterator;" + + " }" + + " public boolean /*'Iterator.hasNext()' contains call to 'next()'*/hasNext/**/() {" + + " return next() != null;" + + " }" + + " public T next() {" + + " return iterator.next();" + + " }" + + " public void remove() {" + + " iterator.remove();" + + " }" + + "}"); + } + + public void testHasNextCallsPrevious() { + doTest("import java.util.*;" + + "abstract class MyIterator implements ListIterator {" + + " private ListIterator iterator;" + + " public MyIterator(ListIterator iterator) {" + + " this.iterator = iterator;" + + " }" + + " public boolean /*'Iterator.hasNext()' contains call to 'next()'*/hasNext/**/() {" + + " return previous() != null;" + + " }" + + " public T next() {" + + " return iterator.next();" + + " }" + + " public T previous() {" + + " return iterator.previous();" + + " }" + + "}"); + } + + @Nullable + @Override + protected InspectionProfileEntry getInspection() { + return new IteratorHasNextCallsIteratorNextInspection(); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/IteratorNextDoesNotThrowNoSuchElementExceptionInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/IteratorNextDoesNotThrowNoSuchElementExceptionInspectionTest.java new file mode 100644 index 000000000000..f5fad269994d --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/IteratorNextDoesNotThrowNoSuchElementExceptionInspectionTest.java @@ -0,0 +1,66 @@ +/* + * Copyright 2000-2015 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.ig.bugs; + +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; +import junit.framework.TestCase; +import org.jetbrains.annotations.Nullable; + +/** + * @author Bas Leijdekkers + */ +public class IteratorNextDoesNotThrowNoSuchElementExceptionInspectionTest extends LightInspectionTestCase { + + public void testPrevious() { + doTest("import java.util.*;" + + "class ReverseListIterator implements Iterator {" + + " private ListIterator iterator;" + + " public ReverseListIterator(List list) {" + + " this.iterator = list.listIterator(list.size());" + + " }" + + " public boolean hasNext() {" + + " return iterator.hasPrevious();" + + " }" + + " public T next() {" + + " return iterator.previous();" + + " }" + + " public void remove() {" + + " iterator.remove();" + + " }" + + "}"); + } + + public void testEmpty() { + doTest("import java.util.*;" + + "class EmptyIterator implements Iterator {" + + " public boolean hasNext() {" + + " return false;" + + " }" + + " public T /*'Iterator.next()' which can't throw 'NoSuchElementException'*/next/**/() {" + + " return null;" + + " }" + + " public void remove() {" + + " }" + + "}"); + } + + @Nullable + @Override + protected InspectionProfileEntry getInspection() { + return new IteratorNextDoesNotThrowNoSuchElementExceptionInspection(); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/controlflow/IfMayBeConditionalInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/controlflow/IfMayBeConditionalInspectionTest.java index 2a3ff34b7677..1f5b254068a5 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/controlflow/IfMayBeConditionalInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/controlflow/IfMayBeConditionalInspectionTest.java @@ -1,12 +1,20 @@ package com.siyeh.ig.controlflow; -import com.siyeh.ig.IGInspectionTestCase; +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.Nullable; -public class IfMayBeConditionalInspectionTest extends IGInspectionTestCase { +public class IfMayBeConditionalInspectionTest extends LightInspectionTestCase { - public void test() throws Exception { - final IfMayBeConditionalInspection tool = new IfMayBeConditionalInspection(); - tool.reportMethodCalls = true; - doTest("com/siyeh/igtest/controlflow/if_may_be_conditional", tool); + public void testIfMayBeConditional() throws Exception { + doTest(); + } + + @Nullable + @Override + protected InspectionProfileEntry getInspection() { + final IfMayBeConditionalInspection inspection = new IfMayBeConditionalInspection(); + inspection.reportMethodCalls = true; + return inspection; } } \ No newline at end of file diff --git a/plugins/devkit/testSources/PluginProjectWizardTest.java b/plugins/devkit/testSources/PluginProjectWizardTest.java index 99ba3f4cbb9c..af96140257ce 100644 --- a/plugins/devkit/testSources/PluginProjectWizardTest.java +++ b/plugins/devkit/testSources/PluginProjectWizardTest.java @@ -36,7 +36,7 @@ public class PluginProjectWizardTest extends NewProjectWizardTestCase { createSdk("devkit", IdeaJdk.getInstance()); Project project = createProjectFromTemplate(PluginModuleType.getInstance().getName(), null, null); VirtualFile baseDir = project.getBaseDir(); - VirtualFile virtualFile = VfsUtilCore.findRelativeFile("META-INF/plugin.xml", baseDir); + VirtualFile virtualFile = VfsUtilCore.findRelativeFile("resources/META-INF/plugin.xml", baseDir); assertNotNull(virtualFile); RunnerAndConfigurationSettings configuration = RunManager.getInstance(project).getSelectedConfiguration(); diff --git a/plugins/maven/maven3-server-common/maven3-server-common.iml b/plugins/maven/maven3-server-common/maven3-server-common.iml index c48f45961ae9..585533b9a91d 100644 --- a/plugins/maven/maven3-server-common/maven3-server-common.iml +++ b/plugins/maven/maven3-server-common/maven3-server-common.iml @@ -4,7 +4,6 @@ - diff --git a/plugins/maven/maven30-server-impl/maven30-server-impl.iml b/plugins/maven/maven30-server-impl/maven30-server-impl.iml index 953e3dc5d7c4..61fd91b52dfa 100644 --- a/plugins/maven/maven30-server-impl/maven30-server-impl.iml +++ b/plugins/maven/maven30-server-impl/maven30-server-impl.iml @@ -4,7 +4,6 @@ - diff --git a/plugins/maven/maven32-server-impl/maven32-server-impl.iml b/plugins/maven/maven32-server-impl/maven32-server-impl.iml index b002fe636334..7d11ef040a60 100644 --- a/plugins/maven/maven32-server-impl/maven32-server-impl.iml +++ b/plugins/maven/maven32-server-impl/maven32-server-impl.iml @@ -4,7 +4,6 @@ - diff --git a/plugins/settings-repository/src/BaseRepositoryManager.kt b/plugins/settings-repository/src/BaseRepositoryManager.kt index b0b9fdb9fe3f..34d9dba052b1 100644 --- a/plugins/settings-repository/src/BaseRepositoryManager.kt +++ b/plugins/settings-repository/src/BaseRepositoryManager.kt @@ -17,6 +17,7 @@ package org.jetbrains.settingsRepository import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.invokeAndWaitIfNeed +import com.intellij.openapi.diagnostic.debug import com.intellij.openapi.fileTypes.StdFileTypes import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.vcs.merge.MergeDialogCustomizer @@ -80,9 +81,7 @@ public abstract class BaseRepositoryManager(protected val dir: File) : Repositor override fun read(path: String): InputStream? { if (isPathIgnored(path)) { - if (LOG.isDebugEnabled) { - LOG.debug("$path is ignored") - } + LOG.debug { "$path is ignored" } return null } @@ -114,15 +113,11 @@ public abstract class BaseRepositoryManager(protected val dir: File) : Repositor override fun write(path: String, content: ByteArray, size: Int): Boolean { if (isPathIgnored(path)) { - if (LOG.isDebugEnabled) { - LOG.debug("$path is ignored") - } + LOG.debug { "$path is ignored" } return false } - if (LOG.isDebugEnabled) { - LOG.debug("Write $path") - } + LOG.debug { "Write $path" } try { lock.write { @@ -145,9 +140,7 @@ public abstract class BaseRepositoryManager(protected val dir: File) : Repositor protected abstract fun addToIndex(file: File, path: String, content: ByteArray, size: Int) override fun delete(path: String) { - if (LOG.isDebugEnabled) { - LOG.debug("Remove $path") - } + LOG.debug { "Remove $path"} lock.write { val file = File(dir, path) @@ -212,7 +205,7 @@ class RepositoryVirtualFile(private val path: String) : LightVirtualFile(PathUti override fun getPath() = path override fun setBinaryContent(content: ByteArray, newModificationStamp: Long, newTimeStamp: Long, requestor: Any?) { - $content = content + this.content = content } override fun getOutputStream(requestor: Any?, newModificationStamp: Long, newTimeStamp: Long): OutputStream { diff --git a/plugins/settings-repository/src/git/commit.kt b/plugins/settings-repository/src/git/commit.kt index 997e9324fd24..379db2d50c76 100644 --- a/plugins/settings-repository/src/git/commit.kt +++ b/plugins/settings-repository/src/git/commit.kt @@ -15,6 +15,7 @@ */ package org.jetbrains.settingsRepository.git +import com.intellij.openapi.diagnostic.debug import com.intellij.openapi.progress.ProgressIndicator import com.intellij.util.PathUtilRt import com.intellij.util.SmartList @@ -54,9 +55,7 @@ fun commit(repository: Repository, indicator: ProgressIndicator?, commitMessageF } } - if (LOG.isDebugEnabled) { - LOG.debug(indexDiffToString(diff)) - } + LOG.debug { indexDiffToString(diff) } indicator?.checkCanceled() diff --git a/plugins/settings-repository/src/git/pull.kt b/plugins/settings-repository/src/git/pull.kt index 7a25678a7f02..e90cc5ac2aac 100644 --- a/plugins/settings-repository/src/git/pull.kt +++ b/plugins/settings-repository/src/git/pull.kt @@ -15,6 +15,7 @@ */ package org.jetbrains.settingsRepository.git +import com.intellij.openapi.diagnostic.debug import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.vfs.VirtualFile import com.intellij.util.SmartList @@ -64,9 +65,7 @@ open internal class Pull(val manager: GitRepositoryManager, val indicator: Progr var refToMerge = prefetchedRefToMerge ?: fetch() ?: return null val mergeResult = merge(refToMerge, mergeStrategy, commitMessage = commitMessage) val mergeStatus = mergeResult.status - if (LOG.isDebugEnabled) { - LOG.debug(mergeStatus.toString()) - } + LOG.debug { mergeStatus.toString() } if (mergeStatus == MergeStatus.CONFLICTING) { return resolveConflicts(mergeResult, repository) diff --git a/plugins/settings-repository/src/git/reset.kt b/plugins/settings-repository/src/git/reset.kt index 294bf47e29f4..94d95a9c4566 100644 --- a/plugins/settings-repository/src/git/reset.kt +++ b/plugins/settings-repository/src/git/reset.kt @@ -15,6 +15,7 @@ */ package org.jetbrains.settingsRepository.git +import com.intellij.openapi.diagnostic.debug import com.intellij.openapi.progress.ProgressIndicator import org.eclipse.jgit.api.MergeResult import org.eclipse.jgit.merge.MergeStrategy @@ -26,9 +27,7 @@ import org.jetbrains.settingsRepository.UpdateResult internal class Reset(manager: GitRepositoryManager, indicator: ProgressIndicator) : Pull(manager, indicator) { fun reset(toTheirs: Boolean, localRepositoryInitializer: (() -> Unit)? = null): UpdateResult { val message = if (toTheirs) "Overwrite local to ${manager.getUpstream()}" else "Overwrite remote ${manager.getUpstream()} to local" - if (LOG.isDebugEnabled) { - LOG.debug(message) - } + LOG.debug { message } val resetResult = repository.resetHard() val result = MutableUpdateResult(resetResult.updated.keySet(), resetResult.removed) diff --git a/python/src/com/jetbrains/python/run/AbstractPythonRunConfiguration.java b/python/src/com/jetbrains/python/run/AbstractPythonRunConfiguration.java index 0ed73cdb56af..4ae6aef48207 100644 --- a/python/src/com/jetbrains/python/run/AbstractPythonRunConfiguration.java +++ b/python/src/com/jetbrains/python/run/AbstractPythonRunConfiguration.java @@ -442,4 +442,9 @@ public abstract class AbstractPythonRunConfiguration