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 org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.jet.lang.resolve.kotlin.VirtualFileFinder;
023    import org.jetbrains.jet.lang.resolve.kotlin.VirtualFileKotlinClassFinder;
024    import org.jetbrains.jet.lang.resolve.name.FqName;
025    
026    public class CliVirtualFileFinder extends VirtualFileKotlinClassFinder implements VirtualFileFinder {
027    
028        @NotNull
029        private final ClassPath classPath;
030    
031        public CliVirtualFileFinder(@NotNull ClassPath path) {
032            classPath = path;
033        }
034    
035        @Nullable
036        @Override
037        public VirtualFile findVirtualFileWithHeader(@NotNull FqName className) {
038            for (VirtualFile root : classPath) {
039                VirtualFile fileInRoot = findKotlinFile(className, root);
040                if (fileInRoot != null) {
041                    return fileInRoot;
042                }
043            }
044            return null;
045        }
046    
047        private VirtualFile findKotlinFile(@NotNull FqName className, @NotNull VirtualFile root) {
048            VirtualFile vFile = findFileInRoot(className.asString(), root, '.');
049            //NOTE: currently we use VirtualFileFinder to find Kotlin binaries only
050            if (vFile != null && createKotlinClass(vFile).getClassHeader() != null) {
051                return vFile;
052            }
053            return null;
054        }
055    
056        @Override
057        public VirtualFile findVirtualFile(@NotNull String internalName) {
058            for (VirtualFile root : classPath) {
059                VirtualFile fileInRoot = findFileInRoot(internalName, root, '/');
060                if (fileInRoot != null) {
061                    return fileInRoot;
062                }
063            }
064            return null;
065        }
066    
067        //NOTE: copied with some changes from CoreJavaFileManager
068        @Nullable
069        private static VirtualFile findFileInRoot(@NotNull String qName, @NotNull VirtualFile root, char separator) {
070            String pathRest = qName;
071            VirtualFile cur = root;
072    
073            while (true) {
074                int dot = pathRest.indexOf(separator);
075                if (dot < 0) break;
076    
077                String pathComponent = pathRest.substring(0, dot);
078                VirtualFile child = cur.findChild(pathComponent);
079    
080                if (child == null) break;
081                pathRest = pathRest.substring(dot + 1);
082                cur = child;
083            }
084    
085            String className = pathRest.replace('.', '$');
086            VirtualFile vFile = cur.findChild(className + ".class");
087            if (vFile != null) {
088                if (!vFile.isValid()) {
089                    //TODO: log
090                    return null;
091                }
092                return vFile;
093            }
094            return null;
095        }
096    
097    }