From 84f9f154b7a41da9e106b07a4781c22c2ddb4dfc Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Fri, 1 Dec 2023 11:30:37 -0500 Subject: [PATCH] Use XCConfig to evaluate config file contents --- Package.resolved | 2 +- Package.swift | 2 +- .../Extensions/PBXProj+BuildSettings.swift | 42 +++ .../XCBuildConfiguration+BuildSettings.swift | 30 ++ .../Rules/ValidateBuildSettingsRule.swift | 45 ++- .../TestData/XCConfFile-Debug.xcconfig | 1 + .../TestData/XCConfFile-Release.xcconfig | 1 + .../XCConfFileTarget-Release.xcconfig | 1 + .../XCConfigFiles.xcodeproj/project.pbxproj | 353 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../ValidateBuildSettingsRuleTests.swift | 16 + 12 files changed, 489 insertions(+), 19 deletions(-) create mode 100644 Sources/XCLinting/Extensions/XCBuildConfiguration+BuildSettings.swift create mode 100644 Tests/XCLintTests/TestData/XCConfFile-Debug.xcconfig create mode 100644 Tests/XCLintTests/TestData/XCConfFile-Release.xcconfig create mode 100644 Tests/XCLintTests/TestData/XCConfFileTarget-Release.xcconfig create mode 100644 Tests/XCLintTests/TestData/XCConfigFiles.xcodeproj/project.pbxproj create mode 100644 Tests/XCLintTests/TestData/XCConfigFiles.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 Tests/XCLintTests/TestData/XCConfigFiles.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Package.resolved b/Package.resolved index 1210651..48a648d 100644 --- a/Package.resolved +++ b/Package.resolved @@ -42,7 +42,7 @@ "location" : "https://github.com/mattmassicotte/XCConfig", "state" : { "branch" : "main", - "revision" : "ffe291c9237407f3f2695d10e567df63ad8b81fd" + "revision" : "2379629e1f44a6476afc709d9fcffb02bf7fa724" } }, { diff --git a/Package.swift b/Package.swift index d290697..b941df3 100644 --- a/Package.swift +++ b/Package.swift @@ -12,7 +12,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/tuist/XcodeProj", from: "8.15.0"), - .package(url: "https://github.com/mattmassicotte/XCConfig", branch: "main"), + .package(url: "https://github.com/mattmassicotte/XCConfig", revision: "2379629e1f44a6476afc709d9fcffb02bf7fa724"), .package(url: "https://github.com/apple/swift-argument-parser", from: "1.2.3"), .package(url: "https://github.com/jpsim/Yams.git", from: "5.0.0"), ], diff --git a/Sources/XCLinting/Extensions/PBXProj+BuildSettings.swift b/Sources/XCLinting/Extensions/PBXProj+BuildSettings.swift index a0e0435..ac679fa 100644 --- a/Sources/XCLinting/Extensions/PBXProj+BuildSettings.swift +++ b/Sources/XCLinting/Extensions/PBXProj+BuildSettings.swift @@ -1,5 +1,6 @@ import Foundation +import XCConfig import XcodeProj extension PBXProj { @@ -16,4 +17,45 @@ extension PBXProj { try block(target.name, list) } } + + func enumerateTargets(_ block: (PBXProject, PBXTarget) throws -> Void) rethrows { + for proj in projects { + for target in proj.targets { + try block(proj, target) + } + } + } + + func enumerateBuildSettingStatements( + rootURL: URL, + _ block: (PBXProject, PBXTarget, XCBuildConfiguration, [[Statement]]) throws -> Void + ) throws { + let sourceRootPath = rootURL.path(percentEncoded: false) + + for proj in projects { + let projConfigList = proj.buildConfigurationList + + for target in proj.targets { + for config in target.buildConfigurationList?.buildConfigurations ?? [] { + print("\(target.name)-\(config.name)") + + let projConfig = projConfigList?.configuration(name: config.name) + let projConfigStatements = try projConfig?.baseConfigurationStatements(with: sourceRootPath) ?? [] + let projStatements = projConfig?.buildSettingsStatements ?? [] + + let configStatements = try config.baseConfigurationStatements(with: sourceRootPath) + let statements = config.buildSettingsStatements + + let heirarchy = [ + projConfigStatements, + projStatements, + configStatements, + statements + ] + + try block(proj, target, config, heirarchy) + } + } + } + } } diff --git a/Sources/XCLinting/Extensions/XCBuildConfiguration+BuildSettings.swift b/Sources/XCLinting/Extensions/XCBuildConfiguration+BuildSettings.swift new file mode 100644 index 0000000..65f07f1 --- /dev/null +++ b/Sources/XCLinting/Extensions/XCBuildConfiguration+BuildSettings.swift @@ -0,0 +1,30 @@ +import Foundation + +import XCConfig +import XcodeProj + +extension XCBuildConfiguration { + func baseConfigurationContent(with sourceRoot: String) throws -> String? { + guard let fullPath = try baseConfiguration?.fullPath(sourceRoot: sourceRoot) else { + return nil + } + + return try String(contentsOf: URL(filePath: fullPath)) + } + + func baseConfigurationStatements(with sourceRoot: String) throws -> [Statement] { + guard let content = try baseConfigurationContent(with: sourceRoot) else { + return [] + } + + return Parser().parse(content) + } + + var buildSettingsStatements: [Statement] { + buildSettings.compactMap { (key, value) -> Statement? in + guard let value = value as? String else { return nil } + + return Statement.assignment(Assignment(key: key, value: value)) + } + } +} diff --git a/Sources/XCLinting/Rules/ValidateBuildSettingsRule.swift b/Sources/XCLinting/Rules/ValidateBuildSettingsRule.swift index e73b37e..db455e9 100644 --- a/Sources/XCLinting/Rules/ValidateBuildSettingsRule.swift +++ b/Sources/XCLinting/Rules/ValidateBuildSettingsRule.swift @@ -10,34 +10,27 @@ struct ValidateBuildSettingsRule { func run(_ environment: XCLinter.Environment) throws -> [Violation] { var violations = [Violation]() - // check top-level - for config in environment.project.pbxproj.buildConfigurations { - violations.append(contentsOf: evaluateTargetSettings("Project", config: config)) - } - - // check targets - environment.project.pbxproj.enumerateBuildConfigurations { name, configList in - for config in configList.buildConfigurations { - violations.append(contentsOf: evaluateTargetSettings(name, config: config)) - } + try enumerateSettings(with: environment) { target, config, settings in + print("\(target.name), \(config.name), \(settings)") + + violations.append(contentsOf: evaluateTargetSettings(target.name, settings: settings)) } return violations } - func evaluateTargetSettings(_ name: String, config: XCBuildConfiguration) -> [Violation] { + func evaluateTargetSettings(_ targetName: String, settings: [BuildSetting: String]) -> [Violation] { var violations = [Violation]() - for pair in config.buildSettings { - guard let setting = BuildSetting(rawValue: pair.key) else { continue } - - let status = setting.evaluateValue(pair.value as? String ?? "") + for (setting, value) in settings { + let name = setting.rawValue + let status = setting.evaluateValue(value) switch status { case .deprecated: - violations.append(.init("\(name):\(pair.key) = \(pair.value) is deprecated")) + violations.append(.init("\(targetName):\(name) = \(value) is deprecated")) case .invalid: - violations.append(.init("\(name):\(pair.key) = \(pair.value) is invalid")) + violations.append(.init("\(targetName):\(name) = \(value) is invalid")) case .valid: break } @@ -45,4 +38,22 @@ struct ValidateBuildSettingsRule { return violations } + + func enumerateSettings( + with environment: XCLinter.Environment, + block: (PBXTarget, XCBuildConfiguration, [BuildSetting: String]) throws -> Void + ) throws { + let project = environment.project + let sourceRootURL = environment.projectRootURL.deletingLastPathComponent() + let evaluator = Evaluator(rootURL: sourceRootURL) + let platformStatements: [Statement] = [] + + try project.pbxproj.enumerateBuildSettingStatements(rootURL: sourceRootURL) { proj, target, config, statementsList in + let heirarchy = [platformStatements] + statementsList + + let settings = try evaluator.evaluate(heirarchy: heirarchy) + + try block(target, config, settings) + } + } } diff --git a/Tests/XCLintTests/TestData/XCConfFile-Debug.xcconfig b/Tests/XCLintTests/TestData/XCConfFile-Debug.xcconfig new file mode 100644 index 0000000..b1dcd44 --- /dev/null +++ b/Tests/XCLintTests/TestData/XCConfFile-Debug.xcconfig @@ -0,0 +1 @@ +ALWAYS_SEARCH_USER_PATHS = NO diff --git a/Tests/XCLintTests/TestData/XCConfFile-Release.xcconfig b/Tests/XCLintTests/TestData/XCConfFile-Release.xcconfig new file mode 100644 index 0000000..00a6ad4 --- /dev/null +++ b/Tests/XCLintTests/TestData/XCConfFile-Release.xcconfig @@ -0,0 +1 @@ +ALWAYS_SEARCH_USER_PATHS = YES diff --git a/Tests/XCLintTests/TestData/XCConfFileTarget-Release.xcconfig b/Tests/XCLintTests/TestData/XCConfFileTarget-Release.xcconfig new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/Tests/XCLintTests/TestData/XCConfFileTarget-Release.xcconfig @@ -0,0 +1 @@ + diff --git a/Tests/XCLintTests/TestData/XCConfigFiles.xcodeproj/project.pbxproj b/Tests/XCLintTests/TestData/XCConfigFiles.xcodeproj/project.pbxproj new file mode 100644 index 0000000..9739892 --- /dev/null +++ b/Tests/XCLintTests/TestData/XCConfigFiles.xcodeproj/project.pbxproj @@ -0,0 +1,353 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + C9891AE12AFC279600C8F393 /* XCConfigFilesApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9891AE02AFC279600C8F393 /* XCConfigFilesApp.swift */; }; + C9891AE32AFC279600C8F393 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9891AE22AFC279600C8F393 /* ContentView.swift */; }; + C9891AE52AFC279800C8F393 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C9891AE42AFC279800C8F393 /* Assets.xcassets */; }; + C9891AE82AFC279800C8F393 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C9891AE72AFC279800C8F393 /* Preview Assets.xcassets */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + C9891ADD2AFC279600C8F393 /* XCConfigFiles.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = XCConfigFiles.app; sourceTree = BUILT_PRODUCTS_DIR; }; + C9891AE02AFC279600C8F393 /* XCConfigFilesApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCConfigFilesApp.swift; sourceTree = ""; }; + C9891AE22AFC279600C8F393 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + C9891AE42AFC279800C8F393 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + C9891AE72AFC279800C8F393 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + C9891AE92AFC279800C8F393 /* XCConfigFiles.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = XCConfigFiles.entitlements; sourceTree = ""; }; + C9891AEF2AFC27D500C8F393 /* XCConfFile-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "XCConfFile-Release.xcconfig"; sourceTree = ""; }; + C9891AF02AFC282700C8F393 /* XCConfFile-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "XCConfFile-Debug.xcconfig"; sourceTree = ""; }; + C9891AF12AFC283800C8F393 /* XCConfFileTarget-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "XCConfFileTarget-Release.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + C9891ADA2AFC279600C8F393 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + C9891AD42AFC279600C8F393 = { + isa = PBXGroup; + children = ( + C9891AF12AFC283800C8F393 /* XCConfFileTarget-Release.xcconfig */, + C9891AF02AFC282700C8F393 /* XCConfFile-Debug.xcconfig */, + C9891AEF2AFC27D500C8F393 /* XCConfFile-Release.xcconfig */, + C9891ADF2AFC279600C8F393 /* XCConfigFiles */, + C9891ADE2AFC279600C8F393 /* Products */, + ); + sourceTree = ""; + }; + C9891ADE2AFC279600C8F393 /* Products */ = { + isa = PBXGroup; + children = ( + C9891ADD2AFC279600C8F393 /* XCConfigFiles.app */, + ); + name = Products; + sourceTree = ""; + }; + C9891ADF2AFC279600C8F393 /* XCConfigFiles */ = { + isa = PBXGroup; + children = ( + C9891AE02AFC279600C8F393 /* XCConfigFilesApp.swift */, + C9891AE22AFC279600C8F393 /* ContentView.swift */, + C9891AE42AFC279800C8F393 /* Assets.xcassets */, + C9891AE92AFC279800C8F393 /* XCConfigFiles.entitlements */, + C9891AE62AFC279800C8F393 /* Preview Content */, + ); + path = XCConfigFiles; + sourceTree = ""; + }; + C9891AE62AFC279800C8F393 /* Preview Content */ = { + isa = PBXGroup; + children = ( + C9891AE72AFC279800C8F393 /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + C9891ADC2AFC279600C8F393 /* XCConfigFiles */ = { + isa = PBXNativeTarget; + buildConfigurationList = C9891AEC2AFC279800C8F393 /* Build configuration list for PBXNativeTarget "XCConfigFiles" */; + buildPhases = ( + C9891AD92AFC279600C8F393 /* Sources */, + C9891ADA2AFC279600C8F393 /* Frameworks */, + C9891ADB2AFC279600C8F393 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = XCConfigFiles; + productName = XCConfigFiles; + productReference = C9891ADD2AFC279600C8F393 /* XCConfigFiles.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + C9891AD52AFC279600C8F393 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1510; + LastUpgradeCheck = 1510; + TargetAttributes = { + C9891ADC2AFC279600C8F393 = { + CreatedOnToolsVersion = 15.1; + }; + }; + }; + buildConfigurationList = C9891AD82AFC279600C8F393 /* Build configuration list for PBXProject "XCConfigFiles" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = C9891AD42AFC279600C8F393; + productRefGroup = C9891ADE2AFC279600C8F393 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + C9891ADC2AFC279600C8F393 /* XCConfigFiles */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + C9891ADB2AFC279600C8F393 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C9891AE82AFC279800C8F393 /* Preview Assets.xcassets in Resources */, + C9891AE52AFC279800C8F393 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + C9891AD92AFC279600C8F393 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C9891AE32AFC279600C8F393 /* ContentView.swift in Sources */, + C9891AE12AFC279600C8F393 /* XCConfigFilesApp.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + C9891AEA2AFC279800C8F393 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = C9891AF02AFC282700C8F393 /* XCConfFile-Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = 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_DOCUMENTATION_COMMENTS = YES; + 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_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 14.1; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + C9891AEB2AFC279800C8F393 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = C9891AEF2AFC27D500C8F393 /* XCConfFile-Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = 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_DOCUMENTATION_COMMENTS = YES; + 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_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 14.1; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + }; + name = Release; + }; + C9891AED2AFC279800C8F393 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = XCConfigFiles/XCConfigFiles.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"XCConfigFiles/Preview Content\""; + DEVELOPMENT_TEAM = 5GXRS83U4Z; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.massicotte.XCConfigFiles; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + C9891AEE2AFC279800C8F393 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = C9891AF12AFC283800C8F393 /* XCConfFileTarget-Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = XCConfigFiles/XCConfigFiles.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"XCConfigFiles/Preview Content\""; + DEVELOPMENT_TEAM = 5GXRS83U4Z; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.massicotte.XCConfigFiles; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + C9891AD82AFC279600C8F393 /* Build configuration list for PBXProject "XCConfigFiles" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C9891AEA2AFC279800C8F393 /* Debug */, + C9891AEB2AFC279800C8F393 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C9891AEC2AFC279800C8F393 /* Build configuration list for PBXNativeTarget "XCConfigFiles" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C9891AED2AFC279800C8F393 /* Debug */, + C9891AEE2AFC279800C8F393 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = C9891AD52AFC279600C8F393 /* Project object */; +} diff --git a/Tests/XCLintTests/TestData/XCConfigFiles.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Tests/XCLintTests/TestData/XCConfigFiles.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/Tests/XCLintTests/TestData/XCConfigFiles.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Tests/XCLintTests/TestData/XCConfigFiles.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Tests/XCLintTests/TestData/XCConfigFiles.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Tests/XCLintTests/TestData/XCConfigFiles.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Tests/XCLintTests/ValidateBuildSettingsRuleTests.swift b/Tests/XCLintTests/ValidateBuildSettingsRuleTests.swift index ae5ee47..0ffec04 100644 --- a/Tests/XCLintTests/ValidateBuildSettingsRuleTests.swift +++ b/Tests/XCLintTests/ValidateBuildSettingsRuleTests.swift @@ -35,4 +35,20 @@ final class ValidateBuildSettingsRuleTests: XCTestCase { XCTAssertFalse(violations.isEmpty) } + + func testInvalidSettingsInXCConfigFile() throws { + let url = try Bundle.module.testDataURL(named: "XCConfigFiles.xcodeproj") + + let project = try XcodeProj(pathString: url.path) + + let env = XCLinter.Environment( + project: project, + projectRootURL: url, + configuration: Configuration() + ) + + let violations = try ValidateBuildSettingsRule().run(env) + + XCTAssertFalse(violations.isEmpty) + } }