1 /** 2 Copyright: Copyright (c) 2017, Joakim Brännström. All rights reserved. 3 License: MPL-2 4 Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 6 This Source Code Form is subject to the terms of the Mozilla Public License, 7 v.2.0. If a copy of the MPL was not distributed with this file, You can obtain 8 one at http://mozilla.org/MPL/2.0/. 9 10 This is a handy range to interate over either all files from the user OR all 11 files in a compilation database. 12 */ 13 module dextool.compilation_db.user_filerange; 14 15 import logger = std.experimental.logger; 16 17 import dextool.compilation_db : CompileCommandFilter, CompileCommandDB, 18 parseFlag, SearchResult, DbCompiler = Compiler; 19 import dextool.type : FileName, AbsolutePath; 20 21 @safe: 22 23 struct UserFileRange { 24 import std.typecons : Nullable; 25 import dextool.compilation_db : SearchResult, ParseFlags; 26 27 enum RangeOver { 28 inFiles, 29 database 30 } 31 32 this(CompileCommandDB db, string[] in_files, string[] cflags, 33 const CompileCommandFilter ccFilter, const DbCompiler userCompiler = DbCompiler.init) { 34 this.db = db; 35 this.cflags = cflags; 36 this.ccFilter = ccFilter; 37 this.inFiles = in_files; 38 this.userCompiler = userCompiler; 39 40 if (in_files.length == 0) { 41 kind = RangeOver.database; 42 } else { 43 kind = RangeOver.inFiles; 44 } 45 } 46 47 private { 48 const RangeOver kind; 49 CompileCommandDB db; 50 string[] inFiles; 51 string[] cflags; 52 const CompileCommandFilter ccFilter; 53 const DbCompiler userCompiler; 54 } 55 56 Nullable!SearchResult front() { 57 assert(!empty, "Can't get front of an empty range"); 58 59 typeof(return) curr; 60 61 final switch (kind) { 62 case RangeOver.inFiles: 63 if (db.length > 0) { 64 curr = db.findFlags(FileName(inFiles[0]), cflags, ccFilter, userCompiler); 65 } else { 66 curr = SearchResult(cflags.dup, AbsolutePath(FileName(inFiles[0]))); 67 } 68 break; 69 case RangeOver.database: 70 curr = SearchResult(db.payload[0].parseFlag(ccFilter, 71 userCompiler), db.payload[0].absoluteFile); 72 curr.get.flags.cflags = cflags ~ curr.get.flags.cflags; 73 break; 74 } 75 76 return curr; 77 } 78 79 void popFront() { 80 assert(!empty, "Can't pop front of an empty range"); 81 82 final switch (kind) { 83 case RangeOver.inFiles: 84 inFiles = inFiles[1 .. $]; 85 break; 86 case RangeOver.database: 87 db.payload = db.payload[1 .. $]; 88 break; 89 } 90 } 91 92 bool empty() @safe pure nothrow const @nogc { 93 final switch (kind) { 94 case RangeOver.inFiles: 95 return inFiles.length == 0; 96 case RangeOver.database: 97 return db.length == 0; 98 } 99 } 100 101 size_t length() @safe pure nothrow const @nogc { 102 final switch (kind) { 103 case RangeOver.inFiles: 104 return inFiles.length; 105 case RangeOver.database: 106 return db.length; 107 } 108 } 109 } 110 111 private: 112 113 import std.typecons : Nullable; 114 115 /// Find flags for fname by searching in the compilation DB. 116 Nullable!SearchResult findFlags(ref CompileCommandDB compdb, FileName fname, const string[] flags, 117 ref const CompileCommandFilter flag_filter, DbCompiler userCompiler = DbCompiler.init) { 118 import dextool.compilation_db : appendOrError; 119 120 auto rval = compdb.appendOrError(flags, fname, flag_filter); 121 logger.error(rval.isNull, "Unable to find any compiler flags for: ", fname); 122 return rval; 123 }