-
-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Provide Annotation class usage linemarker #79, [API] Provide an index…
… with annotated elements stubs #53
- Loading branch information
Showing
11 changed files
with
502 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
111 changes: 111 additions & 0 deletions
111
src/de/espend/idea/php/annotation/AnnotationUsageIndex.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
package de.espend.idea.php.annotation; | ||
|
||
import com.intellij.psi.PsiFile; | ||
import com.intellij.util.indexing.*; | ||
import com.intellij.util.io.DataExternalizer; | ||
import com.intellij.util.io.EnumeratorStringDescriptor; | ||
import com.intellij.util.io.KeyDescriptor; | ||
import com.jetbrains.php.lang.PhpFileType; | ||
import com.jetbrains.php.lang.psi.PhpFile; | ||
import de.espend.idea.php.annotation.util.AnnotationUtil; | ||
import de.espend.idea.php.annotation.util.PhpDocTagAnnotationRecursiveElementWalkingVisitor; | ||
import gnu.trove.THashMap; | ||
import gnu.trove.THashSet; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
import java.io.DataInput; | ||
import java.io.DataOutput; | ||
import java.io.IOException; | ||
import java.util.HashSet; | ||
import java.util.Iterator; | ||
import java.util.Map; | ||
import java.util.Set; | ||
|
||
/** | ||
* @author Daniel Espendiller <daniel@espendiller.net> | ||
*/ | ||
public class AnnotationUsageIndex extends FileBasedIndexExtension<String, Set<String>> { | ||
public static final ID<String, Set<String>> KEY = ID.create("espend.php.annotation.usage"); | ||
private final KeyDescriptor<String> myKeyDescriptor = new EnumeratorStringDescriptor(); | ||
private static StringSetDataExternalizer EXTERNALIZER = new StringSetDataExternalizer(); | ||
|
||
@NotNull | ||
@Override | ||
public ID<String, Set<String>> getName() { | ||
return KEY; | ||
} | ||
|
||
@NotNull | ||
@Override | ||
public DataIndexer<String, Set<String>, FileContent> getIndexer() { | ||
return inputData -> { | ||
final Map<String, Set<String>> map = new THashMap<>(); | ||
|
||
PsiFile psiFile = inputData.getPsiFile(); | ||
if(!(psiFile instanceof PhpFile)) { | ||
return map; | ||
} | ||
|
||
if(!AnnotationUtil.isValidForIndex(inputData)) { | ||
return map; | ||
} | ||
|
||
psiFile.accept(new PhpDocTagAnnotationRecursiveElementWalkingVisitor(pair -> { | ||
map.put(pair.getFirst(), new HashSet<>()); | ||
return true; | ||
})); | ||
|
||
return map; | ||
}; | ||
} | ||
|
||
@NotNull | ||
@Override | ||
public KeyDescriptor<String> getKeyDescriptor() { | ||
return this.myKeyDescriptor; | ||
} | ||
|
||
@NotNull | ||
@Override | ||
public DataExternalizer<Set<String>> getValueExternalizer() { | ||
return EXTERNALIZER; | ||
} | ||
|
||
@NotNull | ||
@Override | ||
public FileBasedIndex.InputFilter getInputFilter() { | ||
return virtualFile -> virtualFile.getFileType() == PhpFileType.INSTANCE; | ||
} | ||
|
||
@Override | ||
public boolean dependsOnFileContent() { | ||
return true; | ||
} | ||
|
||
@Override | ||
public int getVersion() { | ||
return 1; | ||
} | ||
|
||
private static class StringSetDataExternalizer implements DataExternalizer<Set<String>> { | ||
public synchronized void save(@NotNull DataOutput out, Set<String> value) throws IOException { | ||
out.writeInt(value.size()); | ||
Iterator var = value.iterator(); | ||
|
||
while(var.hasNext()) { | ||
String s = (String)var.next(); | ||
EnumeratorStringDescriptor.INSTANCE.save(out, s); | ||
} | ||
} | ||
|
||
public synchronized Set<String> read(@NotNull DataInput in) throws IOException { | ||
Set<String> set = new THashSet<>(); | ||
|
||
for(int r = in.readInt(); r > 0; --r) { | ||
set.add(EnumeratorStringDescriptor.INSTANCE.read(in)); | ||
} | ||
|
||
return set; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
106 changes: 106 additions & 0 deletions
106
src/de/espend/idea/php/annotation/navigation/AnnotationUsageLineMarkerProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
package de.espend.idea.php.annotation.navigation; | ||
|
||
import com.intellij.codeInsight.daemon.LineMarkerInfo; | ||
import com.intellij.codeInsight.daemon.LineMarkerProvider; | ||
import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder; | ||
import com.intellij.openapi.project.Project; | ||
import com.intellij.openapi.util.NotNullLazyValue; | ||
import com.intellij.patterns.PlatformPatterns; | ||
import com.intellij.patterns.PsiElementPattern; | ||
import com.intellij.psi.PsiElement; | ||
import com.intellij.psi.PsiWhiteSpace; | ||
import com.intellij.psi.search.GlobalSearchScope; | ||
import com.intellij.util.indexing.FileBasedIndex; | ||
import com.jetbrains.php.PhpIcons; | ||
import com.jetbrains.php.lang.PhpFileType; | ||
import com.jetbrains.php.lang.PhpLanguage; | ||
import com.jetbrains.php.lang.lexer.PhpTokenTypes; | ||
import com.jetbrains.php.lang.psi.elements.PhpClass; | ||
import de.espend.idea.php.annotation.AnnotationUsageIndex; | ||
import de.espend.idea.php.annotation.util.AnnotationUtil; | ||
import org.apache.commons.lang.StringUtils; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.jetbrains.annotations.Nullable; | ||
|
||
import java.util.Collection; | ||
import java.util.Collections; | ||
import java.util.HashSet; | ||
import java.util.List; | ||
|
||
/** | ||
* @author Daniel Espendiller <daniel@espendiller.net> | ||
*/ | ||
public class AnnotationUsageLineMarkerProvider implements LineMarkerProvider { | ||
@Nullable | ||
@Override | ||
public LineMarkerInfo getLineMarkerInfo(@NotNull PsiElement psiElement) { | ||
return null; | ||
} | ||
|
||
@Override | ||
public void collectSlowLineMarkers(@NotNull List<PsiElement> psiElements, @NotNull Collection<LineMarkerInfo> results) { | ||
for(PsiElement psiElement: psiElements) { | ||
if(!getClassNamePattern().accepts(psiElement)) { | ||
continue; | ||
} | ||
|
||
PsiElement phpClass = psiElement.getContext(); | ||
if(!(phpClass instanceof PhpClass) || !AnnotationUtil.isAnnotationClass((PhpClass) phpClass)) { | ||
return; | ||
} | ||
|
||
String fqn = StringUtils.stripStart(((PhpClass) phpClass).getFQN(), "\\"); | ||
|
||
// find one index annotation class and stop processing on first match | ||
final boolean[] processed = {false}; | ||
FileBasedIndex.getInstance().getFilesWithKey(AnnotationUsageIndex.KEY, new HashSet<>(Collections.singletonList(fqn)), virtualFile -> { | ||
processed[0] = true; | ||
|
||
// stop on first match | ||
return false; | ||
}, GlobalSearchScope.getScopeRestrictedByFileTypes(GlobalSearchScope.allScope(psiElement.getProject()), PhpFileType.INSTANCE)); | ||
|
||
// we found at least one target to provide lazy target linemarker | ||
if(processed[0]) { | ||
NavigationGutterIconBuilder<PsiElement> builder = NavigationGutterIconBuilder.create(PhpIcons.IMPLEMENTS) | ||
.setTargets(new CollectionNotNullLazyValue(psiElement.getProject(), fqn)) | ||
.setTooltipText("Navigate to implementations"); | ||
|
||
results.add(builder.createLineMarkerInfo(psiElement)); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* class "Foo" extends | ||
*/ | ||
private static PsiElementPattern.Capture<PsiElement> getClassNamePattern() { | ||
return PlatformPatterns | ||
.psiElement(PhpTokenTypes.IDENTIFIER) | ||
.afterLeafSkipping( | ||
PlatformPatterns.psiElement(PsiWhiteSpace.class), | ||
PlatformPatterns.psiElement(PhpTokenTypes.kwCLASS) | ||
) | ||
.withParent(PhpClass.class) | ||
.withLanguage(PhpLanguage.INSTANCE); | ||
} | ||
|
||
private static class CollectionNotNullLazyValue extends NotNullLazyValue<Collection<? extends PsiElement>> { | ||
@NotNull | ||
private final Project project; | ||
|
||
@NotNull | ||
private final String fqn; | ||
|
||
CollectionNotNullLazyValue(@NotNull Project project, @NotNull String fqn) { | ||
this.project = project; | ||
this.fqn = fqn; | ||
} | ||
|
||
@NotNull | ||
@Override | ||
protected Collection<? extends PsiElement> compute() { | ||
return AnnotationUtil.getImplementationsForAnnotation(project, fqn); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.