Wrong @PublishedApi usage diagnostic

This commit is contained in:
Mikhael Bogdanov
2016-12-01 16:29:17 +01:00
parent 58263c46cc
commit 7ea29d3397
6 changed files with 132 additions and 0 deletions
@@ -865,6 +865,7 @@ public interface Errors {
DiagnosticFactory1<PsiElement, CallableDescriptor> INLINE_CALL_CYCLE = DiagnosticFactory1.create(ERROR, DEFAULT);
DiagnosticFactory0<PsiElement> NON_LOCAL_RETURN_IN_DISABLED_INLINE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtDeclaration> INLINE_PROPERTY_WITH_BACKING_FIELD = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
DiagnosticFactory0<KtAnnotationEntry> NON_INTERNAL_PUBLISHED_API = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> NON_LOCAL_SUSPENSION_POINT = DiagnosticFactory0.create(ERROR);
@@ -831,6 +831,7 @@ public class DefaultErrorMessages {
MAP.put(NULLABLE_INLINE_PARAMETER, "Inline-parameter ''{0}'' of ''{1}'' must not be nullable. Add ''noinline'' modifier to the parameter declaration or make its type not nullable", ELEMENT_TEXT, SHORT_NAMES_IN_TYPES);
MAP.put(RECURSION_IN_INLINE, "Inline function ''{1}'' cannot be recursive", ELEMENT_TEXT, SHORT_NAMES_IN_TYPES);
MAP.put(INLINE_PROPERTY_WITH_BACKING_FIELD, "Inline property cannot have backing field");
MAP.put(NON_INTERNAL_PUBLISHED_API, "@PublishedApi annotation is only applicable for internal declaration");
//Inline non locals
MAP.put(NON_LOCAL_RETURN_NOT_ALLOWED, "Can''t inline ''{0}'' here: it may contain non-local returns. Add ''crossinline'' modifier to parameter declaration ''{0}''", ELEMENT_TEXT);
MAP.put(INLINE_CALL_CYCLE, "The ''{0}'' invocation is a part of inline cycle", NAME);
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.lexer.KtModifierKeywordToken;
import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker;
import org.jetbrains.kotlin.resolve.checkers.PublishedApiUsageChecker;
import org.jetbrains.kotlin.resolve.checkers.UnderscoreChecker;
import java.util.*;
@@ -244,6 +245,7 @@ public class ModifiersChecker {
checker.check(declaration, descriptor, trace, trace.getBindingContext(), languageVersionSettings);
}
OperatorModifierChecker.INSTANCE.check(declaration, descriptor, trace, languageVersionSettings);
PublishedApiUsageChecker.INSTANCE.check(declaration, descriptor, trace);
}
public void checkTypeParametersModifiers(@NotNull KtModifierListOwner modifierListOwner) {
@@ -0,0 +1,51 @@
/*
* Copyright 2010-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.
*/
package org.jetbrains.kotlin.resolve.checkers
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.types.TypeUtils
object PublishedApiUsageChecker {
fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
trace: BindingTrace
) {
if (descriptor !is DeclarationDescriptorWithVisibility || descriptor.visibility == Visibilities.INTERNAL) return
/*Don't report diagnostic twise*/
if (descriptor is PropertyAccessorDescriptor) return
for (entry in declaration.annotationEntries) {
val annotationDescriptor = trace.get(BindingContext.ANNOTATION, entry) ?: continue
val classDescriptor = TypeUtils.getClassDescriptor(annotationDescriptor.type) ?: continue
if (classDescriptor.fqNameSafe == KotlinBuiltIns.FQ_NAMES.publishedApi) {
trace.report(Errors.NON_INTERNAL_PUBLISHED_API.on(entry))
}
}
}
}
+71
View File
@@ -0,0 +1,71 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
<!NON_INTERNAL_PUBLISHED_API!>@kotlin.PublishedApi<!>
class A
@kotlin.PublishedApi
internal class B
<!NON_INTERNAL_PUBLISHED_API!>@kotlin.PublishedApi<!>
private class C
<!NON_INTERNAL_PUBLISHED_API!>@kotlin.PublishedApi<!>
fun a() {}
@kotlin.PublishedApi
internal fun b() {}
@kotlin.PublishedApi
internal fun c() {}
<!NON_INTERNAL_PUBLISHED_API!>@kotlin.PublishedApi<!>
var ap = 1
@kotlin.PublishedApi
internal var bp = 1
@kotlin.PublishedApi
internal var c = 1
class E {
<!NON_INTERNAL_PUBLISHED_API!>@kotlin.PublishedApi<!>
fun a() {}
@kotlin.PublishedApi
internal fun b() {}
<!NON_INTERNAL_PUBLISHED_API!>@kotlin.PublishedApi<!>
private fun c() {}
<!NON_INTERNAL_PUBLISHED_API!>@kotlin.PublishedApi<!>
protected fun d() {}
<!NON_INTERNAL_PUBLISHED_API!>@kotlin.PublishedApi<!>
val ap = 1
@kotlin.PublishedApi
internal val bp = 1
<!NON_INTERNAL_PUBLISHED_API!>@kotlin.PublishedApi<!>
protected val c = 1
<!NON_INTERNAL_PUBLISHED_API!>@kotlin.PublishedApi<!>
private val d = 1
}
class D <!NON_INTERNAL_PUBLISHED_API!>@kotlin.PublishedApi<!> constructor() {
<!NON_INTERNAL_PUBLISHED_API!>@kotlin.PublishedApi<!>
constructor(a: String) : this()
<!NON_INTERNAL_PUBLISHED_API!>@kotlin.PublishedApi<!>
private constructor(a: String, b: String): this()
@kotlin.PublishedApi
internal constructor(a: String, b: String, c: String): this()
}
@@ -566,6 +566,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("publishedApi.kt")
public void testPublishedApi() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/publishedApi.kt");
doTest(fileName);
}
@TestMetadata("QualifiedExpressions.kt")
public void testQualifiedExpressions() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/QualifiedExpressions.kt");