/** * Get tail part of the full fqn by subtracting head part. * * @param headFQN * @param fullFQN * @return tail fqn. If first part is not a begging of the full fqn, fullFQN will be returned. */ @NotNull public static String tail(@NotNull FqName headFQN, @NotNull FqName fullFQN) { if (!isSubpackageOf(fullFQN, headFQN) || headFQN.isRoot()) { return fullFQN.getFqName(); } return fullFQN.equals(headFQN) ? "" : fullFQN.getFqName().substring(headFQN.getFqName().length() + 1); // (headFQN + '.').length }
/** Return class names form jet sources in given scope which should be visible as Java classes. */ @NotNull @Override public PsiClass[] getClassesByName( @NotNull @NonNls String name, @NotNull GlobalSearchScope scope) { List<PsiClass> result = new ArrayList<PsiClass>(); IDELightClassGenerationSupport lightClassGenerationSupport = IDELightClassGenerationSupport.getInstanceForIDE(project); MultiMap<String, FqName> packageClasses = lightClassGenerationSupport.getAllPackageClasses(scope); // .namespace classes can not be indexed, since they have no explicit declarations Collection<FqName> fqNames = packageClasses.get(name); if (!fqNames.isEmpty()) { for (FqName fqName : fqNames) { PsiClass psiClass = JavaElementFinder.getInstance(project).findClass(fqName.getFqName(), scope); if (psiClass != null) { result.add(psiClass); } } } // Quick check for classes from getAllClassNames() Collection<JetClassOrObject> classOrObjects = JetShortClassNameIndex.getInstance().get(name, project, scope); if (classOrObjects.isEmpty()) { return result.toArray(new PsiClass[result.size()]); } for (JetClassOrObject classOrObject : classOrObjects) { FqName fqName = JetPsiUtil.getFQName(classOrObject); if (fqName != null) { assert fqName.shortName().getName().equals(name) : "A declaration obtained from index has non-matching name:\n" + "in index: " + name + "\n" + "declared: " + fqName.shortName() + "(" + fqName + ")"; PsiClass psiClass = JavaElementFinder.getInstance(project).findClass(fqName.getFqName(), scope); if (psiClass != null) { result.add(psiClass); } } } return result.toArray(new PsiClass[result.size()]); }
@Override public void indexFile(PsiJetFileStub stub, IndexSink sink) { String packageName = stub.getPackageName(); FqName fqName = new FqName(packageName == null ? "" : packageName); sink.occurrence(JetPackageDeclarationIndex.getInstance().getKey(), fqName.getFqName()); while (true) { sink.occurrence(JetAllPackagesIndex.getInstance().getKey(), fqName.getFqName()); if (fqName.isRoot()) { return; } fqName = fqName.parent(); } }
// TODO: includeRuntime should be not a flag but a path to runtime public static void writeToJar( ClassFileFactory factory, final OutputStream fos, @Nullable FqName mainClass, boolean includeRuntime) { try { Manifest manifest = new Manifest(); final Attributes mainAttributes = manifest.getMainAttributes(); mainAttributes.putValue("Manifest-Version", "1.0"); mainAttributes.putValue("Created-By", "JetBrains Kotlin"); if (mainClass != null) { mainAttributes.putValue("Main-Class", mainClass.getFqName()); } JarOutputStream stream = new JarOutputStream(fos, manifest); for (String file : factory.files()) { stream.putNextEntry(new JarEntry(file)); stream.write(factory.asBytes(file)); } if (includeRuntime) { writeRuntimeToJar(stream); } stream.finish(); } catch (IOException e) { throw new CompileEnvironmentException("Failed to generate jar file", e); } }
public static boolean isSubpackageOf( @NotNull final FqName subpackageName, @NotNull FqName packageName) { if (subpackageName.equals(packageName)) { return true; } if (packageName.isRoot()) { return true; } String subpackageNameStr = subpackageName.getFqName(); String packageNameStr = packageName.getFqName(); return (subpackageNameStr.startsWith(packageNameStr) && subpackageNameStr.charAt(packageNameStr.length()) == '.'); }
@NotNull public static FqName withoutFirstSegment(@NotNull FqName fqName) { if (fqName.isRoot() || fqName.parent().isRoot()) { return FqName.ROOT; } String fqNameStr = fqName.getFqName(); return new FqName(fqNameStr.substring(fqNameStr.indexOf('.'), fqNameStr.length())); }
public static void addImportDirectiveOrChangeToFqName( @NotNull FqName importFqn, @NotNull JetFile file, int refOffset, @NotNull PsiElement targetElement) { PsiReference reference = file.findReferenceAt(refOffset); if (reference instanceof JetPsiReference) { PsiElement target = reference.resolve(); if (target != null) { boolean same = file.getManager().areElementsEquivalent(target, targetElement); if (!same) { same = target instanceof PsiClass && importFqn.getFqName().equals(((PsiClass) target).getQualifiedName()); } if (!same) { if (target instanceof PsiMethod) { PsiMethod method = (PsiMethod) target; same = (method.isConstructor() && file.getManager() .areElementsEquivalent(method.getContainingClass(), targetElement)); } } if (!same) { if (target instanceof JetObjectDeclarationName) { same = file.getManager().areElementsEquivalent(target.getParent(), targetElement); } } if (!same) { Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file); TextRange refRange = reference.getElement().getTextRange(); document.replaceString( refRange.getStartOffset(), refRange.getEndOffset(), importFqn.getFqName()); } return; } } addImportDirective(new ImportPath(importFqn, false), null, file); }
@Override public void visitClassType(String name, boolean nullable, boolean forceReal) { FqName ourName = new FqName( name.replace('/', '.').replace('$', '.') // TODO: not sure ); this.classDescriptor = null; if (!forceReal) { classDescriptor = javaSemanticServices .getTypeTransformer() .getKotlinAnalog(ourName, JavaTypeTransformer.TypeUsage.MEMBER_SIGNATURE_INVARIANT); } if (classDescriptor == null) { // TODO: this is the worst code in Kotlin project Matcher matcher = Pattern.compile("jet\\.Function(\\d+)").matcher(ourName.getFqName()); if (matcher.matches()) { classDescriptor = JetStandardClasses.getFunction(Integer.parseInt(matcher.group(1))); } } if (classDescriptor == null) { Matcher matcher = Pattern.compile("jet\\.Tuple(\\d+)").matcher(ourName.getFqName()); if (matcher.matches()) { classDescriptor = JetStandardClasses.getTuple(Integer.parseInt(matcher.group(1))); } } if (this.classDescriptor == null) { this.classDescriptor = javaDescriptorResolver.resolveClass(ourName, DescriptorSearchRule.INCLUDE_KOTLIN); } if (this.classDescriptor == null) { // TODO: report in to trace this.errorType = ErrorUtils.createErrorType("class not found by name: " + ourName); } this.nullable = nullable; this.typeArguments = new ArrayList<TypeProjection>(); }
@Override public void indexProperty(PsiJetPropertyStub stub, IndexSink sink) { String propertyName = stub.getName(); if (propertyName != null) { if (stub.isTopLevel()) { FqName topFQName = stub.getTopFQName(); if (topFQName != null) { sink.occurrence( JetTopLevelPropertiesFqnNameIndex.getInstance().getKey(), topFQName.getFqName()); } } sink.occurrence(JetShortPropertiesNameIndex.getInstance().getKey(), propertyName); } }
@Override public void indexObject(PsiJetObjectStub stub, IndexSink sink) { String name = stub.getName(); assert name != null; sink.occurrence(JetShortClassNameIndex.getInstance().getKey(), name); if (stub.isTopLevel()) { sink.occurrence(JetTopLevelShortObjectNameIndex.getInstance().getKey(), name); } FqName fqName = stub.getFQName(); if (fqName != null) { sink.occurrence(JetFullClassNameIndex.getInstance().getKey(), fqName.getFqName()); } recordClassOrObjectByPackage(stub, sink); }
@Override public void indexFunction(PsiJetFunctionStub stub, IndexSink sink) { String name = stub.getName(); if (name != null) { if (stub.isTopLevel()) { // Collection only top level functions as only they are expected in completion without // explicit import if (!stub.isExtension()) { sink.occurrence(JetShortFunctionNameIndex.getInstance().getKey(), name); } else { sink.occurrence(JetExtensionFunctionNameIndex.getInstance().getKey(), name); } FqName topFQName = stub.getTopFQName(); if (topFQName != null) { sink.occurrence( JetTopLevelFunctionsFqnNameIndex.getInstance().getKey(), topFQName.getFqName()); } } sink.occurrence(JetAllShortFunctionNameIndex.getInstance().getKey(), name); } }
public static boolean isOneSegmentFQN(@NotNull FqName fqn) { return isOneSegmentFQN(fqn.getFqName()); }
@NotNull private static String fqNameToInternalName(@NotNull FqName fqName) { return fqName.getFqName().replace('.', '/'); }