take care of surrogates in encoding-independent way

This commit is contained in:
Alexey Kudravtsev
2016-05-25 16:14:05 +03:00
parent b5df7cff92
commit 482c5ba7f1
@@ -14,12 +14,6 @@
* limitations under the License.
*/
/*
* Created by IntelliJ IDEA.
* User: cdr
* Date: Aug 6, 2007
* Time: 3:09:55 PM
*/
package com.intellij.codeInspection;
import com.intellij.ide.DataManager;
@@ -38,7 +32,6 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.ListPopup;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.encoding.ChangeFileEncodingAction;
import com.intellij.openapi.vfs.encoding.EncodingUtil;
@@ -104,7 +97,7 @@ public class LossyEncodingInspection extends LocalInspectionTool {
// no sense in checking transparently decoded file: all characters there are already safely encoded
if (charset instanceof Native2AsciiCharset) return null;
List<ProblemDescriptor> descriptors = new SmartList<ProblemDescriptor>();
List<ProblemDescriptor> descriptors = new SmartList<>();
boolean ok = checkFileLoadedInWrongEncoding(file, manager, isOnTheFly, virtualFile, charset, descriptors);
if (ok) {
checkIfCharactersWillBeLostAfterSave(file, manager, isOnTheFly, text, charset, descriptors);
@@ -173,11 +166,11 @@ public class LossyEncodingInspection extends LocalInspectionTool {
@NotNull List<ProblemDescriptor> descriptors) {
int errorCount = 0;
int start = -1;
CharBuffer buffer = CharBuffer.wrap(text); // temp buffer for encoding/decoding back a char or a surrogate pair.
for (int i = 0; i <= text.length(); i++) {
char c = i >= text.length() ? 0 : text.charAt(i);
char next = i + 1 >= text.length() ? 0 : text.charAt(i + 1);
char prev = i == 0 ? 0 : text.charAt(i - 1);
if (i == text.length() || isRepresentable(c, next, prev, charset)) {
int end = Character.isHighSurrogate(c) && i<text.length()-1 ? i + 2 : i+1;
if (i == text.length() || isRepresentable(buffer, i, end, charset)) {
if (start != -1) {
TextRange range = new TextRange(start, i);
String message = InspectionsBundle.message("unsupported.character.for.the.charset", charset);
@@ -192,17 +185,22 @@ public class LossyEncodingInspection extends LocalInspectionTool {
else if (start == -1) {
start = i;
}
if (end != i+1) {
i++; // skip surrogate low
}
}
}
private static boolean isRepresentable(final char c, final char next, char prev, @NotNull Charset charset) {
if (charset == CharsetToolkit.UTF8_CHARSET) {
if (Character.isSurrogatePair(c, next) || Character.isSurrogatePair(prev, c)) return true;
}
String str = String.valueOf(c);
ByteBuffer out = charset.encode(str);
private static boolean isRepresentable(@NotNull CharBuffer srcBuffer,
int start,
int end,
@NotNull Charset charset) {
srcBuffer.position(start);
srcBuffer.limit(end);
ByteBuffer out = charset.encode(srcBuffer);
CharBuffer buffer = charset.decode(out);
return str.equals(buffer.toString());
srcBuffer.position(start);
return buffer.equals(srcBuffer);
}
private static class ReloadInAnotherEncodingFix extends ChangeEncodingFix {
@@ -246,7 +244,7 @@ public class LossyEncodingInspection extends LocalInspectionTool {
}
@NotNull
public static DataContext createDataContext(Editor editor, Component component, VirtualFile selectedFile, Project project) {
static DataContext createDataContext(Editor editor, Component component, VirtualFile selectedFile, Project project) {
DataContext parent = DataManager.getInstance().getDataContext(component);
DataContext context = SimpleDataContext.getSimpleContext(PlatformDataKeys.CONTEXT_COMPONENT.getName(), editor == null ? null : editor.getComponent(), parent);
DataContext projectContext = SimpleDataContext.getSimpleContext(CommonDataKeys.PROJECT.getName(), project, context);