Report clashing signatures in the IDE
Expose extra diagnostics about platform signature clashes from light class data #KT-1 In Progress
This commit is contained in:
+21
-10
@@ -52,13 +52,14 @@ import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
||||
import org.jetbrains.jet.lang.resolve.BindingTraceContext;
|
||||
import org.jetbrains.jet.lang.resolve.Diagnostics;
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
public class KotlinJavaFileStubProvider<T extends WithFileStub> implements CachedValueProvider<T> {
|
||||
public class KotlinJavaFileStubProvider<T extends WithFileStubAndExtraDiagnostics> implements CachedValueProvider<T> {
|
||||
|
||||
@NotNull
|
||||
public static KotlinJavaFileStubProvider<KotlinPackageLightClassData> createForPackageClass(
|
||||
@@ -86,8 +87,12 @@ public class KotlinJavaFileStubProvider<T extends WithFileStub> implements Cache
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public KotlinPackageLightClassData createLightClassData(PsiJavaFileStub javaFileStub, BindingContext bindingContext) {
|
||||
return new KotlinPackageLightClassData(javaFileStub);
|
||||
public KotlinPackageLightClassData createLightClassData(
|
||||
PsiJavaFileStub javaFileStub,
|
||||
BindingContext bindingContext,
|
||||
Diagnostics extraDiagnostics
|
||||
) {
|
||||
return new KotlinPackageLightClassData(javaFileStub, extraDiagnostics);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -134,11 +139,15 @@ public class KotlinJavaFileStubProvider<T extends WithFileStub> implements Cache
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public OutermostKotlinClassLightClassData createLightClassData(PsiJavaFileStub javaFileStub, BindingContext bindingContext) {
|
||||
public OutermostKotlinClassLightClassData createLightClassData(
|
||||
PsiJavaFileStub javaFileStub,
|
||||
BindingContext bindingContext,
|
||||
Diagnostics extraDiagnostics
|
||||
) {
|
||||
ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, classOrObject);
|
||||
if (classDescriptor == null) {
|
||||
return new OutermostKotlinClassLightClassData(
|
||||
javaFileStub,
|
||||
javaFileStub, extraDiagnostics,
|
||||
"", classOrObject, null, Collections.<JetClassOrObject, InnerKotlinClassLightClassData>emptyMap()
|
||||
);
|
||||
}
|
||||
@@ -164,6 +173,7 @@ public class KotlinJavaFileStubProvider<T extends WithFileStub> implements Cache
|
||||
|
||||
return new OutermostKotlinClassLightClassData(
|
||||
javaFileStub,
|
||||
extraDiagnostics,
|
||||
jvmInternalName,
|
||||
classOrObject,
|
||||
classDescriptor,
|
||||
@@ -264,6 +274,7 @@ public class KotlinJavaFileStubProvider<T extends WithFileStub> implements Cache
|
||||
|
||||
PsiJavaFileStub javaFileStub = createJavaFileStub(packageFqName, getRepresentativeVirtualFile(files));
|
||||
BindingContext bindingContext;
|
||||
BindingTraceContext forExtraDiagnostics = new BindingTraceContext();
|
||||
try {
|
||||
Stack<StubElement> stubStack = new Stack<StubElement>();
|
||||
stubStack.push(javaFileStub);
|
||||
@@ -280,7 +291,7 @@ public class KotlinJavaFileStubProvider<T extends WithFileStub> implements Cache
|
||||
/*to generate inline flag on methods*/true,
|
||||
null,
|
||||
null,
|
||||
new BindingTraceContext() // TODO
|
||||
forExtraDiagnostics
|
||||
);
|
||||
state.beforeCompile();
|
||||
|
||||
@@ -292,7 +303,6 @@ public class KotlinJavaFileStubProvider<T extends WithFileStub> implements Cache
|
||||
if (pop != javaFileStub) {
|
||||
LOG.error("Unbalanced stack operations: " + pop);
|
||||
}
|
||||
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
throw e;
|
||||
@@ -302,8 +312,9 @@ public class KotlinJavaFileStubProvider<T extends WithFileStub> implements Cache
|
||||
throw e;
|
||||
}
|
||||
|
||||
Diagnostics extraDiagnostics = forExtraDiagnostics.getBindingContext().getDiagnostics();
|
||||
return Result.create(
|
||||
stubGenerationStrategy.createLightClassData(javaFileStub, bindingContext),
|
||||
stubGenerationStrategy.createLightClassData(javaFileStub, bindingContext, extraDiagnostics),
|
||||
local ? PsiModificationTracker.MODIFICATION_COUNT : PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT
|
||||
);
|
||||
}
|
||||
@@ -362,12 +373,12 @@ public class KotlinJavaFileStubProvider<T extends WithFileStub> implements Cache
|
||||
cause);
|
||||
}
|
||||
|
||||
private interface StubGenerationStrategy<T extends WithFileStub> {
|
||||
private interface StubGenerationStrategy<T extends WithFileStubAndExtraDiagnostics> {
|
||||
@NotNull Collection<JetFile> getFiles();
|
||||
@NotNull FqName getPackageFqName();
|
||||
|
||||
@NotNull LightClassConstructionContext getContext(@NotNull Collection<JetFile> files);
|
||||
@NotNull T createLightClassData(PsiJavaFileStub javaFileStub, BindingContext bindingContext);
|
||||
@NotNull T createLightClassData(PsiJavaFileStub javaFileStub, BindingContext bindingContext, Diagnostics extraDiagnostics);
|
||||
|
||||
GenerationState.GenerateClassFilter getGenerateClassFilter();
|
||||
void generate(@NotNull GenerationState state, @NotNull Collection<JetFile> files);
|
||||
|
||||
+1
-1
@@ -251,7 +251,7 @@ public class KotlinLightClassForExplicitDeclaration extends KotlinWrappingLightC
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static OutermostKotlinClassLightClassData getLightClassData(JetClassOrObject classOrObject) {
|
||||
public static OutermostKotlinClassLightClassData getLightClassData(JetClassOrObject classOrObject) {
|
||||
JetClassOrObject outermostClassOrObject = getOutermostClassOrObject(classOrObject);
|
||||
return CachedValuesManager.getManager(classOrObject.getProject()).getCachedValue(
|
||||
outermostClassOrObject,
|
||||
|
||||
@@ -19,11 +19,14 @@ package org.jetbrains.jet.asJava
|
||||
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor
|
||||
import org.jetbrains.jet.lang.psi.JetClassOrObject
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext
|
||||
import org.jetbrains.jet.lang.resolve.Diagnostics
|
||||
|
||||
trait LightClassData
|
||||
|
||||
trait WithFileStub {
|
||||
trait WithFileStubAndExtraDiagnostics {
|
||||
val javaFileStub: PsiJavaFileStub
|
||||
val extraDiagnostics: Diagnostics
|
||||
}
|
||||
|
||||
trait LightClassDataForKotlinClass: LightClassData {
|
||||
@@ -33,8 +36,9 @@ trait LightClassDataForKotlinClass: LightClassData {
|
||||
}
|
||||
|
||||
data class KotlinPackageLightClassData(
|
||||
override val javaFileStub: PsiJavaFileStub
|
||||
): LightClassData, WithFileStub
|
||||
override val javaFileStub: PsiJavaFileStub,
|
||||
override val extraDiagnostics: Diagnostics
|
||||
): LightClassData, WithFileStubAndExtraDiagnostics
|
||||
|
||||
data class InnerKotlinClassLightClassData(
|
||||
override val jvmInternalName: String,
|
||||
@@ -44,8 +48,9 @@ data class InnerKotlinClassLightClassData(
|
||||
|
||||
data class OutermostKotlinClassLightClassData(
|
||||
override val javaFileStub: PsiJavaFileStub,
|
||||
override val extraDiagnostics: Diagnostics,
|
||||
override val jvmInternalName: String,
|
||||
override val classOrObject: JetClassOrObject,
|
||||
override val descriptor: ClassDescriptor?,
|
||||
val allInnerClasses: Map<JetClassOrObject, InnerKotlinClassLightClassData>
|
||||
): LightClassDataForKotlinClass, WithFileStub
|
||||
): LightClassDataForKotlinClass, WithFileStubAndExtraDiagnostics
|
||||
@@ -279,6 +279,7 @@ fun main(args: Array<String>) {
|
||||
model("checker", recursive = false)
|
||||
model("checker/regression")
|
||||
model("checker/rendering")
|
||||
model("checker/duplicateJvmSignature")
|
||||
model("checker/infos", testMethod = "doTestWithInfos")
|
||||
}
|
||||
|
||||
|
||||
@@ -277,6 +277,7 @@
|
||||
<highlightRangeExtension implementation="org.jetbrains.jet.plugin.highlighter.JetPsiChecker"/>
|
||||
|
||||
<annotator language="jet" implementationClass="org.jetbrains.jet.plugin.highlighter.DebugInfoAnnotator"/>
|
||||
<annotator language="jet" implementationClass="org.jetbrains.jet.plugin.highlighter.DuplicateJvmSignatureAnnotator"/>
|
||||
<problemHighlightFilter implementation="org.jetbrains.jet.plugin.highlighter.KotlinProblemHighlightFilter"/>
|
||||
|
||||
<extendWordSelectionHandler implementation="org.jetbrains.jet.plugin.editor.wordSelection.JetStatementGroupSelectioner"/>
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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.jet.plugin.highlighter;
|
||||
|
||||
import com.intellij.lang.annotation.AnnotationHolder;
|
||||
import com.intellij.lang.annotation.Annotator;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.asJava.KotlinLightClassForExplicitDeclaration;
|
||||
import org.jetbrains.jet.asJava.KotlinLightClassForPackage;
|
||||
import org.jetbrains.jet.lang.psi.JetClassBody;
|
||||
import org.jetbrains.jet.lang.psi.JetClassOrObject;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.jet.lang.resolve.Diagnostics;
|
||||
import org.jetbrains.jet.plugin.project.TargetPlatform;
|
||||
import org.jetbrains.jet.plugin.project.TargetPlatformDetector;
|
||||
|
||||
public class DuplicateJvmSignatureAnnotator implements Annotator {
|
||||
|
||||
@Override
|
||||
public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {
|
||||
Diagnostics diagnostics;
|
||||
|
||||
PsiElement parent = element.getParent();
|
||||
if (parent instanceof JetFile) {
|
||||
if (TargetPlatformDetector.getPlatform((JetFile) parent) != TargetPlatform.JVM) return;
|
||||
diagnostics = getDiagnosticsForPackage((JetFile) parent);
|
||||
}
|
||||
else if (parent instanceof JetClassBody) {
|
||||
PsiElement parentsParent = parent.getParent();
|
||||
if (!(parentsParent instanceof JetClassOrObject)) return;
|
||||
|
||||
if (TargetPlatformDetector.getPlatform(((JetClassBody) parent).getContainingJetFile()) != TargetPlatform.JVM) return;
|
||||
|
||||
diagnostics = getDiagnosticsForNonLocalClass((JetClassOrObject) parentsParent);
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
JetPsiChecker.annotateElement(element, holder, diagnostics);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Diagnostics getDiagnosticsForPackage(JetFile file) {
|
||||
Project project = file.getProject();
|
||||
return KotlinLightClassForPackage.FileStubCache.getInstance(project).get(
|
||||
file.getPackageFqName(),
|
||||
GlobalSearchScope.allScope(project)
|
||||
).getValue().getExtraDiagnostics();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Diagnostics getDiagnosticsForNonLocalClass(JetClassOrObject jetClassOrObject) {
|
||||
return KotlinLightClassForExplicitDeclaration.getLightClassData(jetClassOrObject).getExtraDiagnostics();
|
||||
}
|
||||
}
|
||||
@@ -41,13 +41,12 @@ import org.jetbrains.jet.lang.diagnostics.Errors;
|
||||
import org.jetbrains.jet.lang.diagnostics.Severity;
|
||||
import org.jetbrains.jet.lang.diagnostics.rendering.DefaultErrorMessages;
|
||||
import org.jetbrains.jet.lang.psi.JetCodeFragment;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.Diagnostics;
|
||||
import org.jetbrains.jet.plugin.JetPluginUtil;
|
||||
import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage;
|
||||
import org.jetbrains.jet.plugin.project.ResolveSessionForBodies;
|
||||
import org.jetbrains.jet.plugin.quickfix.JetIntentionActionsFactory;
|
||||
import org.jetbrains.jet.plugin.quickfix.QuickFixes;
|
||||
|
||||
@@ -117,12 +116,7 @@ public class JetPsiChecker implements Annotator, HighlightRangeExtension {
|
||||
element.accept(visitor);
|
||||
}
|
||||
|
||||
if (JetPluginUtil.isInSource(element, /* includeLibrarySources = */ false) || file instanceof JetCodeFragment) {
|
||||
ElementAnnotator elementAnnotator = new ElementAnnotator(element, holder);
|
||||
for (Diagnostic diagnostic : bindingContext.getDiagnostics().forElement(element)) {
|
||||
elementAnnotator.registerDiagnosticAnnotations(diagnostic);
|
||||
}
|
||||
}
|
||||
annotateElement(element, holder, bindingContext.getDiagnostics());
|
||||
|
||||
if (element instanceof JetFile) {
|
||||
//noinspection StaticMethodReferencedViaSubclass
|
||||
@@ -130,6 +124,15 @@ public class JetPsiChecker implements Annotator, HighlightRangeExtension {
|
||||
}
|
||||
}
|
||||
|
||||
public static void annotateElement(PsiElement element, AnnotationHolder holder, Diagnostics diagnostics) {
|
||||
if (JetPluginUtil.isInSource(element, /* includeLibrarySources = */ false) || element.getContainingFile() instanceof JetCodeFragment) {
|
||||
ElementAnnotator elementAnnotator = new ElementAnnotator(element, holder);
|
||||
for (Diagnostic diagnostic : diagnostics.forElement(element)) {
|
||||
elementAnnotator.registerDiagnosticAnnotations(diagnostic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForceHighlightParents(@NotNull PsiFile file) {
|
||||
return file instanceof JetFile;
|
||||
@@ -283,4 +286,5 @@ public class JetPsiChecker implements Annotator, HighlightRangeExtension {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
class C {
|
||||
<error>val x = 1</error>
|
||||
<error>fun getX() = 1</error>
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class C {
|
||||
class object {
|
||||
<error>val x = 1</error>
|
||||
<error>fun getX() = 1</error>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
fun foo() {
|
||||
class C {
|
||||
<error>val x = 1</error>
|
||||
<error>fun getX() = 1</error>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class B {
|
||||
class C {
|
||||
<error>val x = 1</error>
|
||||
<error>fun getX() = 1</error>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
object C {
|
||||
<error>val x = 1</error>
|
||||
<error>fun getX() = 1</error>
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo() =
|
||||
object {
|
||||
<error>val x = 1</error>
|
||||
<error>fun getX() = 1</error>
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
<error>val x = 1</error>
|
||||
<error>fun getX() = 1</error>
|
||||
@@ -30,7 +30,7 @@ import org.jetbrains.jet.checkers.AbstractJetPsiCheckerTest;
|
||||
|
||||
/** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@InnerTestClasses({JetPsiCheckerTestGenerated.Checker.class, JetPsiCheckerTestGenerated.Regression.class, JetPsiCheckerTestGenerated.Rendering.class, JetPsiCheckerTestGenerated.Infos.class})
|
||||
@InnerTestClasses({JetPsiCheckerTestGenerated.Checker.class, JetPsiCheckerTestGenerated.Regression.class, JetPsiCheckerTestGenerated.Rendering.class, JetPsiCheckerTestGenerated.DuplicateJvmSignature.class, JetPsiCheckerTestGenerated.Infos.class})
|
||||
public class JetPsiCheckerTestGenerated extends AbstractJetPsiCheckerTest {
|
||||
@TestMetadata("idea/testData/checker")
|
||||
public static class Checker extends AbstractJetPsiCheckerTest {
|
||||
@@ -421,6 +421,64 @@ public class JetPsiCheckerTestGenerated extends AbstractJetPsiCheckerTest {
|
||||
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/checker/duplicateJvmSignature")
|
||||
@InnerTestClasses({DuplicateJvmSignature.FunctionAndProperty.class})
|
||||
public static class DuplicateJvmSignature extends AbstractJetPsiCheckerTest {
|
||||
public void testAllFilesPresentInDuplicateJvmSignature() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/checker/duplicateJvmSignature"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/checker/duplicateJvmSignature/functionAndProperty")
|
||||
public static class FunctionAndProperty extends AbstractJetPsiCheckerTest {
|
||||
public void testAllFilesPresentInFunctionAndProperty() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/checker/duplicateJvmSignature/functionAndProperty"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("class.kt")
|
||||
public void testClass() throws Exception {
|
||||
doTest("idea/testData/checker/duplicateJvmSignature/functionAndProperty/class.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("classObject.kt")
|
||||
public void testClassObject() throws Exception {
|
||||
doTest("idea/testData/checker/duplicateJvmSignature/functionAndProperty/classObject.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("localClass.kt")
|
||||
public void testLocalClass() throws Exception {
|
||||
doTest("idea/testData/checker/duplicateJvmSignature/functionAndProperty/localClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nestedClass.kt")
|
||||
public void testNestedClass() throws Exception {
|
||||
doTest("idea/testData/checker/duplicateJvmSignature/functionAndProperty/nestedClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("object.kt")
|
||||
public void testObject() throws Exception {
|
||||
doTest("idea/testData/checker/duplicateJvmSignature/functionAndProperty/object.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("objectExpression.kt")
|
||||
public void testObjectExpression() throws Exception {
|
||||
doTest("idea/testData/checker/duplicateJvmSignature/functionAndProperty/objectExpression.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("topLevel.kt")
|
||||
public void testTopLevel() throws Exception {
|
||||
doTest("idea/testData/checker/duplicateJvmSignature/functionAndProperty/topLevel.kt");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static Test innerSuite() {
|
||||
TestSuite suite = new TestSuite("DuplicateJvmSignature");
|
||||
suite.addTestSuite(DuplicateJvmSignature.class);
|
||||
suite.addTestSuite(FunctionAndProperty.class);
|
||||
return suite;
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/checker/infos")
|
||||
public static class Infos extends AbstractJetPsiCheckerTest {
|
||||
public void testAllFilesPresentInInfos() throws Exception {
|
||||
@@ -464,6 +522,7 @@ public class JetPsiCheckerTestGenerated extends AbstractJetPsiCheckerTest {
|
||||
suite.addTestSuite(Checker.class);
|
||||
suite.addTestSuite(Regression.class);
|
||||
suite.addTestSuite(Rendering.class);
|
||||
suite.addTest(DuplicateJvmSignature.innerSuite());
|
||||
suite.addTestSuite(Infos.class);
|
||||
return suite;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user