Skip to content

Commit

Permalink
First draft for import organization (part of clean-up).
Browse files Browse the repository at this point in the history
  • Loading branch information
fvgh committed Jun 13, 2019
1 parent f06c7cb commit 351a637
Show file tree
Hide file tree
Showing 9 changed files with 562 additions and 4 deletions.
4 changes: 2 additions & 2 deletions _ext/eclipse-jdt/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ ext {

dependencies {
compile "com.diffplug.spotless:spotless-eclipse-base:${VER_SPOTLESS_ECLISPE_BASE}"
compile("org.eclipse.jdt:org.eclipse.jdt.core:${VER_ECLIPSE_JDT_CORE}") {
compile("org.eclipse.jdt:org.eclipse.jdt.core.manipulation:${VER_ECLIPSE_JDT_CORE_MANIPULATION}") {
exclude group: 'org.eclipse.jdt', module: 'org.eclipse.jdt.launching'
exclude group: 'org.eclipse.platform', module: 'org.eclipse.ant.core'
exclude group: 'org.eclipse.platform', module: 'org.eclipse.core.expressions'
exclude group: 'org.eclipse.platform', module: 'org.eclipse.core.filesystem'
}
}
4 changes: 2 additions & 2 deletions _ext/eclipse-jdt/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Mayor/Minor versions correspond to the minimum Eclipse version supported/tested.
# Patch version is incremented for backward compatible patches of this library.
ext_version=4.8.0
ext_version=4.11.0
ext_artifactId=spotless-eclipse-jdt
ext_description=Eclipse's JDT formatter bundled for Spotless

Expand All @@ -11,5 +11,5 @@ ext_group=com.diffplug.spotless
ext_VER_JAVA=1.8

# Compile
VER_ECLIPSE_JDT_CORE=[3.12.0,4.0.0[
VER_ECLIPSE_JDT_CORE_MANIPULATION=[1.11.0,2.0.0[
VER_SPOTLESS_ECLISPE_BASE=[3.0.0,4.0.0[
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*
* Copyright 2016 DiffPlug
*
* 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.diffplug.spotless.extra.eclipse.java;

import java.util.Properties;

import org.eclipse.core.internal.runtime.InternalPlatform;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.content.IContentTypeManager;
import org.eclipse.core.runtime.preferences.DefaultScope;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.manipulation.CodeStyleConfiguration;
import org.eclipse.jdt.core.manipulation.JavaManipulation;
import org.eclipse.jdt.core.manipulation.OrganizeImportsOperation;
import org.eclipse.jdt.core.manipulation.SharedASTProviderCore;
import org.eclipse.jdt.internal.core.JavaCorePreferenceInitializer;
import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettingsConstants;

import com.diffplug.spotless.extra.eclipse.base.SpotlessEclipseFramework;

/** Clean-up step which calls out to the Eclipse JDT clean-up / import sorter. */
public class EclipseJdtCleanUpStepImpl {

/* The JDT UI shall be used for creating the settings. */
private final static String JDT_UI_PLUGIN_ID = "org.eclipse.jdt.ui";

private final IJavaProject jdtConfiguration;

public EclipseJdtCleanUpStepImpl(Properties settings) throws Exception {
if (SpotlessEclipseFramework.setup(
core -> {
/*
* For the Clean-Up, the indexer needs to exists (but is not used).
* The indexer is not created in headless mode by the JDT.
* To signal a non-headless mode, the platform state needs to by active
* (it is only resolved by default).
*/
core.add(new org.eclipse.core.internal.registry.osgi.Activator());
core.add(new org.eclipse.core.internal.runtime.PlatformActivator());
core.add(new org.eclipse.core.internal.preferences.Activator());
core.add(new org.eclipse.core.internal.runtime.Activator());
},
config -> {
config.hideEnvironment();
config.disableDebugging();
config.ignoreUnsupportedPreferences();
config.useTemporaryLocations();
config.changeSystemLineSeparator();

/*
* The default no content type specific handling is insufficient.
* The Java source type needs to be recognized by file extension.
*/
config.add(IContentTypeManager.class, new JavaContentTypeManager());
config.useSlf4J(EclipseJdtCleanUpStepImpl.class.getPackage().getName());

//Initialization of jdtConfiguration requires OS set
config.set(InternalPlatform.PROP_OS, "");
},
plugins -> {
plugins.applyDefault();

//JDT configuration requires an existing project source folder.
plugins.add(new org.eclipse.core.internal.filesystem.Activator());
plugins.add(new JavaCore());
})) {
new JavaCorePreferenceInitializer().initializeDefaultPreferences();
initializeJdtUiDefaultSettings();
}
jdtConfiguration = EclipseJdtFactory.createProject(settings);
}

private static void initializeJdtUiDefaultSettings() {
JavaManipulation.setPreferenceNodeId(JDT_UI_PLUGIN_ID);
IEclipsePreferences prefs = DefaultScope.INSTANCE.getNode(JDT_UI_PLUGIN_ID);

prefs.put(CodeStyleConfiguration.ORGIMPORTS_IMPORTORDER, "java;javax;org;com");
prefs.put(CodeStyleConfiguration.ORGIMPORTS_ONDEMANDTHRESHOLD, "99");
prefs.put(CodeStyleConfiguration.ORGIMPORTS_STATIC_ONDEMANDTHRESHOLD, "99");

prefs.put(CodeGenerationSettingsConstants.CODEGEN_KEYWORD_THIS, "false");
prefs.put(CodeGenerationSettingsConstants.CODEGEN_USE_OVERRIDE_ANNOTATION, "false");
prefs.put(CodeGenerationSettingsConstants.CODEGEN_ADD_COMMENTS, "true");
prefs.put(CodeGenerationSettingsConstants.ORGIMPORTS_IGNORELOWERCASE, "true");
}

public String organizeImport(String raw) throws Exception {
ICompilationUnit sourceContainer = EclipseJdtFactory.createJavaSource(raw, jdtConfiguration);
CompilationUnit ast = SharedASTProviderCore.getAST(sourceContainer, SharedASTProviderCore.WAIT_YES, null);
OrganizeImportsOperation formatOperation = new OrganizeImportsOperation(sourceContainer, ast, true, false, true, null);
try {
formatOperation.run(null);
return sourceContainer.getSource();
} catch (OperationCanceledException | CoreException e) {
throw new IllegalArgumentException("Invalid java syntax for formatting.", e);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/*
* Copyright 2016 DiffPlug
*
* 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.diffplug.spotless.extra.eclipse.java;

import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger;

import org.eclipse.core.internal.resources.OS;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.IBuffer;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.core.BufferManager;
import org.eclipse.jdt.internal.core.CompilationUnit;
import org.eclipse.jdt.internal.core.DefaultWorkingCopyOwner;
import org.eclipse.jdt.internal.core.JavaModelManager;
import org.eclipse.jdt.internal.core.PackageFragment;

/**
* Helper methods to create Java compilation unit.
* <p>
* The helper provides a pseudo extension of the OS (OS specific JARs are not provided with Spotless).
* The OS initialization is required for compilation unit validation
* (see {@code org.eclipse.core.internal.resources.LocationValidator} for details).
* </p>
*/
class EclipseJdtFactory extends OS {

private final static String ROOT_AS_SRC = "";
private final static String PROJECT_NAME = "spotless";
private final static String SOURCE_NAME = "source.java";
private final static AtomicInteger UNIQUE_PROJECT_ID = new AtomicInteger(0);

private final static Map<String, String> DEFAULT_OPTIONS;

static {
Map<String, String> defaultOptions = new HashMap<>();
defaultOptions.put(JavaCore.COMPILER_SOURCE, getJavaCoreVersion());
DEFAULT_OPTIONS = Collections.unmodifiableMap(defaultOptions);
}

private static String getJavaCoreVersion() {
final String javaVersion = System.getProperty("java.version");
final List<String> orderedSupportedCoreVersions = JavaCore.getAllVersions();
for (String coreVersion : orderedSupportedCoreVersions) {
if (javaVersion.startsWith(coreVersion)) {
return coreVersion;
}
}
return orderedSupportedCoreVersions.get(orderedSupportedCoreVersions.size() - 1);
}

/**
* Creates a JAVA project and applies the configuration.
* @param settings Configuration settings
* @return Configured JAVA project
* @throws Exception In case the project creation fails
*/
public final static IJavaProject createProject(Properties settings) throws Exception {
String uniqueProjectName = String.format("%s-%d", PROJECT_NAME, UNIQUE_PROJECT_ID.incrementAndGet());
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(uniqueProjectName);
// The project must be open before items (natures, folders, sources, ...) can be created
project.create(null);
project.open(0, null);
//If the project nature is not set, things like AST are not created for the Java projects
IProjectDescription description = project.getDescription();
description.setNatureIds(new String[]{JavaCore.NATURE_ID});
project.setDescription(description, null);
IJavaProject jProject = JavaCore.create(project);

Map<String, String> settingsMap = new HashMap<>(DEFAULT_OPTIONS);
settings.forEach((key, value) -> {
settingsMap.put(key.toString(), value.toString());
});
jProject.setOptions(settingsMap);

// Eclipse source files require an existing source folder for creation
IPackageFragmentRoot src = jProject.getPackageFragmentRoot(jProject.getProject());
IPackageFragment pkg = src.createPackageFragment(ROOT_AS_SRC, true, null);
IFolder folder = project.getFolder(uniqueProjectName);
folder.create(0, false, null);

// Eclipse clean-up requires an existing source file
pkg.createCompilationUnit(SOURCE_NAME, "", true, null);

//
disableSecondaryTypes(project);

return jProject;
}

private static void disableSecondaryTypes(IProject project) {
JavaModelManager.PerProjectInfo info = JavaModelManager.getJavaModelManager().getPerProjectInfo(project, true);
info.secondaryTypes = new Hashtable<String, Map<String, IType>>();
}

public static ICompilationUnit createJavaSource(String contents, IJavaProject jProject) throws Exception {
IPackageFragmentRoot src = jProject.getPackageFragmentRoot(jProject.getProject());
IPackageFragment pkg = src.getPackageFragment(ROOT_AS_SRC);
return new RamCompilationUnit((PackageFragment) pkg, contents);
}

/** Spotless keeps compilation units in RAM as long as they are worked on. */
private static class RamCompilationUnit extends CompilationUnit {

//Each RMA compilation unit has its own buffer manager. A drop is therefore prevented.
private final RamBufferManager manager;

RamCompilationUnit(PackageFragment parent, String contents) {
super(parent, SOURCE_NAME, DefaultWorkingCopyOwner.PRIMARY);
manager = new RamBufferManager();
IBuffer buffer = BufferManager.createBuffer(this);
buffer.setContents(contents.toCharArray());
manager.add(buffer);
}

@Override
public boolean exists() {
return true;
}

@Override
protected BufferManager getBufferManager() {
return manager;
}

@Override
public void save(IProgressMonitor pm, boolean force) throws JavaModelException {
//RAM CU is never saved to disk
}

@Override
public ICompilationUnit getWorkingCopy(IProgressMonitor monitor) throws JavaModelException {
throw new UnsupportedOperationException("Spotless RAM compilation unit cannot be copied.");
}

@Override
public boolean equals(Object obj) {
return this == obj; //Working copies are not supported
}
}

/** Work-around required package privileges when adding buffer for manager singleton */
private static class RamBufferManager extends BufferManager {
void add(IBuffer buffer) {
addBuffer(buffer);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright 2016 DiffPlug
*
* 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.diffplug.spotless.extra.eclipse.java;

import org.eclipse.core.internal.content.ContentType;
import org.eclipse.core.internal.content.ContentTypeCatalog;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.jdt.internal.compiler.util.SuffixConstants;

import com.diffplug.spotless.extra.eclipse.base.service.NoContentTypeSpecificHandling;

/**
* Java compilation unit validation requires Java content type to be recognized.
* <p>
* See {@code org.eclipse.jdt.internal.core.util.Util} for details.
* </p>
*/
public class JavaContentTypeManager extends NoContentTypeSpecificHandling {

private final IContentType contentType;

public JavaContentTypeManager() {
contentType = ContentType.createContentType(
new ContentTypeCatalog(null, 0),
"",
"",
(byte) 0,
new String[]{SuffixConstants.EXTENSION_java, SuffixConstants.EXTENSION_JAVA},
new String[0],
new String[0],
"",
"",
null,
null);
}

@Override
public IContentType getContentType(String contentTypeIdentifier) {
return contentType;
}

@Override
public IContentType[] getAllContentTypes() {
return new IContentType[]{contentType};
}

}
Loading

0 comments on commit 351a637

Please sign in to comment.