[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.
This commit is contained in:
Daniil Ovchinnikov
2018-05-24 01:33:17 +03:00
parent a4d87d1606
commit 8bf85bb2f4
5 changed files with 59 additions and 24 deletions
@@ -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)
@@ -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
}
}
@@ -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
@@ -26,7 +26,7 @@ import java.io.IOException;
* @author ilyas
*/
public class GrStubFileElementType extends IStubFileElementType<GrFileStub> {
public static final int STUB_VERSION = 41;
public static final int STUB_VERSION = 42;
public GrStubFileElementType(Language language) {
super(language);
@@ -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'
}
}