aboutsummaryrefslogtreecommitdiffstats
path: root/lint
diff options
context:
space:
mode:
authorTor Norbye <tnorbye@google.com>2012-10-17 09:33:03 -0700
committerTor Norbye <tnorbye@google.com>2012-10-17 11:47:41 -0700
commit0c2963e3256dd15ee9ea063db2834c88096e91f1 (patch)
tree3f99e6b4996bea2fce3b3950a1a8a94e4b7edd46 /lint
parent9a4d4e966de39c63d8840e8950688899fe382c34 (diff)
downloadsdk-0c2963e3256dd15ee9ea063db2834c88096e91f1.zip
sdk-0c2963e3256dd15ee9ea063db2834c88096e91f1.tar.gz
sdk-0c2963e3256dd15ee9ea063db2834c88096e91f1.tar.bz2
32849: Fix CRLF line ending handling in the partial formatter
Fix the handling of \r characters in the code which applies formatting deltas into existing documents. It could end up inserting the formatted portion in the middle of a \r\n pair, which made Eclipse extremely confused (https://bugs.eclipse.org/bugs/show_bug.cgi?id=375421) This fixes 32849: Eclipse android adt xml editing artifacting (unsynced) lines of text when changes are made in the graphical interface It also adds a lint check to identify *existing* files that already have these mangled line endings, along with a quickfix to make the correction. Change-Id: I1e7024f2786e4cb0233c2c6b98c3d3f942703ea0
Diffstat (limited to 'lint')
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/Location.java7
-rw-r--r--lint/libs/lint_checks/src/com/android/tools/lint/checks/BuiltinIssueRegistry.java9
-rw-r--r--lint/libs/lint_checks/src/com/android/tools/lint/checks/DosLineEndingDetector.java114
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/DosLineEndingDetectorTest.java49
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/crcrlf.xml14
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/crcrlf_ignore.xml19
6 files changed, 210 insertions, 2 deletions
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Location.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Location.java
index f574189..183e7c1 100644
--- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Location.java
+++ b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Location.java
@@ -235,6 +235,7 @@ public class Location {
Position start = null;
int line = 0;
int lineOffset = 0;
+ char prev = 0;
for (int offset = 0; offset <= size; offset++) {
if (offset == startOffset) {
start = new DefaultPosition(line, offset - lineOffset, offset);
@@ -246,8 +247,14 @@ public class Location {
char c = contents.charAt(offset);
if (c == '\n') {
lineOffset = offset + 1;
+ if (prev != '\r') {
+ line++;
+ }
+ } else if (c == '\r') {
line++;
+ lineOffset = offset + 1;
}
+ prev = c;
}
return Location.create(file);
}
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 aafcd5c..22a6c9d 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 = 120;
+ final int initialCapacity = 121;
List<Issue> issues = new ArrayList<Issue>(initialCapacity);
issues.add(AccessibilityDetector.ISSUE);
@@ -102,6 +102,7 @@ public class BuiltinIssueRegistry extends IssueRegistry {
issues.add(TranslationDetector.MISSING);
issues.add(HardcodedValuesDetector.ISSUE);
issues.add(Utf8Detector.ISSUE);
+ issues.add(DosLineEndingDetector.ISSUE);
issues.add(ProguardDetector.WRONGKEEP);
issues.add(ProguardDetector.SPLITCONFIG);
issues.add(PxUsageDetector.PX_ISSUE);
@@ -306,7 +307,7 @@ public class BuiltinIssueRegistry extends IssueRegistry {
// to give a hint to the user that some fixes don't require manual work
if (sAdtFixes == null) {
- sAdtFixes = new HashSet<Issue>(20);
+ sAdtFixes = new HashSet<Issue>(25);
sAdtFixes.add(InefficientWeightDetector.INEFFICIENT_WEIGHT);
sAdtFixes.add(AccessibilityDetector.ISSUE);
sAdtFixes.add(InefficientWeightDetector.BASELINE_WEIGHTS);
@@ -327,6 +328,10 @@ public class BuiltinIssueRegistry extends IssueRegistry {
sAdtFixes.add(UseCompoundDrawableDetector.ISSUE);
sAdtFixes.add(ApiDetector.UNSUPPORTED);
sAdtFixes.add(TypoDetector.ISSUE);
+ sAdtFixes.add(ManifestOrderDetector.ALLOW_BACKUP);
+ sAdtFixes.add(MissingIdDetector.ISSUE);
+ sAdtFixes.add(TranslationDetector.MISSING);
+ sAdtFixes.add(DosLineEndingDetector.ISSUE);
}
return sAdtFixes.contains(issue);
diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/DosLineEndingDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/DosLineEndingDetector.java
new file mode 100644
index 0000000..c2e735c
--- /dev/null
+++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/DosLineEndingDetector.java
@@ -0,0 +1,114 @@
+/*
+ * 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.annotations.NonNull;
+import com.android.tools.lint.detector.api.Category;
+import com.android.tools.lint.detector.api.Issue;
+import com.android.tools.lint.detector.api.LayoutDetector;
+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.android.tools.lint.detector.api.XmlContext;
+
+import org.w3c.dom.Document;
+
+/**
+ * Checks that the line endings in DOS files are consistent
+ */
+public class DosLineEndingDetector extends LayoutDetector {
+ /** Detects mangled DOS line ending documents */
+ public static final Issue ISSUE = Issue.create(
+ "MangledCRLF", //$NON-NLS-1$
+ "Checks that files with DOS line endings are consistent",
+
+ "On Windows, line endings are typically recorded as carriage return plus " +
+ "newline: \\r\\n.\n" +
+ "\n" +
+ "This detector looks for invalid line endings with repeated carriage return " +
+ "characters (without newlines). Previous versions of the ADT plugin could " +
+ "accidentally introduce these into the file, and when editing the file, the " +
+ "editor could produce confusing visual artifacts.",
+
+ Category.CORRECTNESS,
+ 2,
+ Severity.ERROR,
+ DosLineEndingDetector.class,
+ Scope.RESOURCE_FILE_SCOPE)
+ .setMoreInfo("https://bugs.eclipse.org/bugs/show_bug.cgi?id=375421"); //$NON-NLS-1$
+
+ /** Constructs a new {@link DosLineEndingDetector} */
+ public DosLineEndingDetector() {
+ }
+
+ @Override
+ public @NonNull Speed getSpeed() {
+ return Speed.NORMAL;
+ }
+
+ @Override
+ public void visitDocument(@NonNull XmlContext context, @NonNull Document document) {
+ String contents = context.getContents();
+ if (contents == null) {
+ return;
+ }
+
+ // We could look for *consistency* and complain if you mix \n and \r\n too,
+ // but that isn't really a problem (most editors handle it) so let's
+ // not complain needlessly.
+
+ char prev = 0;
+ for (int i = 0, n = contents.length(); i < n; i++) {
+ char c = contents.charAt(i);
+ if (c == '\r' && prev == '\r') {
+ String message = "Incorrect line ending: found carriage return (\\r) without " +
+ "corresponding newline (\\n)";
+
+ // Mark the whole line as the error range, since pointing just to the
+ // line ending makes the error invisible in IDEs and error reports etc
+ // Find the most recent non-blank line
+ boolean blankLine = true;
+ for (int index = i - 2; index < i; index++) {
+ char d = contents.charAt(index);
+ if (!Character.isWhitespace(d)) {
+ blankLine = false;
+ }
+ }
+
+ int lineBegin = i;
+ for (int index = i - 2; index >= 0; index--) {
+ char d = contents.charAt(index);
+ if (d == '\n') {
+ lineBegin = index + 1;
+ if (!blankLine) {
+ break;
+ }
+ } else if (!Character.isWhitespace(d)) {
+ blankLine = false;
+ }
+ }
+
+ int lineEnd = Math.min(contents.length(), i + 1);
+ Location location = Location.create(context.file, contents, lineBegin, lineEnd);
+ context.report(ISSUE, document.getDocumentElement(), location, message, null);
+ return;
+ }
+ prev = c;
+ }
+ }
+}
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/DosLineEndingDetectorTest.java b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/DosLineEndingDetectorTest.java
new file mode 100644
index 0000000..3682420
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/DosLineEndingDetectorTest.java
@@ -0,0 +1,49 @@
+/*
+ * 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 DosLineEndingDetectorTest extends AbstractCheckTest {
+ @Override
+ protected Detector getDetector() {
+ return new DosLineEndingDetector();
+ }
+
+ public void test() throws Exception {
+ assertEquals(
+ "res/layout/crcrlf.xml:4: Error: Incorrect line ending: found carriage return (\\r) without corresponding newline (\\n) [MangledCRLF]\n" +
+ " android:layout_height=\"match_parent\" >\r\n" +
+ "^\n" +
+ "1 errors, 0 warnings\n",
+ lintProject("res/layout/crcrlf.xml"));
+ }
+
+ public void testIgnore() throws Exception {
+ assertEquals(
+ "No warnings.",
+ lintProject("res/layout/crcrlf_ignore.xml"));
+ }
+
+ public void testNegative() throws Exception {
+ // Make sure we don't get warnings for a correct file
+ assertEquals(
+ "No warnings.",
+ lintProject("res/layout/layout1.xml"));
+ }
+}
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/crcrlf.xml b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/crcrlf.xml
new file mode 100644
index 0000000..d029725
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/crcrlf.xml
@@ -0,0 +1,14 @@
+<RelativeLayout 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" >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_centerVertical="true"
+ android:text="Hello"
+ tools:context=".MainActivity" />
+
+</RelativeLayout>
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/crcrlf_ignore.xml b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/crcrlf_ignore.xml
new file mode 100644
index 0000000..680a765
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/crcrlf_ignore.xml
@@ -0,0 +1,19 @@
+<RelativeLayout 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"
+ tools:ignore="MangledCRLF" >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_centerVertical="true"
+ android:text="@string/app_name"
+ tools:context=".MainActivity" />
+
+
+
+
+
+</RelativeLayout>