private void dropUnregisteredIndices() { final Set<String> indicesToDrop = new HashSet<String>( myPreviouslyRegistered != null ? myPreviouslyRegistered.registeredIndices : Collections.<String>emptyList()); for (ID<?, ?> key : myIndices.keySet()) { indicesToDrop.remove(key.toString()); } for (String s : indicesToDrop) { FileUtil.delete(IndexInfrastructure.getIndexRootDir(ID.create(s))); } }
/** @author Eugene Zhuravlev Date: Apr 28, 2008 */ public class AntImportsIndex extends ScalarIndexExtension<Integer> { public static final ID<Integer, Void> INDEX_NAME = ID.create("ant-imports"); private static final int VERSION = 5; public static final Integer ANT_FILES_WITH_IMPORTS_KEY = new Integer(0); private static final DataIndexer<Integer, Void, FileContent> DATA_INDEXER = new DataIndexer<Integer, Void, FileContent>() { @NotNull public Map<Integer, Void> map(final FileContent inputData) { final Map<Integer, Void> map = new HashMap<Integer, Void>(); NanoXmlUtil.parse( new StringReader(inputData.getContentAsText().toString()), new NanoXmlUtil.IXMLBuilderAdapter() { private boolean isFirstElement = true; public void startElement( final String elemName, final String nsPrefix, final String nsURI, final String systemID, final int lineNr) throws Exception { if (isFirstElement) { if (!"project".equalsIgnoreCase(elemName)) { stop(); } isFirstElement = false; } else { if ("import".equalsIgnoreCase(elemName) || "include".equalsIgnoreCase(elemName)) { map.put(ANT_FILES_WITH_IMPORTS_KEY, null); stop(); } } } public void addAttribute( final String key, final String nsPrefix, final String nsURI, final String value, final String type) throws Exception { // if (myAttributes != null) { // myAttributes.add(key); // } } public void elementAttributesProcessed( final String name, final String nsPrefix, final String nsURI) throws Exception { // if (myAttributes != null) { // if (!(myAttributes.contains("name") && myAttributes.contains("default"))) { // stop(); // } // myAttributes = null; // } } }); return map; } }; private static final FileBasedIndex.InputFilter INPUT_FILTER = new FileBasedIndex.InputFilter() { public boolean acceptInput(final VirtualFile file) { return file.getFileType() instanceof XmlFileType; } }; public int getVersion() { return VERSION; } public ID<Integer, Void> getName() { return INDEX_NAME; } public DataIndexer<Integer, Void, FileContent> getIndexer() { return DATA_INDEXER; } public KeyDescriptor<Integer> getKeyDescriptor() { return EnumeratorIntegerDescriptor.INSTANCE; } public FileBasedIndex.InputFilter getInputFilter() { return INPUT_FILTER; } public boolean dependsOnFileContent() { return true; } }
public final class KotlinClassFileIndex extends ScalarIndexExtension<FqName> { private static final Logger LOG = Logger.getInstance(KotlinClassFileIndex.class); private static final int VERSION = 2; public static final ID<FqName, Void> KEY = ID.create(KotlinClassFileIndex.class.getCanonicalName()); private static final KeyDescriptor<FqName> KEY_DESCRIPTOR = new KeyDescriptor<FqName>() { @Override public void save(DataOutput out, FqName value) throws IOException { out.writeUTF(value.asString()); } @Override public FqName read(DataInput in) throws IOException { return new FqName(in.readUTF()); } @Override public int getHashCode(FqName value) { return value.asString().hashCode(); } @Override public boolean isEqual(FqName val1, FqName val2) { if (val1 == null) { return val2 == null; } return val1.equals(val1); } }; private static final FileBasedIndex.InputFilter INPUT_FILTER = new FileBasedIndex.InputFilter() { @Override public boolean acceptInput(VirtualFile file) { return file.getFileType() == StdFileTypes.CLASS; } }; public static final DataIndexer<FqName, Void, FileContent> INDEXER = new DataIndexer<FqName, Void, FileContent>() { @NotNull @Override public Map<FqName, Void> map(FileContent inputData) { try { KotlinJvmBinaryClass kotlinClass = VirtualFileFinder.SERVICE .getInstance(inputData.getProject()) .createKotlinClass(inputData.getFile()); KotlinClassHeader header = kotlinClass.getClassHeader(); if (header != null && header.getKind() != KotlinClassHeader.Kind.INCOMPATIBLE_ABI_VERSION) { return Collections.singletonMap( kotlinClass.getClassName().getFqNameForClassNameWithoutDollars(), null); } } catch (Throwable e) { LOG.warn("Error while indexing file " + inputData.getFileName(), e); } return Collections.emptyMap(); } }; @NotNull @Override public ID<FqName, Void> getName() { return KEY; } @NotNull @Override public DataIndexer<FqName, Void, FileContent> getIndexer() { return INDEXER; } @Override public KeyDescriptor<FqName> getKeyDescriptor() { return KEY_DESCRIPTOR; } @Override public FileBasedIndex.InputFilter getInputFilter() { return INPUT_FILTER; } @Override public boolean dependsOnFileContent() { return true; } @Override public int getVersion() { return VERSION; } }
public class GroovyTraitMethodsFileIndex extends SingleEntryFileBasedIndexExtension<PsiJavaFileStub> implements DataExternalizer<PsiJavaFileStub> { public static final ID<Integer, PsiJavaFileStub> INDEX_ID = ID.create("groovy.trait.methods"); public static final String HELPER_SUFFIX = "$Trait$Helper.class"; private static final Logger LOG = Logger.getInstance(GroovyTraitMethodsFileIndex.class); private final InputFilter myFilter; private final SingleEntryIndexer<PsiJavaFileStub> myIndexer; private final SerializationManagerEx mySerializer; public GroovyTraitMethodsFileIndex(@NotNull SerializationManagerEx serializer) { myFilter = new DefaultFileTypeSpecificInputFilter(JavaClassFileType.INSTANCE) { @Override public boolean acceptInput(@NotNull VirtualFile file) { return StringUtil.endsWith(file.getNameSequence(), HELPER_SUFFIX); } }; myIndexer = new SingleEntryIndexer<PsiJavaFileStub>(true) { @Override protected PsiJavaFileStub computeValue(@NotNull FileContent inputData) { return index(inputData.getFile(), inputData.getContent()); } }; mySerializer = serializer; } @NotNull @Override public ID<Integer, PsiJavaFileStub> getName() { return INDEX_ID; } @Override public int getVersion() { return ClassFileStubBuilder.STUB_VERSION; } @NotNull @Override public InputFilter getInputFilter() { return myFilter; } @NotNull @Override public SingleEntryIndexer<PsiJavaFileStub> getIndexer() { return myIndexer; } @NotNull @Override public DataExternalizer<PsiJavaFileStub> getValueExternalizer() { return this; } private static PsiJavaFileStub index(VirtualFile file, byte[] content) { try { PsiJavaFileStub root = new PsiJavaFileStubImpl("", true); new ClassReader(content) .accept(new GrTraitMethodVisitor(file, root), EMPTY_ATTRIBUTES, ClassReader.SKIP_CODE); return root; } catch (Exception e) { LOG.info(file.getPath(), e); return null; } } @Override public void save(@NotNull DataOutput out, PsiJavaFileStub value) throws IOException { BufferExposingByteArrayOutputStream buffer = new BufferExposingByteArrayOutputStream(); mySerializer.serialize(value, buffer); out.writeInt(buffer.size()); out.write(buffer.getInternalBuffer(), 0, buffer.size()); } @Override public PsiJavaFileStub read(@NotNull DataInput in) throws IOException { try { byte[] buffer = new byte[in.readInt()]; in.readFully(buffer); return (PsiJavaFileStub) mySerializer.deserialize(new ByteArrayInputStream(buffer)); } catch (SerializerNotFoundException e) { throw new IOException(e); } } private static class GrTraitMethodVisitor extends StubBuildingVisitor<VirtualFile> { public GrTraitMethodVisitor(VirtualFile file, StubElement root) { super(file, null, root, 0, null); } @Override public void visit( int version, int access, String name, String signature, String superName, String[] interfaces) { super.visit(version, access, "gr_trait_helper", null, null, null); } @Override public void visitSource(String source, String debug) {} @Override public void visitOuterClass(String owner, String name, String desc) {} @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { return null; } @Override public void visitInnerClass(String name, String outerName, String innerName, int access) {} @Nullable @Override public FieldVisitor visitField( int access, String name, String desc, String signature, Object value) { return null; } @Nullable @Override public MethodVisitor visitMethod( int access, String name, String desc, String signature, String[] exceptions) { if ((access & ACC_SYNTHETIC) == 0 && (access & ACC_STATIC) != 0 && name != null) { Type[] args = Type.getArgumentTypes(desc); if (args.length > 0 && args[0].getSort() == Type.OBJECT && CommonClassNames.JAVA_LANG_CLASS.equals(args[0].getClassName())) { return super.visitMethod(access, name, desc, signature, exceptions); } } return null; } } }
/** @author Eugene Zhuravlev Date: Jan 16, 2008 */ public class IdIndex extends FileBasedIndexExtension<IdIndexEntry, Integer> { @NonNls public static final ID<IdIndexEntry, Integer> NAME = ID.create("IdIndex"); private final FileBasedIndex.InputFilter myInputFilter = new FileBasedIndex.InputFilter() { @Override public boolean acceptInput(final VirtualFile file) { final FileType fileType = file.getFileType(); return isIndexable(fileType) && !ProjectUtil.isProjectOrWorkspaceFile(file, fileType); } }; private final DataExternalizer<Integer> myValueExternalizer = new DataExternalizer<Integer>() { @Override public void save(final DataOutput out, final Integer value) throws IOException { out.writeByte(value.intValue()); } @Override public Integer read(final DataInput in) throws IOException { return Integer.valueOf(in.readByte()); } }; private final KeyDescriptor<IdIndexEntry> myKeyDescriptor = new InlineKeyDescriptor<IdIndexEntry>() { @Override public IdIndexEntry fromInt(int n) { return new IdIndexEntry(n); } @Override public int toInt(IdIndexEntry idIndexEntry) { return idIndexEntry.getWordHashCode(); } }; private final DataIndexer<IdIndexEntry, Integer, FileContent> myIndexer = new DataIndexer<IdIndexEntry, Integer, FileContent>() { @Override @NotNull public Map<IdIndexEntry, Integer> map(final FileContent inputData) { final FileTypeIdIndexer indexer = IdTableBuilding.getFileTypeIndexer(inputData.getFileType()); if (indexer != null) { return indexer.map(inputData); } return Collections.emptyMap(); } }; @Override public int getVersion() { return 9; // TODO: version should enumerate all word scanner versions and build version upon // that set } @Override public boolean dependsOnFileContent() { return true; } @NotNull @Override public ID<IdIndexEntry, Integer> getName() { return NAME; } @NotNull @Override public DataIndexer<IdIndexEntry, Integer, FileContent> getIndexer() { return myIndexer; } @Override public DataExternalizer<Integer> getValueExternalizer() { return myValueExternalizer; } @Override public KeyDescriptor<IdIndexEntry> getKeyDescriptor() { return myKeyDescriptor; } @Override public FileBasedIndex.InputFilter getInputFilter() { return myInputFilter; } private static boolean isIndexable(FileType fileType) { return fileType instanceof LanguageFileType || fileType instanceof CustomSyntaxTableFileType || IdTableBuilding.isIdIndexerRegistered(fileType) || CacheBuilderRegistry.getInstance().getCacheBuilder(fileType) != null; } }
public class JavaFxControllerClassIndex extends ScalarIndexExtension<String> { @NonNls public static final ID<String, Void> NAME = ID.create("JavaFxControllerClassIndex"); private final EnumeratorStringDescriptor myKeyDescriptor = new EnumeratorStringDescriptor(); private final MyInputFilter myInputFilter = new MyInputFilter(); private final MyDataIndexer myDataIndexer = new MyDataIndexer(); @Override @NotNull public ID<String, Void> getName() { return NAME; } @Override @NotNull public DataIndexer<String, Void, FileContent> getIndexer() { return myDataIndexer; } @Override public KeyDescriptor<String> getKeyDescriptor() { return myKeyDescriptor; } @Override public FileBasedIndex.InputFilter getInputFilter() { return myInputFilter; } @Override public boolean dependsOnFileContent() { return true; } @Override public int getVersion() { return 0; } private static class MyDataIndexer implements DataIndexer<String, Void, FileContent> { private static final SAXParser SAX_PARSER = createParser(); private static SAXParser createParser() { try { return SAXParserFactory.newInstance().newSAXParser(); } catch (Exception e) { return null; } } @Override @NotNull public Map<String, Void> map(final FileContent inputData) { final String className = getControllerClassName(inputData.getContentAsText().toString()); if (className != null) { return Collections.singletonMap(className, null); } return Collections.emptyMap(); } @Nullable private static String getControllerClassName(String content) { if (!content.contains(JavaFXNamespaceProvider.JAVAFX_NAMESPACE)) { return null; } final String[] className = new String[] {null}; try { SAX_PARSER.parse( new InputSource(new StringReader(content)), new DefaultHandler() { public void startElement( String uri, String localName, String qName, Attributes attributes) throws SAXException { className[0] = attributes.getValue("", FxmlConstants.FX_CONTROLLER); throw new SAXException("controllers are accepted on top level only"); } }); } catch (Exception e) { // Do nothing. } return className[0]; } } private static class MyInputFilter implements FileBasedIndex.InputFilter { @Override public boolean acceptInput(final VirtualFile file) { return JavaFxFileTypeFactory.isFxml(file); } } public static List<PsiFile> findFxmlWithController(final Project project, String className) { return findFxmlWithController( project, className, new Function<VirtualFile, PsiFile>() { @Override public PsiFile fun(VirtualFile file) { return PsiManager.getInstance(project).findFile(file); } }, ProjectScope.getAllScope(project)); } public static List<VirtualFile> findFxmlsWithController( final Project project, @NotNull String className) { return findFxmlWithController( project, className, Function.ID, ProjectScope.getAllScope(project)); } public static <T> List<T> findFxmlWithController( final Project project, final String className, final Function<VirtualFile, T> f, final GlobalSearchScope scope) { return ApplicationManager.getApplication() .runReadAction( new Computable<List<T>>() { @Override public List<T> compute() { final Collection<VirtualFile> files; try { files = FileBasedIndex.getInstance() .getContainingFiles( NAME, className, GlobalSearchScope.projectScope(project).intersectWith(scope)); } catch (IndexNotReadyException e) { return Collections.emptyList(); } if (files.isEmpty()) return Collections.emptyList(); List<T> result = new ArrayList<T>(); for (VirtualFile file : files) { if (!file.isValid()) continue; final T fFile = f.fun(file); if (fFile != null) { result.add(fFile); } } return result; } }); } }
/** Indexes .mps files and makes an index model->List <SNodeDescriptor> */ public class RootNodeNameIndex extends SingleEntryFileBasedIndexExtension<List<SNodeDescriptor>> { @NonNls public static final ID<Integer, List<SNodeDescriptor>> NAME = ID.create("RootNodeNameIndex2"); private static final Logger LOG = LogManager.getLogger(RootNodeNameIndex.class); private static final Key<SModel> PARSED_MODEL = new Key<SModel>("parsed-model"); public static SModel doModelParsing(FileContent inputData) { SModel model = inputData.getUserData(PARSED_MODEL); if (model == null) { String ext = FileUtil.getExtension(inputData.getFileName()); if (MPSFileTypeFactory.MPS_ROOT_FILE_TYPE.equals(inputData.getFile().getFileType())) { ext = MPSFileTypeFactory.MPS_HEADER_FILE_TYPE.getDefaultExtension(); } ModelFactory factory = PersistenceFacade.getInstance().getModelFactory(ext); if (factory == null) { return null; } if (factory instanceof FolderModelFactory) { model = PersistenceUtil.loadModel( VirtualFileUtils.toIFile( MPSFileTypeFactory.MPS_ROOT_FILE_TYPE.equals(inputData.getFile().getFileType()) ? inputData.getFile().getParent().findChild(MPSExtentions.DOT_MODEL_HEADER) : inputData.getFile())); } else { model = factory.isBinary() ? PersistenceUtil.loadModel(inputData.getContent(), ext) : PersistenceUtil.loadModel(inputData.getContentAsText().toString(), ext); } if (model == null) { return null; } inputData.putUserData(PARSED_MODEL, model); } return model; } @Override @NotNull public ID<Integer, List<SNodeDescriptor>> getName() { return NAME; } public static Iterable<SNode> getRootsToIterate(SModel model) { if (SModelStereotype.isStubModelStereotype( jetbrains.mps.util.SNodeOperations.getModelStereotype(model))) return new EmptyIterable<SNode>(); return new ConditionalIterable<SNode>(model.getRootNodes(), new MyCondition()); } @Override public DataExternalizer<List<SNodeDescriptor>> getValueExternalizer() { return new SNodeDescriptorListEnumerator(); } @NotNull @Override public SingleEntryIndexer<List<SNodeDescriptor>> getIndexer() { return new MyIndexer(); } @Override public InputFilter getInputFilter() { return new MyInputFilter(); } @Override public boolean dependsOnFileContent() { return true; } @Override public int getVersion() { return 6; } @Override public int getCacheSize() { return DEFAULT_CACHE_SIZE; } private static class MyCondition implements Condition<SNode> { @Override public boolean met(SNode node) { return !node.getNodeId().toString().contains("$"); } } private static class MyInputFilter implements FileBasedIndex.InputFilter { @Override public boolean acceptInput(VirtualFile file) { FileType fileType = file.getFileType(); return MPSFileTypeFactory.MPS_FILE_TYPE.equals(fileType) || MPSFileTypeFactory.MPS_BINARY_FILE_TYPE.equals(fileType); } } private class MyIndexer extends SingleEntryIndexer<List<SNodeDescriptor>> { private MyIndexer() { super(false); } @Override protected List<SNodeDescriptor> computeValue(@NotNull final FileContent inputData) { final List<SNodeDescriptor> descriptors = new ArrayList<SNodeDescriptor>(); ModelAccess.instance() .runIndexing( new Runnable() { @Override public void run() { try { SModel model = doModelParsing(inputData); for (final SNode node : getRootsToIterate(model)) { String persistentName = node.getProperty(SNodeUtil.property_INamedConcept_name); String nodeName = (persistentName == null) ? "null" : persistentName; String conceptFqName = node.getConcept().getQualifiedName(); SModelReference modelRef = model.getReference(); SNodeId id = node.getNodeId(); SNodeDescriptor value = SNodeDescriptor.fromModelReference(nodeName, conceptFqName, modelRef, id); descriptors.add(value); } } catch (Exception e) { LOG.error( "Cannot index model file " + inputData.getFileName() + "; " + e.getMessage()); } } }); return descriptors; } } }
/** @author Eugene Zhuravlev Date: Jan 20, 2008 */ public class TodoIndex extends FileBasedIndexExtension<TodoIndexEntry, Integer> { @NonNls public static final ID<TodoIndexEntry, Integer> NAME = ID.create("TodoIndex"); public TodoIndex(MessageBus messageBus) { messageBus .connect() .subscribe( IndexPatternProvider.INDEX_PATTERNS_CHANGED, new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { FileBasedIndex.requestRebuild(NAME); } }); } private final KeyDescriptor<TodoIndexEntry> myKeyDescriptor = new KeyDescriptor<TodoIndexEntry>() { @Override public int getHashCode(final TodoIndexEntry value) { return value.hashCode(); } @Override public boolean isEqual(final TodoIndexEntry val1, final TodoIndexEntry val2) { return val1.equals(val2); } @Override public void save(final DataOutput out, final TodoIndexEntry value) throws IOException { out.writeUTF(value.pattern); out.writeBoolean(value.caseSensitive); } @Override public TodoIndexEntry read(final DataInput in) throws IOException { final String pattern = in.readUTF(); final boolean caseSensitive = in.readBoolean(); return new TodoIndexEntry(pattern, caseSensitive); } }; private final DataExternalizer<Integer> myValueExternalizer = new DataExternalizer<Integer>() { @Override public void save(final DataOutput out, final Integer value) throws IOException { out.writeInt(value.intValue()); } @Override public Integer read(final DataInput in) throws IOException { return Integer.valueOf(in.readInt()); } }; private final DataIndexer<TodoIndexEntry, Integer, FileContent> myIndexer = new DataIndexer<TodoIndexEntry, Integer, FileContent>() { @Override @NotNull public Map<TodoIndexEntry, Integer> map(final FileContent inputData) { final VirtualFile file = inputData.getFile(); final DataIndexer<TodoIndexEntry, Integer, FileContent> indexer = IdTableBuilding.getTodoIndexer(inputData.getFileType(), file); if (indexer != null) { return indexer.map(inputData); } return Collections.emptyMap(); } }; private final FileBasedIndex.InputFilter myInputFilter = new FileBasedIndex.InputFilter() { @Override public boolean acceptInput(final VirtualFile file) { if (!(file.getFileSystem() instanceof LocalFileSystem)) { return false; // do not index TODOs in library sources } final FileType fileType = file.getFileType(); if (ProjectUtil.isProjectOrWorkspaceFile(file, fileType)) { return false; } if (fileType instanceof LanguageFileType) { final Language lang = ((LanguageFileType) fileType).getLanguage(); final ParserDefinition parserDef = LanguageParserDefinitions.INSTANCE.forLanguage(lang); final TokenSet commentTokens = parserDef != null ? parserDef.getCommentTokens() : null; return commentTokens != null; } return IdTableBuilding.isTodoIndexerRegistered(fileType) || fileType instanceof AbstractFileType; } }; @Override public int getVersion() { return 4; } @Override public boolean dependsOnFileContent() { return true; } @NotNull @Override public ID<TodoIndexEntry, Integer> getName() { return NAME; } @NotNull @Override public DataIndexer<TodoIndexEntry, Integer, FileContent> getIndexer() { return myIndexer; } @Override public KeyDescriptor<TodoIndexEntry> getKeyDescriptor() { return myKeyDescriptor; } @Override public DataExternalizer<Integer> getValueExternalizer() { return myValueExternalizer; } @Override public FileBasedIndex.InputFilter getInputFilter() { return myInputFilter; } }
/** @author Alexei Vasin */ public class IniDirectiveIndex extends ScalarIndexExtension<String> { private static final Logger LOG = Logger.getInstance("#ini4idea.lang.psi.IniDirectiveIndex"); @NonNls public static final ID<String, Void> NAME = ID.create("IniDirectiveIndex"); private final EnumeratorStringDescriptor myKeyDescriptor = new EnumeratorStringDescriptor(); private final MyInputFilter myInputFilter = new MyInputFilter(); private final MyDataIndexer myDataIndexer = new MyDataIndexer(); @NotNull @Override public ID<String, Void> getName() { return NAME; } @NotNull @Override public DataIndexer<String, Void, FileContent> getIndexer() { return myDataIndexer; } @NotNull @Override public KeyDescriptor<String> getKeyDescriptor() { return myKeyDescriptor; } @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return myInputFilter; } @Override public boolean dependsOnFileContent() { return true; } @Override public int getVersion() { return 1; } private static class MyDataIndexer implements DataIndexer<String, Void, FileContent> { @Override @NotNull public Map<String, Void> map(@NotNull final FileContent inputData) { String className; Map<String, Void> result = new HashMap<String, Void>(); try { className = inputData.getContentAsText().toString(); String a[] = className.split("\n"); for (String s : a) { if (s.contains("=")) { result.put(s.substring(0, s.indexOf("=")), null); } } } catch (Exception e) { // ignore LOG.error(e.toString()); } return result; /* if (className != null) { return Collections.singletonMap(className, null); } */ // return Collections.emptyMap(); } } private static class MyInputFilter implements FileBasedIndex.InputFilter { @Override public boolean acceptInput(@NotNull final VirtualFile file) { return file.getFileType() == IniFileType.INSTANCE; } } /* public static Collection<NavigationItem> getItemsByName(final String name, Project project) { Collection<VirtualFile> files = FileBasedIndex.getInstance().getContainingFiles(NAME, name, GlobalSearchScope.projectScope(project)); final Collection<NavigationItem> result = new ArrayList<NavigationItem>(); for (VirtualFile vFile : files) { PsiFile file = PsiManager.getInstance(project).findFile(vFile); if (!(file instanceof IniFile)) { continue; } process((IniFile)file, new Consumer<PsiElement>() { @Override public void consume(PsiElement element) { if (name.equals(getName(element))) { result.add((NavigationItem) element); } } }, true); } return result; } */ }
/* * @author max */ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtension<Integer, SerializedStubTree, FileContent> { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.stubs.StubUpdatingIndex"); public static final ID<Integer, SerializedStubTree> INDEX_ID = ID.create("Stubs"); private static final int VERSION = 20; private static final DataExternalizer<SerializedStubTree> KEY_EXTERNALIZER = new DataExternalizer<SerializedStubTree>() { @Override public void save(final DataOutput out, @NotNull final SerializedStubTree v) throws IOException { v.write(out); } @NotNull @Override public SerializedStubTree read(final DataInput in) throws IOException { return new SerializedStubTree(in); } }; private static final FileBasedIndex.InputFilter INPUT_FILTER = new FileBasedIndex.InputFilter() { @Override public boolean acceptInput(@NotNull final VirtualFile file) { return canHaveStub(file); } }; public static boolean canHaveStub(@NotNull VirtualFile file) { final FileType fileType = file.getFileType(); if (fileType instanceof LanguageFileType) { Language l = ((LanguageFileType) fileType).getLanguage(); ParserDefinition parserDefinition = LanguageParserDefinitions.INSTANCE.forLanguage(l); if (parserDefinition == null) return false; final IFileElementType elementType = parserDefinition.getFileNodeType(); return elementType instanceof IStubFileElementType && (((IStubFileElementType) elementType).shouldBuildStubFor(file) || IndexingStamp.isFileIndexed( file, INDEX_ID, IndexInfrastructure.getIndexCreationStamp(INDEX_ID))); } if (fileType.isBinary()) { final BinaryFileStubBuilder builder = BinaryFileStubBuilders.INSTANCE.forFileType(fileType); return builder != null && builder.acceptsFile(file); } return false; } private static final KeyDescriptor<Integer> DATA_DESCRIPTOR = new IntInlineKeyDescriptor(); @NotNull @Override public ID<Integer, SerializedStubTree> getName() { return INDEX_ID; } @Override public int getCacheSize() { return 5; // no need to cache many serialized trees } @Override public boolean isKeyHighlySelective() { return true; } @NotNull @Override public DataIndexer<Integer, SerializedStubTree, FileContent> getIndexer() { return new DataIndexer<Integer, SerializedStubTree, FileContent>() { @Override @NotNull public Map<Integer, SerializedStubTree> map(@NotNull final FileContent inputData) { final Map<Integer, SerializedStubTree> result = new HashMap<Integer, SerializedStubTree>(); ApplicationManager.getApplication() .runReadAction( new Runnable() { @Override public void run() { final StubElement rootStub = StubTreeBuilder.buildStubTree(inputData); if (rootStub == null) return; final BufferExposingByteArrayOutputStream bytes = new BufferExposingByteArrayOutputStream(); SerializationManagerEx.getInstanceEx().serialize(rootStub, bytes); final int key = Math.abs(FileBasedIndex.getFileId(inputData.getFile())); result.put( key, new SerializedStubTree(bytes.getInternalBuffer(), bytes.size(), rootStub)); } }); return result; } }; } @NotNull @Override public KeyDescriptor<Integer> getKeyDescriptor() { return DATA_DESCRIPTOR; } @NotNull @Override public DataExternalizer<SerializedStubTree> getValueExternalizer() { return KEY_EXTERNALIZER; } @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return INPUT_FILTER; } @Override public boolean dependsOnFileContent() { return true; } @Override public int getVersion() { return getCumulativeVersion(); } private static int getCumulativeVersion() { int version = VERSION; for (final FileType fileType : FileTypeManager.getInstance().getRegisteredFileTypes()) { if (fileType instanceof LanguageFileType) { Language l = ((LanguageFileType) fileType).getLanguage(); ParserDefinition parserDefinition = LanguageParserDefinitions.INSTANCE.forLanguage(l); if (parserDefinition != null) { final IFileElementType type = parserDefinition.getFileNodeType(); if (type instanceof IStubFileElementType) { version += ((IStubFileElementType) type).getStubVersion(); } } } else if (fileType.isBinary()) { final BinaryFileStubBuilder builder = BinaryFileStubBuilders.INSTANCE.forFileType(fileType); if (builder != null) { version += builder.getStubVersion(); } } } return version; } @NotNull @Override public UpdatableIndex<Integer, SerializedStubTree, FileContent> createIndexImplementation( final ID<Integer, SerializedStubTree> indexId, @NotNull final FileBasedIndex owner, @NotNull IndexStorage<Integer, SerializedStubTree> storage) throws StorageException { if (storage instanceof MemoryIndexStorage) { final MemoryIndexStorage<Integer, SerializedStubTree> memStorage = (MemoryIndexStorage<Integer, SerializedStubTree>) storage; memStorage.addBufferingStateListsner( new MemoryIndexStorage.BufferingStateListener() { @Override public void bufferingStateChanged(final boolean newState) { ((StubIndexImpl) StubIndexImpl.getInstance()).setDataBufferingEnabled(newState); } @Override public void memoryStorageCleared() { ((StubIndexImpl) StubIndexImpl.getInstance()).cleanupMemoryStorage(); } }); } return new MyIndex(indexId, storage, getIndexer()); } private static void updateStubIndices( @NotNull final Collection<StubIndexKey> indexKeys, final int inputId, @NotNull final Map<StubIndexKey, Map<Object, int[]>> oldStubTree, @NotNull final Map<StubIndexKey, Map<Object, int[]>> newStubTree) { final StubIndexImpl stubIndex = (StubIndexImpl) StubIndex.getInstance(); for (StubIndexKey key : indexKeys) { final Map<Object, int[]> oldMap = oldStubTree.get(key); final Map<Object, int[]> newMap = newStubTree.get(key); final Map<Object, int[]> _oldMap = oldMap != null ? oldMap : Collections.<Object, int[]>emptyMap(); final Map<Object, int[]> _newMap = newMap != null ? newMap : Collections.<Object, int[]>emptyMap(); stubIndex.updateIndex(key, inputId, _oldMap, _newMap); } } @NotNull private static Collection<StubIndexKey> getAffectedIndices( @NotNull final Map<StubIndexKey, Map<Object, int[]>> oldStubTree, @NotNull final Map<StubIndexKey, Map<Object, int[]>> newStubTree) { Set<StubIndexKey> allIndices = new HashSet<StubIndexKey>(); allIndices.addAll(oldStubTree.keySet()); allIndices.addAll(newStubTree.keySet()); return allIndices; } private static class MyIndex extends MapReduceIndex<Integer, SerializedStubTree, FileContent> { private StubIndexImpl myStubIndex; public MyIndex( final ID<Integer, SerializedStubTree> indexId, final IndexStorage<Integer, SerializedStubTree> storage, final DataIndexer<Integer, SerializedStubTree, FileContent> indexer) throws StorageException { super(indexId, indexer, storage); checkNameStorage(); } @Override public void flush() throws StorageException { final StubIndexImpl stubIndex = getStubIndex(); try { for (StubIndexKey key : stubIndex.getAllStubIndexKeys()) { stubIndex.flush(key); } } finally { super.flush(); } } @Override protected void updateWithMap( final int inputId, @NotNull final Map<Integer, SerializedStubTree> newData, @NotNull Callable<Collection<Integer>> oldKeysGetter) throws StorageException { checkNameStorage(); final Map<StubIndexKey, Map<Object, int[]>> newStubTree = getStubTree(newData); final StubIndexImpl stubIndex = getStubIndex(); final Collection<StubIndexKey> allStubIndices = stubIndex.getAllStubIndexKeys(); try { // first write-lock affected stub indices to avoid deadlocks for (StubIndexKey key : allStubIndices) { stubIndex.getWriteLock(key).lock(); } try { getWriteLock().lock(); final Map<Integer, SerializedStubTree> oldData = readOldData(inputId); final Map<StubIndexKey, Map<Object, int[]>> oldStubTree = getStubTree(oldData); super.updateWithMap(inputId, newData, oldKeysGetter); updateStubIndices( getAffectedIndices(oldStubTree, newStubTree), inputId, oldStubTree, newStubTree); } finally { getWriteLock().unlock(); } } finally { for (StubIndexKey key : allStubIndices) { stubIndex.getWriteLock(key).unlock(); } } } private StubIndexImpl getStubIndex() { StubIndexImpl index = myStubIndex; if (index == null) { index = myStubIndex = (StubIndexImpl) StubIndex.getInstance(); } return index; } private static void checkNameStorage() throws StorageException { final SerializationManagerEx serializationManager = SerializationManagerEx.getInstanceEx(); if (serializationManager.isNameStorageCorrupted()) { serializationManager.repairNameStorage(); //noinspection ThrowFromFinallyBlock throw new StorageException("NameStorage for stubs serialization has been corrupted"); } } private static Map<StubIndexKey, Map<Object, int[]>> getStubTree( @NotNull final Map<Integer, SerializedStubTree> data) { final Map<StubIndexKey, Map<Object, int[]>> stubTree; if (!data.isEmpty()) { final SerializedStubTree stub = data.values().iterator().next(); stubTree = new StubTree((PsiFileStub) stub.getStub(true), false).indexStubTree(); } else { stubTree = Collections.emptyMap(); } return stubTree; } /*MUST be called under the WriteLock*/ @NotNull private Map<Integer, SerializedStubTree> readOldData(final int key) throws StorageException { final Map<Integer, SerializedStubTree> result = new HashMap<Integer, SerializedStubTree>(); IndexStorage<Integer, SerializedStubTree> indexStorage = myStorage; if (indexStorage instanceof MemoryIndexStorage) { final MemoryIndexStorage<Integer, SerializedStubTree> memIndexStorage = (MemoryIndexStorage<Integer, SerializedStubTree>) indexStorage; if (!memIndexStorage.isBufferingEnabled()) { // if buffering is not enabled, use backend storage to make sure // the returned stub tree contains no data corresponding to unsaved documents. // This will ensure that correct set of old keys is used for update indexStorage = memIndexStorage.getBackendStorage(); } } try { final ValueContainer<SerializedStubTree> valueContainer = indexStorage.read(key); if (valueContainer.size() != 1) { LOG.assertTrue(valueContainer.size() == 0); return result; } result.put(key, valueContainer.getValueIterator().next()); return result; } catch (RuntimeException e) { final Throwable cause = e.getCause(); if (cause instanceof IOException) { throw new StorageException(cause); } throw e; } } @Override public void clear() throws StorageException { final StubIndexImpl stubIndex = StubIndexImpl.getInstanceOrInvalidate(); final Collection<StubIndexKey> allStubIndexKeys = stubIndex != null ? stubIndex.getAllStubIndexKeys() : Collections.<StubIndexKey>emptyList(); try { for (StubIndexKey key : allStubIndexKeys) { //noinspection ConstantConditions stubIndex.getWriteLock(key).lock(); } getWriteLock().lock(); if (stubIndex != null) { stubIndex.clearAllIndices(); } super.clear(); } finally { getWriteLock().unlock(); for (StubIndexKey key : allStubIndexKeys) { //noinspection ConstantConditions stubIndex.getWriteLock(key).unlock(); } } } @Override public void dispose() { try { super.dispose(); } finally { getStubIndex().dispose(); } } } }
/** @author vlan */ public class PyModuleNameIndex extends ScalarIndexExtension<String> { public static final ID<String, Void> NAME = ID.create("Py.module.name"); private final EnumeratorStringDescriptor myKeyDescriptor = new EnumeratorStringDescriptor(); private final DataIndexer<String, Void, FileContent> myDataIndexer = new DataIndexer<String, Void, FileContent>() { @NotNull @Override public Map<String, Void> map(@NotNull FileContent inputData) { final VirtualFile file = inputData.getFile(); final String name = file.getName(); if (PyNames.INIT_DOT_PY.equals(name)) { final VirtualFile parent = file.getParent(); if (parent != null && parent.isDirectory()) { return Collections.singletonMap(parent.getName(), null); } } else { return Collections.singletonMap(FileUtil.getNameWithoutExtension(name), null); } return Collections.emptyMap(); } }; @NotNull @Override public ID<String, Void> getName() { return NAME; } @NotNull @Override public DataIndexer<String, Void, FileContent> getIndexer() { return myDataIndexer; } @NotNull @Override public KeyDescriptor<String> getKeyDescriptor() { return myKeyDescriptor; } @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return new DefaultFileTypeSpecificInputFilter(PythonFileType.INSTANCE); } @Override public boolean dependsOnFileContent() { return true; } @Override public int getVersion() { return 0; } @NotNull public static Collection<String> getAllKeys(@NotNull Project project) { return FileBasedIndex.getInstance().getAllKeys(NAME, project); } @NotNull public static List<PyFile> find( @NotNull String name, @NotNull Project project, boolean includeNonProjectItems) { final List<PyFile> results = new ArrayList<PyFile>(); final GlobalSearchScope scope = includeNonProjectItems ? PyProjectScopeBuilder.excludeSdkTestsScope(project) : GlobalSearchScope.projectScope(project); final Collection<VirtualFile> files = FileBasedIndex.getInstance().getContainingFiles(NAME, name, scope); for (VirtualFile virtualFile : files) { final PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile); if (psiFile instanceof PyFile) { if (!PyUserSkeletonsUtil.isUnderUserSkeletonsDirectory(psiFile)) { results.add((PyFile) psiFile); } } } return results; } }
public static <K, V> ID<K, V> generateIndexId(final String indexName, final Project project) { return ID.create( String.format( "compilerOutputIndex.%s.%d", indexName, Math.abs(project.getBasePath().hashCode()))); }
public class JavaFxControllerClassIndex extends ScalarIndexExtension<String> { @NonNls public static final ID<String, Void> NAME = ID.create("JavaFxControllerClassIndex"); private final EnumeratorStringDescriptor myKeyDescriptor = new EnumeratorStringDescriptor(); private final MyInputFilter myInputFilter = new MyInputFilter(); private final MyDataIndexer myDataIndexer = new MyDataIndexer(); @Override @NotNull public ID<String, Void> getName() { return NAME; } @Override @NotNull public DataIndexer<String, Void, FileContent> getIndexer() { return myDataIndexer; } @NotNull @Override public KeyDescriptor<String> getKeyDescriptor() { return myKeyDescriptor; } @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return myInputFilter; } @Override public boolean dependsOnFileContent() { return true; } @Override public int getVersion() { return 1; } private static class MyDataIndexer implements DataIndexer<String, Void, FileContent> { @Override @NotNull public Map<String, Void> map(@NotNull final FileContent inputData) { final String className = getControllerClassName(inputData.getContentAsText().toString()); if (className != null) { return Collections.singletonMap(className, null); } return Collections.emptyMap(); } @Nullable private static String getControllerClassName(String content) { if (!content.contains(JavaFxNamespaceDataProvider.JAVAFX_NAMESPACE)) { return null; } final String[] className = new String[] {null}; class StopException extends RuntimeException {} try { NanoXmlUtil.parse( new StringReader(content), new NanoXmlUtil.IXMLBuilderAdapter() { private boolean myFxRootUsed = false; @Override public void addAttribute( String key, String nsPrefix, String nsURI, String value, String type) throws Exception { if (value != null && (FxmlConstants.FX_CONTROLLER.equals(nsPrefix + ":" + key) || FxmlConstants.TYPE.equals(key) && myFxRootUsed)) { className[0] = value; } } @Override public void elementAttributesProcessed(String name, String nsPrefix, String nsURI) throws Exception { throw new StopException(); } @Override public void startElement( String name, String nsPrefix, String nsURI, String systemID, int lineNr) throws Exception { myFxRootUsed = FxmlConstants.FX_ROOT.equals(nsPrefix + ":" + name); } }); } catch (StopException ignore) { } return className[0]; } } public static class MyInputFilter extends DefaultFileTypeSpecificInputFilter { public MyInputFilter() { super(StdFileTypes.XML); } @Override public boolean acceptInput(@NotNull final VirtualFile file) { return JavaFxFileTypeFactory.isFxml(file); } } public static List<PsiFile> findFxmlWithController( final Project project, @NotNull String className) { return findFxmlWithController( project, className, new Function<VirtualFile, PsiFile>() { @Override public PsiFile fun(VirtualFile file) { return PsiManager.getInstance(project).findFile(file); } }, ProjectScope.getAllScope(project)); } public static List<VirtualFile> findFxmlsWithController( final Project project, @NotNull String className) { return findFxmlWithController( project, className, Function.ID, ProjectScope.getAllScope(project)); } public static <T> List<T> findFxmlWithController( final Project project, @NotNull final String className, final Function<VirtualFile, T> f, final GlobalSearchScope scope) { return ApplicationManager.getApplication() .runReadAction( new Computable<List<T>>() { @Override public List<T> compute() { final Collection<VirtualFile> files; try { files = FileBasedIndex.getInstance() .getContainingFiles( NAME, className, GlobalSearchScope.projectScope(project).intersectWith(scope)); } catch (IndexNotReadyException e) { return Collections.emptyList(); } if (files.isEmpty()) return Collections.emptyList(); List<T> result = new ArrayList<T>(); for (VirtualFile file : files) { if (!file.isValid()) continue; final T fFile = f.fun(file); if (fFile != null) { result.add(fFile); } } return result; } }); } }
/** @author spleaner */ public class HtmlLinkTagIndex extends SingleEntryFileBasedIndexExtension< HtmlLinkTagIndex.InfoHolder<HtmlLinkTagIndex.LinkInfo>> { public static final ID<Integer, InfoHolder<LinkInfo>> INDEX_ID = ID.create("HtmlLinkTagIndex"); @NonNls private static final String LINK = "link"; @NonNls private static final String HREF_ATTR = "href"; @NonNls private static final String MEDIA_ATTR = "media"; @NonNls private static final String REL_ATTR = "rel"; @NonNls private static final String TITLE_ATTR = "title"; @NonNls private static final String TYPE_ATTR = "type"; private final FileBasedIndex.InputFilter myInputFilter = new FileBasedIndex.InputFilter() { public boolean acceptInput(final VirtualFile file) { if (!(file.getFileSystem() instanceof LocalFileSystem)) { return false; } final FileType fileType = file.getFileType(); if (!(fileType instanceof LanguageFileType)) { return false; } final LanguageFileType languageFileType = (LanguageFileType) fileType; final Language language = languageFileType.getLanguage(); return language instanceof TemplateLanguage || (language instanceof XMLLanguage && language != XMLLanguage.INSTANCE); } }; private final DataExternalizer<InfoHolder<LinkInfo>> myValueExternalizer = new DataExternalizer<InfoHolder<LinkInfo>>() { public void save(DataOutput out, InfoHolder<LinkInfo> value) throws IOException { out.writeInt(value.myValues.length); for (final LinkInfo linkInfo : value.myValues) { out.writeInt(linkInfo.offset); out.writeBoolean(linkInfo.scripted); if (!linkInfo.scripted) { writeString(linkInfo.value, out); } writeString(linkInfo.media, out); writeString(linkInfo.type, out); writeString(linkInfo.rel, out); writeString(linkInfo.title, out); } } private void writeString(String s, DataOutput out) throws IOException { out.writeBoolean(s != null); if (s != null) { out.writeUTF(s); } } public InfoHolder<LinkInfo> read(DataInput in) throws IOException { final int size = in.readInt(); final List<LinkInfo> list = new ArrayList<LinkInfo>(size); for (int i = 0; i < size; i++) { final int offset = in.readInt(); final boolean scripted = in.readBoolean(); final String href = !scripted ? (in.readBoolean() ? in.readUTF() : null) : null; final String media = in.readBoolean() ? in.readUTF() : null; final String type = in.readBoolean() ? in.readUTF() : null; final String rel = in.readBoolean() ? in.readUTF() : null; final String title = in.readBoolean() ? in.readUTF() : null; list.add(new LinkInfo(offset, scripted, href, media, type, rel, title)); } return new InfoHolder<LinkInfo>(list.toArray(new LinkInfo[list.size()])); } }; public ID<Integer, InfoHolder<LinkInfo>> getName() { return INDEX_ID; } public interface LinkReferenceResult { @Nullable PsiFile getReferencedFile(); @Nullable PsiFile resolve(); boolean isScriptedReference(); @Nullable String getMediaValue(); @Nullable String getRelValue(); @Nullable String getTitleValue(); } @NotNull public static List<LinkReferenceResult> getReferencedFiles( @NotNull final VirtualFile _file, @NotNull final Project project) { final List<LinkReferenceResult> result = new ArrayList<LinkReferenceResult>(); if (!(_file.getFileSystem() instanceof LocalFileSystem)) { return result; } FileBasedIndex.getInstance() .processValues( INDEX_ID, FileBasedIndex.getFileId(_file), null, new FileBasedIndex.ValueProcessor<InfoHolder<LinkInfo>>() { public boolean process(final VirtualFile file, final InfoHolder<LinkInfo> value) { final PsiManager psiManager = PsiManager.getInstance(project); final PsiFile psiFile = psiManager.findFile(file); if (psiFile != null) { for (final LinkInfo linkInfo : value.myValues) { if (linkInfo.value != null || linkInfo.scripted) { final PsiFileSystemItem[] item = new PsiFileSystemItem[] {null}; if (linkInfo.value != null) { final LeafElement newValueElement = Factory.createSingleLeafElement( XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN, "\"" + linkInfo.value + "\"", 0, linkInfo.value.length() + 2, null, psiManager, psiFile); final PsiElement element = newValueElement.getPsi(); final FileReferenceSet set = new FileReferenceSet( StringUtil.stripQuotesAroundValue(element.getText()), element, 1, null, true); final FileReference lastReference = set.getLastReference(); if (lastReference != null) { final PsiFileSystemItem resolved = lastReference.resolve(); if (resolved instanceof PsiFile) { item[0] = resolved; } } } result.add(new MyLinkReferenceResult(item, linkInfo, psiFile)); } } } return true; } }, GlobalSearchScope.allScope(project)); return result; } public SingleEntryIndexer<InfoHolder<LinkInfo>> getIndexer() { return new SingleEntryIndexer<InfoHolder<LinkInfo>>(false) { protected InfoHolder<LinkInfo> computeValue(@NotNull FileContent inputData) { final Language language = ((LanguageFileType) inputData.getFileType()).getLanguage(); final List<LinkInfo> result = new ArrayList<LinkInfo>(); if (HTMLLanguage.INSTANCE == language || XHTMLLanguage.INSTANCE == language) { mapHtml(inputData, language, result); } else { mapJsp(inputData, result); } return new InfoHolder<LinkInfo>(result.toArray(new LinkInfo[result.size()])); } }; } private static void mapJsp(FileContent inputData, final List<LinkInfo> result) { final FileViewProvider viewProvider = inputData.getPsiFile().getViewProvider(); PsiFile psiFile = null; if (viewProvider instanceof TemplateLanguageFileViewProvider) { final Language dataLanguage = ((TemplateLanguageFileViewProvider) viewProvider).getTemplateDataLanguage(); if (dataLanguage == HTMLLanguage.INSTANCE || dataLanguage == XHTMLLanguage.INSTANCE) { psiFile = viewProvider.getPsi(dataLanguage); } } else { psiFile = viewProvider.getPsi(viewProvider.getBaseLanguage()); } if (psiFile != null) { final XmlRecursiveElementVisitor visitor = new XmlRecursiveElementVisitor() { @Override public void visitXmlTag(XmlTag tag) { if (LINK.equalsIgnoreCase(tag.getLocalName())) { final String href = getAttributeValue(tag, HREF_ATTR); final String media = getAttributeValue(tag, MEDIA_ATTR); final String type = getAttributeValue(tag, TYPE_ATTR); final String rel = getAttributeValue(tag, REL_ATTR); final String title = getAttributeValue(tag, TITLE_ATTR); addResult( result, tag.getTextOffset(), href, media, type, rel, title, isHrefScripted(tag)); } super.visitXmlTag(tag); } }; psiFile.accept(visitor); } } private static void mapHtml(FileContent inputData, Language language, List<LinkInfo> result) { final Lexer original = HTMLLanguage.INSTANCE == language ? new HtmlHighlightingLexer() : new XHtmlHighlightingLexer(); final Lexer lexer = new FilterLexer( original, new FilterLexer.Filter() { public boolean reject(final IElementType type) { return XmlElementType.XML_WHITE_SPACE == type; } }); final CharSequence data = inputData.getContentAsText(); lexer.start(data); IElementType tokenType = lexer.getTokenType(); boolean linkTag = false; while (tokenType != null) { if (XmlElementType.XML_TAG_NAME == tokenType) { final String tagName = data.subSequence(lexer.getTokenStart(), lexer.getTokenEnd()).toString(); linkTag = LINK.equalsIgnoreCase(tagName); // if (BODY_TAG.equalsIgnoreCase(tagName)) { // break; // there are no LINK tags under the body // } } if (linkTag && XmlElementType.XML_NAME == tokenType) { int linkTagOffset = lexer.getTokenStart(); String href = null; String type = null; String media = null; String rel = null; String title = null; while (true) { if (tokenType == null || tokenType == XmlTokenType.XML_END_TAG_START || tokenType == XmlTokenType.XML_EMPTY_ELEMENT_END || tokenType == XmlTokenType.XML_START_TAG_START) { break; } if (XmlElementType.XML_NAME == tokenType) { final String attrName = data.subSequence(lexer.getTokenStart(), lexer.getTokenEnd()).toString(); if (HREF_ATTR.equalsIgnoreCase(attrName)) { href = parseAttributeValue(lexer, data); } else if (MEDIA_ATTR.equalsIgnoreCase(attrName)) { media = parseAttributeValue(lexer, data); } else if (TYPE_ATTR.equalsIgnoreCase(attrName)) { type = parseAttributeValue(lexer, data); } else if (REL_ATTR.equalsIgnoreCase(attrName)) { rel = parseAttributeValue(lexer, data); } else if (TITLE_ATTR.equalsIgnoreCase(attrName)) { title = parseAttributeValue(lexer, data); } } lexer.advance(); tokenType = lexer.getTokenType(); } addResult(result, linkTagOffset, href, media, type, rel, title, false); } lexer.advance(); tokenType = lexer.getTokenType(); } } private static boolean isHrefScripted(final XmlTag tag) { final XmlAttribute attribute = tag.getAttribute(HREF_ATTR); if (attribute != null) { final XmlAttributeValue value = attribute.getValueElement(); if (value != null) { if (PsiTreeUtil.getChildOfType(value, OuterLanguageElement.class) != null) { return true; } } } return false; } @Nullable private static String getAttributeValue(final XmlTag tag, final String attrName) { final XmlAttribute attribute = tag.getAttribute(attrName); if (attribute != null) { final XmlAttributeValue value = attribute.getValueElement(); if (value != null) { if (PsiTreeUtil.getChildOfType(value, OuterLanguageElement.class) == null) { return value.getValue(); } } } return null; } @Nullable private static String parseAttributeValue(final Lexer lexer, CharSequence data) { lexer.advance(); IElementType tokenType = lexer.getTokenType(); if (XmlElementType.XML_EQ == tokenType) { lexer.advance(); tokenType = lexer.getTokenType(); if (tokenType == XmlElementType.XML_ATTRIBUTE_VALUE_START_DELIMITER) { lexer.advance(); tokenType = lexer.getTokenType(); if (XmlElementType.XML_ATTRIBUTE_VALUE_TOKEN == tokenType) { return data.subSequence(lexer.getTokenStart(), lexer.getTokenEnd()).toString(); } } else if (tokenType != XmlTokenType.XML_TAG_END && tokenType != XmlTokenType.XML_EMPTY_ELEMENT_END) { return data.subSequence(lexer.getTokenStart(), lexer.getTokenEnd()).toString(); } } return null; } private static void addResult( final List<LinkInfo> result, final int offset, final String hrefValue, final String mediaValue, final String typeValue, final String relValue, final String titleValue, final boolean scripted) { result.add( new LinkInfo(offset, scripted, hrefValue, mediaValue, typeValue, relValue, titleValue)); } public DataExternalizer<InfoHolder<LinkInfo>> getValueExternalizer() { return myValueExternalizer; } public FileBasedIndex.InputFilter getInputFilter() { return myInputFilter; } public int getVersion() { return 4; } public static class LinkInfo { public int offset; public String value; public String media; public String type; public String rel; public String title; public boolean scripted; public LinkInfo( final int textOffset, final boolean scriptedRef, @Nullable final String hrefValue, @Nullable final String mediaValue, @Nullable final String typeValue, @Nullable final String relValue, @Nullable final String titleValue) { offset = textOffset; scripted = scriptedRef; value = hrefValue; media = mediaValue; type = typeValue; rel = relValue; title = titleValue; } @Override public boolean equals(final Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; final LinkInfo linkInfo = (LinkInfo) o; if (offset != linkInfo.offset) return false; if (scripted != linkInfo.scripted) return false; if (media != null ? !media.equals(linkInfo.media) : linkInfo.media != null) return false; if (rel != null ? !rel.equals(linkInfo.rel) : linkInfo.rel != null) return false; if (title != null ? !title.equals(linkInfo.title) : linkInfo.title != null) return false; if (type != null ? !type.equals(linkInfo.type) : linkInfo.type != null) return false; if (value != null ? !value.equals(linkInfo.value) : linkInfo.value != null) return false; return true; } @Override public int hashCode() { int result = offset; result = 31 * result + (value != null ? value.hashCode() : 0); result = 31 * result + (media != null ? media.hashCode() : 0); result = 31 * result + (type != null ? type.hashCode() : 0); result = 31 * result + (rel != null ? rel.hashCode() : 0); result = 31 * result + (title != null ? title.hashCode() : 0); result = 31 * result + (scripted ? 1 : 0); return result; } } private static class MyLinkReferenceResult implements LinkReferenceResult { private final PsiFileSystemItem[] myItem; private final LinkInfo myLinkInfo; private final PsiFile myPsiFile; public MyLinkReferenceResult( final PsiFileSystemItem[] item, final LinkInfo linkInfo, final PsiFile psiFile) { myItem = item; myLinkInfo = linkInfo; myPsiFile = psiFile; } public PsiFile getReferencedFile() { return (PsiFile) myItem[0]; } public PsiFile resolve() { final PsiFile referencedFile = getReferencedFile(); if (referencedFile != null) { return referencedFile; } if (myPsiFile != null) { final PsiElement psiElement = myPsiFile.findElementAt(myLinkInfo.offset); if (psiElement != null) { final PsiElement parent = psiElement.getParent(); if (parent instanceof XmlTag) { final XmlAttribute attribute = ((XmlTag) parent).getAttribute(HREF_ATTR); if (attribute != null) { final XmlAttributeValue value = attribute.getValueElement(); if (value != null) { final PsiReference[] references = value.getReferences(); for (PsiReference reference : references) { final PsiElement element = reference.resolve(); if (element instanceof PsiFile) { return (PsiFile) element; } } } } } } } return null; } public boolean isScriptedReference() { return myLinkInfo.scripted; } public String getMediaValue() { return myLinkInfo.media; } public String getRelValue() { return myLinkInfo.rel; } public String getTitleValue() { return myLinkInfo.title; } } static class InfoHolder<T> { public T[] myValues; InfoHolder(final T[] values) { myValues = values; } @Override public boolean equals(final Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; final InfoHolder that = (InfoHolder) o; if (!Arrays.equals(myValues, that.myValues)) return false; return true; } @Override public int hashCode() { return myValues != null ? Arrays.hashCode(myValues) : 0; } } }
private ID<Integer, Long> getFileTimestampsIndexId() { return ID.create( String.format( "advisor.ext.ClassFilesTimeStamps.%d", Math.abs(myProject.getBasePath().hashCode()))); }
/** @author Dmitry Avdeev */ public class XmlNamespaceIndex extends XmlIndex<String> { @Nullable public static String getNamespace(@NotNull VirtualFile file, final Project project) { final List<String> list = FileBasedIndex.getInstance().getValues(NAME, file.getUrl(), createFilter(project)); return list.size() == 0 ? null : list.get(0); } public static List<IndexedRelevantResource<String, String>> getResourcesByNamespace( String namespace, final Project project, Module module) { List<IndexedRelevantResource<String, String>> resources = IndexedRelevantResource.getResources(NAME, namespace, module, project, null); Collections.sort(resources); return resources; } public static List<IndexedRelevantResource<String, String>> getAllResources( @NotNull final Module module) { return getAllResources(module, null); } public static List<IndexedRelevantResource<String, String>> getAllResources( @NotNull final Module module, @Nullable NullableFunction< List<IndexedRelevantResource<String, String>>, IndexedRelevantResource<String, String>> chooser) { return IndexedRelevantResource.getAllResources(NAME, module, chooser); } private static final ID<String, String> NAME = ID.create("XmlNamespaces"); @Override @NotNull public ID<String, String> getName() { return NAME; } @Override @NotNull public DataIndexer<String, String, FileContent> getIndexer() { return new DataIndexer<String, String, FileContent>() { @Override @NotNull public Map<String, String> map(final FileContent inputData) { final String ns = XsdNamespaceBuilder.computeNamespace( new UnsyncByteArrayInputStream(inputData.getContent())); final HashMap<String, String> map = new HashMap<String, String>(2); if (ns != null) { map.put(ns, ""); } map.put(inputData.getFile().getUrl(), ns == null ? "" : ns); return map; } }; } @Override public DataExternalizer<String> getValueExternalizer() { return KEY_DESCRIPTOR; } }
/** @author peter */ public class DomFileIndex extends ScalarIndexExtension<String> { public static final ID<String, Void> NAME = ID.create("DomFileIndex"); private static final FileBasedIndex.InputFilter INPUT_FILTER = new FileBasedIndex.InputFilter() { public boolean acceptInput(final VirtualFile file) { return file.getFileType() == StdFileTypes.XML; } }; private final DataIndexer<String, Void, FileContent> myDataIndexer; public DomFileIndex() { myDataIndexer = new DataIndexer<String, Void, FileContent>() { @NotNull public Map<String, Void> map(final FileContent inputData) { final Set<String> namespaces = new THashSet<String>(); final XmlFileHeader header = NanoXmlUtil.parseHeader(new ByteArrayInputStream(inputData.getContent())); ContainerUtil.addIfNotNull(header.getPublicId(), namespaces); ContainerUtil.addIfNotNull(header.getSystemId(), namespaces); ContainerUtil.addIfNotNull(header.getRootTagNamespace(), namespaces); final String tagName = header.getRootTagLocalName(); if (StringUtil.isNotEmpty(tagName)) { final THashMap<String, Void> result = new THashMap<String, Void>(); final DomApplicationComponent component = DomApplicationComponent.getInstance(); for (final DomFileDescription description : component.getFileDescriptions(tagName)) { final String[] strings = description.getAllPossibleRootTagNamespaces(); if (strings.length == 0 || ContainerUtil.intersects(Arrays.asList(strings), namespaces)) { result.put(description.getRootElementClass().getName(), null); } } for (final DomFileDescription description : component.getAcceptingOtherRootTagNameDescriptions()) { final String[] strings = description.getAllPossibleRootTagNamespaces(); if (strings.length == 0 || ContainerUtil.intersects(Arrays.asList(strings), namespaces)) { result.put(description.getRootElementClass().getName(), null); } } return result; } return Collections.emptyMap(); } }; } public ID<String, Void> getName() { return NAME; } public DataIndexer<String, Void, FileContent> getIndexer() { return myDataIndexer; } public KeyDescriptor<String> getKeyDescriptor() { return new EnumeratorStringDescriptor(); } public FileBasedIndex.InputFilter getInputFilter() { return INPUT_FILTER; } public boolean dependsOnFileContent() { return true; } public int getVersion() { final DomApplicationComponent component = DomApplicationComponent.getInstance(); int result = 0; for (DomFileDescription description : component.getAllFileDescriptions()) { result += description.getVersion(); result += description .getRootTagName() .hashCode(); // so that a plugin enabling/disabling could trigger the reindexing } return result; } }
/** @by Maxim.Mossienko on 12/11/13. */ public class DuplicatesIndex extends FileBasedIndexExtension<Integer, TIntArrayList> implements PsiDependentIndex { static boolean ourEnabled = SystemProperties.getBooleanProperty("idea.enable.duplicates.online.calculation", true); static final boolean ourEnabledLightProfiles = true; private static boolean ourEnabledOldProfiles = false; @NonNls public static final ID<Integer, TIntArrayList> NAME = ID.create("DuplicatesIndex"); private static final int myBaseVersion = 25; private final FileBasedIndex.InputFilter myInputFilter = new FileBasedIndex.InputFilter() { @Override public boolean acceptInput(@NotNull final VirtualFile file) { return ourEnabled && findDuplicatesProfile(file.getFileType()) != null && file.isInLocalFileSystem() // skip library sources ; } }; private final DataExternalizer<TIntArrayList> myValueExternalizer = new DataExternalizer<TIntArrayList>() { @Override public void save(@NotNull DataOutput out, TIntArrayList list) throws IOException { if (list.size() == 2) { DataInputOutputUtil.writeINT(out, list.getQuick(0)); DataInputOutputUtil.writeINT(out, list.getQuick(1)); } else { DataInputOutputUtil.writeINT(out, -list.size()); int prev = 0; for (int i = 0, len = list.size(); i < len; i += 2) { int value = list.getQuick(i); DataInputOutputUtil.writeINT(out, value - prev); prev = value; DataInputOutputUtil.writeINT(out, list.getQuick(i + 1)); } } } @Override public TIntArrayList read(@NotNull DataInput in) throws IOException { int capacityOrValue = DataInputOutputUtil.readINT(in); if (capacityOrValue >= 0) { TIntArrayList list = new TIntArrayList(2); list.add(capacityOrValue); list.add(DataInputOutputUtil.readINT(in)); return list; } capacityOrValue = -capacityOrValue; TIntArrayList list = new TIntArrayList(capacityOrValue); int prev = 0; while (capacityOrValue > 0) { int value = DataInputOutputUtil.readINT(in) + prev; list.add(value); prev = value; list.add(DataInputOutputUtil.readINT(in)); capacityOrValue -= 2; } return list; } }; private final DataIndexer<Integer, TIntArrayList, FileContent> myIndexer = new DataIndexer<Integer, TIntArrayList, FileContent>() { @Override @NotNull public Map<Integer, TIntArrayList> map(@NotNull final FileContent inputData) { FileType type = inputData.getFileType(); DuplicatesProfile profile = findDuplicatesProfile(type); if (profile == null || !profile.acceptsContentForIndexing(inputData)) return Collections.emptyMap(); try { FileContentImpl fileContent = (FileContentImpl) inputData; if (profile instanceof LightDuplicateProfile && ourEnabledLightProfiles) { final THashMap<Integer, TIntArrayList> result = new THashMap<>(); LighterAST ast = fileContent.getLighterASTForPsiDependentIndex(); ((LightDuplicateProfile) profile) .process( ast, new LightDuplicateProfile.Callback() { @Override public void process( int hash, int hash2, @NotNull LighterAST ast, @NotNull LighterASTNode... nodes) { TIntArrayList list = result.get(hash); if (list == null) { result.put(hash, list = new TIntArrayList(2)); } list.add(nodes[0].getStartOffset()); list.add(hash2); } }); return result; } MyFragmentsCollector collector = new MyFragmentsCollector(profile, ((LanguageFileType) type).getLanguage()); DuplocateVisitor visitor = profile.createVisitor(collector, true); visitor.visitNode(fileContent.getPsiFileForPsiDependentIndex()); return collector.getMap(); } catch (StackOverflowError ae) { return Collections.emptyMap(); // todo Maksim } } }; @Nullable public static DuplicatesProfile findDuplicatesProfile(FileType fileType) { if (!(fileType instanceof LanguageFileType)) return null; Language language = ((LanguageFileType) fileType).getLanguage(); DuplicatesProfile profile = DuplicatesProfile.findProfileForLanguage(language); return profile != null && (ourEnabledOldProfiles && profile.supportDuplicatesIndex() || profile instanceof LightDuplicateProfile) ? profile : null; } @Override public int getVersion() { return myBaseVersion + (ourEnabled ? 0xFF : 0) + (ourEnabledLightProfiles ? 0x7F : 0) + (ourEnabledOldProfiles ? 0x21 : 0); } @Override public boolean dependsOnFileContent() { return true; } @NotNull @Override public ID<Integer, TIntArrayList> getName() { return NAME; } @NotNull @Override public DataIndexer<Integer, TIntArrayList, FileContent> getIndexer() { return myIndexer; } @NotNull @Override public DataExternalizer<TIntArrayList> getValueExternalizer() { return myValueExternalizer; } @NotNull @Override public KeyDescriptor<Integer> getKeyDescriptor() { return EnumeratorIntegerDescriptor.INSTANCE; } @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return myInputFilter; } // private static final TracingData myTracingData = new TracingData(); private static final TracingData myTracingData = null; private static class MyFragmentsCollector implements FragmentsCollector { private final THashMap<Integer, TIntArrayList> myMap = new THashMap<>(); private final DuplicatesProfile myProfile; private final DuplocatorState myDuplocatorState; public MyFragmentsCollector(DuplicatesProfile profile, Language language) { myProfile = profile; myDuplocatorState = profile.getDuplocatorState(language); } @Override public void add(int hash, int cost, @Nullable PsiFragment frag) { if (!isIndexedFragment(frag, cost, myProfile, myDuplocatorState)) { return; } if (myTracingData != null) myTracingData.record(hash, cost, frag); TIntArrayList list = myMap.get(hash); if (list == null) { myMap.put(hash, list = new TIntArrayList()); } list.add(frag.getStartOffset()); list.add(0); } public THashMap<Integer, TIntArrayList> getMap() { return myMap; } } static boolean isIndexedFragment( @Nullable PsiFragment frag, int cost, DuplicatesProfile profile, DuplocatorState duplocatorState) { if (frag == null) return false; return profile.shouldPutInIndex(frag, cost, duplocatorState); } @TestOnly public static boolean setEnabled(boolean value) { boolean old = ourEnabled; ourEnabled = value; return old; } @TestOnly public static boolean setEnabledOldProfiles(boolean value) { boolean old = ourEnabledOldProfiles; ourEnabledOldProfiles = value; return old; } @Override public boolean hasSnapshotMapping() { return true; } }
/** @author Daniel Espendiller <*****@*****.**> */ public class YamlTranslationStubIndex extends FileBasedIndexExtension<String, Set<String>> { public static final ID<String, Set<String>> KEY = ID.create("fr.adrienbrault.idea.symfony2plugin.translations"); private final KeyDescriptor<String> myKeyDescriptor = new EnumeratorStringDescriptor(); @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) { Map<String, Set<String>> map = new THashMap<>(); if (!Symfony2ProjectComponent.isEnabledForIndex(inputData.getProject())) { return map; } String extension = inputData.getFile().getExtension(); if ("xlf".equalsIgnoreCase(extension) || "xliff".equalsIgnoreCase(extension)) { return getXlfStringMap(inputData, map); } PsiFile psiFile = inputData.getPsiFile(); if (!(psiFile instanceof YAMLFile)) { return map; } // check physical file position if (!isValidTranslationFile(inputData, psiFile)) { return map; } String domainName = this.getDomainName(inputData.getFileName()); if (domainName == null) { return map; } final Set<String> translationKeySet = new HashSet<>(); YamlTranslationVistor.collectFileTranslations( (YAMLFile) psiFile, (keyName, yamlKeyValue) -> { translationKeySet.add(keyName); return true; }); if (translationKeySet.size() == 0) { return map; } map.put(domainName, translationKeySet); return map; } private boolean isValidTranslationFile(FileContent inputData, PsiFile psiFile) { // dont index all yaml files; "Resources/translations" should be good for now String relativePath = VfsUtil.getRelativePath(inputData.getFile(), psiFile.getProject().getBaseDir(), '/'); if (relativePath != null) { return relativePath.contains("Resources/translations"); } // Resources/translations/messages.de.yml // @TODO: Resources/translations/de/messages.yml String path = inputData.getFile().getPath(); if (path.endsWith("Resources/translations/" + inputData.getFileName())) { return true; } return false; } private Map<String, Set<String>> getXlfStringMap( FileContent inputData, Map<String, Set<String>> map) { // testing files are not that nice String relativePath = VfsUtil.getRelativePath(inputData.getFile(), inputData.getProject().getBaseDir(), '/'); if (relativePath != null && (relativePath.contains("/Test/") || relativePath.contains("/Tests/") || relativePath.contains("/Fixture/") || relativePath.contains("/Fixtures/"))) { return map; } String domainName = this.getDomainName(inputData.getFileName()); if (domainName == null) { return map; } InputStream inputStream; try { inputStream = inputData.getFile().getInputStream(); } catch (IOException e) { return map; } Set<String> set = TranslationUtil.getXliffTranslations(inputStream); if (set.size() > 0) { map.put(domainName, set); } return map; } @Nullable private String getDomainName(@NotNull String fileName) { // foo.fr.yml // dont index fr.yml int domainSplit = fileName.indexOf("."); if (domainSplit <= 2) { return null; } return fileName.substring(0, domainSplit); } }; } @NotNull @Override public ID<String, Set<String>> getName() { return KEY; } @NotNull @Override public KeyDescriptor<String> getKeyDescriptor() { return this.myKeyDescriptor; } @NotNull public DataExternalizer<Set<String>> getValueExternalizer() { return new StringSetDataExternalizer(); } @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return file -> file.getFileType() == YAMLFileType.YML || "xlf".equalsIgnoreCase(file.getExtension()) || "xliff".equalsIgnoreCase(file.getExtension()); } @Override public boolean dependsOnFileContent() { return true; } @Override public int getVersion() { return 4; } }