mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-200832 Deprecation inspection: recognise externally deprecated APIs.
Extend API to support repeatable annotations and annotations from different external roots.
This commit is contained in:
+39
-11
@@ -2,6 +2,7 @@
|
||||
package com.intellij.codeInspection.deprecation;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.codeInsight.ExternalAnnotationsManager;
|
||||
import com.intellij.codeInsight.daemon.JavaErrorMessages;
|
||||
import com.intellij.codeInsight.daemon.impl.analysis.HighlightMessageUtil;
|
||||
import com.intellij.codeInsight.daemon.impl.analysis.JavaHighlightUtil;
|
||||
@@ -26,6 +27,7 @@ import com.intellij.psi.javadoc.PsiDocTag;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.refactoring.util.RefactoringChangeUtil;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import one.util.streamex.MoreCollectors;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -145,7 +147,7 @@ abstract class DeprecationInspectionBase extends AbstractBaseJavaLocalInspection
|
||||
final PsiClass containingClass = method.getContainingClass();
|
||||
assert containingClass != null;
|
||||
final PsiClass superClass = containingClass.getSuperClass();
|
||||
if (hasDefaultDeprecatedConstructor(superClass, myForRemoval)) {
|
||||
if (superClass != null && hasDefaultDeprecatedConstructor(superClass, myForRemoval)) {
|
||||
if (superClass instanceof PsiAnonymousClass) {
|
||||
final PsiExpressionList argumentList = ((PsiAnonymousClass)superClass).getArgumentList();
|
||||
if (argumentList != null && !argumentList.isEmpty()) return;
|
||||
@@ -174,7 +176,7 @@ abstract class DeprecationInspectionBase extends AbstractBaseJavaLocalInspection
|
||||
final PsiMethod[] currentConstructors = aClass.getConstructors();
|
||||
if (currentConstructors.length == 0) {
|
||||
final PsiClass superClass = aClass.getSuperClass();
|
||||
if (hasDefaultDeprecatedConstructor(superClass, myForRemoval)) {
|
||||
if (superClass != null && hasDefaultDeprecatedConstructor(superClass, myForRemoval)) {
|
||||
final boolean isAnonymous = aClass instanceof PsiAnonymousClass;
|
||||
if (isAnonymous) {
|
||||
final PsiExpressionList argumentList = ((PsiAnonymousClass)aClass).getArgumentList();
|
||||
@@ -225,8 +227,27 @@ abstract class DeprecationInspectionBase extends AbstractBaseJavaLocalInspection
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean hasDefaultDeprecatedConstructor(PsiClass superClass, boolean forRemoval) {
|
||||
return superClass != null && Arrays.stream(superClass.getConstructors())
|
||||
private static boolean hasDefaultDeprecatedConstructor(@NotNull PsiClass superClass, boolean forRemoval) {
|
||||
PsiMethod[] constructors = superClass.getConstructors();
|
||||
if (constructors.length == 0) {
|
||||
/*
|
||||
The default constructor of a class can be externally annotated (IDEA-200832).
|
||||
There cannot be inferred annotations for a default constructor,
|
||||
so here is no need to check all annotations returned
|
||||
by `AnnotationUtil.findAnnotations()`, but only external ones.
|
||||
|
||||
Note that there may be multiple external annotations roots,
|
||||
so we check them all.
|
||||
*/
|
||||
List<PsiAnnotation> externalDeprecated = ExternalAnnotationsManager
|
||||
.getInstance(superClass.getProject())
|
||||
.findDefaultConstructorExternalAnnotations(superClass, CommonClassNames.JAVA_LANG_DEPRECATED);
|
||||
|
||||
return externalDeprecated != null
|
||||
&& !externalDeprecated.isEmpty()
|
||||
&& ContainerUtil.exists(externalDeprecated, annotation -> isMarkedForRemoval(annotation) == forRemoval);
|
||||
}
|
||||
return Arrays.stream(constructors)
|
||||
.anyMatch(constructor -> constructor.getParameterList().isEmpty() &&
|
||||
constructor.isDeprecated() &&
|
||||
isMarkedForRemoval(constructor, forRemoval));
|
||||
@@ -306,7 +327,11 @@ abstract class DeprecationInspectionBase extends AbstractBaseJavaLocalInspection
|
||||
}
|
||||
|
||||
private static boolean isMarkedForRemoval(PsiModifierListOwner element, boolean forRemoval) {
|
||||
return isMarkedForRemoval(element) == forRemoval;
|
||||
PsiAnnotation annotation = AnnotationUtil.findAnnotation(element, CommonClassNames.JAVA_LANG_DEPRECATED);
|
||||
if (annotation == null) {
|
||||
return !forRemoval;
|
||||
}
|
||||
return isMarkedForRemoval(annotation) == forRemoval;
|
||||
}
|
||||
|
||||
private static boolean isInSameOutermostClass(PsiElement refElement, PsiElement elementToHighlight, boolean ignoreInSameOutermostClass) {
|
||||
@@ -324,12 +349,15 @@ abstract class DeprecationInspectionBase extends AbstractBaseJavaLocalInspection
|
||||
return maybeClass instanceof PsiClass ? (PsiClass)maybeClass : null;
|
||||
}
|
||||
|
||||
private static boolean isMarkedForRemoval(@Nullable PsiModifierListOwner element) {
|
||||
PsiAnnotation annotation = AnnotationUtil.findAnnotation(element, CommonClassNames.JAVA_LANG_DEPRECATED);
|
||||
if (annotation == null) {
|
||||
return false;
|
||||
}
|
||||
PsiAnnotationMemberValue value = annotation.findAttributeValue("forRemoval");
|
||||
/**
|
||||
* Returns value of {@link Deprecated#forRemoval} attribute, which is available since Java 9.
|
||||
*
|
||||
* @param deprecatedAnnotation annotation instance to extract value of
|
||||
* @return {@code true} if the {@code forRemoval} attribute is set to true,
|
||||
* {@code false} if it isn't set or is set to {@code false}.
|
||||
*/
|
||||
private static boolean isMarkedForRemoval(@NotNull PsiAnnotation deprecatedAnnotation) {
|
||||
PsiAnnotationMemberValue value = deprecatedAnnotation.findAttributeValue("forRemoval");
|
||||
Object result = null;
|
||||
if (value instanceof PsiLiteral) {
|
||||
result = ((PsiLiteral)value).getValue();
|
||||
|
||||
@@ -182,7 +182,7 @@ public class ExternalAnnotationsManagerImpl extends ReadableExternalAnnotationsM
|
||||
notifyAfterAnnotationChanging(listOwner, annotationFQName, false);
|
||||
return false;
|
||||
}
|
||||
String externalName = getExternalName(listOwner, false);
|
||||
String externalName = getExternalName(listOwner);
|
||||
WriteCommandAction.writeCommandAction(project).run(() -> {
|
||||
appendChosenAnnotationsRoot(entry, newRoot);
|
||||
XmlFile xmlFileInRoot = findXmlFileInRoot(findExternalAnnotationsXmlFiles(listOwner), newRoot);
|
||||
@@ -279,7 +279,7 @@ public class ExternalAnnotationsManagerImpl extends ReadableExternalAnnotationsM
|
||||
}
|
||||
|
||||
Set<PsiFile> annotationFiles = xmlFiles == null ? new THashSet<>() : new THashSet<>(xmlFiles);
|
||||
String externalName = getExternalName(listOwner, false);
|
||||
String externalName = getExternalName(listOwner);
|
||||
WriteCommandAction.writeCommandAction(project).run(() -> {
|
||||
if (existingXml != null) {
|
||||
annotateExternally(listOwner, annotationFQName, existingXml, fromFile, value, externalName);
|
||||
@@ -355,7 +355,7 @@ public class ExternalAnnotationsManagerImpl extends ReadableExternalAnnotationsM
|
||||
.runWriteCommandAction(myPsiManager.getProject(), ExternalAnnotationsManagerImpl.class.getName(), null, () -> {
|
||||
PsiDocumentManager.getInstance(myPsiManager.getProject()).commitAllDocuments();
|
||||
try {
|
||||
tag.setAttribute("name", StringUtil.escapeXml(getExternalName(element, false)));
|
||||
tag.setAttribute("name", StringUtil.escapeXml(getExternalName(element)));
|
||||
commitChanges(file);
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
@@ -410,7 +410,7 @@ public class ExternalAnnotationsManagerImpl extends ReadableExternalAnnotationsM
|
||||
if (rootTag == null) {
|
||||
continue;
|
||||
}
|
||||
final String externalName = getExternalName(listOwner, false);
|
||||
final String externalName = getExternalName(listOwner);
|
||||
|
||||
final List<XmlTag> tagsToProcess = new ArrayList<>();
|
||||
for (XmlTag tag : rootTag.getSubTags()) {
|
||||
|
||||
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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 com.intellij.codeInsight;
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
@@ -50,12 +36,64 @@ public abstract class ExternalAnnotationsManager {
|
||||
@Nullable
|
||||
public abstract PsiAnnotation findExternalAnnotation(@NotNull PsiModifierListOwner listOwner, @NotNull String annotationFQN);
|
||||
|
||||
/**
|
||||
* Returns external annotations with fully qualified name of {@code annotationFQN}
|
||||
* associated with {@code listOwner}.
|
||||
*
|
||||
* Multiple results may be returned for repeatable annotations and annotations
|
||||
* from several external annotations roots.
|
||||
*
|
||||
* @param listOwner API element to return external annotations of
|
||||
* @param annotationFQN fully qualified name of the annotation to search for
|
||||
* @return external annotations of the {@code listOwner}
|
||||
*/
|
||||
@NotNull
|
||||
public abstract List<PsiAnnotation> findExternalAnnotations(@NotNull PsiModifierListOwner listOwner, @NotNull String annotationFQN);
|
||||
|
||||
|
||||
// Method used in Kotlin plugin
|
||||
public abstract boolean isExternalAnnotationWritable(@NotNull PsiModifierListOwner listOwner, @NotNull String annotationFQN);
|
||||
|
||||
@Nullable
|
||||
public abstract PsiAnnotation[] findExternalAnnotations(@NotNull PsiModifierListOwner listOwner);
|
||||
|
||||
/**
|
||||
* Returns external annotations associated with default
|
||||
* constructor of the {@code aClass}, if the constructor exists.
|
||||
* <p>
|
||||
* Default constructors should be handled specially
|
||||
* because they don't have {@code PsiModifierListOwner},
|
||||
* nor they are returned in {@link PsiClass#getConstructors()}.
|
||||
* <p>
|
||||
* Yet default constructors may be externally annotated
|
||||
* in corresponding {@code annotations.xml}:
|
||||
* <pre>{@code <item name='com.example.Foo Foo()'>
|
||||
* <annotation name='org.some.Annotation'/>
|
||||
* </item>}</pre>
|
||||
*
|
||||
* @param aClass class of which default constructor's external annotations are to be found
|
||||
* @return external annotations of the default constructor of {@code aClass} or {@code null}
|
||||
* if the class doesn't have a default constructor
|
||||
*/
|
||||
@Nullable
|
||||
public abstract List<PsiAnnotation> findDefaultConstructorExternalAnnotations(@NotNull PsiClass aClass);
|
||||
|
||||
/**
|
||||
* Returns external annotations with fully qualified name of {@code annotationFQN}
|
||||
* associated with default constructor of the {@code aClass}, if the constructor exists.
|
||||
*
|
||||
* Multiple annotations may be returned since there may be repeatable annotations
|
||||
* or annotations from several external annotations roots.
|
||||
*
|
||||
* @param aClass class of which default constructor's external annotations are to be found
|
||||
* @param annotationFQN fully qualified name of annotation class to search for
|
||||
* @return annotations of the default constructor of {@code aClass}, or {@code null} if the
|
||||
* class doesn't have a default constructor.
|
||||
* @see #findDefaultConstructorExternalAnnotations(PsiClass)
|
||||
*/
|
||||
@Nullable
|
||||
public abstract List<PsiAnnotation> findDefaultConstructorExternalAnnotations(@NotNull PsiClass aClass, @NotNull String annotationFQN);
|
||||
|
||||
public abstract void annotateExternally(@NotNull PsiModifierListOwner listOwner,
|
||||
@NotNull String annotationFQName,
|
||||
@NotNull PsiFile fromFile,
|
||||
|
||||
+91
-27
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-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.
|
||||
*/
|
||||
// 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 com.intellij.codeInsight;
|
||||
|
||||
import com.intellij.lang.java.parser.JavaParser;
|
||||
@@ -35,6 +21,8 @@ import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.MostlySingularMultiMap;
|
||||
import com.intellij.util.text.CharSequenceReader;
|
||||
import gnu.trove.THashSet;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.xml.sax.Attributes;
|
||||
@@ -48,6 +36,7 @@ import javax.xml.parsers.SAXParserFactory;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public abstract class BaseExternalAnnotationsManager extends ExternalAnnotationsManager {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.BaseExternalAnnotationsManager");
|
||||
@@ -65,6 +54,25 @@ public abstract class BaseExternalAnnotationsManager extends ExternalAnnotations
|
||||
LowMemoryWatcher.register(this::dropCache, psiManager.getProject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns canonical string presentation of {@code listOwner}
|
||||
* used in external annotations files.
|
||||
*
|
||||
* @param listOwner API element to return external name of
|
||||
* @return external name or {@code null} if the {@code listOwner}
|
||||
* is of unknown type (neither class, method, field nor parameter)
|
||||
*/
|
||||
@Nullable
|
||||
protected static String getExternalName(@NotNull PsiModifierListOwner listOwner) {
|
||||
return getExternalName(listOwner, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #getExternalName(PsiModifierListOwner)} instead
|
||||
* since external annotations files don't contain parameters' names anyway.
|
||||
*/
|
||||
@ApiStatus.ScheduledForRemoval(inVersion = "2019.3")
|
||||
@Deprecated
|
||||
@Nullable
|
||||
protected static String getExternalName(@NotNull PsiModifierListOwner listOwner, boolean showParamName) {
|
||||
return PsiFormatUtil.getExternalName(listOwner, showParamName, Integer.MAX_VALUE);
|
||||
@@ -85,9 +93,45 @@ public abstract class BaseExternalAnnotationsManager extends ExternalAnnotations
|
||||
@Override
|
||||
@Nullable
|
||||
public PsiAnnotation findExternalAnnotation(@NotNull final PsiModifierListOwner listOwner, @NotNull final String annotationFQN) {
|
||||
List<AnnotationData> list = collectExternalAnnotations(listOwner);
|
||||
AnnotationData data = findByFQN(list, annotationFQN);
|
||||
return data == null ? null : data.getAnnotation(this);
|
||||
List<PsiAnnotation> result = findExternalAnnotations(listOwner, annotationFQN);
|
||||
return result.isEmpty() ? null : result.get(0);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<PsiAnnotation> findExternalAnnotations(@NotNull PsiModifierListOwner listOwner, @NotNull String annotationFQN) {
|
||||
List<AnnotationData> result = collectExternalAnnotations(listOwner);
|
||||
return filterAnnotations(result, annotationFQN);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<PsiAnnotation> findDefaultConstructorExternalAnnotations(@NotNull PsiClass aClass, @NotNull String annotationFQN) {
|
||||
if (aClass.getConstructors().length > 0) {
|
||||
return null;
|
||||
}
|
||||
List<AnnotationData> result = collectDefaultConstructorExternalAnnotations(aClass);
|
||||
return filterAnnotations(result, annotationFQN);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<PsiAnnotation> filterAnnotations(@NotNull List<AnnotationData> result, @NotNull String annotationFQN) {
|
||||
return StreamEx.of(result)
|
||||
.filter(data -> data.annotationClassFqName.equals(annotationFQN))
|
||||
.map(data -> data.getAnnotation(this))
|
||||
.toCollection(SmartList::new);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<PsiAnnotation> findDefaultConstructorExternalAnnotations(@NotNull PsiClass aClass) {
|
||||
if (aClass.getConstructors().length > 0) {
|
||||
return null;
|
||||
}
|
||||
List<AnnotationData> result = collectDefaultConstructorExternalAnnotations(aClass);
|
||||
return StreamEx.of(result)
|
||||
.map(data -> data.getAnnotation(this))
|
||||
.toCollection(SmartList::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -110,21 +154,36 @@ public abstract class BaseExternalAnnotationsManager extends ExternalAnnotations
|
||||
}
|
||||
|
||||
private static final List<AnnotationData> NO_DATA = new ArrayList<>(1);
|
||||
private final ConcurrentMostlySingularMultiMap<PsiModifierListOwner, AnnotationData> cache = new ConcurrentMostlySingularMultiMap<>();
|
||||
private final ConcurrentMostlySingularMultiMap<Object, AnnotationData> cache = new ConcurrentMostlySingularMultiMap<>();
|
||||
|
||||
// interner for storing annotation FQN
|
||||
private final CharTableImpl charTable = new CharTableImpl();
|
||||
|
||||
@NotNull
|
||||
private List<AnnotationData> collectExternalAnnotations(@NotNull PsiModifierListOwner listOwner) {
|
||||
if (!hasAnyAnnotationsRoots()) return Collections.emptyList();
|
||||
private List<AnnotationData> collectDefaultConstructorExternalAnnotations(@NotNull PsiClass aClass) {
|
||||
//External annotations of default constructor are stored at the same annotations files as class' ones.
|
||||
List<PsiFile> annotationsFiles = findExternalAnnotationsFiles(aClass);
|
||||
if (annotationsFiles == null) return NO_DATA;
|
||||
|
||||
String defCtrExternalName = getExternalName(aClass) + " " + aClass.getName() + "()";
|
||||
return collectExternalAnnotations(defCtrExternalName, () -> doCollect(defCtrExternalName, annotationsFiles, false));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<AnnotationData> collectExternalAnnotations(@NotNull PsiModifierListOwner listOwner) {
|
||||
return collectExternalAnnotations(listOwner, () -> doCollect(listOwner, false));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<AnnotationData> collectExternalAnnotations(@NotNull Object cacheKey,
|
||||
@NotNull Supplier<List<AnnotationData>> dataSupplier) {
|
||||
if (!hasAnyAnnotationsRoots()) return Collections.emptyList();
|
||||
List<AnnotationData> cached;
|
||||
while (true) {
|
||||
cached = (List<AnnotationData>)cache.get(listOwner);
|
||||
cached = (List<AnnotationData>)cache.get(cacheKey);
|
||||
if (cached == NO_DATA || !cached.isEmpty()) return cached;
|
||||
List<AnnotationData> computed = doCollect(listOwner, false);
|
||||
if (cache.replace(listOwner, cached, computed)) {
|
||||
List<AnnotationData> computed = dataSupplier.get();
|
||||
if (cache.replace(cacheKey, cached, computed)) {
|
||||
cached = computed;
|
||||
break;
|
||||
}
|
||||
@@ -182,11 +241,16 @@ public abstract class BaseExternalAnnotationsManager extends ExternalAnnotations
|
||||
List<PsiFile> files = findExternalAnnotationsFiles(listOwner);
|
||||
if (files == null) return NO_DATA;
|
||||
|
||||
String externalName = getExternalName(listOwner, false);
|
||||
String externalName = getExternalName(listOwner);
|
||||
if (externalName == null) return NO_DATA;
|
||||
|
||||
return doCollect(externalName, files, onlyWritable);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<AnnotationData> doCollect(@NotNull String externalName, @NotNull List<PsiFile> annotationsFiles, boolean onlyWritable) {
|
||||
SmartList<AnnotationData> result = new SmartList<>();
|
||||
for (PsiFile file : files) {
|
||||
for (PsiFile file : annotationsFiles) {
|
||||
if (!file.isValid()) continue;
|
||||
if (onlyWritable && !file.isWritable()) continue;
|
||||
|
||||
@@ -423,7 +487,7 @@ public abstract class BaseExternalAnnotationsManager extends ExternalAnnotations
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endElement(String uri, String localName, String qName) throws SAXException {
|
||||
public void endElement(String uri, String localName, String qName) {
|
||||
if ("item".equals(qName)) {
|
||||
myExternalName = null;
|
||||
}
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<problems>
|
||||
<problem>
|
||||
<file>Test.java</file>
|
||||
<line>4</line>
|
||||
<description>Default constructor in 'a.A' is deprecated</description>
|
||||
</problem>
|
||||
</problems>
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<root>
|
||||
<item name='a.A A()'>
|
||||
<annotation name='java.lang.Deprecated'/>
|
||||
</item>
|
||||
</root>
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
import a.A;
|
||||
|
||||
//Here "Default constructor in A is deprecated" warning must be reported.
|
||||
public class Test extends A {
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package a;
|
||||
|
||||
//This class' default constructor is externally deprecated.
|
||||
public class A {
|
||||
}
|
||||
+21
-15
@@ -1,23 +1,13 @@
|
||||
/*
|
||||
* Copyright 2000-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.
|
||||
*/
|
||||
// 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 com.intellij.java.codeInspection;
|
||||
|
||||
import com.intellij.JavaTestUtil;
|
||||
import com.intellij.codeInspection.deprecation.DeprecationInspection;
|
||||
import com.intellij.openapi.roots.JavaModuleExternalPaths;
|
||||
import com.intellij.openapi.roots.ModuleRootModificationUtil;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.testFramework.InspectionTestCase;
|
||||
|
||||
/**
|
||||
@@ -79,4 +69,20 @@ public class DeprecationInspectionTest extends InspectionTestCase {
|
||||
doTest("deprecation/" + getTestName(true), tool);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up external deprecation annotations
|
||||
* for the current test module.
|
||||
*/
|
||||
private void configureExternalAnnotationsUrls(String... urls) {
|
||||
ModuleRootModificationUtil.updateModel(myModule, (root) -> {
|
||||
JavaModuleExternalPaths extension = root.getModuleExtension(JavaModuleExternalPaths.class);
|
||||
extension.setExternalAnnotationUrls(urls);
|
||||
});
|
||||
}
|
||||
|
||||
public void testExternallyDeprecatedDefaultConstructor() {
|
||||
String url = VfsUtilCore.pathToUrl(FileUtil.toSystemIndependentName(getTestDataPath()) + "/deprecation/externallyDeprecatedDefaultConstructor/extAnnotations");
|
||||
configureExternalAnnotationsUrls(url);
|
||||
doTest();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user