mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
checks for dollar-slash strings
This commit is contained in:
@@ -294,4 +294,8 @@ Equals=Equals
|
||||
default.initializers.are.not.allowed.in.abstract.method=Default initializers are not allowed in abstract methods
|
||||
groovy.does.not.support.constructor.type.arguments=Groovy does not support constructor type arguments
|
||||
illegal.escape.character.in.string.literal=Illegal escape character in string literal
|
||||
dollar.slash.end.expected=Dollar slash ending expected
|
||||
dollar.slash.end.expected=Dollar slash ending expected
|
||||
regex.cannot.be.first.argument.of.command.method.call=Regex cannot be first argument of command method call
|
||||
add.parentheses=Add parentheses
|
||||
add.parentheses.to.command.method.call=Add parentheses to command method call
|
||||
dollar.slash.strings.are.not.allowed.in.0=Dollar-slash strings are not allowed in Groovy {0}
|
||||
@@ -835,6 +835,63 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
|
||||
checkStringLiteral(literal, text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitRegexExpression(GrRegex regex) {
|
||||
String text = regex.getText();
|
||||
String quote = GrStringUtil.getStartQuote(text);
|
||||
|
||||
final GroovyConfigUtils config = GroovyConfigUtils.getInstance();
|
||||
|
||||
if ("$/".equals(quote)) {
|
||||
if (!config.isVersionAtLeast(regex, GroovyConfigUtils.GROOVY1_9)) {
|
||||
myHolder
|
||||
.createErrorAnnotation(regex, GroovyBundle.message("dollar.slash.strings.are.not.allowed.in.0", config.getSDKVersion(regex)));
|
||||
}
|
||||
if (regex.getParent() instanceof GrCommandArgumentList &&
|
||||
((GrCommandArgumentList)regex.getParent()).getAllArguments()[0] == regex) {
|
||||
final Annotation annotation =
|
||||
myHolder.createErrorAnnotation(regex, GroovyBundle.message("regex.cannot.be.first.argument.of.command.method.call"));
|
||||
annotation.registerFix(new AddParenthesesFix());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (String part : regex.getTextParts()) {
|
||||
if (!GrStringUtil.parseRegexCharacters(part, new StringBuilder(part.length()), null, regex.getText().startsWith("/"))) {
|
||||
myHolder.createErrorAnnotation(regex, GroovyBundle.message("illegal.escape.character.in.string.literal"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ("/".equals(quote)) {
|
||||
if (!config.isVersionAtLeast(regex, GroovyConfigUtils.GROOVY1_8)) {
|
||||
if (text.contains("\n") || text.contains("\r")) {
|
||||
myHolder.createErrorAnnotation(regex, GroovyBundle
|
||||
.message("multiline.slashy.strings.are.not.allowed.in.groovy.0", config.getSDKVersion(regex)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (regex.getInjections().length > 0) {
|
||||
if (!config.isVersionAtLeast(regex, GroovyConfigUtils.GROOVY1_8)) {
|
||||
myHolder.createErrorAnnotation(regex, GroovyBundle
|
||||
.message("slashy.strings.with.injections.are.not.allowed.in.groovy.0", config.getSDKVersion(regex)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitGStringExpression(GrString gstring) {
|
||||
for (String part : gstring.getTextParts()) {
|
||||
if (!GrStringUtil.parseStringCharacters(part, new StringBuilder(part.length()), null)) {
|
||||
myHolder.createErrorAnnotation(gstring, GroovyBundle.message("illegal.escape.character.in.string.literal"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkStringLiteral(PsiElement literal, String text) {
|
||||
|
||||
StringBuilder builder = new StringBuilder(text.length());
|
||||
@@ -842,71 +899,16 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
|
||||
if (quote.isEmpty()) return;
|
||||
|
||||
String substring = text.substring(quote.length());
|
||||
|
||||
String[] parts;
|
||||
PsiElement child = literal.getFirstChild();
|
||||
if (child == null) child = literal;
|
||||
IElementType elementType = child.getNode().getElementType();
|
||||
boolean isSimpleString = elementType == GroovyTokenTypes.mSTRING_LITERAL ||
|
||||
elementType == GroovyTokenTypes.mGSTRING_LITERAL ||
|
||||
elementType == GroovyTokenTypes.mREGEX_LITERAL;
|
||||
if (isSimpleString) {
|
||||
parts = new String[]{substring};
|
||||
}
|
||||
else if (literal instanceof GrString) {
|
||||
parts = ((GrString)literal).getTextParts();
|
||||
}
|
||||
else {
|
||||
if (!GrStringUtil.parseStringCharacters(substring, new StringBuilder(text.length()), null)) {
|
||||
myHolder.createErrorAnnotation(literal, GroovyBundle.message("illegal.escape.character.in.string.literal"));
|
||||
return;
|
||||
}
|
||||
|
||||
for (String part : parts) {
|
||||
if (literal instanceof GrRegex) {
|
||||
if (!GrStringUtil.parseRegexCharacters(part, new StringBuilder(text.length()), null, literal.getText().startsWith("/"))) {
|
||||
myHolder.createErrorAnnotation(literal, GroovyBundle.message("illegal.escape.character.in.string.literal"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!GrStringUtil.parseStringCharacters(part, new StringBuilder(text.length()), null)) {
|
||||
myHolder.createErrorAnnotation(literal, GroovyBundle.message("illegal.escape.character.in.string.literal"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (isSimpleString) {
|
||||
int[] offsets = new int[substring.length() + 1];
|
||||
boolean result = GrStringUtil.parseStringCharacters(substring, builder, offsets);
|
||||
LOG.assertTrue(result);
|
||||
if (!builder.toString().endsWith(quote) || substring.charAt(offsets[builder.length() - quote.length()]) == '\\') {
|
||||
myHolder.createErrorAnnotation(literal, GroovyBundle.message("string.end.expected"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOG.assertTrue(literal instanceof GrString);
|
||||
//absence of closing quote is registered by lexer
|
||||
}
|
||||
|
||||
|
||||
if (quote.equals("/")) {
|
||||
if (!GroovyConfigUtils.getInstance().isVersionAtLeast(literal, GroovyConfigUtils.GROOVY1_8)) {
|
||||
if (text.contains("\n") || text.contains("\r")) {
|
||||
myHolder.createErrorAnnotation(literal, GroovyBundle.message("multiline.slashy.strings.are.not.allowed.in.groovy.0",
|
||||
GroovyConfigUtils.getInstance().getSDKVersion(literal)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (literal instanceof GrRegex && ((GrRegex)literal).getInjections().length > 0) {
|
||||
if (!GroovyConfigUtils.getInstance().isVersionAtLeast(literal, GroovyConfigUtils.GROOVY1_8)) {
|
||||
myHolder.createErrorAnnotation(literal, GroovyBundle.message("slashy.strings.with.injections.are.not.allowed.in.groovy.0",
|
||||
GroovyConfigUtils.getInstance().getSDKVersion(literal)));
|
||||
return;
|
||||
}
|
||||
int[] offsets = new int[substring.length() + 1];
|
||||
boolean result = GrStringUtil.parseStringCharacters(substring, builder, offsets);
|
||||
LOG.assertTrue(result);
|
||||
if (!builder.toString().endsWith(quote) || substring.charAt(offsets[builder.length() - quote.length()]) == '\\') {
|
||||
myHolder.createErrorAnnotation(literal, GroovyBundle.message("string.end.expected"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
*
|
||||
* 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 org.jetbrains.plugins.groovy.annotator.intentions;
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.groovy.GroovyBundle;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrApplicationStatement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCommandArgumentList;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
|
||||
|
||||
/**
|
||||
* @author Max Medvedev
|
||||
*/
|
||||
public class AddParenthesesFix implements IntentionAction {
|
||||
private static final Logger LOG = Logger.getInstance(AddParenthesesFix.class);
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getText() {
|
||||
return GroovyBundle.message("add.parentheses");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return GroovyBundle.message("add.parentheses.to.command.method.call");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
|
||||
final int offset = editor.getCaretModel().getOffset();
|
||||
final PsiElement at = file.findElementAt(offset);
|
||||
final GrCommandArgumentList argList = PsiTreeUtil.getParentOfType(at, GrCommandArgumentList.class);
|
||||
return argList != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
|
||||
final int offset = editor.getCaretModel().getOffset();
|
||||
final PsiElement at = file.findElementAt(offset);
|
||||
final GrCommandArgumentList argList = PsiTreeUtil.getParentOfType(at, GrCommandArgumentList.class);
|
||||
if (argList == null) return;
|
||||
|
||||
final PsiElement parent = argList.getParent();
|
||||
LOG.assertTrue(parent instanceof GrApplicationStatement);
|
||||
|
||||
final GrExpression newExpr;
|
||||
try {
|
||||
newExpr = GroovyPsiElementFactory.getInstance(project)
|
||||
.createExpressionFromText(((GrApplicationStatement)parent).getInvokedExpression().getText() + '(' + argList.getText() + ')');
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
LOG.error(e);
|
||||
return;
|
||||
}
|
||||
|
||||
parent.replace(newExpr);
|
||||
editor.getCaretModel().moveToOffset(offset + 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startInWriteAction() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -52,6 +52,7 @@ public abstract class GroovyConfigUtils extends AbstractConfigUtils {
|
||||
public static final String NO_VERSION = "<no version>";
|
||||
public static final String GROOVY1_7 = "1.7";
|
||||
public static final String GROOVY1_8 = "1.8";
|
||||
public static final String GROOVY1_9 = "1.9";
|
||||
|
||||
private GroovyConfigUtils() {
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ public class GrStringUtil {
|
||||
private static final String DOUBLE_QUOTES = "\"";
|
||||
private static final String TRIPLE_DOUBLE_QUOTES = "\"\"\"";
|
||||
private static final String SLASH = "/";
|
||||
private static final String DOLLAR_SLASH = "$/";
|
||||
private static final String SLASH_DOLLAR = "/$";
|
||||
|
||||
private GrStringUtil() {
|
||||
}
|
||||
@@ -179,6 +181,15 @@ public class GrStringUtil {
|
||||
String quote = getStartQuote(s);
|
||||
int sL = s.length();
|
||||
int qL = quote.length();
|
||||
if (sL >= qL * 2 && DOLLAR_SLASH.equals(quote)) {
|
||||
if (s.endsWith(SLASH_DOLLAR)) {
|
||||
return s.substring(qL, sL - qL);
|
||||
}
|
||||
else {
|
||||
return s.substring(qL);
|
||||
}
|
||||
}
|
||||
|
||||
if (sL >= qL * 2 && s.endsWith(quote)) {
|
||||
return s.substring(qL, sL - qL);
|
||||
}
|
||||
@@ -337,6 +348,7 @@ public class GrStringUtil {
|
||||
if (text.startsWith(TRIPLE_DOUBLE_QUOTES)) return TRIPLE_DOUBLE_QUOTES;
|
||||
if (text.startsWith(DOUBLE_QUOTES)) return DOUBLE_QUOTES;
|
||||
if (text.startsWith(SLASH)) return SLASH;
|
||||
if (text.startsWith(DOLLAR_SLASH)) return DOLLAR_SLASH;
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
print '\n'
|
||||
print <error descr="Illegal escape character in string literal">'\y'</error>
|
||||
ptint <error descr="Illegal escape character in string literal">"\n\a\t"</error>
|
||||
print "\n\a${x}\t"
|
||||
print <error descr="Illegal escape character in string literal">"\n\a${x}\t"</error>
|
||||
print "\n${x}\t"
|
||||
print "\n${x}\"<EOLError descr="String end expected"></EOLError>
|
||||
print "\n\"<EOLError descr="String end expected"></EOLError>
|
||||
print '''\n'''
|
||||
print <error descr="Illegal escape character in string literal">'''\y'''</error>
|
||||
print """\n\a${x}\t"""
|
||||
ptint """""\n\a\t"""
|
||||
print <error descr="Illegal escape character in string literal">"""\n\a${x}\t"""</error>
|
||||
ptint <error descr="Illegal escape character in string literal">"""""\n\a\t"""</error>
|
||||
print """\n${x}\t"""
|
||||
print "dfg\$fg"
|
||||
print 'fg\$fg'
|
||||
|
||||
Reference in New Issue
Block a user