mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-15 02:59:33 +07:00
[properties, inspection, fix] non-ISO 8859-1 characters for java 1.8 and below IDEA-360007
GitOrigin-RevId: 7a45cac5966b251a5db6759c16f3709392c5a3fc
This commit is contained in:
committed by
intellij-monorepo-bot
parent
429a0591ac
commit
9aac209c72
@@ -84,6 +84,7 @@ feature.effectively.final=Effectively final variables
|
||||
feature.try.with.resources.refs=Resource references
|
||||
feature.modules=Modules
|
||||
feature.private.interface.methods=Private interface methods
|
||||
feature.utf8.property.files=Property files in UTF-8 encoding
|
||||
feature.collection.factories=Collection factory methods
|
||||
feature.lvti=Local variable type inference
|
||||
feature.var.lambda.parameter='var' in lambda parameters
|
||||
|
||||
@@ -51,6 +51,7 @@ public enum JavaFeature {
|
||||
MODULES(LanguageLevel.JDK_1_9, "feature.modules"),
|
||||
COLLECTION_FACTORIES(LanguageLevel.JDK_1_9, "feature.collection.factories"),
|
||||
PRIVATE_INTERFACE_METHODS(LanguageLevel.JDK_1_9, "feature.private.interface.methods"),
|
||||
UTF8_PROPERTY_FILES(LanguageLevel.JDK_1_9, "feature.utf8.property.files"),
|
||||
LVTI(LanguageLevel.JDK_10, "feature.lvti"),
|
||||
VAR_LAMBDA_PARAMETER(LanguageLevel.JDK_11, "feature.var.lambda.parameter"),
|
||||
NESTMATES(LanguageLevel.JDK_11, "feature.nestmates"),
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<html>
|
||||
<body>
|
||||
Reports characters in property files that are unsupported by the ISO-8859-1 charset when Java 1.8 or earlier is used.
|
||||
The inspection checks if a property file contains characters that cannot be mapped to ISO-8859-1 and suggests converting them to Unicode escape sequences for compatibility.
|
||||
<p>Configure the inspection:</p>
|
||||
<p>
|
||||
Use the <b>Convert to escape sequences</b> quick-fix to ensure compatibility with ISO-8859-1 encoding:
|
||||
</p>
|
||||
|
||||
<p><b>Example:</b></p>
|
||||
<pre><code>
|
||||
key=Java + ☕ = 🍀
|
||||
</code></pre>
|
||||
<p>After the quick-fix is applied:</p>
|
||||
<pre><code>
|
||||
key=Java + \u2615 = \uD83C\uDF40
|
||||
</code></pre>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1895,6 +1895,7 @@ f:com.intellij.openapi.fileTypes.BinaryFileTypeDecompilers
|
||||
f:com.intellij.openapi.fileTypes.CharsetUtil
|
||||
- <init>():V
|
||||
- s:extractCharsetFromFileContent(com.intellij.openapi.project.Project,com.intellij.openapi.vfs.VirtualFile,com.intellij.openapi.fileTypes.FileType,java.lang.CharSequence):java.nio.charset.Charset
|
||||
- s:findUnmappableCharacters(java.lang.CharSequence,java.nio.charset.Charset):com.intellij.openapi.util.TextRange
|
||||
com.intellij.openapi.fileTypes.DirectoryFileType
|
||||
- com.intellij.openapi.fileTypes.FileType
|
||||
com.intellij.openapi.fileTypes.FileType
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.openapi.fileTypes;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.ReflectionUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.*;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@@ -34,4 +39,87 @@ public final class CharsetUtil {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given text contains characters that cannot be mapped to the specified charset during encoding.
|
||||
*
|
||||
* @param text the character sequence to be checked
|
||||
* @param charset the charset to be used for encoding
|
||||
* @return a {@code TextRange} representing the range of unmappable characters, or {@code null} if all characters can be mapped
|
||||
*/
|
||||
public static @Nullable TextRange findUnmappableCharacters(@Nullable CharSequence text, @NotNull Charset charset) {
|
||||
if(text == null || text.length() == 0) return null;
|
||||
return findUnmappableRange(CharBuffer.wrap(text), Ref.create(), CharBuffer.allocate(text.length()), charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies the range of characters that either fail to encode or decode properly with the specified charset.
|
||||
*
|
||||
* @param inputBuffer the input character buffer to be checked
|
||||
* @param encodedBufferRef a reference to the output byte buffer for storing encoded bytes
|
||||
* @param decodedBuffer a character buffer to hold the decoded characters
|
||||
* @param charset the charset used for encoding and decoding
|
||||
* @return a {@code TextRange} object representing the range of unmappable characters, or {@code null} if all characters are mappable
|
||||
*/
|
||||
private static @Nullable TextRange findUnmappableRange(@NotNull CharBuffer inputBuffer,
|
||||
@NotNull Ref<ByteBuffer> encodedBufferRef,
|
||||
@NotNull CharBuffer decodedBuffer,
|
||||
@NotNull Charset charset) {
|
||||
CharsetEncoder encoder = charset.newEncoder()
|
||||
.onUnmappableCharacter(CodingErrorAction.REPORT)
|
||||
.onMalformedInput(CodingErrorAction.REPORT);
|
||||
int remainingChars = inputBuffer.limit();
|
||||
|
||||
ByteBuffer encodedBuffer = encodedBufferRef.get();
|
||||
if (encodedBuffer == null) {
|
||||
encodedBufferRef.set(encodedBuffer = ByteBuffer.allocate((int)(encoder.averageBytesPerChar() * remainingChars)));
|
||||
}
|
||||
encodedBuffer.rewind();
|
||||
encodedBuffer.limit(encodedBuffer.capacity());
|
||||
inputBuffer.rewind();
|
||||
inputBuffer.position(0);
|
||||
CoderResult encodeResult;
|
||||
|
||||
while (true) {
|
||||
encodeResult = inputBuffer.hasRemaining() ? encoder.encode(inputBuffer, encodedBuffer, true) : CoderResult.UNDERFLOW;
|
||||
if (encodeResult.isUnderflow()) {
|
||||
encodeResult = encoder.flush(encodedBuffer);
|
||||
}
|
||||
if (!encodeResult.isOverflow()) {
|
||||
break;
|
||||
}
|
||||
|
||||
ByteBuffer tempBuffer = ByteBuffer.allocate(3 * encodedBuffer.capacity() / 2 + 1);
|
||||
encodedBuffer.flip();
|
||||
tempBuffer.put(encodedBuffer);
|
||||
encodedBufferRef.set(encodedBuffer = tempBuffer);
|
||||
}
|
||||
|
||||
if (encodeResult.isError()) {
|
||||
return TextRange.from(inputBuffer.position(), encodeResult.length());
|
||||
}
|
||||
|
||||
int encodedLength = encodedBuffer.position();
|
||||
CharsetDecoder decoder = charset.newDecoder()
|
||||
.onUnmappableCharacter(CodingErrorAction.REPORT)
|
||||
.onMalformedInput(CodingErrorAction.REPORT);
|
||||
encodedBuffer.rewind();
|
||||
encodedBuffer.limit(encodedLength);
|
||||
decodedBuffer.rewind();
|
||||
|
||||
CoderResult decodeResult = decoder.decode(encodedBuffer, decodedBuffer, true);
|
||||
if (decodeResult.isError()) {
|
||||
return TextRange.from(decodedBuffer.position(), decodeResult.length());
|
||||
}
|
||||
|
||||
if (decodedBuffer.position() != remainingChars) {
|
||||
return TextRange.from(Math.min(remainingChars, decodedBuffer.position()), 1);
|
||||
}
|
||||
|
||||
inputBuffer.rewind();
|
||||
inputBuffer.position(0);
|
||||
decodedBuffer.rewind();
|
||||
int commonPrefixLength = StringUtil.commonPrefixLength(inputBuffer, decodedBuffer);
|
||||
return commonPrefixLength == remainingChars ? null : TextRange.from(commonPrefixLength, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,10 @@ import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
|
||||
import com.intellij.openapi.fileTypes.CharsetUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.popup.ListPopup;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.CharsetToolkit;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.encoding.ChangeFileEncodingAction;
|
||||
@@ -31,9 +30,7 @@ import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.*;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.*;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -173,17 +170,12 @@ public final class LossyEncodingInspection extends LocalInspectionTool {
|
||||
@NotNull CharSequence text,
|
||||
@NotNull Charset charset,
|
||||
@NotNull List<ProblemDescriptor> descriptors) {
|
||||
CharBuffer buffer = CharBuffer.wrap(text);
|
||||
|
||||
int textLength = text.length();
|
||||
CharBuffer back = CharBuffer.allocate(textLength); // must be enough, error otherwise
|
||||
|
||||
Ref<ByteBuffer> outRef = Ref.create();
|
||||
|
||||
//do not report too many errors
|
||||
for (int pos = 0, errorCount = 0; pos < text.length() && errorCount < 200; errorCount++) {
|
||||
TextRange errRange = nextUnmappable(buffer, pos, outRef, back, charset);
|
||||
TextRange errRange = CharsetUtil.findUnmappableCharacters(text.subSequence(pos, text.length()), charset);
|
||||
if (errRange == null) break;
|
||||
errRange = errRange.shiftRight(pos);
|
||||
|
||||
ProblemDescriptor lastDescriptor = ContainerUtil.getLastItem(descriptors);
|
||||
if (lastDescriptor != null && lastDescriptor.getTextRangeInElement().getEndOffset() == errRange.getStartOffset()) {
|
||||
// combine two adjacent descriptors
|
||||
@@ -199,70 +191,6 @@ public final class LossyEncodingInspection extends LocalInspectionTool {
|
||||
}
|
||||
}
|
||||
|
||||
// returns null if OK
|
||||
// range of the characters either failed to be encoded to bytes or failed to be decoded back or decoded to the chars different from the original
|
||||
private static TextRange nextUnmappable(@NotNull CharBuffer in,
|
||||
int position,
|
||||
@NotNull Ref<ByteBuffer> outRef,
|
||||
@NotNull CharBuffer back,
|
||||
@NotNull Charset charset) {
|
||||
CharsetEncoder encoder = charset.newEncoder()
|
||||
.onUnmappableCharacter(CodingErrorAction.REPORT)
|
||||
.onMalformedInput(CodingErrorAction.REPORT);
|
||||
int textLength = in.limit() - position;
|
||||
|
||||
ByteBuffer out = outRef.get();
|
||||
if (out == null) {
|
||||
outRef.set(out = ByteBuffer.allocate((int)(encoder.averageBytesPerChar() * textLength)));
|
||||
}
|
||||
out.rewind();
|
||||
out.limit(out.capacity());
|
||||
in.rewind();
|
||||
in.position(position);
|
||||
CoderResult cr;
|
||||
for (;;) {
|
||||
cr = in.hasRemaining() ? encoder.encode(in, out, true) : CoderResult.UNDERFLOW;
|
||||
if (cr.isUnderflow()) {
|
||||
cr = encoder.flush(out);
|
||||
}
|
||||
|
||||
if (!cr.isOverflow()) {
|
||||
break;
|
||||
}
|
||||
|
||||
int n = 3 * out.capacity()/2 + 1;
|
||||
ByteBuffer tmp = ByteBuffer.allocate(n);
|
||||
out.flip();
|
||||
tmp.put(out);
|
||||
outRef.set(out = tmp);
|
||||
}
|
||||
if (cr.isError()) {
|
||||
return TextRange.from(in.position(), cr.length());
|
||||
}
|
||||
// phew, encoded successfully. now check if we can decode it back with char-to-char precision
|
||||
int outLength = out.position();
|
||||
CharsetDecoder decoder = charset.newDecoder()
|
||||
.onUnmappableCharacter(CodingErrorAction.REPORT)
|
||||
.onMalformedInput(CodingErrorAction.REPORT);
|
||||
out.rewind();
|
||||
out.limit(outLength);
|
||||
back.rewind();
|
||||
CoderResult dr = decoder.decode(out, back, true);
|
||||
if (dr.isError()) {
|
||||
return TextRange.from(back.position(), dr.length());
|
||||
}
|
||||
if (back.position() != textLength) {
|
||||
return TextRange.from(Math.min(textLength, back.position()), 1);
|
||||
}
|
||||
// ok, we decoded it back to string. now compare if the strings are identical
|
||||
in.rewind();
|
||||
in.position(position);
|
||||
back.rewind();
|
||||
int len = StringUtil.commonPrefixLength(in, back);
|
||||
if (len == textLength) return null;
|
||||
return TextRange.from(len, 1); // let's report only the first diff char
|
||||
}
|
||||
|
||||
private static final class ReloadInAnotherEncodingFix extends ChangeEncodingFix {
|
||||
ReloadInAnotherEncodingFix(@NotNull PsiFile file) {
|
||||
super(file);
|
||||
|
||||
@@ -58,6 +58,11 @@
|
||||
groupBundle="messages.PropertiesBundle" groupKey="properties.files.inspection.group.display.name"
|
||||
enabledByDefault="true" level="WARNING"
|
||||
implementationClass="com.intellij.lang.properties.UnusedMessageFormatParameterInspection"/>
|
||||
<localInspection groupPath="Java" language="UAST" shortName="UnsupportedCharacter" bundle="messages.JavaI18nBundle"
|
||||
key="unsupported.character.display.name"
|
||||
groupBundle="messages.PropertiesBundle" groupKey="properties.files.inspection.group.display.name"
|
||||
enabledByDefault="true" level="WARNING"
|
||||
implementationClass="com.intellij.lang.properties.UnsupportedCharacterInspection"/>
|
||||
<localInspection groupPath="Java" language="JAVA" shortName="DuplicateStringLiteralInspection" bundle="messages.JavaI18nBundle"
|
||||
key="inspection.duplicates.display.name" groupKey="group.names.internationalization.issues" groupBundle="messages.InspectionsBundle" enabledByDefault="false"
|
||||
level="WARNING"
|
||||
|
||||
@@ -88,6 +88,9 @@ rename.prefix.based.property.key.error.message=Could not rename property key ''{
|
||||
resource.bundle.contains.locales.with.suspicious.locale.languages.desciptor=Resource bundle contains locales with suspicious locale languages
|
||||
unused.message.format.parameter.display.name=Missing message format parameter
|
||||
unused.message.format.parameter.problem.descriptor=Using parameter {0} without using parameter {1} in <code>#ref<code> #loc
|
||||
unsupported.character.display.name=Unsupported character
|
||||
unsupported.character.problem.descriptor=Unsupported characters for the charset ''{0}''
|
||||
unsupported.character.inspection.fix.description=Convert to escape sequences
|
||||
intention.family.name.mark.as.nlssafe=Mark as @NlsSafe
|
||||
capitalization.kind.title=title
|
||||
capitalization.kind.sentence=sentence
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.lang.properties;
|
||||
|
||||
import com.intellij.codeInspection.LocalInspectionToolSession;
|
||||
import com.intellij.codeInspection.ProblemHighlightType;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import com.intellij.java.i18n.JavaI18nBundle;
|
||||
import com.intellij.lang.properties.charset.Native2AsciiCharset;
|
||||
import com.intellij.lang.properties.psi.Property;
|
||||
import com.intellij.lang.properties.references.PropertyReference;
|
||||
import com.intellij.modcommand.ModPsiUpdater;
|
||||
import com.intellij.modcommand.PsiUpdateModCommandQuickFix;
|
||||
import com.intellij.openapi.fileTypes.CharsetUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.encoding.EncodingRegistry;
|
||||
import com.intellij.pom.java.JavaFeature;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class UnsupportedCharacterInspection extends PropertiesInspectionBase {
|
||||
private static final Charset OLD_JAVA_DEFAULT_CHARSET = StandardCharsets.ISO_8859_1;
|
||||
private static final Charset NEW_JAVA_DEFAULT_CHARSET = StandardCharsets.UTF_8;
|
||||
|
||||
@Override
|
||||
public @NotNull PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder,
|
||||
boolean isOnTheFly,
|
||||
@NotNull LocalInspectionToolSession session) {
|
||||
return new PsiElementVisitor() {
|
||||
@Override
|
||||
public void visitElement(@NotNull PsiElement element) {
|
||||
super.visitElement(element);
|
||||
if (PsiUtil.isAvailable(JavaFeature.UTF8_PROPERTY_FILES, element)) return;
|
||||
PsiReference[] references = element.getReferences();
|
||||
for (PsiReference reference : references) {
|
||||
if (reference instanceof PropertyReference propertyReference) {
|
||||
if (!(propertyReference.resolve() instanceof Property property)) continue;
|
||||
if (elementHasError(element, property)) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean elementHasError(@NotNull PsiElement element, @Nullable Property property) {
|
||||
if (property == null) return false;
|
||||
PsiFile psiFile = property.getContainingFile();
|
||||
if (psiFile.getFileType() != PropertiesFileType.INSTANCE) return false;
|
||||
VirtualFile file = psiFile.getVirtualFile();
|
||||
if (file == null) return false;
|
||||
EncodingRegistry encoding = EncodingRegistry.getInstance();
|
||||
boolean isCustomized = encoding.getDefaultCharsetForPropertiesFiles(file) != null ||
|
||||
encoding.getEncoding(file, true) != NEW_JAVA_DEFAULT_CHARSET;
|
||||
return !isCustomized && hasErrorCharacter(element, property.getValue());
|
||||
}
|
||||
|
||||
private boolean hasErrorCharacter(@NotNull PsiElement element, @Nullable String value) {
|
||||
if (value == null) return false;
|
||||
TextRange error = CharsetUtil.findUnmappableCharacters(value, OLD_JAVA_DEFAULT_CHARSET);
|
||||
if (error == null) return false;
|
||||
holder.registerProblem(element, JavaI18nBundle.message("unsupported.character.problem.descriptor",
|
||||
OLD_JAVA_DEFAULT_CHARSET.displayName()),
|
||||
ProblemHighlightType.WEAK_WARNING, new EncodePropertyFix());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static final class EncodePropertyFix extends PsiUpdateModCommandQuickFix {
|
||||
|
||||
@Override
|
||||
protected void applyFix(@NotNull Project project, @NotNull PsiElement element, @NotNull ModPsiUpdater updater) {
|
||||
if (PsiUtil.isAvailable(JavaFeature.UTF8_PROPERTY_FILES, element)) return;
|
||||
PsiReference[] references = element.getReferences();
|
||||
for (PsiReference reference : references) {
|
||||
if (reference instanceof PropertyReference propertyReference &&
|
||||
propertyReference.resolve() instanceof Property property) {
|
||||
String propertyValue = property.getValue();
|
||||
TextRange errorValue = CharsetUtil.findUnmappableCharacters(propertyValue, OLD_JAVA_DEFAULT_CHARSET);
|
||||
if (errorValue != null) {
|
||||
ByteBuffer encoded = Native2AsciiCharset.wrap(OLD_JAVA_DEFAULT_CHARSET).encode(propertyValue);
|
||||
String newValue = OLD_JAVA_DEFAULT_CHARSET.decode(encoded).toString();
|
||||
updater.getWritable(property).setValue(newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getFamilyName() {
|
||||
return JavaI18nBundle.message("unsupported.character.inspection.fix.description");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInspection.i18n;
|
||||
|
||||
import com.intellij.lang.properties.UnsupportedCharacterInspection;
|
||||
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
|
||||
import com.intellij.openapi.vfs.encoding.EncodingManager;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase;
|
||||
import org.intellij.lang.annotations.Language;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class UnsupportedCharacterInspectionTest extends JavaCodeInsightFixtureTestCase {
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
myFixture.enableInspections(new UnsupportedCharacterInspection());
|
||||
myFixture.addClass("""
|
||||
package java.util;
|
||||
public class ResourceBundle {
|
||||
public static ResourceBundle getBundle(String baseName) { return null; }
|
||||
public String getString(String key) { return null; }
|
||||
}
|
||||
""");
|
||||
|
||||
}
|
||||
|
||||
public void testJava8WithConversion() throws IOException {
|
||||
javaVersion(LanguageLevel.JDK_1_8);
|
||||
|
||||
PsiFile javaFile = addClass("Test.java", """
|
||||
import java.util.*;
|
||||
public final class Test {
|
||||
public static void main(String[] args) {
|
||||
String value = ResourceBundle.getBundle("test").getString(<weak_warning descr="Unsupported characters for the charset 'ISO-8859-1'">"<caret>key1"</weak_warning>);
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
PsiFile props = addFile("test.properties", "key1=Java + ☕");
|
||||
fileEncoding(props, StandardCharsets.UTF_8);
|
||||
propertiesEncoding(props, null);
|
||||
|
||||
checkHighlighting(javaFile);
|
||||
applyFix(javaFile, "Convert to escape sequences");
|
||||
checkFile(props, "key1=Java + \\u2615");
|
||||
}
|
||||
|
||||
public void testJava8PlusConstantWithConversion() throws IOException {
|
||||
javaVersion(LanguageLevel.JDK_1_8);
|
||||
|
||||
PsiFile javaFile = addClass("Test.java", """
|
||||
import java.util.*;
|
||||
public final class Test {
|
||||
private static final String KEY = <weak_warning descr="Unsupported characters for the charset 'ISO-8859-1'">"<caret>key1"</weak_warning>;
|
||||
public static void main(String[] args) {
|
||||
String value = ResourceBundle.getBundle("test").getString(KEY);
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
PsiFile props = addFile("test.properties", "key1=Java + ☕");
|
||||
fileEncoding(props, StandardCharsets.UTF_8);
|
||||
propertiesEncoding(props, null);
|
||||
|
||||
checkHighlighting(javaFile);
|
||||
applyFix(javaFile, "Convert to escape sequences");
|
||||
checkFile(props, "key1=Java + \\u2615");
|
||||
}
|
||||
|
||||
public void testJava9NoConversionNeeded() {
|
||||
javaVersion(LanguageLevel.JDK_1_9);
|
||||
|
||||
PsiFile javaFile = addClass("Test.java", """
|
||||
import java.util.*;
|
||||
public final class Test {
|
||||
public static void main(String[] args) {
|
||||
String value = ResourceBundle.getBundle("test").getString("<caret>key1");
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
PsiFile props = addFile("test.properties", "key1=Java + ☕");
|
||||
fileEncoding(props, StandardCharsets.UTF_8);
|
||||
propertiesEncoding(props, null);
|
||||
|
||||
checkHighlighting(javaFile);
|
||||
}
|
||||
|
||||
public void testJava8WithCustomizedEncoding() {
|
||||
javaVersion(LanguageLevel.JDK_1_8);
|
||||
|
||||
PsiFile javaFile = addClass("Test.java", """
|
||||
import java.util.*;
|
||||
public final class Test {
|
||||
public static void main(String[] args) {
|
||||
String value = ResourceBundle.getBundle("test").getString("<caret>key1");
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
PsiFile props = addFile("test.properties", "key1=Java + ☕");
|
||||
fileEncoding(props, StandardCharsets.US_ASCII);
|
||||
propertiesEncoding(props, null);
|
||||
|
||||
checkHighlighting(javaFile);
|
||||
}
|
||||
|
||||
public void testJava8WithCustomizedEncoding2() {
|
||||
javaVersion(LanguageLevel.JDK_1_8);
|
||||
|
||||
PsiFile javaFile = addClass("Test.java", """
|
||||
import java.util.*;
|
||||
public final class Test {
|
||||
public static void main(String[] args) {
|
||||
String value = ResourceBundle.getBundle("test").getString("<caret>key1");
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
PsiFile props = addFile("test.properties", "key1=Java + ☕");
|
||||
fileEncoding(props, StandardCharsets.UTF_8);
|
||||
propertiesEncoding(props, StandardCharsets.UTF_8);
|
||||
|
||||
checkHighlighting(javaFile);
|
||||
}
|
||||
|
||||
public void testJava8NoConversionNeeded() {
|
||||
javaVersion(LanguageLevel.JDK_1_8);
|
||||
|
||||
PsiFile javaFile = addClass("Test.java", """
|
||||
import java.util.*;
|
||||
public final class Test {
|
||||
public static void main(String[] args) {
|
||||
String value = ResourceBundle.getBundle("test").getString("<caret>key1");
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
PsiFile props = addFile("test.properties", "key1=Java + Coffee");
|
||||
fileEncoding(props, StandardCharsets.UTF_8);
|
||||
propertiesEncoding(props, null);
|
||||
|
||||
checkHighlighting(javaFile);
|
||||
}
|
||||
|
||||
private void javaVersion(LanguageLevel jdk) {
|
||||
LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(jdk);
|
||||
}
|
||||
|
||||
private static void fileEncoding(PsiFile file, Charset charset) {
|
||||
EncodingManager.getInstance().setEncoding(file.getVirtualFile(), charset);
|
||||
}
|
||||
|
||||
private static void propertiesEncoding(PsiFile file, Charset charset) {
|
||||
EncodingManager.getInstance().setDefaultCharsetForPropertiesFiles(file.getVirtualFile(), charset);
|
||||
}
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private PsiFile addClass(String fileName, @Language("JAVA") String fileContent) {
|
||||
return myFixture.configureByText(fileName, fileContent);
|
||||
}
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private PsiFile addFile(String fileName, String fileContent) {
|
||||
return myFixture.configureByText(fileName, fileContent);
|
||||
}
|
||||
|
||||
private void checkHighlighting(PsiFile file) {
|
||||
myFixture.testHighlighting(true, false, true, file.getVirtualFile());
|
||||
}
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private void applyFix(PsiFile file, String fixName) {
|
||||
myFixture.configureFromExistingVirtualFile(file.getVirtualFile());
|
||||
myFixture.launchAction(myFixture.findSingleIntention(fixName));
|
||||
}
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private static void checkFile(PsiFile file, String expectedContent) throws IOException {
|
||||
assertEquals(expectedContent, file.getText());
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
<orderEntry type="module" module-name="intellij.xml.psi" />
|
||||
<orderEntry type="module" module-name="intellij.platform.projectModel" />
|
||||
<orderEntry type="module" module-name="intellij.platform.lang" />
|
||||
<orderEntry type="module" module-name="intellij.platform.boot" />
|
||||
<orderEntry type="module" module-name="intellij.platform.boot" exported="" />
|
||||
<orderEntry type="module" module-name="intellij.platform.util.jdom" />
|
||||
<orderEntry type="module" module-name="intellij.platform.core.ui" />
|
||||
</component>
|
||||
|
||||
Reference in New Issue
Block a user