// Path: src/com/aopphp/go/util/PluginUtil.java
// public class PluginUtil {
// 
//     /**
//      * Returns a map with php use imports
//      *
//      * @param psiFile Instance of file, should be PHP
//      * @return Mapping of short names to the FQN
//      */
//     public static Map<String, String> getFileUseImports(PsiFile psiFile) {
// 
//         // search for use alias in local file
//         final Map<String, String> useImports = new HashMap<String, String>();
// 
//         if (psiFile instanceof PhpFile) {
//             for (final PhpNamedElement element : ((PhpFile) psiFile).getTopLevelDefs().values()) {
//                 if (element instanceof PhpUse) {
//                     final PhpUse phpUse = (PhpUse) element;
//                     String alias = phpUse.getAliasName();
//                     if(alias != null) {
//                         useImports.put(alias, phpUse.getFQN());
//                     } else {
//                         useImports.put(phpUse.getName(), phpUse.getFQN());
//                     }
//                 }
//             }
//         }
// 
//         return useImports;
//     }
// 
// 
//     @Nullable
//     public static String getClassNameReference(PhpDocTag phpDocTag) {
//         return getClassNameReference(phpDocTag, getFileUseImports(phpDocTag.getContainingFile()));
//     }
// 
//     @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;
// 
//     }
// 
//     /**
//      * Checks if the given element is aspect
//      *
//      * @param element Instance of PSI element
//      * @return true if element is aspect or false
//      */
//     public static boolean isAspect(PsiElement element) {
//         if (!(element instanceof PhpClass)) {
//             return false;
//         }
// 
//         String[] interfaceNames = ((PhpClass) element).getInterfaceNames();
//         for (String interfaceName : interfaceNames) {
//             if (interfaceName.equals("\\Go\\Aop\\Aspect")) {
//                 return true;
//             }
//         }
// 
//         return false;
//     }
// }


import com.aopphp.go.util.PluginUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ReflectionUtil;
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.documentation.phpdoc.psi.PhpDocComment;
import com.jetbrains.php.lang.documentation.phpdoc.psi.tags.PhpDocTag;
import com.jetbrains.php.lang.psi.PhpFile;
import com.jetbrains.php.lang.psi.elements.PhpNamedElement;
import com.jetbrains.php.lang.psi.stubs.indexes.PhpConstantNameIndex;
import com.jetbrains.php.lang.psi.stubs.indexes.StringSetDataExternalizer;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
package com.aopphp.go.index;



/**
 * This index collects all annotated elements in the files
 */
public class AnnotatedPhpNamedElementIndex extends FileBasedIndexExtension<String, Set<String>> {

    public static final ID<String, Set<String>> KEY = ID.create("com.aopphp.go.annotated.elements");
    private static final KeyDescriptor<String> ENUMERATOR_STRING_DESCRIPTOR = new EnumeratorStringDescriptor();
    private static final StringSetDataExternalizer STRING_SET_DATA_EXTERNALIZER = ReflectionUtil.newInstance(StringSetDataExternalizer.class);

    @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) {
                PsiFile psiFile = inputData.getPsiFile();
                if(!(psiFile instanceof PhpFile)) {
                    return Collections.emptyMap();
                }

                return new AbstractDataIndexer<Set<String>>((PhpFile) psiFile) {

                    private Map<String, String> fileImports;

                    @Override
                    protected void visitPhpDocTag(final PhpDocTag phpDocTag, final Map<String, Set<String>> map) {
                        if (fileImports == null) {
// Path: src/com/aopphp/go/util/PluginUtil.java
// public class PluginUtil {
// 
//     /**
//      * Returns a map with php use imports
//      *
//      * @param psiFile Instance of file, should be PHP
//      * @return Mapping of short names to the FQN
//      */
//     public static Map<String, String> getFileUseImports(PsiFile psiFile) {
// 
//         // search for use alias in local file
//         final Map<String, String> useImports = new HashMap<String, String>();
// 
//         if (psiFile instanceof PhpFile) {
//             for (final PhpNamedElement element : ((PhpFile) psiFile).getTopLevelDefs().values()) {
//                 if (element instanceof PhpUse) {
//                     final PhpUse phpUse = (PhpUse) element;
//                     String alias = phpUse.getAliasName();
//                     if(alias != null) {
//                         useImports.put(alias, phpUse.getFQN());
//                     } else {
//                         useImports.put(phpUse.getName(), phpUse.getFQN());
//                     }
//                 }
//             }
//         }
// 
//         return useImports;
//     }
// 
// 
//     @Nullable
//     public static String getClassNameReference(PhpDocTag phpDocTag) {
//         return getClassNameReference(phpDocTag, getFileUseImports(phpDocTag.getContainingFile()));
//     }
// 
//     @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;
// 
//     }
// 
//     /**
//      * Checks if the given element is aspect
//      *
//      * @param element Instance of PSI element
//      * @return true if element is aspect or false
//      */
//     public static boolean isAspect(PsiElement element) {
//         if (!(element instanceof PhpClass)) {
//             return false;
//         }
// 
//         String[] interfaceNames = ((PhpClass) element).getInterfaceNames();
//         for (String interfaceName : interfaceNames) {
//             if (interfaceName.equals("\\Go\\Aop\\Aspect")) {
//                 return true;
//             }
//         }
// 
//         return false;
//     }
// }


// Path: src/com/aopphp/go/index/AnnotatedPhpNamedElementIndex.java
import com.aopphp.go.util.PluginUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ReflectionUtil;
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.documentation.phpdoc.psi.PhpDocComment;
import com.jetbrains.php.lang.documentation.phpdoc.psi.tags.PhpDocTag;
import com.jetbrains.php.lang.psi.PhpFile;
import com.jetbrains.php.lang.psi.elements.PhpNamedElement;
import com.jetbrains.php.lang.psi.stubs.indexes.PhpConstantNameIndex;
import com.jetbrains.php.lang.psi.stubs.indexes.StringSetDataExternalizer;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.Map;
import java.util.Set;

package com.aopphp.go.index;



/**
 * This index collects all annotated elements in the files
 */
public class AnnotatedPhpNamedElementIndex extends FileBasedIndexExtension<String, Set<String>> {

    public static final ID<String, Set<String>> KEY = ID.create("com.aopphp.go.annotated.elements");
    private static final KeyDescriptor<String> ENUMERATOR_STRING_DESCRIPTOR = new EnumeratorStringDescriptor();
    private static final StringSetDataExternalizer STRING_SET_DATA_EXTERNALIZER = ReflectionUtil.newInstance(StringSetDataExternalizer.class);

    @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) {
                PsiFile psiFile = inputData.getPsiFile();
                if(!(psiFile instanceof PhpFile)) {
                    return Collections.emptyMap();
                }

                return new AbstractDataIndexer<Set<String>>((PhpFile) psiFile) {

                    private Map<String, String> fileImports;

                    @Override
                    protected void visitPhpDocTag(final PhpDocTag phpDocTag, final Map<String, Set<String>> map) {
                        if (fileImports == null) {
                            fileImports = PluginUtil.getFileUseImports(phpDocTag.getContainingFile());