From 28df3a62cf14f5d5de9ea33343d39c3622e9048d Mon Sep 17 00:00:00 2001 From: Maxim Medvedev Date: Wed, 8 Jun 2011 21:49:44 +0400 Subject: [PATCH] IDEA-70787 Groovy: Method call don't resolve if method name is a string literal. --- .../arithmetic/PathExpression.java | 13 ++++++- .../primary/PrimaryExpression.java | 39 ++++++++++++------- .../primary/StringConstructorExpression.java | 11 ------ .../lang/parser/ExpressionsParsingTest.groovy | 3 ++ .../lang/resolve/ResolveMethodTest.groovy | 12 ++++++ .../expressions/path/stringMethodCall1.test | 9 +++++ .../expressions/path/stringMethodCall2.test | 18 +++++++++ .../resolve/method/stringRefExpr1/a.groovy | 3 ++ .../resolve/method/stringRefExpr2/a.groovy | 3 ++ .../resolve/method/stringRefExpr3/a.groovy | 3 ++ 10 files changed, 87 insertions(+), 27 deletions(-) create mode 100644 plugins/groovy/testdata/parsing/groovy/expressions/path/stringMethodCall1.test create mode 100644 plugins/groovy/testdata/parsing/groovy/expressions/path/stringMethodCall2.test create mode 100644 plugins/groovy/testdata/resolve/method/stringRefExpr1/a.groovy create mode 100644 plugins/groovy/testdata/resolve/method/stringRefExpr2/a.groovy create mode 100644 plugins/groovy/testdata/resolve/method/stringRefExpr3/a.groovy diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arithmetic/PathExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arithmetic/PathExpression.java index 2abd3cad518c..ba5e4b9c6805 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arithmetic/PathExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arithmetic/PathExpression.java @@ -50,10 +50,19 @@ public class PathExpression implements GroovyElementTypes { */ public static Result parsePathExprQualifierForExprStatement(PsiBuilder builder, GroovyParser parser) { PsiBuilder.Marker marker = builder.mark(); - final IElementType qualifierType = PrimaryExpression.parsePrimaryExpression(builder, parser); + final PsiBuilder.Marker marker1 = builder.mark(); + IElementType qualifierType = PrimaryExpression.parsePrimaryExpression(builder, parser); if (qualifierType != WRONGWAY) { Result result; if (isPathElementStart(builder)) { + if (builder.getTokenType() == mLPAREN && qualifierType == LITERAL) { + marker1.rollbackTo(); + qualifierType = PrimaryExpression.parsePrimaryExpression(builder, parser, true); + assert qualifierType != WRONGWAY; + } + else { + marker1.drop(); + } PsiBuilder.Marker newMarker = marker.precede(); marker.drop(); if (checkForLCurly(builder)) { @@ -67,12 +76,14 @@ public class PathExpression implements GroovyElementTypes { } } else { + marker1.drop(); marker.drop(); result = INVOKED_EXPR; } return result; } else { + marker1.drop(); marker.drop(); return WRONG_WAY; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/PrimaryExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/PrimaryExpression.java index 2c889765a7f7..dac94ad6b66e 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/PrimaryExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/PrimaryExpression.java @@ -36,47 +36,56 @@ import org.jetbrains.plugins.groovy.lang.parser.parsing.util.ParserUtils; */ public class PrimaryExpression implements GroovyElementTypes { - public static IElementType parsePrimaryExpression(PsiBuilder builder, GroovyParser parser) { - if (TokenSets.BUILT_IN_TYPE.contains(builder.getTokenType())) { + public static IElementType parsePrimaryExpression(PsiBuilder builder, GroovyParser parser) { + return parsePrimaryExpression(builder, parser, false); + } + public static IElementType parsePrimaryExpression(PsiBuilder builder, GroovyParser parser, boolean literalsAsRefExprs) { + + final IElementType tokenType = builder.getTokenType(); + if (TokenSets.BUILT_IN_TYPE.contains(tokenType)) { ParserUtils.eatElement(builder, BUILT_IN_TYPE_EXPRESSION); return BUILT_IN_TYPE_EXPRESSION; } - if (kTHIS == builder.getTokenType()) { + if (kTHIS == tokenType) { ParserUtils.eatElement(builder, THIS_REFERENCE_EXPRESSION); return THIS_REFERENCE_EXPRESSION; } - if (kSUPER == builder.getTokenType()) { + if (kSUPER == tokenType) { ParserUtils.eatElement(builder, SUPER_REFERENCE_EXPRESSION); return SUPER_REFERENCE_EXPRESSION; } - if (kNEW == builder.getTokenType()) { + if (kNEW == tokenType) { return newExprParse(builder, parser); } - if (mIDENT == builder.getTokenType()) { + if (mIDENT == tokenType) { ParserUtils.eatElement(builder, REFERENCE_EXPRESSION); return REFERENCE_EXPRESSION; } - if (mGSTRING_BEGIN == builder.getTokenType()) { + if (mGSTRING_BEGIN == tokenType) { return StringConstructorExpression.parse(builder, parser); } - if (mREGEX_BEGIN == builder.getTokenType()) { + if (mREGEX_BEGIN == tokenType) { return RegexConstructorExpression.parse(builder, parser); } - if (mLBRACK == builder.getTokenType()) { + if (mLBRACK == tokenType) { return ListOrMapConstructorExpression.parse(builder, parser); } - if (mLPAREN == builder.getTokenType()) { + if (mLPAREN == tokenType) { return parenthesizedExprParse(builder, parser); } - if (mLCURLY == builder.getTokenType()) { + if (mLCURLY == tokenType) { return OpenOrClosableBlock.parseClosableBlock(builder, parser); } - if (TokenSets.CONSTANTS.contains(builder.getTokenType())) { - ParserUtils.eatElement(builder, LITERAL); - return LITERAL; + if (tokenType == mSTRING_LITERAL || + tokenType == mGSTRING_LITERAL || + tokenType == mREGEX_LITERAL) { + return ParserUtils.eatElement(builder, literalsAsRefExprs ? REFERENCE_EXPRESSION : LITERAL); } - if (mWRONG_REGEX_LITERAL == builder.getTokenType()) { + if (TokenSets.CONSTANTS.contains(tokenType)) { + return ParserUtils.eatElement(builder, LITERAL); + } + if (mWRONG_REGEX_LITERAL == tokenType) { PsiBuilder.Marker marker = builder.mark(); builder.advanceLexer(); builder.error(GroovyBundle.message("wrong.string")); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/StringConstructorExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/StringConstructorExpression.java index c17cfdad04a4..e4ac24ae22b7 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/StringConstructorExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/StringConstructorExpression.java @@ -35,17 +35,6 @@ public class StringConstructorExpression implements GroovyElementTypes { Marker sMarker = builder.mark(); if (ParserUtils.getToken(builder, mGSTRING_BEGIN)) { - ParserUtils.getToken(builder, mGSTRING_CONTENT); - if (mGSTRING_END.equals(builder.getTokenType())) { - sMarker.rollbackTo(); - sMarker = builder.mark(); - builder.advanceLexer(); - builder.advanceLexer(); - builder.advanceLexer(); - sMarker.done(LITERAL); - return LITERAL; - } - while (ParserUtils.getToken(builder, mGSTRING_CONTENT) || mDOLLAR.equals(builder.getTokenType())) { if (mDOLLAR.equals(builder.getTokenType())) { stringConstructorValuePart(builder, parser); diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy index ca41c84868ef..da89e29ed17a 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy @@ -281,4 +281,7 @@ public class ExpressionsParsingTest extends GroovyParsingTestCase { public void testcommandExpr$keywords() {doTest()} public void testDiamond() {doTest()} + + void testpath$stringMethodCall1() {doTest()} + void testpath$stringMethodCall2() {doTest()} } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveMethodTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveMethodTest.groovy index 85e6d88a51da..d6dcfa02096f 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveMethodTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveMethodTest.groovy @@ -713,4 +713,16 @@ class Foo { PsiReference ref = configureByFile("staticImportInSamePackage/A.groovy", "A.groovy"); assertNotNull(ref.resolve()) } + + void testStringRefExpr1() { + assertNotNull(resolve("a.groovy")); + } + + void testStringRefExpr2() { + assertNotNull(resolve("a.groovy")); + } + + void testStringRefExpr3() { + assertNotNull(resolve("a.groovy")); + } } diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/path/stringMethodCall1.test b/plugins/groovy/testdata/parsing/groovy/expressions/path/stringMethodCall1.test new file mode 100644 index 000000000000..570dd565016e --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/path/stringMethodCall1.test @@ -0,0 +1,9 @@ +'foo'() +----- +Groovy script + Method call + Reference expression + PsiElement(string)(''foo'') + Arguments + PsiElement(()('(') + PsiElement())(')') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/path/stringMethodCall2.test b/plugins/groovy/testdata/parsing/groovy/expressions/path/stringMethodCall2.test new file mode 100644 index 000000000000..44b0e78720fb --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/path/stringMethodCall2.test @@ -0,0 +1,18 @@ +'foo'.substring(0, 1) +----- +Groovy script + Method call + Reference expression + Literal + PsiElement(string)(''foo'') + PsiElement(.)('.') + PsiElement(identifier)('substring') + Arguments + PsiElement(()('(') + Literal + PsiElement(Integer)('0') + PsiElement(,)(',') + PsiWhiteSpace(' ') + Literal + PsiElement(Integer)('1') + PsiElement())(')') \ No newline at end of file diff --git a/plugins/groovy/testdata/resolve/method/stringRefExpr1/a.groovy b/plugins/groovy/testdata/resolve/method/stringRefExpr1/a.groovy new file mode 100644 index 000000000000..f6b636731b04 --- /dev/null +++ b/plugins/groovy/testdata/resolve/method/stringRefExpr1/a.groovy @@ -0,0 +1,3 @@ +def foo(){} + +'foo'() \ No newline at end of file diff --git a/plugins/groovy/testdata/resolve/method/stringRefExpr2/a.groovy b/plugins/groovy/testdata/resolve/method/stringRefExpr2/a.groovy new file mode 100644 index 000000000000..2d91530b5e38 --- /dev/null +++ b/plugins/groovy/testdata/resolve/method/stringRefExpr2/a.groovy @@ -0,0 +1,3 @@ +def foo(){} + +"foo"() \ No newline at end of file diff --git a/plugins/groovy/testdata/resolve/method/stringRefExpr3/a.groovy b/plugins/groovy/testdata/resolve/method/stringRefExpr3/a.groovy new file mode 100644 index 000000000000..4905ed36cba9 --- /dev/null +++ b/plugins/groovy/testdata/resolve/method/stringRefExpr3/a.groovy @@ -0,0 +1,3 @@ +def 'foo bar'(){} + +'foo bar'() \ No newline at end of file