aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ComplementingConfiguration.java33
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/Configuration.java19
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/NestedConfiguration.java3
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java15
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderPreviewManager.java8
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderService.java51
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/tests/functests/layoutRendering/ApiDemosRenderingTest.java1
-rw-r--r--layoutlib_api/src/com/android/ide/common/rendering/api/Bridge.java2
-rw-r--r--layoutlib_api/src/com/android/ide/common/rendering/api/Capability.java6
-rw-r--r--layoutlib_api/src/com/android/ide/common/rendering/api/SessionParams.java9
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/client/api/LintClient.java18
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/client/api/LintDriver.java22
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintUtils.java3
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/Project.java67
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/Scope.java7
-rw-r--r--lint/libs/lint_checks/src/com/android/tools/lint/checks/BuiltinIssueRegistry.java3
-rw-r--r--lint/libs/lint_checks/src/com/android/tools/lint/checks/IconDetector.java12
-rw-r--r--lint/libs/lint_checks/src/com/android/tools/lint/checks/OverrideDetector.java271
-rw-r--r--lint/libs/lint_checks/src/com/android/tools/lint/checks/RequiredAttributeDetector.java15
-rw-r--r--lint/libs/lint_checks/src/com/android/tools/lint/checks/UnusedResourceDetector.java8
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/OnClickDetectorTest.java4
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/OverrideDetectorTest.java47
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/Class1$Class4.class.databin0 -> 368 bytes
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/Class1.class.databin0 -> 812 bytes
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/Class2$Class3.class.databin0 -> 457 bytes
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/Class2.class.databin0 -> 942 bytes
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/src/pkg1/Class1.java.txt29
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/src/pkg2/Class2.java.txt33
28 files changed, 661 insertions, 25 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ComplementingConfiguration.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ComplementingConfiguration.java
index 66a29c8..7ff0354 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ComplementingConfiguration.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ComplementingConfiguration.java
@@ -17,7 +17,9 @@ package com.android.ide.eclipse.adt.internal.editors.layout.configuration;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
+import com.android.ide.common.rendering.api.Capability;
import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo;
+import com.android.resources.Density;
import com.android.resources.NightMode;
import com.android.resources.UiMode;
import com.android.sdklib.IAndroidTarget;
@@ -100,6 +102,9 @@ public class ComplementingConfiguration extends NestedConfiguration {
@NonNull Configuration parent) {
ComplementingConfiguration configuration =
new ComplementingConfiguration(other.mConfigChooser, parent);
+ configuration.setDisplayName(other.getDisplayName());
+ configuration.setActivity(other.getActivity());
+ configuration.mUpdateDisplayName = other.mUpdateDisplayName;
configuration.mOverrideLocale = other.mOverrideLocale;
configuration.mOverrideTarget = other.mOverrideTarget;
configuration.mOverrideDevice = other.mOverrideDevice;
@@ -279,9 +284,17 @@ public class ComplementingConfiguration extends NestedConfiguration {
to = biggest + 0.1;
}
+ boolean canScaleNinePatch = supports(Capability.FIXED_SCALABLE_NINE_PATCH);
for (Device d : devices) {
double size = getScreenSize(d);
if (size >= from && size < to) {
+ if (!canScaleNinePatch) {
+ Density density = getDensity(d);
+ if (density == Density.TV || density == Density.LOW) {
+ continue;
+ }
+ }
+
device = d;
break;
}
@@ -294,6 +307,26 @@ public class ComplementingConfiguration extends NestedConfiguration {
return device;
}
+
+ /**
+ * Returns the density of the given device
+ *
+ * @param device the device to check
+ * @return the density or null
+ */
+ @Nullable
+ public static Density getDensity(@NonNull Device device) {
+ Hardware hardware = device.getDefaultHardware();
+ if (hardware != null) {
+ Screen screen = hardware.getScreen();
+ if (screen != null) {
+ return screen.getPixelDensity();
+ }
+ }
+
+ return null;
+ }
+
private static double getScreenSize(@NonNull Device device) {
Hardware hardware = device.getDefaultHardware();
if (hardware != null) {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/Configuration.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/Configuration.java
index 1615722..c0b57ac 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/Configuration.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/Configuration.java
@@ -23,6 +23,7 @@ import static com.android.SdkConstants.STYLE_RESOURCE_PREFIX;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.ide.common.api.Rect;
+import com.android.ide.common.rendering.api.Capability;
import com.android.ide.common.resources.ResourceRepository;
import com.android.ide.common.resources.configuration.DensityQualifier;
import com.android.ide.common.resources.configuration.DeviceConfigHelper;
@@ -36,6 +37,7 @@ import com.android.ide.common.resources.configuration.ScreenSizeQualifier;
import com.android.ide.common.resources.configuration.UiModeQualifier;
import com.android.ide.common.resources.configuration.VersionQualifier;
import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.internal.editors.layout.gle2.RenderService;
import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo;
import com.android.ide.eclipse.adt.internal.resources.ResourceHelper;
import com.android.ide.eclipse.adt.internal.resources.manager.ProjectResources;
@@ -197,6 +199,7 @@ public class Configuration {
copy.mLocale = original.getLocale();
copy.mUiMode = original.getUiMode();
copy.mNightMode = original.getNightMode();
+ copy.mDisplayName = original.getDisplayName();
return copy;
}
@@ -1062,6 +1065,22 @@ public class Configuration {
return null;
}
+ /**
+ * Returns true if this configuration supports the given rendering
+ * capability
+ *
+ * @param capability the capability to check
+ * @return true if the capability is supported
+ */
+ public boolean supports(Capability capability) {
+ IAndroidTarget target = getTarget();
+ if (target != null) {
+ return RenderService.supports(target, capability);
+ }
+
+ return false;
+ }
+
@Override
public String toString() {
return Objects.toStringHelper(this.getClass())
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/NestedConfiguration.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/NestedConfiguration.java
index 432abdb..7c2559c 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/NestedConfiguration.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/NestedConfiguration.java
@@ -83,6 +83,9 @@ public class NestedConfiguration extends Configuration {
@NonNull Configuration parent) {
NestedConfiguration configuration =
new NestedConfiguration(other.mConfigChooser, parent);
+ configuration.setDisplayName(values.getDisplayName());
+ configuration.setActivity(values.getActivity());
+
configuration.mOverrideLocale = other.mOverrideLocale;
if (configuration.mOverrideLocale) {
configuration.setLocale(values.getLocale(), true);
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java
index 93fdb5e..9b8eeea 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java
@@ -2048,6 +2048,21 @@ public class GraphicalEditorPart extends EditorPart
"or fix the theme style references.\n\n");
}
+ List<Throwable> trace = logger.getFirstTrace();
+ if (trace != null
+ && trace.toString().contains(
+ "java.lang.IndexOutOfBoundsException: Index: 2, Size: 2") //$NON-NLS-1$
+ && mConfigChooser.getConfiguration().getDensity() == Density.TV) {
+ addBoldText(mErrorLabel,
+ "It looks like you are using a render target where the layout library " +
+ "does not support the tvdpi density.\n\n");
+ addText(mErrorLabel, "Please try either updating to " +
+ "the latest available version (using the SDK manager), or if no updated " +
+ "version is available for this specific version of Android, try using " +
+ "a more recent render target version.\n\n");
+
+ }
+
if (hasAaptErrors && logger.seenTagPrefix(LayoutLog.TAG_RESOURCES_PREFIX)) {
// Text will automatically be wrapped by the error widget so no reason
// to insert linebreaks in this error message:
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderPreviewManager.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderPreviewManager.java
index 80391cd..f90e9ac 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderPreviewManager.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderPreviewManager.java
@@ -23,6 +23,7 @@ import static com.android.ide.eclipse.adt.internal.editors.layout.gle2.RenderPre
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.ide.common.api.Rect;
+import com.android.ide.common.rendering.api.Capability;
import com.android.ide.common.resources.configuration.DensityQualifier;
import com.android.ide.common.resources.configuration.DeviceConfigHelper;
import com.android.ide.common.resources.configuration.FolderConfiguration;
@@ -894,6 +895,7 @@ public class RenderPreviewManager {
ConfigurationChooser chooser = getChooser();
List<Device> devices = chooser.getDeviceList();
Configuration configuration = chooser.getConfiguration();
+ boolean canScaleNinePatch = configuration.supports(Capability.FIXED_SCALABLE_NINE_PATCH);
// Rearrange the devices a bit such that the most interesting devices bubble
// to the front
@@ -935,7 +937,11 @@ public class RenderPreviewManager {
DensityQualifier density = c.getDensityQualifier();
if (density != null) {
Density d = density.getValue();
- if (Density.LOW.equals(d)) {
+ if (d == Density.LOW) {
+ interesting = false;
+ }
+
+ if (!canScaleNinePatch && d == Density.TV) {
interesting = false;
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderService.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderService.java
index ccf4068..2a1f3b7 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderService.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderService.java
@@ -17,10 +17,12 @@ package com.android.ide.eclipse.adt.internal.editors.layout.gle2;
import static com.android.SdkConstants.LAYOUT_RESOURCE_PREFIX;
+import com.android.annotations.NonNull;
import com.android.ide.common.api.IClientRulesEngine;
import com.android.ide.common.api.INode;
import com.android.ide.common.api.Rect;
import com.android.ide.common.rendering.LayoutLibrary;
+import com.android.ide.common.rendering.api.Capability;
import com.android.ide.common.rendering.api.DrawableParams;
import com.android.ide.common.rendering.api.IImageFactory;
import com.android.ide.common.rendering.api.ILayoutPullParser;
@@ -49,7 +51,13 @@ import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElement
import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo;
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiDocumentNode;
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
+import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
+import com.android.ide.eclipse.adt.internal.sdk.Sdk;
import com.android.resources.Density;
+import com.android.sdklib.IAndroidTarget;
+import com.android.sdklib.devices.ButtonType;
+import com.android.sdklib.devices.Device;
+import com.android.sdklib.devices.Hardware;
import org.eclipse.core.resources.IProject;
import org.xmlpull.v1.XmlPullParser;
@@ -81,6 +89,7 @@ public class RenderService {
private final ResourceResolver mResourceResolver;
private final int mMinSdkVersion;
private final int mTargetSdkVersion;
+ private final boolean mSoftwareButtons;
private final LayoutLibrary mLayoutLib;
private final IImageFactory mImageFactory;
private final Density mDensity;
@@ -120,6 +129,7 @@ public class RenderService {
mProjectCallback = editor.getProjectCallback(true /*reset*/, mLayoutLib);
mMinSdkVersion = editor.getMinSdkVersion();
mTargetSdkVersion = editor.getTargetSdkVersion();
+ mSoftwareButtons = getButtonType(config) == ButtonType.SOFT;
}
private RenderService(GraphicalEditorPart editor, FolderConfiguration configuration,
@@ -137,6 +147,7 @@ public class RenderService {
mProjectCallback = editor.getProjectCallback(true /*reset*/, mLayoutLib);
mMinSdkVersion = editor.getMinSdkVersion();
mTargetSdkVersion = editor.getTargetSdkVersion();
+ mSoftwareButtons = getButtonType(config) == ButtonType.SOFT;
// TODO: Look up device etc and offer additional configuration options here?
Density density = Density.MEDIUM;
@@ -152,6 +163,44 @@ public class RenderService {
mScreenSize = configuration.getScreenSizeQualifier();
}
+ @NonNull
+ private static ButtonType getButtonType(@NonNull Configuration configuration) {
+ Device device = configuration.getDevice();
+ if (device != null) {
+ Hardware hardware = device.getDefaultHardware();
+ if (hardware != null) {
+ return hardware.getButtonType();
+ }
+ }
+
+ return ButtonType.SOFT;
+ }
+
+ /**
+ * Returns true if this configuration supports the given rendering
+ * capability
+ *
+ * @param target the target to look up the layout library for
+ * @param capability the capability to check
+ * @return true if the capability is supported
+ */
+ public static boolean supports(
+ @NonNull IAndroidTarget target,
+ @NonNull Capability capability) {
+ Sdk sdk = Sdk.getCurrent();
+ if (sdk != null) {
+ AndroidTargetData targetData = sdk.getTargetData(target);
+ if (targetData != null) {
+ LayoutLibrary layoutLib = targetData.getLayoutLibrary();
+ if (layoutLib != null) {
+ return layoutLib.supports(capability);
+ }
+ }
+ }
+
+ return false;
+ }
+
/**
* Sets the screen size and density to use for rendering
*
@@ -398,6 +447,7 @@ public class RenderService {
mProjectCallback,
mMinSdkVersion,
mTargetSdkVersion,
+ mSoftwareButtons,
mLogger);
// Request margin and baseline information.
@@ -533,6 +583,7 @@ public class RenderService {
mProjectCallback,
mMinSdkVersion,
mTargetSdkVersion,
+ mSoftwareButtons,
mLogger);
params.setLayoutOnly();
params.setForceNoDecor();
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/tests/functests/layoutRendering/ApiDemosRenderingTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/tests/functests/layoutRendering/ApiDemosRenderingTest.java
index 30f23de..7a6eef4 100644
--- a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/tests/functests/layoutRendering/ApiDemosRenderingTest.java
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/tests/functests/layoutRendering/ApiDemosRenderingTest.java
@@ -263,6 +263,7 @@ public class ApiDemosRenderingTest extends SdkTestCase {
projectCallBack,
1, // minSdkVersion
1, // targetSdkVersion
+ false, // softwareButtons
null //logger
));
diff --git a/layoutlib_api/src/com/android/ide/common/rendering/api/Bridge.java b/layoutlib_api/src/com/android/ide/common/rendering/api/Bridge.java
index 06a01d5..a19b8d5 100644
--- a/layoutlib_api/src/com/android/ide/common/rendering/api/Bridge.java
+++ b/layoutlib_api/src/com/android/ide/common/rendering/api/Bridge.java
@@ -32,7 +32,7 @@ import java.util.Map;
*/
public abstract class Bridge {
- public final static int API_CURRENT = 8;
+ public final static int API_CURRENT = 9;
/**
* Returns the API level of the layout library.
diff --git a/layoutlib_api/src/com/android/ide/common/rendering/api/Capability.java b/layoutlib_api/src/com/android/ide/common/rendering/api/Capability.java
index a7ab7ae..5ad438d 100644
--- a/layoutlib_api/src/com/android/ide/common/rendering/api/Capability.java
+++ b/layoutlib_api/src/com/android/ide/common/rendering/api/Capability.java
@@ -61,5 +61,9 @@ public enum Capability {
*/
FULL_ANIMATED_VIEW_MANIPULATION,
ADAPTER_BINDING,
- EXTENDED_VIEWINFO;
+ EXTENDED_VIEWINFO,
+ /**
+ * Ability to properly resize nine-patch assets.
+ */
+ FIXED_SCALABLE_NINE_PATCH;
}
diff --git a/layoutlib_api/src/com/android/ide/common/rendering/api/SessionParams.java b/layoutlib_api/src/com/android/ide/common/rendering/api/SessionParams.java
index a620b05..e3edbd2 100644
--- a/layoutlib_api/src/com/android/ide/common/rendering/api/SessionParams.java
+++ b/layoutlib_api/src/com/android/ide/common/rendering/api/SessionParams.java
@@ -52,6 +52,7 @@ public class SessionParams extends RenderParams {
private final ILayoutPullParser mLayoutDescription;
private final RenderingMode mRenderingMode;
+ private final boolean mSoftwareButtons;
private boolean mLayoutOnly = false;
private Map<ResourceReference, AdapterBinding> mAdapterBindingMap;
private boolean mExtendedViewInfoMode = false;
@@ -72,6 +73,7 @@ public class SessionParams extends RenderParams {
* the project.
* @param minSdkVersion the minSdkVersion of the project
* @param targetSdkVersion the targetSdkVersion of the project
+ * @param softwareButtons whether the device use software buttons
* @param log the object responsible for displaying warning/errors to the user.
*/
public SessionParams(
@@ -83,18 +85,21 @@ public class SessionParams extends RenderParams {
RenderResources renderResources,
IProjectCallback projectCallback,
int minSdkVersion, int targetSdkVersion,
+ boolean softwareButtons,
LayoutLog log) {
super(projectKey, screenWidth, screenHeight, density, xdpi, ydpi,
renderResources, projectCallback, minSdkVersion, targetSdkVersion, log);
mLayoutDescription = layoutDescription;
mRenderingMode = renderingMode;
+ mSoftwareButtons = softwareButtons;
}
public SessionParams(SessionParams params) {
super(params);
mLayoutDescription = params.mLayoutDescription;
mRenderingMode = params.mRenderingMode;
+ mSoftwareButtons = params.mSoftwareButtons;
if (params.mAdapterBindingMap != null) {
mAdapterBindingMap = new HashMap<ResourceReference, AdapterBinding>(
params.mAdapterBindingMap);
@@ -110,6 +115,10 @@ public class SessionParams extends RenderParams {
return mRenderingMode;
}
+ public boolean hasSoftwareButtons() {
+ return mSoftwareButtons;
+ }
+
public void setLayoutOnly() {
mLayoutOnly = true;
}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintClient.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintClient.java
index 2e21c06..2a68ddf 100644
--- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintClient.java
+++ b/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintClient.java
@@ -20,6 +20,7 @@ import static com.android.SdkConstants.CLASS_FOLDER;
import static com.android.SdkConstants.DOT_JAR;
import static com.android.SdkConstants.GEN_FOLDER;
import static com.android.SdkConstants.LIBS_FOLDER;
+import static com.android.SdkConstants.RES_FOLDER;
import static com.android.SdkConstants.SRC_FOLDER;
import com.android.SdkConstants;
@@ -233,6 +234,23 @@ public abstract class LintClient {
}
/**
+ * Returns the resource folder.
+ *
+ * @param project the project to look up the resource folder for
+ * @return a file pointing to the resource folder, or null if the project
+ * does not contain any resources
+ */
+ @Nullable
+ public File getResourceFolder(@NonNull Project project) {
+ File res = new File(project.getDir(), RES_FOLDER);
+ if (res.exists()) {
+ return res;
+ }
+
+ return null;
+ }
+
+ /**
* Returns the {@link SdkInfo} to use for the given project.
*
* @param project the project to look up an {@link SdkInfo} for
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintDriver.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintDriver.java
index aad1ad7..7f6c0ee 100644
--- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintDriver.java
+++ b/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintDriver.java
@@ -523,6 +523,13 @@ public class LintDriver {
assert detector instanceof Detector.ClassScanner : detector;
}
}
+
+ List<Detector> classCodeDetectors = mScopeDetectors.get(Scope.ALL_CLASS_FILES);
+ if (classCodeDetectors != null) {
+ for (Detector detector : classCodeDetectors) {
+ assert detector instanceof Detector.ClassScanner : detector;
+ }
+ }
}
}
@@ -819,8 +826,8 @@ public class LintDriver {
if (files != null) {
checkIndividualResources(project, main, xmlDetectors, files);
} else {
- File res = new File(project.getDir(), RES_FOLDER);
- if (res.exists() && xmlDetectors.size() > 0) {
+ File res = project.getResourceFolder();
+ if (res != null && xmlDetectors.size() > 0) {
checkResFolder(project, main, res, xmlDetectors);
}
}
@@ -850,7 +857,9 @@ public class LintDriver {
return;
}
- if (mScope.contains(Scope.CLASS_FILE) || mScope.contains(Scope.JAVA_LIBRARIES)) {
+ if (mScope.contains(Scope.CLASS_FILE)
+ || mScope.contains(Scope.ALL_CLASS_FILES)
+ || mScope.contains(Scope.JAVA_LIBRARIES)) {
checkClasses(project, main);
}
@@ -1054,6 +1063,7 @@ public class LintDriver {
}
runClassDetectors(Scope.CLASS_FILE, classEntries, project, main);
+ runClassDetectors(Scope.ALL_CLASS_FILES, classEntries, project, main);
}
private void checkIndividualClassFiles(
@@ -1664,6 +1674,12 @@ public class LintDriver {
@Override
@Nullable
+ public File getResourceFolder(@NonNull Project project) {
+ return mDelegate.getResourceFolder(project);
+ }
+
+ @Override
+ @Nullable
public IDomParser getDomParser() {
return mDelegate.getDomParser();
}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintUtils.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintUtils.java
index 60c9e97..c0d5a85 100644
--- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintUtils.java
+++ b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintUtils.java
@@ -668,6 +668,9 @@ public class LintUtils {
return false;
}
}
+ } else if (Project.isAospFrameworksProject(dir)) {
+ // Hardcoded AOSP support for the frameworks project
+ return true;
}
return hasManifest;
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Project.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Project.java
index b584020..eb41807 100644
--- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Project.java
+++ b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Project.java
@@ -25,9 +25,11 @@ import static com.android.SdkConstants.ATTR_PACKAGE;
import static com.android.SdkConstants.ATTR_TARGET_SDK_VERSION;
import static com.android.SdkConstants.PROGUARD_CONFIG;
import static com.android.SdkConstants.PROJECT_PROPERTIES;
+import static com.android.SdkConstants.RES_FOLDER;
import static com.android.SdkConstants.TAG_USES_SDK;
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.Configuration;
@@ -247,6 +249,9 @@ public class Project {
@NonNull
public List<File> getJavaSourceFolders() {
if (mJavaSourceFolders == null) {
+ if (isAospFrameworksProject(mDir)) {
+ return Collections.singletonList(new File(mDir, "java")); //$NON-NLS-1$
+ }
if (isAospBuildEnvironment()) {
String top = getAospTop();
if (mDir.getAbsolutePath().startsWith(top)) {
@@ -268,6 +273,21 @@ public class Project {
@NonNull
public List<File> getJavaClassFolders() {
if (mJavaClassFolders == null) {
+ if (isAospFrameworksProject(mDir)) {
+ File top = mDir.getParentFile().getParentFile().getParentFile();
+ if (top != null) {
+ File out = new File(top, "out");
+ if (out.exists()) {
+ String relative =
+ "target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar";
+ File jar = new File(out, relative.replace('/', File.separatorChar));
+ if (jar.exists()) {
+ mJavaClassFolders = Collections.singletonList(jar);
+ return mJavaClassFolders;
+ }
+ }
+ }
+ }
if (isAospBuildEnvironment()) {
String top = getAospTop();
if (mDir.getAbsolutePath().startsWith(top)) {
@@ -304,6 +324,28 @@ public class Project {
}
/**
+ * Returns the resource folder.
+ *
+ * @return a file pointing to the resource folder, or null if the project
+ * does not contain any resources
+ */
+ @Nullable
+ public File getResourceFolder() {
+ File folder = mClient.getResourceFolder(this);
+
+ if (folder != null && isAospFrameworksProject(mDir)) {
+ // No manifest file for this project: just init the manifest values here
+ mMinSdk = mTargetSdk = SdkConstants.HIGHEST_KNOWN_API;
+ folder = new File(folder, RES_FOLDER);
+ if (!folder.exists()) {
+ folder = null;
+ }
+ }
+
+ return folder;
+ }
+
+ /**
* Returns the relative path of a given file relative to the user specified
* directory (which is often the project directory but sometimes a higher up
* directory when a directory tree is being scanned
@@ -643,6 +685,31 @@ public class Project {
return sAospBuild.booleanValue();
}
+ /**
+ * Is this the frameworks AOSP project? Needs some hardcoded support since
+ * it doesn't have a manifest file, etc.
+ *
+ * @param dir the project directory to check
+ * @return true if this looks like the frameworks/base/core project
+ */
+ static boolean isAospFrameworksProject(@NonNull File dir) {
+ if (!dir.getPath().endsWith("core")) { //$NON-NLS-1$
+ return false;
+ }
+
+ File parent = dir.getParentFile();
+ if (parent == null || !parent.getName().equals("base")) { //$NON-NLS-1$
+ return false;
+ }
+
+ parent = parent.getParentFile();
+ if (parent == null || !parent.getName().equals("frameworks")) { //$NON-NLS-1$
+ return false;
+ }
+
+ return true;
+ }
+
/** Get the root AOSP dir, if any */
private static String getAospTop() {
return System.getenv("ANDROID_BUILD_TOP"); //$NON-NLS-1$
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Scope.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Scope.java
index a917c11..fcafb64 100644
--- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Scope.java
+++ b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Scope.java
@@ -70,6 +70,13 @@ public enum Scope {
*/
CLASS_FILE,
+ /**
+ * The analysis considers <b>all</b> the Java class files together.
+ * <p>
+ * This flag is mutually exclusive with {@link #CLASS_FILE}.
+ */
+ ALL_CLASS_FILES,
+
/** The analysis considers the manifest file */
MANIFEST,
diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/BuiltinIssueRegistry.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/BuiltinIssueRegistry.java
index d1c8f67..aafcd5c 100644
--- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/BuiltinIssueRegistry.java
+++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/BuiltinIssueRegistry.java
@@ -55,7 +55,7 @@ public class BuiltinIssueRegistry extends IssueRegistry {
private static final List<Issue> sIssues;
static {
- final int initialCapacity = 119;
+ final int initialCapacity = 120;
List<Issue> issues = new ArrayList<Issue>(initialCapacity);
issues.add(AccessibilityDetector.ISSUE);
@@ -86,6 +86,7 @@ public class BuiltinIssueRegistry extends IssueRegistry {
issues.add(TooManyViewsDetector.TOO_MANY);
issues.add(TooManyViewsDetector.TOO_DEEP);
issues.add(GridLayoutDetector.ISSUE);
+ issues.add(OverrideDetector.ISSUE);
issues.add(OnClickDetector.ISSUE);
issues.add(ViewTagDetector.ISSUE);
issues.add(LocaleDetector.STRING_LOCALE);
diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/IconDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/IconDetector.java
index 2f416b5..9d9cf14 100644
--- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/IconDetector.java
+++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/IconDetector.java
@@ -32,7 +32,6 @@ import static com.android.SdkConstants.DRAWABLE_MDPI;
import static com.android.SdkConstants.DRAWABLE_PREFIX;
import static com.android.SdkConstants.DRAWABLE_XHDPI;
import static com.android.SdkConstants.MENU_TYPE;
-import static com.android.SdkConstants.RES_FOLDER;
import static com.android.SdkConstants.R_CLASS;
import static com.android.SdkConstants.R_DRAWABLE_PREFIX;
import static com.android.SdkConstants.TAG_ACTIVITY;
@@ -53,6 +52,7 @@ import com.android.tools.lint.detector.api.Issue;
import com.android.tools.lint.detector.api.JavaContext;
import com.android.tools.lint.detector.api.LintUtils;
import com.android.tools.lint.detector.api.Location;
+import com.android.tools.lint.detector.api.Project;
import com.android.tools.lint.detector.api.ResourceXmlDetector;
import com.android.tools.lint.detector.api.Scope;
import com.android.tools.lint.detector.api.Severity;
@@ -335,17 +335,17 @@ public class IconDetector extends ResourceXmlDetector implements Detector.JavaSc
@Override
public void afterCheckLibraryProject(@NonNull Context context) {
- checkResourceFolder(context, context.getProject().getDir());
+ checkResourceFolder(context, context.getProject());
}
@Override
public void afterCheckProject(@NonNull Context context) {
- checkResourceFolder(context, context.getProject().getDir());
+ checkResourceFolder(context, context.getProject());
}
- private void checkResourceFolder(Context context, File dir) {
- File res = new File(dir, RES_FOLDER);
- if (res.isDirectory()) {
+ private void checkResourceFolder(Context context, @NonNull Project project) {
+ File res = project.getResourceFolder();
+ if (res != null) {
File[] folders = res.listFiles();
if (folders != null) {
boolean checkFolders = context.isEnabled(ICON_DENSITIES)
diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/OverrideDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/OverrideDetector.java
new file mode 100644
index 0000000..137bc21
--- /dev/null
+++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/OverrideDetector.java
@@ -0,0 +1,271 @@
+/*
+ * 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.checks;
+
+import static com.android.SdkConstants.CONSTRUCTOR_NAME;
+import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
+import static org.objectweb.asm.Opcodes.ACC_PROTECTED;
+import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
+import static org.objectweb.asm.Opcodes.ACC_STATIC;
+
+import com.android.annotations.NonNull;
+import com.android.tools.lint.client.api.LintDriver;
+import com.android.tools.lint.detector.api.Category;
+import com.android.tools.lint.detector.api.ClassContext;
+import com.android.tools.lint.detector.api.Context;
+import com.android.tools.lint.detector.api.Detector;
+import com.android.tools.lint.detector.api.Detector.ClassScanner;
+import com.android.tools.lint.detector.api.Issue;
+import com.android.tools.lint.detector.api.Location;
+import com.android.tools.lint.detector.api.Scope;
+import com.android.tools.lint.detector.api.Severity;
+import com.android.tools.lint.detector.api.Speed;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.google.common.collect.Sets.SetView;
+
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.MethodNode;
+
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * Checks for accidental overrides
+ */
+public class OverrideDetector extends Detector implements ClassScanner {
+ /** Accidental overrides */
+ public static final Issue ISSUE = Issue.create(
+ "DalvikOverride", //$NON-NLS-1$
+ "Looks for methods treated as overrides by Dalvik",
+
+ "The Android virtual machine will treat a package private method in one " +
+ "class as overriding a package private method in its super class, even if " +
+ "they are in separate packages. This may be surprising, but for compatibility " +
+ "reasons the behavior has not been changed (yet).\n" +
+ "\n" +
+ "If you really did intend for this method to override the other, make the " +
+ "method `protected` instead.\n" +
+ "\n" +
+ "If you did *not* intend the override, consider making the method private, or " +
+ "changing its name or signature.",
+
+ Category.CORRECTNESS,
+ 7,
+ Severity.ERROR,
+ OverrideDetector.class,
+ EnumSet.of(Scope.ALL_CLASS_FILES));
+
+ /** map from owner class name to JVM signatures for its package private methods */
+ private Map<String, Set<String>> mPackagePrivateMethods = Maps.newHashMap();
+
+ /** Map from owner to signature to super class being overridden */
+ private Map<String, Map<String, String>> mErrors;
+
+ /**
+ * Map from owner to signature to corresponding location. When there are
+ * errors a single error can have locations for both the overriding and
+ * overridden methods.
+ */
+ private Map<String, Map<String, Location>> mLocations;
+
+ /** Constructs a new {@link OverrideDetector} */
+ public OverrideDetector() {
+ }
+
+ @Override
+ public @NonNull Speed getSpeed() {
+ return Speed.NORMAL;
+ }
+
+ @Override
+ public void afterCheckProject(@NonNull Context context) {
+ // Process the check in two passes:
+ //
+ // In the first pass, gather the full set of package private methods for
+ // each class.
+ // When all classes have been processed at the end of the first pass,
+ // find out whether any of the methods are potentially overriding those
+ // in its super classes.
+ //
+ // If so, request a second pass. In the second pass, we gather full locations
+ // for both the base and overridden method calls, and store these.
+ // If the location is found to be in a suppressed context, remove that error
+ // entry.
+ //
+ // At the end of the second pass, we generate the errors, combining locations
+ // from both the overridden and overriding methods.
+ if (context.getPhase() == 1) {
+ Set<String> classes = mPackagePrivateMethods.keySet();
+ LintDriver driver = context.getDriver();
+ for (String owner : classes) {
+ Set<String> methods = mPackagePrivateMethods.get(owner);
+ String superClass = driver.getSuperClass(owner);
+ int packageIndex = owner.lastIndexOf('/');
+ while (superClass != null) {
+ int superPackageIndex = superClass.lastIndexOf('/');
+
+ // Only compare methods that differ in packages
+ if (packageIndex == -1 || superPackageIndex != packageIndex ||
+ !owner.regionMatches(0, superClass, 0, packageIndex)) {
+ Set<String> superMethods = mPackagePrivateMethods.get(superClass);
+ if (superMethods != null) {
+ SetView<String> intersection = Sets.intersection(methods,
+ superMethods);
+ if (!intersection.isEmpty()) {
+ if (mLocations == null) {
+ mLocations = Maps.newHashMap();
+ }
+ // We need a separate data structure to keep track of which
+ // signatures are in error,
+ if (mErrors == null) {
+ mErrors = Maps.newHashMap();
+ }
+
+ for (String signature : intersection) {
+ Map<String, Location> locations = mLocations.get(owner);
+ if (locations == null) {
+ locations = Maps.newHashMap();
+ mLocations.put(owner, locations);
+ }
+ locations.put(signature, null);
+
+ locations = mLocations.get(superClass);
+ if (locations == null) {
+ locations = Maps.newHashMap();
+ mLocations.put(superClass, locations);
+ }
+ locations.put(signature, null);
+
+
+ Map<String, String> errors = mErrors.get(owner);
+ if (errors == null) {
+ errors = Maps.newHashMap();
+ mErrors.put(owner, errors);
+ }
+ errors.put(signature, superClass);
+ }
+ }
+ }
+ }
+ superClass = driver.getSuperClass(superClass);
+ }
+ }
+
+ if (mErrors != null) {
+ context.requestRepeat(this, ISSUE.getScope());
+ }
+ } else {
+ assert context.getPhase() == 2;
+
+ for (Entry<String, Map<String, String>> ownerEntry : mErrors.entrySet()) {
+ String owner = ownerEntry.getKey();
+ Map<String, String> methodToSuper = ownerEntry.getValue();
+ for (Entry<String, String> entry : methodToSuper.entrySet()) {
+ String signature = entry.getKey();
+ String superClass = entry.getValue();
+
+ Map<String, Location> ownerLocations = mLocations.get(owner);
+ if (ownerLocations != null) {
+ Location location = ownerLocations.get(signature);
+ if (location != null) {
+ Map<String, Location> superLocations = mLocations.get(superClass);
+ if (superLocations != null) {
+ Location superLocation = superLocations.get(signature);
+ if (superLocation != null) {
+ location.setSecondary(superLocation);
+ superLocation.setMessage(
+ "This method is treated as overridden");
+ }
+ }
+ String methodName = signature;
+ int index = methodName.indexOf('(');
+ if (index != -1) {
+ methodName = methodName.substring(0, index);
+ }
+ String message = String.format(
+ "This package private method may be unintentionally " +
+ "overriding %1$s in %2$s", methodName,
+ ClassContext.getFqcn(superClass));
+ context.report(ISSUE, location, message, null);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("rawtypes") // ASM4 API
+ @Override
+ public void checkClass(@NonNull ClassContext context, @NonNull ClassNode classNode) {
+ List methodList = classNode.methods;
+ if (context.getPhase() == 1) {
+ for (Object m : methodList) {
+ MethodNode method = (MethodNode) m;
+ int access = method.access;
+ // Only record non-static package private methods
+ if ((access & (ACC_STATIC|ACC_PRIVATE|ACC_PROTECTED|ACC_PUBLIC)) != 0) {
+ continue;
+ }
+
+ // Ignore constructors too
+ if (CONSTRUCTOR_NAME.equals(method.name)) {
+ continue;
+ }
+
+ String owner = classNode.name;
+ Set<String> methods = mPackagePrivateMethods.get(owner);
+ if (methods == null) {
+ methods = Sets.newHashSetWithExpectedSize(methodList.size());
+ mPackagePrivateMethods.put(owner, methods);
+ }
+ methods.add(method.name + method.desc);
+ }
+ } else {
+ assert context.getPhase() == 2;
+ Map<String, Location> methods = mLocations.get(classNode.name);
+ if (methods == null) {
+ // No locations needed from this class
+ return;
+ }
+
+ for (Object m : methodList) {
+ MethodNode method = (MethodNode) m;
+
+ String signature = method.name + method.desc;
+ if (methods.containsKey(signature)){
+ if (method != null && context.getDriver().isSuppressed(ISSUE, method)) {
+ Map<String, String> errors = mErrors.get(classNode.name);
+ if (errors != null) {
+ errors.remove(signature);
+ }
+ continue;
+ }
+
+ Location location = context.getLocation(method, classNode);
+ methods.put(signature, location);
+ String description = ClassContext.createSignature(classNode.name,
+ method.name, method.desc);
+ location.setClientData(description);
+ }
+ }
+ }
+ }
+}
diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/RequiredAttributeDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/RequiredAttributeDetector.java
index 81b0626..a71f4b4 100644
--- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/RequiredAttributeDetector.java
+++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/RequiredAttributeDetector.java
@@ -319,7 +319,15 @@ public class RequiredAttributeDetector extends LayoutDetector implements Detecto
String parentTag = element.getParentNode() != null
? element.getParentNode().getNodeName() : "";
- if (TABLE_LAYOUT.equals(parentTag) || TABLE_ROW.equals(parentTag)) {
+ if (TABLE_LAYOUT.equals(parentTag)
+ || TABLE_ROW.equals(parentTag)
+ || GRID_LAYOUT.equals(parentTag)
+ || FQCN_GRID_LAYOUT_V7.equals(parentTag)) {
+ return;
+ }
+
+ String tag = element.getTagName();
+ if (tag.equals(VIEW_INCLUDE)) {
return;
}
@@ -368,11 +376,6 @@ public class RequiredAttributeDetector extends LayoutDetector implements Detecto
}
}
- String tag = element.getTagName();
- if (tag.equals(VIEW_INCLUDE) || tag.equals(GRID_LAYOUT)
- || tag.equals(FQCN_GRID_LAYOUT_V7)) {
- return;
- }
String message;
if (!(hasWidth || hasHeight)) {
if (certain) {
diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/UnusedResourceDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/UnusedResourceDetector.java
index 1b4163e..5a3f174 100644
--- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/UnusedResourceDetector.java
+++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/UnusedResourceDetector.java
@@ -26,7 +26,6 @@ import static com.android.SdkConstants.DOT_XML;
import static com.android.SdkConstants.RESOURCE_CLR_STYLEABLE;
import static com.android.SdkConstants.RESOURCE_CLZ_ARRAY;
import static com.android.SdkConstants.RESOURCE_CLZ_ID;
-import static com.android.SdkConstants.RES_FOLDER;
import static com.android.SdkConstants.R_ATTR_PREFIX;
import static com.android.SdkConstants.R_CLASS;
import static com.android.SdkConstants.R_ID_PREFIX;
@@ -261,8 +260,11 @@ public class UnusedResourceDetector extends ResourceXmlDetector implements Detec
if (type != null && LintUtils.isFileBasedResourceType(type)) {
String name = resource.substring(secondDot + 1);
- File res = new File(context.getProject().getDir(), RES_FOLDER);
- File[] folders = res.listFiles();
+ File[] folders = null;
+ File res = context.getProject().getResourceFolder();
+ if (res != null) {
+ folders = res.listFiles();
+ }
if (folders != null) {
// Process folders in alphabetical order such that we process
// based folders first: we want the locations in base folder
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/OnClickDetectorTest.java b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/OnClickDetectorTest.java
index e9f70d4..e4d8bb5 100644
--- a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/OnClickDetectorTest.java
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/OnClickDetectorTest.java
@@ -54,8 +54,7 @@ public class OnClickDetectorTest extends AbstractCheckTest {
"res/layout/onclick.xml:58: Error: Corresponding method handler 'public void simple_typo(android.view.View)' not found (did you mean void test.pkg.OnClickActivity#simple_tyop(android.view.View) ?) [OnClick]\n" +
" android:onClick=\"simple_typo\"\n" +
" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" +
- "9 errors, 0 warnings\n" +
- "",
+ "9 errors, 0 warnings\n",
lintProject(
"bytecode/.classpath=>.classpath",
@@ -73,5 +72,4 @@ public class OnClickDetectorTest extends AbstractCheckTest {
lintProject("res/layout/accessibility.xml"));
}
-
}
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/OverrideDetectorTest.java b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/OverrideDetectorTest.java
new file mode 100644
index 0000000..68f80f9
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/OverrideDetectorTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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.checks;
+
+import com.android.tools.lint.detector.api.Detector;
+
+@SuppressWarnings("javadoc")
+public class OverrideDetectorTest extends AbstractCheckTest {
+ @Override
+ protected Detector getDetector() {
+ return new OverrideDetector();
+ }
+
+ public void test() throws Exception {
+ assertEquals(
+ "src/pkg2/Class2.java:7: Error: This package private method may be unintentionally overriding method in pkg1.Class1 [DalvikOverride]\n" +
+ " void method() { // Flag this as an accidental override\n" +
+ " ~~~~~~\n" +
+ " src/pkg1/Class1.java:4: This method is treated as overridden\n" +
+ "1 errors, 0 warnings\n",
+
+ lintProject(
+ "bytecode/.classpath=>.classpath",
+ "bytecode/AndroidManifest.xml=>AndroidManifest.xml",
+ "src/pkg1/Class1.java.txt=>src/pkg1/Class1.java",
+ "src/pkg2/Class2.java.txt=>src/pkg2/Class2.java",
+ "bytecode/Class1.class.data=>bin/classes/pkg1/Class1.class",
+ "bytecode/Class1$Class4.class.data=>bin/classes/pkg1/Class1$Class4.class",
+ "bytecode/Class2.class.data=>bin/classes/pkg2/Class2.class",
+ "bytecode/Class2$Class3.class.data=>bin/classes/pkg2/Class2$Class3.class"
+ ));
+ }
+}
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/Class1$Class4.class.data b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/Class1$Class4.class.data
new file mode 100644
index 0000000..bfd88db
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/Class1$Class4.class.data
Binary files differ
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/Class1.class.data b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/Class1.class.data
new file mode 100644
index 0000000..cee3058
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/Class1.class.data
Binary files differ
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/Class2$Class3.class.data b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/Class2$Class3.class.data
new file mode 100644
index 0000000..2a58332
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/Class2$Class3.class.data
Binary files differ
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/Class2.class.data b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/Class2.class.data
new file mode 100644
index 0000000..1b72f03
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/Class2.class.data
Binary files differ
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/src/pkg1/Class1.java.txt b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/src/pkg1/Class1.java.txt
new file mode 100644
index 0000000..193ff3c
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/src/pkg1/Class1.java.txt
@@ -0,0 +1,29 @@
+package pkg1;
+
+public class Class1 {
+ void method() {
+ }
+
+ void method2(int foo) {
+ }
+
+ void method3() {
+ }
+
+ void method4() {
+ }
+
+ void method5() {
+ }
+
+ void method6() {
+ }
+
+ void method7() {
+ }
+
+ public static class Class4 extends Class1 {
+ void method() { // Not an error: same package
+ }
+ }
+}
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/src/pkg2/Class2.java.txt b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/src/pkg2/Class2.java.txt
new file mode 100644
index 0000000..651c021
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/src/pkg2/Class2.java.txt
@@ -0,0 +1,33 @@
+package pkg2;
+
+import android.annotation.SuppressLint;
+import pkg1.Class1;
+
+public class Class2 extends Class1 {
+ void method() { // Flag this as an accidental override
+ }
+
+ void method2(String foo) { // not an override: different signature
+ }
+
+ static void method4() { // not an override: static
+ }
+
+ private void method3() { // not an override: private
+ }
+
+ protected void method5() { // not an override: protected
+ }
+
+ public void method6() { // not an override: public
+ }
+
+ @SuppressLint("DalvikOverride")
+ public void method7() { // suppressed: no warning
+ }
+
+ public class Class3 extends Object {
+ void method() { // Not an override: not a subclass
+ }
+ }
+}