summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Norbye <tnorbye@google.com>2013-10-10 00:04:20 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2013-10-10 00:04:20 +0000
commitf2be3c6a35095de7775fe5c62e798ba06f637e18 (patch)
tree15fb5efddec5bc5f4f2faf4fb336085a5f9fe881
parentbaa15109e42be30745e3deb434b6b2de60ad962d (diff)
parent2545b451003624e1fcde856cb5dab7bd0a9b713e (diff)
downloadbase-f2be3c6a35095de7775fe5c62e798ba06f637e18.tar.gz
Merge "Prevent stack overflow problem with improperly configured lint projects. DO NOT MERGE" into tools_r22.2
-rw-r--r--lint/cli/src/test/java/com/android/tools/lint/client/api/ProjectTest.java94
-rw-r--r--lint/libs/lint-api/src/main/java/com/android/tools/lint/detector/api/Project.java25
2 files changed, 116 insertions, 3 deletions
diff --git a/lint/cli/src/test/java/com/android/tools/lint/client/api/ProjectTest.java b/lint/cli/src/test/java/com/android/tools/lint/client/api/ProjectTest.java
index 4f3c9ef783..c9193213a3 100644
--- a/lint/cli/src/test/java/com/android/tools/lint/client/api/ProjectTest.java
+++ b/lint/cli/src/test/java/com/android/tools/lint/client/api/ProjectTest.java
@@ -16,12 +16,18 @@
package com.android.tools.lint.client.api;
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
import com.android.tools.lint.checks.AbstractCheckTest;
import com.android.tools.lint.checks.UnusedResourceDetector;
import com.android.tools.lint.detector.api.Detector;
+import com.android.tools.lint.detector.api.Project;
+import com.android.tools.lint.detector.api.Severity;
import java.io.File;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
public class ProjectTest extends AbstractCheckTest {
@Override
@@ -53,6 +59,94 @@ public class ProjectTest extends AbstractCheckTest {
checkLint(Arrays.asList(master, library)));
}
+ public void testInvalidLibraryReferences1() throws Exception {
+ TestClient client = new TestClient();
+ File dir = new File("project");
+ TestProject project1 = new TestProject(client, dir);
+ client.registerProject(dir, project1);
+ project1.setDirectLibraries(Collections.<Project>singletonList(project1));
+ List<Project> libraries = project1.getAllLibraries();
+ assertNotNull(libraries);
+ assertEquals(
+ "Warning: Internal lint error: cyclic library dependency for Project [dir=project]",
+ client.getLoggedOutput());
+ }
+
+ public void testInvalidLibraryReferences2() throws Exception {
+ TestClient client = new TestClient();
+ File dir1 = new File("project1");
+ File dir2 = new File("project2");
+ TestProject project1 = new TestProject(client, dir1);
+ client.registerProject(dir1, project1);
+ TestProject project2 = new TestProject(client, dir2);
+ client.registerProject(dir2, project2);
+ project2.setDirectLibraries(Collections.<Project>singletonList(project1));
+ project1.setDirectLibraries(Collections.<Project>singletonList(project2));
+ List<Project> libraries = project1.getAllLibraries();
+ assertNotNull(libraries);
+ assertEquals(
+ "Warning: Internal lint error: cyclic library dependency for Project [dir=project1]",
+ client.getLoggedOutput());
+ assertEquals(1, libraries.size());
+ assertSame(project2, libraries.get(0));
+ assertEquals(1, project2.getAllLibraries().size());
+ assertSame(project1, project2.getAllLibraries().get(0));
+ }
+
+ public void testOkLibraryReferences() throws Exception {
+ TestClient client = new TestClient();
+ File dir1 = new File("project1");
+ File dir2 = new File("project2");
+ File dir3 = new File("project3");
+ TestProject project1 = new TestProject(client, dir1);
+ client.registerProject(dir1, project1);
+ TestProject project2 = new TestProject(client, dir2);
+ client.registerProject(dir2, project2);
+ TestProject project3 = new TestProject(client, dir3);
+ client.registerProject(dir3, project3);
+ project1.setDirectLibraries(Arrays.<Project>asList(project2, project3));
+ project2.setDirectLibraries(Collections.<Project>singletonList(project3));
+ project3.setDirectLibraries(Collections.<Project>emptyList());
+ List<Project> libraries = project1.getAllLibraries();
+ assertNotNull(libraries);
+ assertEquals(
+ "",
+ client.getLoggedOutput());
+ assertEquals(2, libraries.size());
+ assertTrue(libraries.contains(project2));
+ assertTrue(libraries.contains(project3));
+ assertEquals(1, project2.getAllLibraries().size());
+ assertSame(project3, project2.getAllLibraries().get(0));
+ assertTrue(project3.getAllLibraries().isEmpty());
+ }
+
+ private class TestClient extends TestLintClient {
+ @SuppressWarnings("StringBufferField")
+ private StringBuilder mLog = new StringBuilder();
+
+ @Override
+ public void log(@NonNull Severity severity, @Nullable Throwable exception,
+ @Nullable String format, @Nullable Object... args) {
+ assertNotNull(format);
+ mLog.append(severity.getDescription()).append(": ");
+ mLog.append(String.format(format, args));
+ }
+
+ public String getLoggedOutput() {
+ return mLog.toString();
+ }
+ }
+
+ private static class TestProject extends Project {
+ protected TestProject(@NonNull LintClient client, @NonNull File dir) {
+ super(client, dir, dir);
+ }
+
+ public void setDirectLibraries(List<Project> libraries) {
+ mDirectLibraries = libraries;
+ }
+ }
+
@Override
protected Detector getDetector() {
return new UnusedResourceDetector();
diff --git a/lint/libs/lint-api/src/main/java/com/android/tools/lint/detector/api/Project.java b/lint/libs/lint-api/src/main/java/com/android/tools/lint/detector/api/Project.java
index 983d5cc03d..508d8043b5 100644
--- a/lint/libs/lint-api/src/main/java/com/android/tools/lint/detector/api/Project.java
+++ b/lint/libs/lint-api/src/main/java/com/android/tools/lint/detector/api/Project.java
@@ -42,6 +42,7 @@ import com.google.common.annotations.Beta;
import com.google.common.base.CharMatcher;
import com.google.common.base.Charsets;
import com.google.common.base.Splitter;
+import com.google.common.collect.Sets;
import com.google.common.io.Closeables;
import com.google.common.io.Files;
@@ -58,6 +59,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
+import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -608,7 +610,11 @@ public class Project {
}
List<Project> all = new ArrayList<Project>();
- addLibraryProjects(all);
+ Set<Project> seen = Sets.newHashSet();
+ Set<Project> path = Sets.newHashSet();
+ seen.add(this);
+ path.add(this);
+ addLibraryProjects(all, seen, path);
mAllLibraries = all;
}
@@ -620,12 +626,25 @@ public class Project {
* recursively into the given collection of projects
*
* @param collection the collection to add the projects into
+ * @param seen full set of projects we've processed
+ * @param path the current path of library dependencies followed
*/
- private void addLibraryProjects(@NonNull Collection<Project> collection) {
+ private void addLibraryProjects(@NonNull Collection<Project> collection,
+ @NonNull Set<Project> seen, @NonNull Set<Project> path) {
for (Project library : mDirectLibraries) {
+ if (seen.contains(library)) {
+ if (path.contains(library)) {
+ mClient.log(Severity.WARNING, null,
+ "Internal lint error: cyclic library dependency for %1$s", library);
+ }
+ continue;
+ }
collection.add(library);
+ seen.add(library);
+ path.add(library);
// Recurse
- library.addLibraryProjects(collection);
+ library.addLibraryProjects(collection, seen, path);
+ path.remove(library);
}
}