001    /*
002     * Copyright 2010-2013 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.jet.cli.jvm.compiler;
018    
019    import com.intellij.openapi.vfs.VirtualFile;
020    import com.intellij.psi.search.GlobalSearchScope;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.annotations.Nullable;
023    import org.jetbrains.jet.cli.jvm.compiler.ClassPath;
024    import org.jetbrains.jet.lang.resolve.java.resolver.KotlinClassFileHeader;
025    import org.jetbrains.jet.lang.resolve.java.vfilefinder.VirtualFileFinder;
026    import org.jetbrains.jet.lang.resolve.name.FqName;
027    
028    public class CliVirtualFileFinder implements VirtualFileFinder {
029    
030        @NotNull
031        private final ClassPath classPath;
032    
033        public CliVirtualFileFinder(@NotNull ClassPath path) {
034            classPath = path;
035        }
036    
037    
038        @Nullable
039        @Override
040        public VirtualFile find(@NotNull FqName className, @NotNull GlobalSearchScope scope) {
041            //TODO: use scope
042            return find(className);
043        }
044    
045        @Nullable
046        @Override
047        public VirtualFile find(@NotNull FqName className) {
048            for (VirtualFile root : classPath) {
049                VirtualFile fileInRoot = findFileInRoot(className.asString(), root);
050                if (fileInRoot != null) {
051                    return fileInRoot;
052                }
053            }
054            return null;
055        }
056    
057        //NOTE: copied with some changes from CoreJavaFileManager
058        @Nullable
059        private static VirtualFile findFileInRoot(@NotNull String qName, @NotNull VirtualFile root) {
060            String pathRest = qName;
061            VirtualFile cur = root;
062    
063            while (true) {
064                int dot = pathRest.indexOf('.');
065                if (dot < 0) break;
066    
067                String pathComponent = pathRest.substring(0, dot);
068                VirtualFile child = cur.findChild(pathComponent);
069    
070                if (child == null) break;
071                pathRest = pathRest.substring(dot + 1);
072                cur = child;
073            }
074    
075            String className = pathRest.replace('.', '$');
076            VirtualFile vFile = cur.findChild(className + ".class");
077            if (vFile != null) {
078                if (!vFile.isValid()) {
079                    //TODO: log
080                    return null;
081                }
082                //NOTE: currently we use VirtualFileFinder to find Kotlin binaries only
083                if (KotlinClassFileHeader.readKotlinHeaderFromClassFile(vFile).getType() != KotlinClassFileHeader.HeaderType.NONE) {
084                    return vFile;
085                }
086            }
087            return null;
088        }
089    }