/*
* 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.jetbrains.lang.dart.ide.marker;
import com.intellij.codeHighlighting.Pass;
import com.intellij.codeInsight.daemon.DaemonBundle;
import com.intellij.codeInsight.daemon.GutterIconNavigationHandler;
import com.intellij.codeInsight.daemon.LineMarkerInfo;
import com.intellij.codeInsight.daemon.LineMarkerProvider;
import com.intellij.codeInsight.daemon.impl.PsiElementListNavigator;
import com.intellij.icons.AllIcons;
import com.intellij.ide.util.DefaultPsiElementCellRenderer;
import com.intellij.openapi.editor.markup.GutterIconRenderer;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.search.GlobalSearchScope;
import com.jetbrains.lang.dart.analyzer.DartAnalysisServerService;
import com.jetbrains.lang.dart.analyzer.DartServerData;
import com.jetbrains.lang.dart.ide.actions.DartInheritorsSearcher;
import com.jetbrains.lang.dart.psi.DartComponent;
import com.jetbrains.lang.dart.psi.DartComponentName;
import com.jetbrains.lang.dart.util.DartResolveUtil;
import org.dartlang.analysis.server.protocol.TypeHierarchyItem;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.List;
public class DartServerImplementationsMarkerProvider implements LineMarkerProvider {
@Override
public void collectSlowLineMarkers(@NotNull final List<PsiElement> elements, @NotNull final Collection<LineMarkerInfo> result) {
}
@Override
public LineMarkerInfo getLineMarkerInfo(@NotNull final PsiElement element) {
if (!(element instanceof DartComponentName)) {
return null;
}
final DartComponentName name = (DartComponentName)element;
return createMarker(name);
}
@Nullable
private static LineMarkerInfo createMarker(@NotNull final DartComponentName name) {
final DartAnalysisServerService service = DartAnalysisServerService.getInstance(name.getProject());
final VirtualFile file = name.getContainingFile().getVirtualFile();
if (file == null || !file.isInLocalFileSystem()) {
return null;
}
final int nameOffset = name.getTextRange().getStartOffset();
final int nameLength = name.getTextLength();
// ignore Object
if ("Object".equals(name.getName())) {
return null;
}
// classes
for (DartServerData.DartRegion implementedClassRegion : service.getImplementedClasses(file)) {
if (implementedClassRegion.getOffset() == nameOffset && implementedClassRegion.getLength() == nameLength) {
return createMarkerClass(name);
}
}
// members
for (DartServerData.DartRegion implementedMemberRegion : service.getImplementedMembers(file)) {
if (implementedMemberRegion.getOffset() == nameOffset && implementedMemberRegion.getLength() == nameLength) {
return createMarkerMember(name);
}
}
// not found
return null;
}
@NotNull
private static LineMarkerInfo createMarkerClass(@NotNull final DartComponentName name) {
final VirtualFile file = name.getContainingFile().getVirtualFile();
final int nameOffset = name.getTextRange().getStartOffset();
return new LineMarkerInfo<>(name, name.getTextRange(), AllIcons.Gutter.OverridenMethod, Pass.LINE_MARKERS,
element -> DaemonBundle.message("class.is.subclassed.too.many"),
(GutterIconNavigationHandler<PsiElement>)(e, elt) -> {
final List<TypeHierarchyItem> items = DartAnalysisServerService.getInstance(name.getProject())
.search_getTypeHierarchy(file, nameOffset, false);
if (items.isEmpty()) {
return;
}
// TODO(scheglov) Consider using just Element(s), not PsiElement(s) for better performance
final List<DartComponent> components =
DartInheritorsSearcher
.getSubClasses(name.getProject(), GlobalSearchScope.allScope(name.getProject()), items);
PsiElementListNavigator.openTargets(e, DartResolveUtil.getComponentNameArray(components),
DaemonBundle.message("navigation.title.subclass", name.getName(),
components.size(), ""),
"Subclasses of " + name.getName(),
new DefaultPsiElementCellRenderer());
}, GutterIconRenderer.Alignment.RIGHT);
}
@NotNull
private static LineMarkerInfo createMarkerMember(@NotNull final DartComponentName name) {
final VirtualFile file = name.getContainingFile().getVirtualFile();
final int nameOffset = name.getTextRange().getStartOffset();
return new LineMarkerInfo<>(name, name.getTextRange(), AllIcons.Gutter.OverridenMethod, Pass.LINE_MARKERS,
element -> DaemonBundle.message("method.is.overridden.too.many"),
(GutterIconNavigationHandler<PsiElement>)(e, elt) -> {
final List<TypeHierarchyItem> items = DartAnalysisServerService.getInstance(name.getProject())
.search_getTypeHierarchy(file, nameOffset, false);
if (items.isEmpty()) {
return;
}
// TODO(scheglov) Consider using just Element(s), not PsiElement(s) for better performance
final List<DartComponent> components =
DartInheritorsSearcher
.getSubMembers(name.getProject(), GlobalSearchScope.allScope(name.getProject()), items);
PsiElementListNavigator.openTargets(e, DartResolveUtil.getComponentNameArray(components),
DaemonBundle
.message("navigation.title.overrider.method", name.getName(),
components.size()),
"Overriding methods of " + name.getName(),
new DefaultPsiElementCellRenderer());
}, GutterIconRenderer.Alignment.RIGHT);
}
}