platform: extensible package dependency visitor

This commit is contained in:
Roman Shevchenko
2015-05-20 11:01:26 +02:00
parent 3dc83f7651
commit 047edc1b36
7 changed files with 187 additions and 78 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* 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.
@@ -13,74 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* User: anna
* Date: 21-Jan-2008
*/
package com.intellij.packageDependencies;
import com.intellij.psi.*;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.PsiElementVisitor;
/** @deprecated use {@link DependencyVisitorFactory} (to be removed in IDEA 17) */
@SuppressWarnings("deprecation")
public class JavaDependenciesVisitorFactory extends DependenciesVisitorFactory {
@Override
public PsiElementVisitor createVisitor(final DependenciesBuilder.DependencyProcessor processor) {
return new JavaRecursiveElementVisitor() {
@Override
public void visitReferenceExpression(PsiReferenceExpression expression) {
visitReferenceElement(expression);
}
@Override
public void visitElement(PsiElement element) {
super.visitElement(element);
PsiReference[] refs = element.getReferences();
for (PsiReference ref : refs) {
PsiElement resolved = ref.resolve();
if (resolved != null) {
processor.process(ref.getElement(), resolved);
}
}
}
@Override
public void visitLiteralExpression(PsiLiteralExpression expression) {
// empty
// TODO: thus we'll skip property references and references to file resources. We can't validate them anyway now since
// TODO: rule syntax does not allow this.
}
@Override
public void visitDocComment(PsiDocComment comment) {
//empty
}
@Override
public void visitImportStatement(PsiImportStatement statement) {
if (!DependencyValidationManager.getInstance(statement.getProject()).skipImportStatements()) {
visitElement(statement);
}
}
@Override
public void visitMethodCallExpression(PsiMethodCallExpression expression) {
super.visitMethodCallExpression(expression);
PsiMethod psiMethod = expression.resolveMethod();
if (psiMethod != null) {
PsiType returnType = psiMethod.getReturnType();
if (returnType != null) {
PsiClass psiClass = PsiUtil.resolveClassInType(returnType);
if (psiClass != null) {
if (!(psiClass instanceof PsiTypeParameter)) {
processor.process(expression, psiClass);
}
}
}
}
}
};
public PsiElementVisitor createVisitor(DependenciesBuilder.DependencyProcessor processor) {
return new JavaDependencyVisitorFactory().getVisitor(processor, DependencyVisitorFactory.VisitorOptions.SKIP_IMPORTS);
}
}
@@ -0,0 +1,85 @@
/*
* 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.
*/
package com.intellij.packageDependencies;
import com.intellij.psi.*;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.util.PsiUtil;
import org.jetbrains.annotations.NotNull;
public class JavaDependencyVisitorFactory extends DependencyVisitorFactory {
@NotNull
@Override
public PsiElementVisitor getVisitor(@NotNull DependenciesBuilder.DependencyProcessor processor, @NotNull VisitorOptions options) {
return new MyVisitor(processor, options);
}
private static class MyVisitor extends JavaRecursiveElementVisitor {
private final DependenciesBuilder.DependencyProcessor myProcessor;
private final VisitorOptions myOptions;
public MyVisitor(DependenciesBuilder.DependencyProcessor processor, VisitorOptions options) {
myProcessor = processor;
myOptions = options;
}
@Override
public void visitReferenceExpression(PsiReferenceExpression expression) {
visitReferenceElement(expression);
}
@Override
public void visitElement(PsiElement element) {
super.visitElement(element);
for (PsiReference ref : element.getReferences()) {
PsiElement resolved = ref.resolve();
if (resolved != null) {
myProcessor.process(ref.getElement(), resolved);
}
}
}
@Override
public void visitLiteralExpression(PsiLiteralExpression expression) { }
@Override
public void visitDocComment(PsiDocComment comment) { }
@Override
public void visitImportStatement(PsiImportStatement statement) {
if (!myOptions.skipImports()) {
visitElement(statement);
}
}
@Override
public void visitMethodCallExpression(PsiMethodCallExpression expression) {
super.visitMethodCallExpression(expression);
PsiMethod psiMethod = expression.resolveMethod();
if (psiMethod != null) {
PsiType returnType = psiMethod.getReturnType();
if (returnType != null) {
PsiClass psiClass = PsiUtil.resolveClassInType(returnType);
if (psiClass != null && !(psiClass instanceof PsiTypeParameter)) {
myProcessor.process(expression, psiClass);
}
}
}
}
}
}
@@ -157,9 +157,15 @@ public abstract class DependenciesBuilder {
return ProjectUtilCore.displayUrlRelativeToProject(virtualFile, virtualFile.getPresentableUrl(), getProject(), true, false);
}
public static void analyzeFileDependencies(PsiFile file, DependencyProcessor processor) {
public static void analyzeFileDependencies(@NotNull PsiFile file, @NotNull DependencyProcessor processor) {
analyzeFileDependencies(file, processor, DependencyVisitorFactory.VisitorOptions.fromSettings(file.getProject()));
}
public static void analyzeFileDependencies(@NotNull PsiFile file,
@NotNull DependencyProcessor processor,
@NotNull DependencyVisitorFactory.VisitorOptions options) {
file.putUserData(PsiFileEx.BATCH_REFERENCE_PROCESSING, Boolean.TRUE);
file.accept(DependenciesVisitorFactory.getInstance().createVisitor(processor));
file.accept(DependencyVisitorFactory.createVisitor(file, processor, options));
file.putUserData(PsiFileEx.BATCH_REFERENCE_PROCESSING, null);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* 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.
@@ -13,21 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* User: anna
* Date: 21-Jan-2008
*/
package com.intellij.packageDependencies;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiRecursiveElementVisitor;
import com.intellij.psi.PsiReference;
import com.intellij.psi.*;
/** @deprecated use {@link DependencyVisitorFactory} (to be removed in IDEA 17) */
public class DependenciesVisitorFactory {
@SuppressWarnings("deprecation")
public static DependenciesVisitorFactory getInstance() {
return ServiceManager.getService(DependenciesVisitorFactory.class);
}
@@ -0,0 +1,79 @@
/*
* 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.
*/
package com.intellij.packageDependencies;
import com.intellij.lang.LanguageExtension;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;
public abstract class DependencyVisitorFactory {
private static final LanguageExtension<DependencyVisitorFactory> EP_NAME =
new LanguageExtension<DependencyVisitorFactory>("com.intellij.packageDependencies.visitor");
public static abstract class VisitorOptions {
public abstract boolean skipImports();
public static final VisitorOptions SKIP_IMPORTS = new VisitorOptions() {
@Override
public boolean skipImports() {
return true;
}
};
public static VisitorOptions fromSettings(@NotNull Project project) {
final DependencyValidationManager manager = DependencyValidationManager.getInstance(project);
return new VisitorOptions() {
@Override
public boolean skipImports() {
return manager.skipImportStatements();
}
};
}
}
@NotNull
public abstract PsiElementVisitor getVisitor(@NotNull DependenciesBuilder.DependencyProcessor processor, @NotNull VisitorOptions options);
@NotNull
public static PsiElementVisitor createVisitor(@NotNull PsiFile file,
@NotNull DependenciesBuilder.DependencyProcessor processor,
@NotNull VisitorOptions options) {
DependencyVisitorFactory factory = EP_NAME.forLanguage(file.getLanguage());
return factory != null ? factory.getVisitor(processor, options) : new DefaultVisitor(processor);
}
private static class DefaultVisitor extends PsiRecursiveElementVisitor {
private final DependenciesBuilder.DependencyProcessor myProcessor;
public DefaultVisitor(@NotNull DependenciesBuilder.DependencyProcessor processor) {
myProcessor = processor;
}
@Override
public void visitElement(PsiElement element) {
super.visitElement(element);
for (PsiReference ref : element.getReferences()) {
PsiElement resolved = ref.resolve();
if (resolved != null) {
myProcessor.process(ref.getElement(), resolved);
}
}
}
}
}
@@ -834,6 +834,10 @@
<extensionPoint name="inspectionElementsMerger" interface="com.intellij.codeInspection.ex.InspectionElementsMerger"/>
<extensionPoint name="scratch.rootType" interface="com.intellij.ide.scratch.RootType"/>
<extensionPoint name="packageDependencies.visitor" beanClass="com.intellij.lang.LanguageExtensionPoint">
<with attribute="implementationClass" implements="com.intellij.packageDependencies.DependencyVisitorFactory"/>
</extensionPoint>
</extensionPoints>
</idea-plugin>
+1
View File
@@ -1298,6 +1298,7 @@
<applicationService serviceInterface="com.intellij.packageDependencies.DependenciesVisitorFactory"
serviceImplementation="com.intellij.packageDependencies.JavaDependenciesVisitorFactory"/>
<packageDependencies.visitor language="JAVA" implementationClass="com.intellij.packageDependencies.JavaDependencyVisitorFactory"/>
<exceptionFilter implementation="com.intellij.execution.filters.ExceptionBaseFilterFactory"/>
<exceptionFilter implementation="com.intellij.execution.filters.ExceptionExFilterFactory"/>