Skip to content

Commit

Permalink
Push the source code for PiranhaObjC
Browse files Browse the repository at this point in the history
  • Loading branch information
mkr-plse committed Nov 27, 2019
1 parent 131806a commit 7e7252d
Show file tree
Hide file tree
Showing 47 changed files with 2,418 additions and 152 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
.gradle
java/.gradle
*/build/
.idea
piranha.iml
objc/process
objc/piranha-objc
155 changes: 4 additions & 151 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,159 +8,12 @@ Feature flags are commonly used to enable gradual rollout or experiment with new

Piranha is a tool to automatically refactor code related to stale flags. At a higher level, the input to the tool is the name of the flag and the expected behavior, after specifying a list of APIs related to flags in a properties file. Piranha will use these inputs to automatically refactor the code according to the expected behavior.

Currently, Piranha is used to refactor Java code. We plan on supporting
other languages soon.
This repository contains three independent versions of Piranha, one for each of the three supported languages: Objective-C, Swift, and Java.

## Installation

### Overview

Piranha requires that you build your code with [Error Prone](http://errorprone.info), version 2.3.2 or higher. See the [Error Prone documentation](http://errorprone.info/docs/installation) for instructions on getting started with Error Prone and integration with your build system.

### Gradle

To integrate Piranha into your Java project you'll need a version of the following additions to your `build.gradle` file:

```
plugins {
id "com.github.sherter.google-java-format" version "0.7.1"
id "net.ltgt.errorprone" version "0.6" apply false
id "java"
}
sourceCompatibility = "1.8"
targetCompatibility = "1.8"
dependencies {
annotationProcessor "com.uber.piranha:piranha:0.0.1"
errorprone "com.google.errorprone:error_prone_core:2.3.2"
errorproneJavac "com.google.errorprone:javac:9+181-r4173-1"
}
import net.ltgt.gradle.errorprone.CheckSeverity
tasks.withType(JavaCompile) {
options.errorprone {
check("Piranha", CheckSeverity.WARN)
}
options.errorprone.errorproneArgs << "-XepPatchChecks:Piranha"
options.errorprone.errorproneArgs << "-XepPatchLocation:IN_PLACE"
// The lines below should be replaced by code that loads the specific flag to patch
// and final treatment condition.
options.errorprone.errorproneArgs << "-XepOpt:Piranha:FlagName=SAMPLE_STALE_FLAG"
options.errorprone.errorproneArgs << "-XepOpt:Piranha:IsTreated=true"
options.errorprone.errorproneArgs << "-XepOpt:Piranha:Config=config/piranha.properties"
}
```

The `plugins` section pulls in the [Gradle Error Prone plugin](https://github.com/tbroyer/gradle-errorprone-plugin) for Error Prone integration. In `dependencies`, the `annotationProcessor` line loads Piranha, the `errorprone` line ensures that a compatible version of Error Prone is used, and the `errorproneJavac` line is needed for JDK 8 compatibility.

In the `tasks.withType(JavaCompile)` section, we pass some configuration options to Piranha. First `check("Piranha", CheckSeverity.WARN)` sets Piranha issues to the warning level. Then, `option.errorprone.errorproneArgs` is used to add a set of arguments to Piranha. `XepPatchChecks:Piranha` and `-XepPatchLocation:IN_PLACE` arguments are used together to enable in-place refactoring of the code. `-XepOpt:Piranha:FlagName` is used to specify a stale flag name that is used in the code, `-XepOpt:Piranha:IsTreated` is used to specify whether the treatment (`true`) branch or the control (`false`) branch needs to be taken during refactoring. Then `-XepOpt:Piranha:Config` is used to provide the properties file which specifies the APIs and annotations that are considered for refactoring.

The properties file has the following template:

```
treatedMethods=treated,flagEnabled
controlMethods=flagDisabled
emptyMethods=enableFlag,disableFlag
treatmentGroupMethods=isToggleInGroup
annotations=FlagTesting
linkURL=<provide_your_url>
```

The `treatedMethods` are the APIs which correspond to the treatment behavior of the flag, `controlMethods` correspond to the control behavior of the flag. In the above example, the API `flagEnabled` corresponds to treatment behavior. Hence, when `IsTreated` flag is set to `true`, `flagEnabled(SAMPLE_STALE_FLAG)` will be evaluated to `true`. Similarly, `flagDisabled(SAMPLE_STALE_FLAG)` which corresponds to the control behavior will evaluate to `false`.

The `emptyMethods` specify the APIs which need to be discarded from the code. For example, a statement `enableFlag(SAMPLE_STALE_FLAG);` will be deleted from the code.

The `annotations` specify the annotations used (e.g., in unit testing) to determine treatment or control behavior. For example:

```
@FlagTesting(treated = TestExperimentName.SAMPLE_STALE_FLAG)
public void some_unit_test() { ... }
```

will be refactored to

```
public void some_unit_test() { ... }
```

when `IsTreated` is `true`, and will be deleted completely when `IsTreated` is `false`.

Finally, the setting `linkURL` in the properties file is to provide a URL describing the Piranha tooling and any custom configurations associated with the codebase.


## Example refactoring

Consider a simple example

```
public class MyClass {
private XPTest expt;
...
public void foo() {
if(expt.flagEnabled(TestExperimentName.SAMPLE_STALE_FLAG)) {
System.out.println("Hello World");
}
}
public void bar() {
if(expt.flagDisabled(TestExperimentName.SAMPLE_STALE_FLAG)) {
System.out.println("Hi World");
}
}
}
```

and the following arguments to Piranha

```
options.errorprone.errorproneArgs << "-XepOpt:Piranha:FlagName=SAMPLE_STALE_FLAG"
options.errorprone.errorproneArgs << "-XepOpt:Piranha:IsTreated=true"
options.errorprone.errorproneArgs << "-XepOpt:Piranha:Config=config/piranha.properties
```
where `piranha.properties` contains the following,

```
treatedMethods=treated,flagEnabled
controlMethods=flagDisabled
emptyMethods=enableFlag,disableFlag
annotations=FlagTesting
linkURL=<provide_your_url>
```

the refactored output will be

```
public class MyClass {
private XPTest expt;
...
public void foo() {
System.out.println("Hello World");
}
public void bar() {
}
}
```

When `IsTreated` is `false`, then the refactored output will be

```
public class MyClass {
private XPTest expt;
...
public void foo() {
}
public void bar() {
System.out.println("Hi World");
}
}
```

This example is present in the [sample](https://github.com/uber/piranha/sample/) directory.
To use/build each version, look under the corresponding [lang]/ directory and follow instructions in the corresponding [lang]/README.md file. Make sure to cd into that directory to build any related code following the instructions in the README.

[PiranhaJava](https://github.com/uber/piranha/java/README.md)
[PiranhaObjC](https://github.com/uber/piranha/objc/README.md)

## Support

Expand Down
151 changes: 151 additions & 0 deletions java/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# PiranhaJava

## Installation

### Overview

Piranha requires that you build your code with [Error Prone](http://errorprone.info), version 2.3.2 or higher. See the [Error Prone documentation](http://errorprone.info/docs/installation) for instructions on getting started with Error Prone and integration with your build system.

### Gradle

To integrate Piranha into your Java project you'll need a version of the following additions to your `build.gradle` file:

```
plugins {
id "com.github.sherter.google-java-format" version "0.7.1"
id "net.ltgt.errorprone" version "0.6" apply false
id "java"
}
sourceCompatibility = "1.8"
targetCompatibility = "1.8"
dependencies {
annotationProcessor "com.uber.piranha:piranha:0.0.1"
errorprone "com.google.errorprone:error_prone_core:2.3.2"
errorproneJavac "com.google.errorprone:javac:9+181-r4173-1"
}
import net.ltgt.gradle.errorprone.CheckSeverity
tasks.withType(JavaCompile) {
options.errorprone {
check("Piranha", CheckSeverity.WARN)
}
options.errorprone.errorproneArgs << "-XepPatchChecks:Piranha"
options.errorprone.errorproneArgs << "-XepPatchLocation:IN_PLACE"
// The lines below should be replaced by code that loads the specific flag to patch
// and final treatment condition.
options.errorprone.errorproneArgs << "-XepOpt:Piranha:FlagName=SAMPLE_STALE_FLAG"
options.errorprone.errorproneArgs << "-XepOpt:Piranha:IsTreated=true"
options.errorprone.errorproneArgs << "-XepOpt:Piranha:Config=config/piranha.properties"
}
```

The `plugins` section pulls in the [Gradle Error Prone plugin](https://github.com/tbroyer/gradle-errorprone-plugin) for Error Prone integration. In `dependencies`, the `annotationProcessor` line loads Piranha, the `errorprone` line ensures that a compatible version of Error Prone is used, and the `errorproneJavac` line is needed for JDK 8 compatibility.

In the `tasks.withType(JavaCompile)` section, we pass some configuration options to Piranha. First `check("Piranha", CheckSeverity.WARN)` sets Piranha issues to the warning level. Then, `option.errorprone.errorproneArgs` is used to add a set of arguments to Piranha. `XepPatchChecks:Piranha` and `-XepPatchLocation:IN_PLACE` arguments are used together to enable in-place refactoring of the code. `-XepOpt:Piranha:FlagName` is used to specify a stale flag name that is used in the code, `-XepOpt:Piranha:IsTreated` is used to specify whether the treatment (`true`) branch or the control (`false`) branch needs to be taken during refactoring. Then `-XepOpt:Piranha:Config` is used to provide the properties file which specifies the APIs and annotations that are considered for refactoring.

The properties file has the following template:

```
treatedMethods=treated,flagEnabled
controlMethods=flagDisabled
emptyMethods=enableFlag,disableFlag
treatmentGroupMethods=isToggleInGroup
annotations=FlagTesting
linkURL=<provide_your_url>
```

The `treatedMethods` are the APIs which correspond to the treatment behavior of the flag, `controlMethods` correspond to the control behavior of the flag. In the above example, the API `flagEnabled` corresponds to treatment behavior. Hence, when `IsTreated` flag is set to `true`, `flagEnabled(SAMPLE_STALE_FLAG)` will be evaluated to `true`. Similarly, `flagDisabled(SAMPLE_STALE_FLAG)` which corresponds to the control behavior will evaluate to `false`.

The `emptyMethods` specify the APIs which need to be discarded from the code. For example, a statement `enableFlag(SAMPLE_STALE_FLAG);` will be deleted from the code.

The `annotations` specify the annotations used (e.g., in unit testing) to determine treatment or control behavior. For example:

```
@FlagTesting(treated = TestExperimentName.SAMPLE_STALE_FLAG)
public void some_unit_test() { ... }
```

will be refactored to

```
public void some_unit_test() { ... }
```

when `IsTreated` is `true`, and will be deleted completely when `IsTreated` is `false`.

Finally, the setting `linkURL` in the properties file is to provide a URL describing the Piranha tooling and any custom configurations associated with the codebase.


## Example refactoring

Consider a simple example

```
public class MyClass {
private XPTest expt;
...
public void foo() {
if(expt.flagEnabled(TestExperimentName.SAMPLE_STALE_FLAG)) {
System.out.println("Hello World");
}
}
public void bar() {
if(expt.flagDisabled(TestExperimentName.SAMPLE_STALE_FLAG)) {
System.out.println("Hi World");
}
}
}
```

and the following arguments to Piranha

```
options.errorprone.errorproneArgs << "-XepOpt:Piranha:FlagName=SAMPLE_STALE_FLAG"
options.errorprone.errorproneArgs << "-XepOpt:Piranha:IsTreated=true"
options.errorprone.errorproneArgs << "-XepOpt:Piranha:Config=config/piranha.properties
```
where `piranha.properties` contains the following,

```
treatedMethods=treated,flagEnabled
controlMethods=flagDisabled
emptyMethods=enableFlag,disableFlag
annotations=FlagTesting
linkURL=<provide_your_url>
```

the refactored output will be

```
public class MyClass {
private XPTest expt;
...
public void foo() {
System.out.println("Hello World");
}
public void bar() {
}
}
```

When `IsTreated` is `false`, then the refactored output will be

```
public class MyClass {
private XPTest expt;
...
public void foo() {
}
public void bar() {
System.out.println("Hi World");
}
}
```

This example is present in the [sample](https://github.com/uber/piranha/java/sample/) directory.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
5 changes: 5 additions & 0 deletions objc/ACKNOWLEDGEMENTS
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
1) Some aspects of the refactoring are based on this blog article:
http://www.goldsborough.me/c++/clang/llvm/tools/2017/02/24/00-00-06-emitting_diagnostics_and_fixithints_in_clang_tools/

2) A majority of the test cases (as of Nov 11, 2019) are due to Nick Lauer.

13 changes: 13 additions & 0 deletions objc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Development

- To update the functionality, modify the necessary sources in the `src` directory
- Run `generate-piranha-artifact.sh` (or `generate-dylib.sh`, if the `llvm` sources are already downloaded)
- Run tests by executing `test.sh` and ensuring there are no changes in the refactorings

# Usage
- Run `piranha-objc.sh` with the appropriate parameters (file, flagname, type).
-- Update `XcodeSDK` path appropriately
- See the examples in `tests` directory for the original code and refactored code.

# TODO
- Refactoring the implementation to accept other APIs
32 changes: 32 additions & 0 deletions objc/generate-dylib.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/usr/bin/env bash

#should be invoked after downloading the necessary llvm code

set -exu

PIRANHA_SRC=$(pwd)/src
PIRANHA_DIR=$(pwd)/piranha-objc
BASE_DIR=$(pwd)
PROCESS_DIR=$(pwd)/process
LLVM_PROJECT=$PROCESS_DIR/llvm-project
LLVM_BUILDDIR=$LLVM_PROJECT/llvm/build
DYLIB_OUTPUTDIR=$PROCESS_DIR/llvm-project/llvm/build

cd $LLVM_PROJECT
cp -R $BASE_DIR/src/XPFlagRefactoring/ clang/examples/XPFlagRefactoring

cd $LLVM_BUILDDIR
cmake -DCMAKE_BUILD_TYPE=Release .. -DLLVM_ENABLE_PROJECTS="clang" -DCLANG_BUILD_EXAMPLES="ON"

make -j 12

# generate the artifact
cd $BASE_DIR
rm -rf $PIRANHA_DIR
mkdir $PIRANHA_DIR
mkdir $PIRANHA_DIR/bin
mkdir $PIRANHA_DIR/lib
cp $DYLIB_OUTPUTDIR/lib/XPFlagRefactoring.dylib $PIRANHA_DIR/bin/
cp $DYLIB_OUTPUTDIR/bin/clang $PIRANHA_DIR/bin/
mv $DYLIB_OUTPUTDIR/lib/clang $PIRANHA_DIR/lib/

Loading

0 comments on commit 7e7252d

Please sign in to comment.