Skip to content

Commit 16f58e6

Browse files
authored
Add autosynth examples (#56)
Add code examples for autosynthesized rules
1 parent c6d61dc commit 16f58e6

File tree

15 files changed

+451
-1
lines changed

15 files changed

+451
-1
lines changed

build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ dependencies {
4141
implementation("com.amazonaws:amazon-kinesis-client:1.6.3")
4242
implementation("com.amazonaws:aws-java-sdk-ssm:1.11.201")
4343
implementation("io.netty:netty-all:4.1.72.Final")
44+
implementation("io.grpc:grpc-netty:1.44.0")
4445
implementation("org.springframework.security:spring-security-config:5.6.1")
4546
implementation("org.springframework:spring-web:5.3.14")
4647
implementation("org.springframework:spring-webmvc:5.3.14")
@@ -56,5 +57,5 @@ dependencies {
5657
implementation("com.android.support:support-annotations:27.1.1")
5758
implementation("com.google.code.findbugs:jsr305:3.0.2")
5859
implementation("com.amazonaws:aws-java-sdk-dynamodb:1.12.133")
60+
implementation("com.google.android:android:4.1.1.4")
5961
}
60-
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package rules.inefficient_apis;
2+
3+
import android.app.Activity;
4+
import android.content.Intent;
5+
import android.os.Bundle;
6+
import com.google.common.collect.Maps;
7+
import java.util.HashMap;
8+
import java.util.Map;
9+
10+
class InefficientApis extends Activity {
11+
12+
// {fact rule=inefficient-apis@v1.0 defects=1}
13+
Map<String, Object> copyMapNonCompliant(Map<String, Object> parameterMap) {
14+
// Noncompliant: map will be rehashed after 75% of all keys have been added to the map.
15+
Map<String, Object> map = new HashMap<String, Object>(parameterMap.size());
16+
for (Map.Entry<String, Object> entry : parameterMap.entrySet()) {
17+
map.put(entry.getKey(), entry.getValue());
18+
}
19+
return map;
20+
}
21+
// {/fact}
22+
23+
// {fact rule=inefficient-apis@v1.0 defects=0}
24+
Map<String, Object> copyMapCompliant(Map<String, Object> parameterMap) {
25+
// Compliant: map will not be rehashed because its expected size is provided.
26+
Map<String, Object> map = Maps.newHashMapWithExpectedSize(parameterMap.size());
27+
for (Map.Entry<String, Object> entry : parameterMap.entrySet()) {
28+
map.put(entry.getKey(), entry.getValue());
29+
}
30+
return map;
31+
}
32+
// {/fact}
33+
34+
// {fact rule=inefficient-apis@v1.0 defects=1}
35+
public String getMessageNonCompliant(Bundle savedInstanceState) {
36+
Intent intent = getIntent();
37+
// Noncompliant: using Serializable to pass data between different Android components.
38+
return (String) intent.getSerializableExtra("message");
39+
}
40+
// {/fact}
41+
42+
// {fact rule=inefficient-apis@v1.0 defects=0}
43+
public String getMessageCompliant(Bundle savedInstanceState) {
44+
Intent intent = getIntent();
45+
// Compliant: using Parcelable to pass data between different Android components.
46+
return intent.getParcelableExtra("message");
47+
}
48+
// {/fact}
49+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package rules.missing_check_on_android_startactivity;
2+
3+
import android.content.Context;
4+
import android.content.Intent;
5+
6+
class MissingCheckOnAndroidStartActivity {
7+
8+
// {fact rule=missing-check-on-android-startactivity@v1.0 defects=1}
9+
public void startActivityNonCompliant(Context context, Intent shareIntent) {
10+
// Noncompliant: there might be no application on the device to receive the implicit intent.
11+
context.startActivity(shareIntent);
12+
}
13+
// {/fact}
14+
15+
// {fact rule=missing-check-on-android-startactivity@v1.0 defects=0}
16+
public boolean startActivityCompliant(Context context, Intent shareIntent) {
17+
if (shareIntent.resolveActivity(context.getPackageManager()) != null) {
18+
// Compliant: called only if there is an application on the device to receive the implicit intent.
19+
context.startActivity(shareIntent);
20+
return true;
21+
}
22+
return false;
23+
}
24+
// {/fact}
25+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package rules.missing_check_on_createnewfile;
2+
3+
import java.io.File;
4+
import java.io.IOException;
5+
import java.util.Optional;
6+
import lombok.extern.log4j.Log4j;
7+
8+
@Log4j
9+
class MissingCheckOnCreateNewFile {
10+
11+
// {fact rule=missing-check-on-createnewfile@v1.0 defects=1}
12+
public File createFileNonCompliant(File outputFolder, final String fileName) throws IOException {
13+
File file = new File(outputFolder, fileName);
14+
// Noncompliant: does not check if createNewFile succeeded or failed.
15+
file.createNewFile();
16+
return file;
17+
}
18+
// {/fact}
19+
20+
// {fact rule=missing-check-on-createnewfile@v1.0 defects=0}
21+
public Optional<File> createFileCompliant(File outputFolder, final String fileName) throws IOException {
22+
File file = new File(outputFolder, fileName);
23+
// Compliant: handles the case when createNewFile fails.
24+
if (!file.createNewFile()) {
25+
log.debug("File already exists, using existing file " + file.getAbsolutePath() + ".");
26+
return Optional.empty();
27+
}
28+
return Optional.of(file);
29+
}
30+
// {/fact}
31+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package rules.missing_check_on_method_output;
2+
3+
import java.io.File;
4+
import java.io.FileOutputStream;
5+
import java.io.IOException;
6+
import lombok.extern.log4j.Log4j;
7+
8+
@Log4j
9+
class MissingCheckOnMethodOutput {
10+
11+
// {fact rule=missing-check-on-method-output@v1.0 defects=1}
12+
private void writeMessageNonCompliant(String dirName, String fileName, String message) {
13+
try {
14+
File dir = new File(dirName);
15+
if (!dir.exists()) {
16+
// Noncompliant: code does not handle the case when mkdirs fails.
17+
dir.mkdirs();
18+
}
19+
try (FileOutputStream fos = new FileOutputStream(new File(dir, fileName))) {
20+
fos.write(message.getBytes());
21+
}
22+
} catch (IOException e) {
23+
e.printStackTrace();
24+
}
25+
}
26+
// {/fact}
27+
28+
// {fact rule=missing-check-on-method-output@v1.0 defects=0}
29+
private void writeMessageCompliant(String dirName, String fileName, String message) {
30+
try {
31+
File dir = new File(dirName);
32+
boolean ok = true;
33+
if (!dir.exists()) {
34+
// Compliant: code handles the case when mkdirs fails.
35+
ok = dir.mkdirs();
36+
}
37+
if (ok) {
38+
try (FileOutputStream fos = new FileOutputStream(new File(dir, fileName))) {
39+
fos.write(message.getBytes());
40+
}
41+
} else {
42+
log.warn("output directory not created");
43+
}
44+
} catch (IOException e) {
45+
e.printStackTrace();
46+
}
47+
}
48+
// {/fact}
49+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package rules.missing_getcause_on_invocationtargetexception;
2+
3+
import java.lang.reflect.InvocationTargetException;
4+
import java.lang.reflect.Method;
5+
6+
class MissingGetCauseOnInvocationTargetException {
7+
8+
// {fact rule=missing-getcause-on-invocationtargetexception@v1.0 defects=1}
9+
public Object invokeMethodNonCompliant(Method method, Object[] args) throws Throwable {
10+
// Noncompliant: InvocationTargetException is not caught.
11+
return method.invoke(args);
12+
}
13+
// {/fact}
14+
15+
// {fact rule=missing-getcause-on-invocationtargetexception@v1.0 defects=0}
16+
public Object invokeMethodCompliant(Object proxy, Method method, Object[] args) throws Throwable {
17+
try {
18+
// Compliant: InvocationTargetException is caught and e.getCause() is propagated further.
19+
Object returnValue = method.invoke(args);
20+
return returnValue;
21+
} catch (InvocationTargetException e) {
22+
throw e.getTargetException();
23+
}
24+
}
25+
// {/fact}
26+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package rules.missing_timeout_check_on_awaittermination;
2+
3+
import java.util.concurrent.ExecutorService;
4+
import java.util.concurrent.TimeUnit;
5+
import lombok.extern.log4j.Log4j;
6+
7+
@Log4j
8+
class MissingTimeoutCheckOnAwaitTermination {
9+
10+
// {fact rule=missing-timeout-check-on-awaittermination@v1.0 defects=1}
11+
public void shutdownNonCompliant(ExecutorService executor) {
12+
executor.shutdown();
13+
try {
14+
// Noncompliant: awaitTermination might silently time out before all threads finish their execution.
15+
executor.awaitTermination(10, TimeUnit.SECONDS);
16+
} catch (InterruptedException e) {
17+
log.warn("Failed to wait for all tasks to finish", e);
18+
}
19+
}
20+
// {/fact}
21+
22+
// {fact rule=missing-timeout-check-on-awaittermination@v1.0 defects=0}
23+
public void shutdownCompliant(ExecutorService executor) {
24+
executor.shutdown();
25+
try {
26+
// Compliant: code handles the case when awaitTermination times out.
27+
if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
28+
log.warn("Failed to terminate executor");
29+
}
30+
} catch (InterruptedException e) {
31+
log.warn("Failed to wait for all tasks to finish", e);
32+
}
33+
}
34+
// {/fact}
35+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package rules.missing_timeout_check_on_latch_await;
2+
3+
import java.util.concurrent.CountDownLatch;
4+
import java.util.concurrent.ExecutionException;
5+
import java.util.concurrent.TimeUnit;
6+
import java.util.concurrent.TimeoutException;
7+
8+
class MissingTimeoutCheckOnLatchAwait {
9+
10+
private volatile Object result = null;
11+
private CountDownLatch completionLatch = new CountDownLatch(1);
12+
13+
// {fact rule=missing-timeout-check-on-latch-await@v1.0 defects=1}
14+
public Object getResultNonCompliant(long timeout, TimeUnit unit)
15+
throws InterruptedException, ExecutionException, TimeoutException {
16+
17+
// Noncompliant: code does not check if await timed out or the latch counted down to zero.
18+
completionLatch.await(timeout, unit);
19+
return result;
20+
}
21+
// {/fact}
22+
23+
// {fact rule=missing-timeout-check-on-latch-await@v1.0 defects=0}
24+
public Object getResultCompliant(long timeout, TimeUnit unit)
25+
throws InterruptedException, ExecutionException, TimeoutException {
26+
27+
// Compliant: code handles the case when await times out.
28+
if (!completionLatch.await(timeout, unit)) {
29+
throw new TimeoutException();
30+
}
31+
return result;
32+
}
33+
// {/fact}
34+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package rules.old_android_features;
2+
3+
import android.app.Activity;
4+
import android.content.Context;
5+
import android.view.LayoutInflater;
6+
import android.view.View;
7+
import android.view.ViewGroup;
8+
import android.widget.TextView;
9+
10+
import stubs.ViewHolder;
11+
12+
class OldAndroidFeatures extends Activity {
13+
14+
int layoutResourceId = 0;
15+
16+
// {fact rule=old-android-features@v1.0 defects=1}
17+
public ViewHolder onCreateViewHolderNonCompliant(ViewGroup parent, int viewType) {
18+
// Noncompliant: layout is created programmatically in code, without using the LayoutInflater.
19+
return new ViewHolder(new TextView(parent.getContext()));
20+
}
21+
// {/fact}
22+
23+
// {fact rule=old-android-features@v1.0 defects=0}
24+
public ViewHolder onCreateViewHolderCompliant(ViewGroup parent, int viewType) {
25+
final Context context = parent.getContext();
26+
// Compliant: LayoutInflater is used to inflate views.
27+
LayoutInflater inflater = LayoutInflater.from(context);
28+
View itemView = inflater.inflate(layoutResourceId, parent, false);
29+
return new ViewHolder(itemView);
30+
}
31+
// {/fact}
32+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package rules.output_ignored_on_movetofirst_operation;
2+
3+
import android.content.Context;
4+
import android.database.Cursor;
5+
import android.net.Uri;
6+
7+
class OutputIgnoredOnMoveToFirstOperation {
8+
9+
// {fact rule=output-ignored-on-movetofirst-operation@v1.0 defects=1}
10+
public static String getDataFromURINonCompliant(Context context, Uri uri) {
11+
String[] columns = { "name", "address" };
12+
try (Cursor cursor = context.getContentResolver().query(uri, columns, null, null, null)) {
13+
// Noncompliant: code does not check if the cursor is empty.
14+
cursor.moveToFirst();
15+
return cursor.getString(0);
16+
}
17+
}
18+
// {/fact}
19+
20+
// {fact rule=output-ignored-on-movetofirst-operation@v1.0 defects=0}
21+
public static String getDataFromURICompliant(Context context, Uri uri) {
22+
String[] columns = { "name", "address" };
23+
try (Cursor cursor = context.getContentResolver().query(uri, columns, null, null, null)) {
24+
// Compliant: code handles the case when the cursor is empty.
25+
if (!cursor.moveToFirst()) {
26+
return null;
27+
}
28+
return cursor.getString(0);
29+
}
30+
}
31+
// {/fact}
32+
}

0 commit comments

Comments
 (0)