From 8bf85bb2f4dbcf00ae3664d3438e14395865ef4a Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Thu, 24 May 2018 01:28:40 +0300 Subject: [PATCH] [groovy] create code reference directly using the parser Before the change stubbed references were created from groovy file with error check. If a reference contained an error element, the exception was thrown. Now references are created using parser directly, they will have DummyHolder as a parent, they may contain error elements, but they will be well formed meaning that error is reported only in case of parser being unable to produce reference tree element instead of relying on parsing of some cast expression. This fixes EA-120589. --- .../lang/psi/impl/GroovyDummyElement.kt | 7 ++++ .../lang/psi/impl/GroovyDummyElementType.kt | 18 ++++++++++ .../psi/impl/GroovyPsiElementFactoryImpl.java | 22 +++++++----- .../stubs/elements/GrStubFileElementType.java | 2 +- .../groovy/lang/GroovyStubsTest.groovy | 34 +++++++++++-------- 5 files changed, 59 insertions(+), 24 deletions(-) create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyDummyElement.kt create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyDummyElementType.kt diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyDummyElement.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyDummyElement.kt new file mode 100644 index 000000000000..41962af87c6d --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyDummyElement.kt @@ -0,0 +1,7 @@ +// Copyright 2000-2018 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. +package org.jetbrains.plugins.groovy.lang.psi.impl + +import com.intellij.psi.impl.source.tree.FileElement +import com.intellij.psi.tree.IElementType + +class GroovyDummyElement(val childType: IElementType, text: CharSequence?) : FileElement(GroovyDummyElementType, text) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyDummyElementType.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyDummyElementType.kt new file mode 100644 index 000000000000..6693934d5c34 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyDummyElementType.kt @@ -0,0 +1,18 @@ +// Copyright 2000-2018 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. +package org.jetbrains.plugins.groovy.lang.psi.impl + +import com.intellij.lang.ASTNode +import com.intellij.lang.PsiBuilderFactory +import com.intellij.psi.tree.ILazyParseableElementType +import org.jetbrains.plugins.groovy.GroovyLanguage +import org.jetbrains.plugins.groovy.lang.parser.GroovyParser + +object GroovyDummyElementType : ILazyParseableElementType("GROOVY_DUMMY_ELEMENT", GroovyLanguage) { + + override fun parseContents(chameleon: ASTNode): ASTNode { + val dummyElement = chameleon as GroovyDummyElement + val builder = PsiBuilderFactory.getInstance().createBuilder(chameleon.psi.project, chameleon) + GroovyParser().parseLight(dummyElement.childType, builder) + return builder.treeBuilt + } +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementFactoryImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementFactoryImpl.java index 53e65d94f886..cb5ca0ba103c 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementFactoryImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementFactoryImpl.java @@ -1,6 +1,4 @@ -/* - * Copyright 2000-2017 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-2018 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. package org.jetbrains.plugins.groovy.lang.psi.impl; @@ -10,6 +8,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; +import com.intellij.psi.impl.source.DummyHolder; import com.intellij.psi.impl.source.codeStyle.CodeEditUtil; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiTreeUtil; @@ -44,7 +43,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrEn import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.GrTopStatement; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement; -import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClassTypeElement; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureParameter; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; @@ -56,6 +54,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import static org.jetbrains.plugins.groovy.lang.psi.GroovyElementTypes.CODE_REFERENCE; + /** * @author ven */ @@ -64,9 +64,11 @@ public class GroovyPsiElementFactoryImpl extends GroovyPsiElementFactory { private static final Logger LOG = Logger.getInstance(GroovyPsiElementFactoryImpl.class); private final Project myProject; + private final PsiManager myManager; - public GroovyPsiElementFactoryImpl(Project project) { + public GroovyPsiElementFactoryImpl(Project project, PsiManager manager) { myProject = project; + myManager = manager; } @Override @@ -117,9 +119,13 @@ public class GroovyPsiElementFactoryImpl extends GroovyPsiElementFactory { @NotNull @Override public GrCodeReferenceElement createReferenceElementFromText(@NotNull String refName, final PsiElement context) { - GroovyFile file = createGroovyFileChecked("(" + refName + ")foo", false, context); - GrTypeElement typeElement = ((GrTypeCastExpression) file.getTopStatements()[0]).getCastTypeElement(); - return ((GrClassTypeElement) typeElement).getReferenceElement(); + GroovyDummyElement dummyElement = new GroovyDummyElement(CODE_REFERENCE, refName); + DummyHolder holder = new DummyHolder(myManager, dummyElement, context); + PsiElement element = holder.getFirstChild(); + if (!(element instanceof GrCodeReferenceElement)) { + throw new IncorrectOperationException("Incorrect core reference '" + refName + "'"); + } + return (GrCodeReferenceElement)element; } @NotNull diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrStubFileElementType.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrStubFileElementType.java index 9a7a193926a8..a61b4d81c346 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrStubFileElementType.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrStubFileElementType.java @@ -26,7 +26,7 @@ import java.io.IOException; * @author ilyas */ public class GrStubFileElementType extends IStubFileElementType { - public static final int STUB_VERSION = 41; + public static final int STUB_VERSION = 42; public GrStubFileElementType(Language language) { super(language); diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyStubsTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyStubsTest.groovy index df852b44f32e..7827d4a848b9 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyStubsTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyStubsTest.groovy @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2016 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. - */ +// Copyright 2000-2018 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. package org.jetbrains.plugins.groovy.lang import com.intellij.openapi.command.WriteCommandAction @@ -33,6 +19,10 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyFile import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrEnumDefinitionBody import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrEnumConstant +import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement +import org.jetbrains.plugins.groovy.lang.psi.impl.GrClassReferenceType + +import static org.jetbrains.plugins.groovy.util.TestUtils.disableAstLoading /** * @author peter @@ -76,4 +66,18 @@ class GroovyStubsTest extends LightCodeInsightFixtureTestCase { assert JavaPsiFacade.getInstance(project).findClass("Fooxx", GlobalSearchScope.allScope(project)) } + void 'test error in code reference'() { + myFixture.tempDirFixture.createFile('A.groovy', 'class A extends foo.B< {}') + disableAstLoading project, testRootDisposable + def clazz = myFixture.findClass("A") + assert clazz != null + def extendsTypes = clazz.extendsListTypes + assert extendsTypes.size() == 1 + def type = extendsTypes.first() + assert type instanceof GrClassReferenceType + def reference = type.reference + assert reference instanceof GrCodeReferenceElement + assert reference.referenceName == 'B' + assert reference.qualifiedReferenceName == 'foo.B' + } }