aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lint/cli/src/test/java/com/android/tools/lint/checks/ApiDetectorTest.java13
-rw-r--r--lint/cli/src/test/java/com/android/tools/lint/checks/TranslationDetectorTest.java11
-rw-r--r--lint/cli/src/test/java/com/android/tools/lint/checks/ViewConstructorDetectorTest.java12
-rw-r--r--lint/cli/src/test/java/com/android/tools/lint/checks/data/apicheck/divider.xml37
-rw-r--r--lint/cli/src/test/java/com/android/tools/lint/checks/data/bytecode/AbstractCustomView.class.databin0 -> 334 bytes
-rw-r--r--lint/cli/src/test/java/com/android/tools/lint/checks/data/bytecode/AbstractCustomView.java.txt9
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/AnnotationDetector.java2
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ApiDetector.java137
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ColorUsageDetector.java2
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/NonInternationalizedSmsDetector.java2
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/StringFormatDetector.java11
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ToastDetector.java2
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TranslationDetector.java3
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/UnusedResourceDetector.java5
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ViewConstructorDetector.java5
15 files changed, 182 insertions, 69 deletions
diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/ApiDetectorTest.java b/lint/cli/src/test/java/com/android/tools/lint/checks/ApiDetectorTest.java
index 1d8cdc8..43d3727 100644
--- a/lint/cli/src/test/java/com/android/tools/lint/checks/ApiDetectorTest.java
+++ b/lint/cli/src/test/java/com/android/tools/lint/checks/ApiDetectorTest.java
@@ -60,6 +60,19 @@ public class ApiDetectorTest extends AbstractCheckTest {
));
}
+ public void testAttrWithoutSlash() throws Exception {
+ assertEquals(""
+ + "res/layout/divider.xml:7: Error: ?android:dividerHorizontal requires API level 11 (current min is 1) [NewApi]\n"
+ + " android:divider=\"?android:dividerHorizontal\"\n"
+ + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
+ + "1 errors, 0 warnings\n",
+
+ lintProject(
+ "apicheck/minsdk1.xml=>AndroidManifest.xml",
+ "apicheck/divider.xml=>res/layout/divider.xml"
+ ));
+ }
+
public void testXmlApi14() throws Exception {
assertEquals(
"No warnings.",
diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/TranslationDetectorTest.java b/lint/cli/src/test/java/com/android/tools/lint/checks/TranslationDetectorTest.java
index f13cff1..ee1a2f2 100644
--- a/lint/cli/src/test/java/com/android/tools/lint/checks/TranslationDetectorTest.java
+++ b/lint/cli/src/test/java/com/android/tools/lint/checks/TranslationDetectorTest.java
@@ -209,4 +209,15 @@ public class TranslationDetectorTest extends AbstractCheckTest {
"res/values-es/strings_locale.xml=>res/values/strings.xml",
"res/values-es-rUS/strings.xml"));
}
+
+ public void testAnalytics() throws Exception {
+ // See http://code.google.com/p/android/issues/detail?id=43070
+ assertEquals(
+ "No warnings.",
+
+ lintProject(
+ "res/values/analytics.xml",
+ "res/values-es/donottranslate.xml" // to make app multilingual
+ ));
+ }
}
diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/ViewConstructorDetectorTest.java b/lint/cli/src/test/java/com/android/tools/lint/checks/ViewConstructorDetectorTest.java
index 5517646..a84a74f 100644
--- a/lint/cli/src/test/java/com/android/tools/lint/checks/ViewConstructorDetectorTest.java
+++ b/lint/cli/src/test/java/com/android/tools/lint/checks/ViewConstructorDetectorTest.java
@@ -61,4 +61,16 @@ public class ViewConstructorDetectorTest extends AbstractCheckTest {
"bin/classes/test/pkg/Intermediate$IntermediateCustomV.class"
));
}
+
+ public void testAbstract() throws Exception {
+ assertEquals(
+ "No warnings.",
+
+ lintProject(
+ "bytecode/.classpath=>.classpath",
+ "bytecode/AndroidManifest.xml=>AndroidManifest.xml",
+ "bytecode/AbstractCustomView.java.txt=>src/test/bytecode/AbstractCustomView.java",
+ "bytecode/AbstractCustomView.class.data=>bin/classes/test/bytecode/AbstractCustomView.class"
+ ));
+ }
}
diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/data/apicheck/divider.xml b/lint/cli/src/test/java/com/android/tools/lint/checks/data/apicheck/divider.xml
new file mode 100644
index 0000000..4244319
--- /dev/null
+++ b/lint/cli/src/test/java/com/android/tools/lint/checks/data/apicheck/divider.xml
@@ -0,0 +1,37 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginLeft="16dp"
+ android:layout_marginRight="16dp"
+ android:divider="?android:dividerHorizontal"
+ android:orientation="horizontal"
+ android:showDividers="middle"
+ tools:context=".ItemListActivity" >
+
+ <!--
+ This layout is a two-pane layout for the Items
+ master/detail flow. See res/values-large/refs.xml and
+ res/values-sw600dp/refs.xml for an example of layout aliases
+ that replace the single-pane version of the layout with
+ this two-pane version.
+
+ For more on layout aliases, see:
+ http://developer.android.com/training/multiscreen/screensizes.html#TaskUseAliasFilters
+ -->
+
+ <fragment
+ android:id="@+id/item_list"
+ android:name="com.example.master.ItemListFragment"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ tools:layout="@android:layout/list_content" />
+
+ <FrameLayout
+ android:id="@+id/item_detail_container"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="3" />
+
+</LinearLayout>
diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/data/bytecode/AbstractCustomView.class.data b/lint/cli/src/test/java/com/android/tools/lint/checks/data/bytecode/AbstractCustomView.class.data
new file mode 100644
index 0000000..8dc3dc6
--- /dev/null
+++ b/lint/cli/src/test/java/com/android/tools/lint/checks/data/bytecode/AbstractCustomView.class.data
Binary files differ
diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/data/bytecode/AbstractCustomView.java.txt b/lint/cli/src/test/java/com/android/tools/lint/checks/data/bytecode/AbstractCustomView.java.txt
new file mode 100644
index 0000000..aedbafd
--- /dev/null
+++ b/lint/cli/src/test/java/com/android/tools/lint/checks/data/bytecode/AbstractCustomView.java.txt
@@ -0,0 +1,9 @@
+package test.pkg;
+
+import android.view.View;
+
+public abstract class AbstractCustomView extends View {
+ public AbstractCustomView() {
+ super(null);
+ }
+}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/AnnotationDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/AnnotationDetector.java
index f091269..eca9256 100644
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/AnnotationDetector.java
+++ b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/AnnotationDetector.java
@@ -191,7 +191,7 @@ public class AnnotationDetector extends Detector implements Detector.JavaScanner
// This issue doesn't have AST access: annotations are not
// available for local variables or parameters
- mContext.report(ISSUE,mContext.getLocation(node), String.format(
+ mContext.report(ISSUE, node, mContext.getLocation(node), String.format(
"The @SuppressLint annotation cannot be used on a local " +
"variable with the lint check '%1$s': move out to the " +
"surrounding method", id),
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ApiDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ApiDetector.java
index 936f882..146e9e1 100644
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ApiDetector.java
+++ b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ApiDetector.java
@@ -101,6 +101,7 @@ import lombok.ast.Expression;
import lombok.ast.ForwardingAstVisitor;
import lombok.ast.If;
import lombok.ast.ImportDeclaration;
+import lombok.ast.InlineIfExpression;
import lombok.ast.IntegralLiteral;
import lombok.ast.MethodDeclaration;
import lombok.ast.MethodInvocation;
@@ -311,6 +312,9 @@ public class ApiDetector extends ResourceXmlDetector
if (name.indexOf('.') != -1) {
name = name.replace('.', '_');
}
+ } else if (value.startsWith(ANDROID_THEME_PREFIX)) {
+ owner = "android/R$attr"; //$NON-NLS-1$
+ name = value.substring(ANDROID_THEME_PREFIX.length());
} else {
return;
}
@@ -446,7 +450,8 @@ public class ApiDetector extends ResourceXmlDetector
return;
}
- boolean checkCalls = context.isEnabled(UNSUPPORTED);
+ boolean checkCalls = context.isEnabled(UNSUPPORTED)
+ || context.isEnabled(INLINED);
boolean checkMethods = context.isEnabled(OVERRIDE)
&& context.getMainProject().getBuildSdk() >= 1;
String frameworkParent = null;
@@ -1040,6 +1045,82 @@ public class ApiDetector extends ResourceXmlDetector
return types;
}
+ /**
+ * Checks whether the given instruction is a benign usage of a constant defined in
+ * a later version of Android than the application's {@code minSdkVersion}.
+ *
+ * @param node the instruction to check
+ * @param name the name of the constant
+ * @param owner the field owner
+ * @return true if the given usage is safe on older versions than the introduction
+ * level of the constant
+ */
+ public boolean isBenignConstantUsage(
+ @Nullable lombok.ast.Node node,
+ @NonNull String name,
+ @NonNull String owner) {
+ if (owner.equals("android/os/Build$VERSION_CODES")) { //$NON-NLS-1$
+ // These constants are required for compilation, not execution
+ // and valid code checks it even on older platforms
+ return true;
+ }
+ if (owner.equals("android/view/ViewGroup$LayoutParams") //$NON-NLS-1$
+ && name.equals("MATCH_PARENT")) { //$NON-NLS-1$
+ return true;
+ }
+ if (owner.equals("android/widget/AbsListView") //$NON-NLS-1$
+ && ((name.equals("CHOICE_MODE_NONE") //$NON-NLS-1$
+ || name.equals("CHOICE_MODE_MULTIPLE") //$NON-NLS-1$
+ || name.equals("CHOICE_MODE_SINGLE")))) { //$NON-NLS-1$
+ // android.widget.ListView#CHOICE_MODE_MULTIPLE and friends have API=1,
+ // but in API 11 it was moved up to the parent class AbsListView.
+ // Referencing AbsListView#CHOICE_MODE_MULTIPLE technically requires API 11,
+ // but the constant is the same as the older version, so accept this without
+ // warning.
+ return true;
+ }
+
+ if (node == null) {
+ return false;
+ }
+
+ // It's okay to reference the constant as a case constant (since that
+ // code path won't be taken) or in a condition of an if statement
+ lombok.ast.Node curr = node.getParent();
+ while (curr != null) {
+ Class<? extends lombok.ast.Node> nodeType = curr.getClass();
+ if (nodeType == Case.class) {
+ Case caseStatement = (Case) curr;
+ Expression condition = caseStatement.astCondition();
+ return condition != null && isAncestor(condition, node);
+ } else if (nodeType == If.class) {
+ If ifStatement = (If) curr;
+ Expression condition = ifStatement.astCondition();
+ return condition != null && isAncestor(condition, node);
+ } else if (nodeType == InlineIfExpression.class) {
+ InlineIfExpression ifStatement = (InlineIfExpression) curr;
+ Expression condition = ifStatement.astCondition();
+ return condition != null && isAncestor(condition, node);
+ }
+ curr = curr.getParent();
+ }
+
+ return false;
+ }
+
+ private static boolean isAncestor(
+ @NonNull lombok.ast.Node ancestor,
+ @Nullable lombok.ast.Node node) {
+ while (node != null) {
+ if (node == ancestor) {
+ return true;
+ }
+ node = node.getParent();
+ }
+
+ return false;
+ }
+
private final class ApiVisitor extends ForwardingAstVisitor {
private JavaContext mContext;
private Map<String, String> mClassToImport = Maps.newHashMap();
@@ -1363,60 +1444,6 @@ public class ApiDetector extends ResourceXmlDetector
}
/**
- * Checks whether the given instruction is a benign usage of a constant defined
- * in a later version of Android than the application's {@code minSdkVersion}.
- *
- * @param node the instruction to check
- * @param name the name of the constant
- * @param owner the field owner
- * @return true if the given usage is safe on older versions than the introduction
- * level of the constant
- */
- public boolean isBenignConstantUsage(
- @NonNull lombok.ast.Node node,
- @NonNull String name,
- @NonNull String owner) {
- if (owner.equals("android/os/Build$VERSION_CODES")) { //$NON-NLS-1$
- // These constants are required for compilation, not execution
- // and valid code checks it even on older platforms
- return true;
- }
- if (owner.equals("android/view/ViewGroup$LayoutParams") //$NON-NLS-1$
- && name.equals("MATCH_PARENT")) { //$NON-NLS-1$
- return true;
- }
- if (owner.equals("android/widget/AbsListView") //$NON-NLS-1$
- && ((name.equals("CHOICE_MODE_NONE") //$NON-NLS-1$
- || name.equals("CHOICE_MODE_MULTIPLE") //$NON-NLS-1$
- || name.equals("CHOICE_MODE_SINGLE")))) { //$NON-NLS-1$
- // android.widget.ListView#CHOICE_MODE_MULTIPLE and friends have API=1,
- // but in API 11 it was moved up to the parent class AbsListView.
- // Referencing AbsListView#CHOICE_MODE_MULTIPLE technically requires API 11,
- // but the constant is the same as the older version, so accept this without
- // warning.
- return true;
- }
-
- // It's okay to reference the constant as a case constant (since that
- // code path won't be taken) or in a condition of an if statement
- lombok.ast.Node curr = node.getParent();
- boolean usedInExpression = false;
- while (curr != null) {
- Class<? extends lombok.ast.Node> nodeType = curr.getClass();
- if (nodeType == Case.class) {
- return true;
- } else if (nodeType == BinaryExpression.class) {
- usedInExpression = true;
- } else if (nodeType == If.class) {
- return usedInExpression;
- }
- curr = curr.getParent();
- }
-
- return false;
- }
-
- /**
* Returns the minimum SDK to use according to the given AST node, or null
* if no {@code TargetApi} annotations were found
*
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ColorUsageDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ColorUsageDetector.java
index 622af71..e7ffcb6 100644
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ColorUsageDetector.java
+++ b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ColorUsageDetector.java
@@ -94,7 +94,7 @@ public class ColorUsageDetector extends Detector implements Detector.JavaScanner
if (methodName.endsWith("Color") //$NON-NLS-1$
&& methodName.startsWith("set")) { //$NON-NLS-1$
context.report(
- ISSUE, context.getLocation(select), String.format(
+ ISSUE, select, context.getLocation(select), String.format(
"Should pass resolved color instead of resource id here: " +
"getResources().getColor(%1$s)", select.toString()),
null);
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/NonInternationalizedSmsDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/NonInternationalizedSmsDetector.java
index 3ee7e82..e970572 100644
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/NonInternationalizedSmsDetector.java
+++ b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/NonInternationalizedSmsDetector.java
@@ -91,7 +91,7 @@ public class NonInternationalizedSmsDetector extends Detector implements Detecto
String number = ((StringLiteral) destinationAddress).astValue();
if (!number.startsWith("+")) { //$NON-NLS-1$
- context.report(ISSUE, context.getLocation(destinationAddress),
+ context.report(ISSUE, node, context.getLocation(destinationAddress),
"To make sure the SMS can be sent by all users, please start the SMS number " +
"with a + and a country code or restrict the code invocation to people in the country " +
"you are targeting.",
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/StringFormatDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/StringFormatDetector.java
index 7bb07f2..033996e 100644
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/StringFormatDetector.java
+++ b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/StringFormatDetector.java
@@ -52,7 +52,6 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
-import java.util.Formatter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -322,8 +321,6 @@ public class StringFormatDetector extends ResourceXmlDetector implements Detecto
@Override
public void afterCheckProject(@NonNull Context context) {
if (mFormatStrings != null) {
- Formatter formatter = new Formatter();
-
boolean checkCount = context.isEnabled(ARG_COUNT);
boolean checkValid = context.isEnabled(INVALID);
boolean checkTypes = context.isEnabled(ARG_TYPES);
@@ -342,15 +339,13 @@ public class StringFormatDetector extends ResourceXmlDetector implements Detecto
// Check argument types (and also make sure that the formatting strings are valid)
if (checkValid || checkTypes) {
- checkTypes(context, formatter, checkValid, checkTypes, name, list);
+ checkTypes(context, checkValid, checkTypes, name, list);
}
}
-
- formatter.close();
}
}
- private static void checkTypes(Context context, Formatter formatter, boolean checkValid,
+ private static void checkTypes(Context context, boolean checkValid,
boolean checkTypes, String name, List<Pair<Handle, String>> list) {
Map<Integer, String> types = new HashMap<Integer, String>();
Map<Integer, Handle> typeDefinition = new HashMap<Integer, Handle>();
@@ -927,7 +922,7 @@ public class StringFormatDetector extends ResourceXmlDetector implements Detecto
"Format string '%1$s' is not a valid format string so it should not be " +
"passed to String.format",
name);
- context.report(INVALID, location, message, null);
+ context.report(INVALID, call, location, message, null);
return;
}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ToastDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ToastDetector.java
index 01804af..e245fe8 100644
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ToastDetector.java
+++ b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ToastDetector.java
@@ -94,7 +94,7 @@ public class ToastDetector extends Detector implements Detector.JavaScanner {
if (args.size() == 3) {
Expression duration = args.last();
if (duration instanceof IntegralLiteral) {
- context.report(ISSUE, context.getLocation(duration),
+ context.report(ISSUE, duration, context.getLocation(duration),
"Expected duration Toast.LENGTH_SHORT or Toast.LENGTH_LONG, a custom " +
"duration value is not supported",
null);
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TranslationDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TranslationDetector.java
index 5ca6046..0f892b1 100644
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TranslationDetector.java
+++ b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TranslationDetector.java
@@ -162,7 +162,8 @@ public class TranslationDetector extends ResourceXmlDetector {
}
// Convention seen in various projects
- mIgnoreFile = context.file.getName().startsWith("donottranslate"); //$NON-NLS-1$
+ mIgnoreFile = context.file.getName().startsWith("donottranslate") //$NON-NLS-1$
+ || UnusedResourceDetector.isAnalyticsFile(context);
if (!context.getProject().getReportIssues()) {
mIgnoreFile = true;
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/UnusedResourceDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/UnusedResourceDetector.java
index f960118..caa112a 100644
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/UnusedResourceDetector.java
+++ b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/UnusedResourceDetector.java
@@ -429,8 +429,11 @@ public class UnusedResourceDetector extends ResourceXmlDetector implements Detec
* Returns true if this XML file corresponds to an Analytics configuration file;
* these contain some attributes read by the library which won't be flagged as
* used by the application
+ *
+ * @param context the context used for scanning
+ * @return true if the file represents an analytics file
*/
- private static boolean isAnalyticsFile(XmlContext context) {
+ public static boolean isAnalyticsFile(Context context) {
File file = context.file;
return file.getPath().endsWith(ANALYTICS_FILE) && file.getName().equals(ANALYTICS_FILE);
}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ViewConstructorDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ViewConstructorDetector.java
index 0eba024..4bffdd7 100644
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ViewConstructorDetector.java
+++ b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ViewConstructorDetector.java
@@ -89,6 +89,11 @@ public class ViewConstructorDetector extends Detector implements Detector.ClassS
return;
}
+ // Ignore abstract classes
+ if ((classNode.access & Opcodes.ACC_ABSTRACT) != 0) {
+ return;
+ }
+
if (isViewClass(context, classNode)) {
checkConstructors(context, classNode);
}