From 7f81601123cfb2c3b96ef5178a1942459e03227d Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 24 Oct 2017 17:55:33 +0200 Subject: [PATCH] Do not use IntelliJ extensions for unused parameter suppressor in JS --- .../cfg/ControlFlowInformationProvider.kt | 30 ++++++++++++++----- .../kotlin/resolve/ControlFlowAnalyzer.java | 27 +++++++++++------ .../checkers/PlatformDiagnosticSuppressor.kt | 29 ++++++++++++++++++ .../kotlin/resolve/lazy/ResolveSession.java | 15 ++++++++-- .../idea/project/ResolveElementCache.kt | 8 +++-- idea/src/META-INF/extensions/kotlin2js.xml | 1 - .../kotlin/js/analyze/suppressWarnings.kt | 14 ++++++++- .../js/resolve/JsPlatformConfigurator.kt | 2 ++ 8 files changed, 104 insertions(+), 22 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/PlatformDiagnosticSuppressor.kt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt index 9c2f3afa34b..080f22696b3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt @@ -52,6 +52,7 @@ import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.getDispatchReceiverWi import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.hasThisOrNoDispatchReceiver import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject import org.jetbrains.kotlin.resolve.calls.util.isSingleUnderscore +import org.jetbrains.kotlin.resolve.checkers.PlatformDiagnosticSuppressor import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.types.KotlinType @@ -64,15 +65,26 @@ class ControlFlowInformationProvider private constructor( private val subroutine: KtElement, private val trace: BindingTrace, private val pseudocode: Pseudocode, - private val languageVersionSettings: LanguageVersionSettings + private val languageVersionSettings: LanguageVersionSettings, + private val diagnosticSuppressor: PlatformDiagnosticSuppressor ) { private val pseudocodeVariablesData by lazy { PseudocodeVariablesData(pseudocode, trace.bindingContext) } - constructor(declaration: KtElement, trace: BindingTrace, languageVersionSettings: LanguageVersionSettings) - : this(declaration, trace, ControlFlowProcessor(trace).generatePseudocode(declaration), languageVersionSettings) + constructor( + declaration: KtElement, + trace: BindingTrace, + languageVersionSettings: LanguageVersionSettings, + diagnosticSuppressor: PlatformDiagnosticSuppressor + ) : this( + declaration, + trace, + ControlFlowProcessor(trace).generatePseudocode(declaration), + languageVersionSettings, + diagnosticSuppressor + ) fun checkForLocalClassOrObjectMode() { // Local classes and objects are analyzed twice: when TopDownAnalyzer processes it and as a part of its container. @@ -178,7 +190,8 @@ class ControlFlowInformationProvider private constructor( val expectedType = functionDescriptor?.returnType val providerForLocalDeclaration = ControlFlowInformationProvider( - element, trace, localDeclarationInstruction.body, languageVersionSettings) + element, trace, localDeclarationInstruction.body, languageVersionSettings, diagnosticSuppressor + ) providerForLocalDeclaration.checkFunction(expectedType) } @@ -656,8 +669,10 @@ class ControlFlowInformationProvider private constructor( is KtPrimaryConstructor -> if (!element.hasValOrVar()) { val containingClass = owner.getContainingClassOrObject() val containingClassDescriptor = trace.get(DECLARATION_TO_DESCRIPTOR, containingClass) as? ClassDescriptor - if (!DescriptorUtils.isAnnotationClass(containingClassDescriptor) && containingClassDescriptor?.isExpect == false && - !containingClassDescriptor.isEffectivelyExternal() + if (!DescriptorUtils.isAnnotationClass(containingClassDescriptor) && + containingClassDescriptor?.isExpect == false && + !containingClassDescriptor.isEffectivelyExternal() && + diagnosticSuppressor.shouldReportUnusedParameter(variableDescriptor) ) { report(UNUSED_PARAMETER.on(element, variableDescriptor), ctxt) } @@ -680,7 +695,8 @@ class ControlFlowInformationProvider private constructor( || functionDescriptor.isEffectivelyExternal() || OperatorNameConventions.GET_VALUE == functionName || OperatorNameConventions.SET_VALUE == functionName - || OperatorNameConventions.PROVIDE_DELEGATE == functionName) { + || OperatorNameConventions.PROVIDE_DELEGATE == functionName + || !diagnosticSuppressor.shouldReportUnusedParameter(variableDescriptor)) { return } if (anonymous) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ControlFlowAnalyzer.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ControlFlowAnalyzer.java index 5d15fd7a1ca..a396915894e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ControlFlowAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ControlFlowAnalyzer.java @@ -25,6 +25,7 @@ import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor; import org.jetbrains.kotlin.descriptors.PropertyDescriptor; import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor; import org.jetbrains.kotlin.psi.*; +import org.jetbrains.kotlin.resolve.checkers.PlatformDiagnosticSuppressor; import org.jetbrains.kotlin.types.KotlinType; import java.util.Map; @@ -32,16 +33,21 @@ import java.util.Map; import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE; public class ControlFlowAnalyzer { - @NotNull private final BindingTrace trace; - @NotNull private final KotlinBuiltIns builtIns; - @NotNull private final LanguageVersionSettings languageVersionSettings; + private final BindingTrace trace; + private final KotlinBuiltIns builtIns; + private final LanguageVersionSettings languageVersionSettings; + private final PlatformDiagnosticSuppressor diagnosticSuppressor; public ControlFlowAnalyzer( - @NotNull BindingTrace trace, @NotNull KotlinBuiltIns builtIns, @NotNull LanguageVersionSettings languageVersionSettings + @NotNull BindingTrace trace, + @NotNull KotlinBuiltIns builtIns, + @NotNull LanguageVersionSettings languageVersionSettings, + @NotNull PlatformDiagnosticSuppressor diagnosticSuppressor ) { this.trace = trace; this.builtIns = builtIns; this.languageVersionSettings = languageVersionSettings; + this.diagnosticSuppressor = diagnosticSuppressor; } public void process(@NotNull BodiesResolveContext c) { @@ -74,7 +80,7 @@ public class ControlFlowAnalyzer { private void checkSecondaryConstructor(@NotNull KtSecondaryConstructor constructor) { ControlFlowInformationProvider controlFlowInformationProvider = - new ControlFlowInformationProvider(constructor, trace, languageVersionSettings); + new ControlFlowInformationProvider(constructor, trace, languageVersionSettings, diagnosticSuppressor); controlFlowInformationProvider.checkDeclaration(); controlFlowInformationProvider.checkFunction(builtIns.getUnitType()); } @@ -82,8 +88,9 @@ public class ControlFlowAnalyzer { private void checkDeclarationContainer(@NotNull BodiesResolveContext c, KtDeclarationContainer declarationContainer) { // A pseudocode of class/object initialization corresponds to a class/object // or initialization of properties corresponds to a package declared in a file - ControlFlowInformationProvider controlFlowInformationProvider = - new ControlFlowInformationProvider((KtElement) declarationContainer, trace, languageVersionSettings); + ControlFlowInformationProvider controlFlowInformationProvider = new ControlFlowInformationProvider( + (KtElement) declarationContainer, trace, languageVersionSettings, diagnosticSuppressor + ); if (c.getTopDownAnalysisMode().isLocalDeclarations()) { controlFlowInformationProvider.checkForLocalClassOrObjectMode(); return; @@ -102,9 +109,11 @@ public class ControlFlowAnalyzer { } } - private void checkFunction(@NotNull BodiesResolveContext c, @NotNull KtDeclarationWithBody function, @Nullable KotlinType expectedReturnType) { + private void checkFunction( + @NotNull BodiesResolveContext c, @NotNull KtDeclarationWithBody function, @Nullable KotlinType expectedReturnType + ) { ControlFlowInformationProvider controlFlowInformationProvider = - new ControlFlowInformationProvider(function, trace, languageVersionSettings); + new ControlFlowInformationProvider(function, trace, languageVersionSettings, diagnosticSuppressor); if (c.getTopDownAnalysisMode().isLocalDeclarations()) { controlFlowInformationProvider.checkForLocalClassOrObjectMode(); return; diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/PlatformDiagnosticSuppressor.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/PlatformDiagnosticSuppressor.kt new file mode 100644 index 00000000000..d8fe33fa43f --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/PlatformDiagnosticSuppressor.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2010-2017 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.container.DefaultImplementation +import org.jetbrains.kotlin.descriptors.VariableDescriptor + +@DefaultImplementation(PlatformDiagnosticSuppressor.Default::class) +interface PlatformDiagnosticSuppressor { + fun shouldReportUnusedParameter(parameter: VariableDescriptor): Boolean + + object Default : PlatformDiagnosticSuppressor { + override fun shouldReportUnusedParameter(parameter: VariableDescriptor): Boolean = true + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/ResolveSession.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/ResolveSession.java index b7bc93ae383..6b1e74b0cac 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/ResolveSession.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/ResolveSession.java @@ -34,6 +34,7 @@ import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.*; +import org.jetbrains.kotlin.resolve.checkers.PlatformDiagnosticSuppressor; import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension; import org.jetbrains.kotlin.resolve.lazy.data.KtClassOrObjectInfo; import org.jetbrains.kotlin.resolve.lazy.data.KtScriptInfo; @@ -82,6 +83,7 @@ public class ResolveSession implements KotlinCodeAnalyzer, LazyClassContext { private LanguageVersionSettings languageVersionSettings; private DelegationFilter delegationFilter; private WrappedTypeFactory wrappedTypeFactory; + private PlatformDiagnosticSuppressor platformDiagnosticSuppressor; private final SyntheticResolveExtension syntheticResolveExtension; @@ -135,17 +137,21 @@ public class ResolveSession implements KotlinCodeAnalyzer, LazyClassContext { this.languageVersionSettings = languageVersionSettings; } - @Inject public void setDelegationFilter(@NotNull DelegationFilter delegationFilter) { this.delegationFilter = delegationFilter; } @Inject - public void setWrappedTypeFactory(WrappedTypeFactory wrappedTypeFactory) { + public void setWrappedTypeFactory(@NotNull WrappedTypeFactory wrappedTypeFactory) { this.wrappedTypeFactory = wrappedTypeFactory; } + @Inject + public void setPlatformDiagnosticSuppressor(@NotNull PlatformDiagnosticSuppressor platformDiagnosticSuppressor) { + this.platformDiagnosticSuppressor = platformDiagnosticSuppressor; + } + // Only calls from injectors expected @Deprecated public ResolveSession( @@ -462,6 +468,11 @@ public class ResolveSession implements KotlinCodeAnalyzer, LazyClassContext { return wrappedTypeFactory; } + @NotNull + public PlatformDiagnosticSuppressor getPlatformDiagnosticSuppressor() { + return platformDiagnosticSuppressor; + } + @Override public void assertValid() { module.assertValid(); diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt index 5e9d603cafd..f9261f489fa 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt @@ -349,7 +349,9 @@ class ResolveElementCache( } val controlFlowTrace = DelegatingBindingTrace(trace.bindingContext, "Element control flow resolve", resolveElement, allowSliceRewrite = true) - ControlFlowInformationProvider(resolveElement, controlFlowTrace, resolveElement.languageVersionSettings).checkDeclaration() + ControlFlowInformationProvider( + resolveElement, controlFlowTrace, resolveElement.languageVersionSettings, resolveSession.platformDiagnosticSuppressor + ).checkDeclaration() controlFlowTrace.addOwnDataTo(trace, null, false) return Pair(trace.bindingContext, statementFilterUsed) @@ -485,7 +487,9 @@ class ResolveElementCache( forceResolveAnnotationsInside(property) for (accessor in property.accessors) { - ControlFlowInformationProvider(accessor, trace, accessor.languageVersionSettings).checkDeclaration() + ControlFlowInformationProvider( + accessor, trace, accessor.languageVersionSettings, resolveSession.platformDiagnosticSuppressor + ).checkDeclaration() } return trace diff --git a/idea/src/META-INF/extensions/kotlin2js.xml b/idea/src/META-INF/extensions/kotlin2js.xml index 738a855207a..19f25d6afea 100644 --- a/idea/src/META-INF/extensions/kotlin2js.xml +++ b/idea/src/META-INF/extensions/kotlin2js.xml @@ -2,7 +2,6 @@ org.jetbrains.kotlin - diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/analyze/suppressWarnings.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/analyze/suppressWarnings.kt index fb35b0bfd07..46495cf64ee 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/analyze/suppressWarnings.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/analyze/suppressWarnings.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.js.analyze +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.VariableDescriptor import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.DiagnosticWithParameters1 @@ -23,6 +24,7 @@ import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.js.PredefinedAnnotation.* import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils import org.jetbrains.kotlin.psi.KtSimpleNameExpression +import org.jetbrains.kotlin.resolve.checkers.PlatformDiagnosticSuppressor import org.jetbrains.kotlin.resolve.diagnostics.DiagnosticSuppressor import org.jetbrains.kotlin.resolve.diagnostics.FUNCTION_NO_BODY_ERRORS import org.jetbrains.kotlin.resolve.diagnostics.PROPERTY_NOT_INITIALIZED_ERRORS @@ -30,7 +32,17 @@ import org.jetbrains.kotlin.resolve.diagnostics.SuppressDiagnosticsByAnnotations private val NATIVE_ANNOTATIONS = arrayOf(NATIVE.fqName, NATIVE_INVOKE.fqName, NATIVE_GETTER.fqName, NATIVE_SETTER.fqName) -class SuppressUnusedParameterForJsNative : SuppressDiagnosticsByAnnotations(listOf(Errors.UNUSED_PARAMETER), *NATIVE_ANNOTATIONS) +object JsNativeDiagnosticSuppressor : PlatformDiagnosticSuppressor { + override fun shouldReportUnusedParameter(parameter: VariableDescriptor): Boolean { + var descriptor: DeclarationDescriptor = parameter + while (true) { + val annotations = descriptor.annotations + if (!annotations.isEmpty() && NATIVE_ANNOTATIONS.any(annotations::hasAnnotation)) return false + descriptor = descriptor.containingDeclaration ?: break + } + return true + } +} class SuppressNoBodyErrorsForNativeDeclarations : SuppressDiagnosticsByAnnotations(FUNCTION_NO_BODY_ERRORS + PROPERTY_NOT_INITIALIZED_ERRORS, *NATIVE_ANNOTATIONS) diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsPlatformConfigurator.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsPlatformConfigurator.kt index 127d73b780a..8c2044451ab 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsPlatformConfigurator.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsPlatformConfigurator.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.js.resolve import org.jetbrains.kotlin.container.StorageComponentContainer import org.jetbrains.kotlin.container.useImpl import org.jetbrains.kotlin.container.useInstance +import org.jetbrains.kotlin.js.analyze.JsNativeDiagnosticSuppressor import org.jetbrains.kotlin.js.naming.NameSuggestion import org.jetbrains.kotlin.js.resolve.diagnostics.* import org.jetbrains.kotlin.platform.PlatformToKotlinClassMap @@ -72,5 +73,6 @@ object JsPlatformConfigurator : PlatformConfigurator( container.useImpl() container.useInstance(ExtensionFunctionToExternalIsInlinable) container.useInstance(JsQualifierChecker) + container.useInstance(JsNativeDiagnosticSuppressor) } }