From 9e871f23771fb63ef14d244ed355031ea4c960cd Mon Sep 17 00:00:00 2001 From: Tor Norbye Date: Fri, 21 Dec 2012 15:36:24 -0800 Subject: Prevent circular dependencies in library project dependencies Change-Id: Ia43c2436e01032ace7e2b13e59d60d10f71e7004 --- .../client/api/CircularDependencyException.java | 81 ++++++++++++++++++++++ .../android/tools/lint/client/api/LintClient.java | 9 +++ .../android/tools/lint/client/api/LintDriver.java | 11 ++- .../android/tools/lint/detector/api/Project.java | 21 ++++-- 4 files changed, 114 insertions(+), 8 deletions(-) create mode 100644 lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/CircularDependencyException.java (limited to 'lint/libs') diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/CircularDependencyException.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/CircularDependencyException.java new file mode 100644 index 0000000..337eb27 --- /dev/null +++ b/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/CircularDependencyException.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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.android.tools.lint.client.api; + +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; +import com.android.tools.lint.detector.api.Location; +import com.android.tools.lint.detector.api.Project; +import com.google.common.annotations.Beta; + +/** + * Exception thrown when there is a circular dependency, such as a circular dependency + * of library mProject references + *

+ * NOTE: This is not a public or final API; if you rely on this be prepared + * to adjust your code for the next tools release. + */ +@Beta +public class CircularDependencyException extends RuntimeException { + @Nullable + private Project mProject; + + @Nullable + private Location mLocation; + + CircularDependencyException(@NonNull String message) { + super(message); + } + + /** + * Returns the associated project, if any + * + * @return the associated project, if any + */ + @Nullable + public Project getProject() { + return mProject; + } + + /** + * Sets the associated project, if any + * + * @param project the associated project, if any + */ + public void setProject(@Nullable Project project) { + mProject = project; + } + + /** + * Returns the associated location, if any + * + * @return the associated location, if any + */ + @Nullable + public Location getLocation() { + return mLocation; + } + + /** + * Sets the associated location, if any + * + * @param location the associated location, if any + */ + public void setLocation(@Nullable Location location) { + mLocation = location; + } +} diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintClient.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintClient.java index 7843aa1..9afef42 100644 --- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintClient.java +++ b/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintClient.java @@ -39,6 +39,7 @@ import com.android.utils.StdLogger; import com.android.utils.StdLogger.Level; import com.google.common.annotations.Beta; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import com.google.common.io.Files; import org.w3c.dom.Document; @@ -54,6 +55,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -573,6 +575,8 @@ public abstract class LintClient { return project; } + private Set mProjectDirs = Sets.newHashSet(); + /** * Create a project for the given directory * @param dir the root directory of the project @@ -581,6 +585,11 @@ public abstract class LintClient { */ @NonNull protected Project createProject(@NonNull File dir, @NonNull File referenceDir) { + if (mProjectDirs.contains(dir)) { + throw new CircularDependencyException( + "Circular library dependencies; check your project.properties files carefully"); + } + mProjectDirs.add(dir); return Project.create(this, dir, referenceDir); } diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintDriver.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintDriver.java index a92a9a2..0ff3a9a 100644 --- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintDriver.java +++ b/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintDriver.java @@ -283,7 +283,16 @@ public class LintDriver { mCanceled = false; mScope = scope; - Collection projects = computeProjects(files); + Collection projects; + try { + projects = computeProjects(files); + } catch (CircularDependencyException e) { + Context context = new Context(this, e.getProject(), null, e.getLocation().getFile()); + mCurrentProject = e.getProject(); + context.report(IssueRegistry.LINT_ERROR, e.getLocation(), e.getMessage(), null); + mCurrentProject = null; + return; + } if (projects.isEmpty()) { mClient.log(null, "No projects found for %1$s", files.toString()); return; 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 c31a499..df27b2f 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 @@ -32,6 +32,7 @@ import static com.android.SdkConstants.VALUE_TRUE; import com.android.SdkConstants; import com.android.annotations.NonNull; import com.android.annotations.Nullable; +import com.android.tools.lint.client.api.CircularDependencyException; import com.android.tools.lint.client.api.Configuration; import com.android.tools.lint.client.api.LintClient; import com.android.tools.lint.client.api.SdkInfo; @@ -104,7 +105,7 @@ public class Project { @NonNull public static Project create( @NonNull LintClient client, - @NonNull File dir, + @NonNull File dir, @NonNull File referenceDir) { return new Project(client, dir, referenceDir); } @@ -182,12 +183,18 @@ public class Project { } } - Project libraryPrj = client.getProject(libraryDir, libraryReferenceDir); - mDirectLibraries.add(libraryPrj); - // By default, we don't report issues in inferred library projects. - // The driver will set report = true for those library explicitly - // requested. - libraryPrj.setReportIssues(false); + try { + Project libraryPrj = client.getProject(libraryDir, libraryReferenceDir); + mDirectLibraries.add(libraryPrj); + // By default, we don't report issues in inferred library projects. + // The driver will set report = true for those library explicitly + // requested. + libraryPrj.setReportIssues(false); + } catch (CircularDependencyException e) { + e.setProject(this); + e.setLocation(Location.create(propFile)); + throw e; + } } } finally { Closeables.closeQuietly(is); -- cgit v1.1