diff --git a/AbandonedStrings.xcodeproj/project.pbxproj b/AbandonedStrings.xcodeproj/project.pbxproj
index f37ef55..955e065 100644
--- a/AbandonedStrings.xcodeproj/project.pbxproj
+++ b/AbandonedStrings.xcodeproj/project.pbxproj
@@ -89,7 +89,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0720;
- LastUpgradeCheck = 0720;
+ LastUpgradeCheck = 1210;
ORGANIZATIONNAME = iJoshSmith;
TargetAttributes = {
0361F13B1C605FE0009D519A = {
@@ -100,10 +100,11 @@
};
buildConfigurationList = 0361F1371C605FE0009D519A /* Build configuration list for PBXProject "AbandonedStrings" */;
compatibilityVersion = "Xcode 3.2";
- developmentRegion = English;
+ developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
+ Base,
);
mainGroup = 0361F1331C605FE0009D519A;
productRefGroup = 0361F13D1C605FE0009D519A /* Products */;
@@ -131,17 +132,29 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "-";
@@ -175,17 +188,29 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "-";
@@ -204,22 +229,25 @@
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
+ SWIFT_COMPILATION_MODE = wholemodule;
};
name = Release;
};
0361F1441C605FE0009D519A /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ CODE_SIGN_IDENTITY = "-";
PRODUCT_NAME = "$(TARGET_NAME)";
- SWIFT_VERSION = 3.0;
+ SWIFT_VERSION = 5.0;
};
name = Debug;
};
0361F1451C605FE0009D519A /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ CODE_SIGN_IDENTITY = "-";
PRODUCT_NAME = "$(TARGET_NAME)";
- SWIFT_VERSION = 3.0;
+ SWIFT_VERSION = 5.0;
};
name = Release;
};
diff --git a/AbandonedStrings.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/AbandonedStrings.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/AbandonedStrings.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/AbandonedStrings/main.swift b/AbandonedStrings/main.swift
index 9fffaa8..8556ea3 100755
--- a/AbandonedStrings/main.swift
+++ b/AbandonedStrings/main.swift
@@ -42,7 +42,7 @@ func contentsOfFile(_ filePath: String) -> String {
return try String(contentsOfFile: filePath)
}
catch {
- print("cannot read file!!!")
+ print(error.localizedDescription)
exit(1)
}
}
@@ -52,7 +52,10 @@ func concatenateAllSourceCodeIn(_ directories: [String], withStoryboard: Bool) -
if withStoryboard {
extensions.append("storyboard")
}
- let sourceFiles = findFilesIn(directories, withExtensions: extensions)
+
+ var sourceFiles = findFilesIn(directories, withExtensions: extensions)
+ sourceFiles.removeAll { $0.contains("R.generated.swift") }
+
return sourceFiles.reduce("") { (accumulator, sourceFile) -> String in
return accumulator + contentsOfFile(sourceFile)
}
@@ -73,20 +76,37 @@ func extractStringIdentifiersFrom(_ stringsFile: String) -> [String] {
func extractStringIdentifierFromTrimmedLine(_ line: String) -> String {
let indexAfterFirstQuote = line.index(after: line.startIndex)
let lineWithoutFirstQuote = line[indexAfterFirstQuote...]
- let endIndex = lineWithoutFirstQuote.index(of:"\"")!
+ let endIndex = lineWithoutFirstQuote.firstIndex(of:"\"")!
let identifier = lineWithoutFirstQuote[.. String {
+ let components = identified.components(separatedBy: ".")
+ let reducedComponents = components.reduce("") {
+ if $0.isEmpty {
+ return $1
+ } else {
+ return $0 + $1.prefix(1).uppercased() + $1.dropFirst()
+ }
+ }
+
+ return "R.string.localizable." + reducedComponents
+}
+
func findStringIdentifiersIn(_ stringsFile: String, abandonedBySourceCode sourceCode: String) -> [String] {
return extractStringIdentifiersFrom(stringsFile).filter { identifier in
let quotedIdentifier = "\"\(identifier)\""
let quotedIdentifierForStoryboard = "\"@\(identifier)\""
let signalQuotedIdentifierForJs = "'\(identifier)'"
- let isAbandoned = (sourceCode.contains(quotedIdentifier) == false && sourceCode.contains(quotedIdentifierForStoryboard) == false &&
- sourceCode.contains(signalQuotedIdentifierForJs) == false)
+ let rSwiftIdentifier = makeRSwiftIdentifier(from: identifier)
+
+ let isAbandoned = sourceCode.contains(quotedIdentifier) == false && sourceCode.contains(quotedIdentifierForStoryboard) == false &&
+ sourceCode.contains(signalQuotedIdentifierForJs) == false &&
+ sourceCode.contains(rSwiftIdentifier) == false
+
return isAbandoned
}
}
@@ -138,8 +158,8 @@ func getRootDirectories() -> [String]? {
if isOptionalParameterForStoryboardAvailable() {
c.removeLast()
}
- if isOptionaParameterForWritingAvailable() {
- c.remove(at: c.index(of: "write")!)
+ if isOptionalParameterForWritingAvailable() {
+ c.remove(at: c.firstIndex(of: "write")!)
}
return c
}
@@ -148,7 +168,7 @@ func isOptionalParameterForStoryboardAvailable() -> Bool {
return CommandLine.arguments.last == "storyboard"
}
-func isOptionaParameterForWritingAvailable() -> Bool {
+func isOptionalParameterForWritingAvailable() -> Bool {
return CommandLine.arguments.contains("write")
}
@@ -173,7 +193,7 @@ if let rootDirectories = getRootDirectories() {
print("Abandoned resource strings were detected:")
displayAbandonedIdentifiersInMap(map)
- if isOptionaParameterForWritingAvailable() {
+ if isOptionalParameterForWritingAvailable() {
map.keys.forEach { (stringsFilePath) in
print("\n\nNow modifying \(stringsFilePath) ...")
let updatedStringsFileContent = stringsFile(stringsFilePath, without: map[stringsFilePath]!)
diff --git a/README.md b/README.md
index 26896d1..d350c12 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,6 @@
# Abandoned Resource String Detection
This command line program detects unused resource strings in an iOS or OS X application.
-Updated to Swift 3, thanks to @astaeck on Oct-17-2016
-
## Usage
Open a Terminal to the directory which contains the *AbandonedStrings* executable, and run the following command: