Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: handling of imports in pretty printer #2683

Merged
merged 25 commits into from
Sep 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/comments.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ We also try to understand to which element they are attached.
We use some simple heuristics that work well in nominal cases but cannot address all specific cases.
You can retrieve the comments of each `CtElement` via the API `CtElement.getComments()` which returns a `List<CtComment>`.

The parsing of the comments can be enabled in the Environment via the option `Environment.setCommentsEnable(boolean)` or the command line argument `--enable-comments` (or `-c`).
The parsing of the comments can be enabled in the Environment via the option `Environment.setCommentEnabled(boolean)` or the command line argument `--enable-comments` (or `-c`).

## Javadoc Comments

Expand Down
18 changes: 9 additions & 9 deletions doc/launcher.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,30 +28,30 @@ CtModel model = launcher.getModel();

### Pretty-printing modes

**Autoimport** Spoon can pretty-print code where all classes and methods are fully-qualified. This is not readable for humans but enables fast compilation and is useful when name collisions happen.
Spoon has three pretty-printing modes:

```java
launcher.getEnvironment().setAutoImports(false);
```
**Fully-qualified** Spoon can pretty-print code where all classes and methods are fully-qualified. This is the default behavior on `toString()` on AST elements.
This is not readable for humans but is useful when name collisions happen. If `launcher.getEnvironment().getToStringMode() == FULLYQUALIFIED`, the files written on disk are also fully qualified.

The autoimport mode computes the required imports, add the imports in the pretty-printed files, and writes class names unqualified (w/o package names):

**Autoimport** Spoon can pretty-print code where all classes and methods are imported as long as no conflict exists.

```java
// if true, the pretty-printed code is readable without fully-qualified names
launcher.getEnvironment().setAutoImports(true);
```

**Sniper mode** By default, when pretty-printing, Spoon reformats the code according to its own formatting rules.
The autoimport mode computes the required imports, add the imports in the pretty-printed files, and writes class names unqualified (w/o package names). This involves changing the field `implicit` of some elements of the model, through a set of `ImportAnalyzer`, most notable `ImportCleaner` and `ImportConflictDetector`.
When pretty-printing, Spoon reformats the code according to its own formatting rules that can be configured by providing a custom `TokenWriter`.

The sniper mode enables to rewrite only the transformed AST elements, so that the rest of the code is printed identically to the origin version. This is useful to get small diffs after automated refactoring.
**Sniper mode** The sniper mode enables to rewrite only the transformed AST elements, so that the rest of the code is printed identically to the origin version. This is useful to get small diffs after automated refactoring.

```java
launcher.getEnvironment().setPrettyPrinterCreator(() -> {
return new SniperJavaPrettyPrinter(launcher.getEnvironment());
}
);
```

**Comments** In addition, depending on the value of `Environment#getCommentEnabled`, the comments are removed or kept from the Java files saved to disk (call `Environment#setCommentEnabled(true)` to keep comments).

## The MavenLauncher class

Expand Down
4 changes: 3 additions & 1 deletion src/main/java/spoon/Launcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,9 @@ protected void processArguments() {
// environment initialization
environment.setComplianceLevel(jsapActualArgs.getInt("compliance"));
environment.setLevel(jsapActualArgs.getString("level"));
environment.setAutoImports(jsapActualArgs.getBoolean("imports"));
if (jsapActualArgs.getBoolean("imports")) {
environment.setPrettyPrintingMode(Environment.PRETTY_PRINTING_MODE.AUTOIMPORT);
}

if (jsapActualArgs.getBoolean("noclasspath")) {
Launcher.LOGGER.warn("The usage of --noclasspath argument is now deprecated: noclasspath is now the default behaviour.");
Expand Down
20 changes: 18 additions & 2 deletions src/main/java/spoon/compiler/Environment.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import org.apache.log4j.Level;
import spoon.OutputType;
import spoon.compiler.builder.EncodingProvider;
import spoon.support.modelobs.FineModelChangeListener;
import spoon.processing.FileGenerator;
import spoon.processing.ProblemFixer;
import spoon.processing.ProcessingManager;
Expand All @@ -17,9 +16,10 @@
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtMethod;
import spoon.reflect.visitor.PrettyPrinter;
import spoon.support.OutputDestinationHandler;
import spoon.support.CompressionType;
import spoon.support.OutputDestinationHandler;
import spoon.support.compiler.SpoonProgress;
import spoon.support.modelobs.FineModelChangeListener;
import spoon.support.sniper.SniperJavaPrettyPrinter;

import java.io.File;
Expand All @@ -43,6 +43,10 @@ public interface Environment {
*/
void setComplianceLevel(int level);

PRETTY_PRINTING_MODE getPrettyPrintingMode();

void setPrettyPrintingMode(PRETTY_PRINTING_MODE prettyPrintingMode);

/**
* This method should be called to print out a message with a source
* position link during the processing.
Expand Down Expand Up @@ -430,4 +434,16 @@ void report(Processor<?> processor, Level level,
* contains multiple times the same class
*/
void setIgnoreDuplicateDeclarations(boolean ignoreDuplicateDeclarations);

/** Drives how the model is pretty-printed to disk, or when {@link CtElement#prettyprint()} is called */
enum PRETTY_PRINTING_MODE {
/** no preprocessors are applied to the model before pretty-printing, this is the default behavior of @link {@link CtElement#toString()}. */
VANILLA,

/** autoimport mode, adds as many imports as possible */
AUTOIMPORT,

/** force everything to be fully-qualified */
FULLYQUALIFIED
}
}
16 changes: 16 additions & 0 deletions src/main/java/spoon/reflect/declaration/CtElement.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/
package spoon.reflect.declaration;

import spoon.compiler.Environment;
import spoon.processing.FactoryAccessor;
import spoon.reflect.code.CtComment;
import spoon.reflect.cu.SourcePosition;
Expand All @@ -19,6 +20,7 @@
import spoon.support.DerivedProperty;
import spoon.reflect.annotations.PropertyGetter;
import spoon.reflect.annotations.PropertySetter;
import spoon.support.Experimental;

import java.io.Serializable;
import java.lang.annotation.Annotation;
Expand Down Expand Up @@ -391,4 +393,18 @@ <E extends CtElement> List<E> getAnnotatedChildren(
*/
List<CtElement> getDirectChildren();

/**
* @return a debug version of the source code of this element, with fully-qualified types. Warning, some implicit elements are not shown in the string.
pvojtechovsky marked this conversation as resolved.
Show resolved Hide resolved
*
monperrus marked this conversation as resolved.
Show resolved Hide resolved
* {@link Environment#getPrettyPrintingMode()} is not taken into account, use {@link #prettyprint()} for a nice version of the source code.
*/
String toString();

/**
* @return the source code of this element accorfing to {@link Environment#getPrettyPrintingMode()}.
* Warning: this is not side-effect free, this triggers some {@link spoon.reflect.visitor.ImportAnalyzer} which would change the model: add/remove imports, change the value `implicit` of some model elements, etc.
*/
monperrus marked this conversation as resolved.
Show resolved Hide resolved
@Experimental
String prettyprint();

}
49 changes: 49 additions & 0 deletions src/main/java/spoon/reflect/visitor/DefaultImportComparator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Copyright (C) 2006-2019 INRIA and contributors
*
* Spoon is available either under the terms of the MIT License (see LICENSE-MIT.txt) of the Cecill-C License (see LICENSE-CECILL-C.txt). You as the user are entitled to choose the terms under which to adopt Spoon.
*/
package spoon.reflect.visitor;

import java.util.Comparator;

import spoon.reflect.declaration.CtImport;
import spoon.reflect.declaration.CtImportKind;


/**
* Defines order of imports:
* 1) imports are ordered alphabetically
* 2) static imports are last
*/
public class DefaultImportComparator implements Comparator<CtImport> {

@Override
public int compare(CtImport imp1, CtImport imp2) {
int dif = getImportKindOrder(imp1.getImportKind()) - getImportKindOrder(imp2.getImportKind());
if (dif != 0) {
return dif;
}
String str1 = removeSuffixSemicolon(imp1.toString());
String str2 = removeSuffixSemicolon(imp2.toString());
return str1.compareTo(str2);
}

private static String removeSuffixSemicolon(String str) {
if (str.endsWith(";")) {
return str.substring(0, str.length() - 1);
}
return str;
}

private int getImportKindOrder(CtImportKind importKind) {
switch (importKind) {
case TYPE:
case ALL_TYPES:
return 0;
default:
return 1;
}
}

}
Loading