From 047edc1b36ca86fad86d9fc891db0528b1938112 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 20 May 2015 11:01:26 +0200 Subject: [PATCH] platform: extensible package dependency visitor --- .../JavaDependenciesVisitorFactory.java | 71 ++-------------- .../JavaDependencyVisitorFactory.java | 85 +++++++++++++++++++ .../DependenciesBuilder.java | 10 ++- .../DependenciesVisitorFactory.java | 15 +--- .../DependencyVisitorFactory.java | 79 +++++++++++++++++ .../src/META-INF/LangExtensionPoints.xml | 4 + resources/src/META-INF/IdeaPlugin.xml | 1 + 7 files changed, 187 insertions(+), 78 deletions(-) create mode 100644 java/java-impl/src/com/intellij/packageDependencies/JavaDependencyVisitorFactory.java create mode 100644 platform/analysis-impl/src/com/intellij/packageDependencies/DependencyVisitorFactory.java diff --git a/java/java-impl/src/com/intellij/packageDependencies/JavaDependenciesVisitorFactory.java b/java/java-impl/src/com/intellij/packageDependencies/JavaDependenciesVisitorFactory.java index c0569192fda1..580e87c9cef9 100644 --- a/java/java-impl/src/com/intellij/packageDependencies/JavaDependenciesVisitorFactory.java +++ b/java/java-impl/src/com/intellij/packageDependencies/JavaDependenciesVisitorFactory.java @@ -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); } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/packageDependencies/JavaDependencyVisitorFactory.java b/java/java-impl/src/com/intellij/packageDependencies/JavaDependencyVisitorFactory.java new file mode 100644 index 000000000000..4bbe7e68df46 --- /dev/null +++ b/java/java-impl/src/com/intellij/packageDependencies/JavaDependencyVisitorFactory.java @@ -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); + } + } + } + } + } +} \ No newline at end of file diff --git a/platform/analysis-impl/src/com/intellij/packageDependencies/DependenciesBuilder.java b/platform/analysis-impl/src/com/intellij/packageDependencies/DependenciesBuilder.java index 6fc05b8bcfde..333af2d83981 100644 --- a/platform/analysis-impl/src/com/intellij/packageDependencies/DependenciesBuilder.java +++ b/platform/analysis-impl/src/com/intellij/packageDependencies/DependenciesBuilder.java @@ -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); } diff --git a/platform/analysis-impl/src/com/intellij/packageDependencies/DependenciesVisitorFactory.java b/platform/analysis-impl/src/com/intellij/packageDependencies/DependenciesVisitorFactory.java index a4cc6279e2f9..4e1223bde7be 100644 --- a/platform/analysis-impl/src/com/intellij/packageDependencies/DependenciesVisitorFactory.java +++ b/platform/analysis-impl/src/com/intellij/packageDependencies/DependenciesVisitorFactory.java @@ -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); } diff --git a/platform/analysis-impl/src/com/intellij/packageDependencies/DependencyVisitorFactory.java b/platform/analysis-impl/src/com/intellij/packageDependencies/DependencyVisitorFactory.java new file mode 100644 index 000000000000..28f7a0fad06c --- /dev/null +++ b/platform/analysis-impl/src/com/intellij/packageDependencies/DependencyVisitorFactory.java @@ -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 EP_NAME = + new LanguageExtension("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); + } + } + } + } +} diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index 2aa532f8303d..ca3c87438cc2 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -834,6 +834,10 @@ + + + + diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index 2f1aa5b7bb32..49ac54a2dfba 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -1298,6 +1298,7 @@ +