Skip to content

Commit

Permalink
Provide Annotation class usage linemarker #79, [API] Provide an index…
Browse files Browse the repository at this point in the history
… with annotated elements stubs #53
  • Loading branch information
Haehnchen committed Sep 15, 2017
1 parent 5bf5ef4 commit 922e872
Show file tree
Hide file tree
Showing 5 changed files with 234 additions and 1 deletion.
1 change: 1 addition & 0 deletions META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@

<projectService serviceImplementation="de.espend.idea.php.annotation.Settings"/>
<fileBasedIndex implementation="de.espend.idea.php.annotation.AnnotationStubIndex"/>
<fileBasedIndex implementation="de.espend.idea.php.annotation.AnnotationUsageIndex"/>

<gotoDeclarationHandler implementation="de.espend.idea.php.annotation.navigation.AnnotationGoToDeclarationHandler"/>
<completion.contributor language="PHP" implementationClass="de.espend.idea.php.annotation.completion.AnnotationCompletionContributor"/>
Expand Down
172 changes: 172 additions & 0 deletions src/de/espend/idea/php/annotation/AnnotationUsageIndex.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
package de.espend.idea.php.annotation;

import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiRecursiveElementWalkingVisitor;
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.documentation.phpdoc.psi.tags.PhpDocTag;
import com.jetbrains.php.lang.psi.PhpFile;
import de.espend.idea.php.annotation.util.AnnotationUtil;
import gnu.trove.THashMap;
import gnu.trove.THashSet;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

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 new DataIndexer<String, Set<String>, FileContent>() {
@NotNull
@Override
public Map<String, Set<String>> map(@NotNull FileContent 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 PsiRecursiveElementWalkingVisitor() {
@Override
public void visitElement(PsiElement element) {
if ((element instanceof PhpDocTag)) {
visitPhpDocTag((PhpDocTag) element);
}

super.visitElement(element);
}

private void visitPhpDocTag(@NotNull PhpDocTag phpDocTag) {
// "@var" and user non related tags dont need an action
if(AnnotationUtil.NON_ANNOTATION_TAGS.contains(phpDocTag.getName())) {
return;
}

String annotationFqnName = StringUtils.stripStart(getClassNameReference(phpDocTag, AnnotationUtil.getUseImportMap(phpDocTag)), "\\");

map.put(annotationFqnName, new HashSet<>());
}
});

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;
}

@Nullable
public static String getClassNameReference(PhpDocTag phpDocTag, Map<String, String> useImports) {

if(useImports.size() == 0) {
return null;
}

String annotationName = phpDocTag.getName();
if(StringUtils.isBlank(annotationName)) {
return null;
}

if(annotationName.startsWith("@")) {
annotationName = annotationName.substring(1);
}

String className = annotationName;
String subNamespaceName = "";
if(className.contains("\\")) {
className = className.substring(0, className.indexOf("\\"));
subNamespaceName = annotationName.substring(className.length());
}

if(!useImports.containsKey(className)) {
return null;
}

// normalize name
String annotationFqnName = useImports.get(className) + subNamespaceName;
if(!annotationFqnName.startsWith("\\")) {
annotationFqnName = "\\" + annotationFqnName;
}

return annotationFqnName;
}

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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import com.intellij.psi.PsiReference;
import com.jetbrains.php.PhpIndex;
import com.jetbrains.php.completion.PhpCompletionUtil;
import com.jetbrains.php.lang.PhpLangUtil;
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
import de.espend.idea.php.annotation.extension.PhpAnnotationCompletionProvider;
import de.espend.idea.php.annotation.extension.PhpAnnotationReferenceProvider;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package de.espend.idea.php.annotation.tests;

import de.espend.idea.php.annotation.AnnotationUsageIndex;

import java.io.File;

/**
* @author Daniel Espendiller <daniel@espendiller.net>
* @see de.espend.idea.php.annotation.AnnotationUsageIndex
*/
public class AnnotationUsageIndexTest extends AnnotationLightCodeInsightFixtureTestCase {
public void setUp() throws Exception {
super.setUp();
myFixture.copyFileToProject("classes.php");
myFixture.copyFileToProject("usages.php");
}

public String getTestDataPath() {
return new File(this.getClass().getResource("fixtures").getFile()).getAbsolutePath();
}

public void testThatUsagesAreInIndex() {
assertIndexContains(AnnotationUsageIndex.KEY, "Doctrine\\ORM\\Mapping\\Embedded");
}
}
36 changes: 36 additions & 0 deletions tests/de/espend/idea/php/annotation/tests/fixtures/usages.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace Doctrine\ORM\Mapping
{
/**
* @Annotation
* @Target("PROPERTY")
*/
final class Embedded implements Annotation
{
}

/**
* @Annotation
* @Target("PROPERTY")
*/
final class CustomIdGenerator implements Annotation
{
}
}

namespace My\Model
{
use \Doctrine\ORM\Mapping as ORM;

/**
* @ORM\Embedded
*/
class Item
{
/**
* @ORM\CustomIdGenerator
*/
private $foo;
}
}

0 comments on commit 922e872

Please sign in to comment.