diff options
author | Tor Norbye <tnorbye@google.com> | 2012-10-17 09:33:03 -0700 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2012-10-17 11:47:41 -0700 |
commit | 0c2963e3256dd15ee9ea063db2834c88096e91f1 (patch) | |
tree | 3f99e6b4996bea2fce3b3950a1a8a94e4b7edd46 /lint | |
parent | 9a4d4e966de39c63d8840e8950688899fe382c34 (diff) | |
download | sdk-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')
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>
|