From d0638daf1886851a02044349077fe94925482ada Mon Sep 17 00:00:00 2001 From: Mathias Quintero Date: Sun, 3 Jan 2021 16:15:45 +0100 Subject: [PATCH 1/2] Starting work on diagnostics --- .../xcschemes/Graphaello.xcscheme | 4 +- .../Commands/Codegen/CodegenCommand.swift | 6 + .../Processing/Model/Struct/Property.swift | 10 +- .../Processing/Model/Struct/Warning.swift | 11 + .../Processing/Pipeline/BasicPipeline.swift | 5 + .../SourceCode/SourceCode+decode.swift | 4 + .../1. Extraction/SourceCode/SourceCode.swift | 4 +- .../BasicPropertyExtractor.swift | 3 +- .../Resolving Struct/PropertyResolver.swift | 4 +- .../Diagnostics/Array+WarningDiagnoser.swift | 10 + .../Diagnostics/UnusedWarningDiagnoser.swift | 574 ++++++++++++++++++ .../Diagnostics/WarningDiagnoser.swift | 6 + .../Processing/Pipeline/Pipeline.swift | 2 + .../Processing/Pipeline/PipelineFactory.swift | 3 +- .../Pipeline/Stage/GraphQLStage.swift | 4 +- .../Project/Project+State+Pipeline.swift | 4 + 16 files changed, 641 insertions(+), 13 deletions(-) create mode 100644 Sources/Graphaello/Processing/Model/Struct/Warning.swift create mode 100644 Sources/Graphaello/Processing/Pipeline/Diagnostics/Array+WarningDiagnoser.swift create mode 100644 Sources/Graphaello/Processing/Pipeline/Diagnostics/UnusedWarningDiagnoser.swift create mode 100644 Sources/Graphaello/Processing/Pipeline/Diagnostics/WarningDiagnoser.swift diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/Graphaello.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/Graphaello.xcscheme index 6423813..6397964 100644 --- a/.swiftpm/xcode/xcshareddata/xcschemes/Graphaello.xcscheme +++ b/.swiftpm/xcode/xcshareddata/xcschemes/Graphaello.xcscheme @@ -52,14 +52,14 @@ diff --git a/Sources/Graphaello/Commands/Codegen/CodegenCommand.swift b/Sources/Graphaello/Commands/Codegen/CodegenCommand.swift index c6ed18c..813b071 100644 --- a/Sources/Graphaello/Commands/Codegen/CodegenCommand.swift +++ b/Sources/Graphaello/Commands/Codegen/CodegenCommand.swift @@ -48,6 +48,12 @@ class CodegenCommand : Command { Console.print(title: "๐Ÿ“š Parsing Paths From Structs:") let parsed = try pipeline.parse(extracted: extracted) + + let warnings = try pipeline.diagnose(parsed: parsed) + warnings.forEach { warning in + print(warning.description) + } + Console.print(result: "Found \(parsed.structs.count) structs with values from GraphQL") parsed.structs.forEach { parsed in Console.print(result: "\(inverse: parsed.name)", indentation: 2) diff --git a/Sources/Graphaello/Processing/Model/Struct/Property.swift b/Sources/Graphaello/Processing/Model/Struct/Property.swift index f2f97bf..cb24741 100644 --- a/Sources/Graphaello/Processing/Model/Struct/Property.swift +++ b/Sources/Graphaello/Processing/Model/Struct/Property.swift @@ -9,12 +9,14 @@ struct Property { let code: SourceCode let name: String let type: PropertyType + let usr: String let context: Context - init(code: SourceCode, name: String, type: PropertyType, @ContextBuilder context: () throws -> ContextProtocol) rethrows { + init(code: SourceCode, name: String, type: PropertyType, usr: String, @ContextBuilder context: () throws -> ContextProtocol) rethrows { self.code = code self.name = name self.type = type + self.usr = usr self.context = try Context(context: context) } } @@ -22,7 +24,7 @@ struct Property { extension Property where CurrentStage: GraphQLStage { func map(_ transform: (CurrentStage.Path) throws -> Stage.Path) rethrows -> Property { - return Property(code: code, name: name, type: type, graphqlPath: try graphqlPath.map(transform)) + return Property(code: code, name: name, type: type, usr: usr, graphqlPath: try graphqlPath.map(transform)) } } @@ -30,7 +32,7 @@ extension Property where CurrentStage: GraphQLStage { extension Property { func with(@ContextBuilder context: () throws -> ContextProtocol) rethrows -> Property { - return try Property(code: code, name: name, type: type, context: context) + return try Property(code: code, name: name, type: type, usr: usr, context: context) } } @@ -38,7 +40,7 @@ extension Property { extension Property where CurrentStage: GraphQLStage { func convert() -> Property where Stage.Path == CurrentStage.Path { - return Property(code: code, name: name, type: type, graphqlPath: graphqlPath) + return Property(code: code, name: name, type: type, usr: usr, graphqlPath: graphqlPath) } } diff --git a/Sources/Graphaello/Processing/Model/Struct/Warning.swift b/Sources/Graphaello/Processing/Model/Struct/Warning.swift new file mode 100644 index 0000000..13b9b81 --- /dev/null +++ b/Sources/Graphaello/Processing/Model/Struct/Warning.swift @@ -0,0 +1,11 @@ + +import Foundation + +struct Warning: CustomStringConvertible { + let location: Location + let descriptionText: String + + var description: String { + return "\(location.locationDescription): warning: \(descriptionText)" + } +} diff --git a/Sources/Graphaello/Processing/Pipeline/BasicPipeline.swift b/Sources/Graphaello/Processing/Pipeline/BasicPipeline.swift index c16bde1..a026f83 100644 --- a/Sources/Graphaello/Processing/Pipeline/BasicPipeline.swift +++ b/Sources/Graphaello/Processing/Pipeline/BasicPipeline.swift @@ -10,6 +10,7 @@ struct BasicPipeline: Pipeline { let assembler: Assembler let preparator: Preparator let generator: Generator + var diagnoser: WarningDiagnoser? = nil func extract(from file: WithTargets) throws -> [Struct] { return try extractor.extract(from: file) @@ -44,4 +45,8 @@ struct BasicPipeline: Pipeline { func generate(prepared: Project.State, useFormatting: Bool) throws -> String { return try generator.generate(prepared: prepared, useFormatting: useFormatting) } + + func diagnose(parsed: Struct) throws -> [Warning] { + return try diagnoser?.diagnose(parsed: parsed) ?? [] + } } diff --git a/Sources/Graphaello/Processing/Pipeline/Component/1. Extraction/SourceCode/SourceCode+decode.swift b/Sources/Graphaello/Processing/Pipeline/Component/1. Extraction/SourceCode/SourceCode+decode.swift index 89d08f4..b1221df 100644 --- a/Sources/Graphaello/Processing/Pipeline/Component/1. Extraction/SourceCode/SourceCode+decode.swift +++ b/Sources/Graphaello/Processing/Pipeline/Component/1. Extraction/SourceCode/SourceCode+decode.swift @@ -75,6 +75,10 @@ extension SourceCode { return SwiftDeclarationAttributeKind(rawValue: try decode(key: "key.attribute")) ?? ._custom } + func usr() throws -> String { + return try decode(key: .usr) + } + } extension SourceCode { diff --git a/Sources/Graphaello/Processing/Pipeline/Component/1. Extraction/SourceCode/SourceCode.swift b/Sources/Graphaello/Processing/Pipeline/Component/1. Extraction/SourceCode/SourceCode.swift index bb6db0a..7477225 100644 --- a/Sources/Graphaello/Processing/Pipeline/Component/1. Extraction/SourceCode/SourceCode.swift +++ b/Sources/Graphaello/Processing/Pipeline/Component/1. Extraction/SourceCode/SourceCode.swift @@ -32,11 +32,13 @@ extension SourceCode { extension SourceCode { init(file: WithTargets, index: LineColumnIndex, location: Location) throws { + let arguments = ["-sdk", sdkPath(), "-j4", location.file.absoluteURL.path] + let docs = SwiftDocs(file: file.value, arguments: arguments) self.init(file: file.value, index: index, location: location, targets: file.targets, - dictionary: try Structure(file: file.value).dictionary) + dictionary: docs?.docsDictionary ?? [:]) } init(content: String, parent: SourceCode, location: Location) throws { diff --git a/Sources/Graphaello/Processing/Pipeline/Component/1. Extraction/SubExtractors/Implementations/BasicPropertyExtractor.swift b/Sources/Graphaello/Processing/Pipeline/Component/1. Extraction/SubExtractors/Implementations/BasicPropertyExtractor.swift index 3d73831..7e3b5e9 100644 --- a/Sources/Graphaello/Processing/Pipeline/Component/1. Extraction/SubExtractors/Implementations/BasicPropertyExtractor.swift +++ b/Sources/Graphaello/Processing/Pipeline/Component/1. Extraction/SubExtractors/Implementations/BasicPropertyExtractor.swift @@ -21,7 +21,8 @@ struct BasicPropertyExtractor: PropertyExtractor { return Property(code: code, name: try code.name(), - type: finalType.map { .concrete($0) } ?? .inferred) { + type: finalType.map { .concrete($0) } ?? .inferred, + usr: try code.usr()) { .attributes ~> attributes } diff --git a/Sources/Graphaello/Processing/Pipeline/Component/4. Resolution/SubResolvers/Implementations/Resolving Struct/PropertyResolver.swift b/Sources/Graphaello/Processing/Pipeline/Component/4. Resolution/SubResolvers/Implementations/Resolving Struct/PropertyResolver.swift index 55fe18c..9dfd6a3 100644 --- a/Sources/Graphaello/Processing/Pipeline/Component/4. Resolution/SubResolvers/Implementations/Resolving Struct/PropertyResolver.swift +++ b/Sources/Graphaello/Processing/Pipeline/Component/4. Resolution/SubResolvers/Implementations/Resolving Struct/PropertyResolver.swift @@ -9,14 +9,14 @@ struct PropertyResolver: ValueResolver where Resolver.P using context: StructResolution.Context) throws -> StructResolution.Result> { guard let path = value.graphqlPath else { - return .resolved(Property(code: value.code, name: value.name, type: value.type, graphqlPath: nil)) + return .resolved(Property(code: value.code, name: value.name, type: value.type, usr: value.usr, graphqlPath: nil)) } return try locateErrors(with: path.parsed.extracted.code.location) { return try resolver .resolve(value: path, in: value, using: context) .map { path in - Property(code: value.code, name: value.name, type: value.type, graphqlPath: path) + Property(code: value.code, name: value.name, type: value.type, usr: value.usr, graphqlPath: path) } } } diff --git a/Sources/Graphaello/Processing/Pipeline/Diagnostics/Array+WarningDiagnoser.swift b/Sources/Graphaello/Processing/Pipeline/Diagnostics/Array+WarningDiagnoser.swift new file mode 100644 index 0000000..6a3b5f2 --- /dev/null +++ b/Sources/Graphaello/Processing/Pipeline/Diagnostics/Array+WarningDiagnoser.swift @@ -0,0 +1,10 @@ + +import Foundation + +extension Array: WarningDiagnoser where Element: WarningDiagnoser { + + func diagnose(parsed: Struct) throws -> [Warning] { + return try flatMap { try $0.diagnose(parsed: parsed) } + } + +} diff --git a/Sources/Graphaello/Processing/Pipeline/Diagnostics/UnusedWarningDiagnoser.swift b/Sources/Graphaello/Processing/Pipeline/Diagnostics/UnusedWarningDiagnoser.swift new file mode 100644 index 0000000..653f023 --- /dev/null +++ b/Sources/Graphaello/Processing/Pipeline/Diagnostics/UnusedWarningDiagnoser.swift @@ -0,0 +1,574 @@ + +import Foundation +import SwiftSyntax +import SourceKittenFramework + +private let swiftUIViewProtocols: Set = ["View"] + +struct UnusedWarningDiagnoser: WarningDiagnoser { + func diagnose(parsed: Struct) throws -> [Warning] { + guard !swiftUIViewProtocols.intersection(parsed.inheritedTypes).isEmpty else { + return [] + } + + return try parsed.properties.flatMap { try diagnose(property: $0, from: parsed) } + } + + private func diagnose(property: Property, from parsed: Struct) throws -> [Warning] { + guard property.graphqlPath != nil else { return [] } + + + let path = property.code.location.file.absoluteURL.path + let arguments = ["-sdk", sdkPath(), "-j4", path] + + let request: SourceKitObject = [ + "key.request": UID("source.request.editor.open"), + "key.name": path, + "key.sourcefile": path, + "key.annotated_decl": 1, + "key.fully_annotated_decl": 1, + "key.compilerargs": arguments, + ] + let info = try Request.customRequest(request: request).send() + + var verifier = UsageVerifier(property: property) + +// for substructure in try parsed.code.substructure() { +// switch try substructure.kind() { +// case .varInstance: +//// verifier.verify(syntax: try substructure.syntaxTree()) +// case .functionMethodInstance: +//// verifier.verify(syntax: try substructure.syntaxTree()) +// default: +// break +// } +// } + + guard !verifier.isUsed else { return [] } + return [Warning(location: property.code.location, + descriptionText: "Unused Property `\(property.name)` belongs to a View and is fetching data from GraphQL. This can be wasteful. Consider using it or removing the property.")] + } +} + +struct UsageVerifier { + let property: Property + + private(set) var shouldUseSelf = false + private(set) var isUsed = false + + mutating func verify(syntax: SyntaxProtocol) { + verify(syntax: syntax._syntaxNode) + } + + mutating func verify(syntax: Syntax) { + guard !isUsed else { return } + + let asEnum = syntax.as(SyntaxEnum.self) + switch asEnum { + case .unknown: + return + case .token: + return + case .decl(let decl): + print(decl) + case .expr(let expr): + print(expr) + case .stmt(let stmt): + print(stmt) + case .type: + return + case .pattern(let pattern): + print(pattern) + case .unknownDecl(let decl): + print(decl) + case .unknownExpr(let expr): + print(expr) + case .unknownStmt(let stmt): + print(stmt) + case .unknownType: + return + case .unknownPattern(let pattern): + print(pattern) + case .codeBlockItem(let item): + print(item) + case .codeBlockItemList(let list): + for item in list { + verify(syntax: item) + } + case .codeBlock(let block): + print(block) + case .inOutExpr: + return + case .poundColumnExpr(let expr): + print(expr) + case .tupleExprElementList(let tuple): + print(tuple) + case .arrayElementList(let arrayElementList): + print(arrayElementList) + case .dictionaryElementList(let dictionaryElementList): + print(dictionaryElementList) + case .stringLiteralSegments(let segments): + print(segments) + case .tryExpr(let expr): + print(expr) + case .declNameArgument(let decl): + print(decl) + case .declNameArgumentList(let list): + for item in list { + verify(syntax: item) + } + case .declNameArguments(let list): + print(list) + case .identifierExpr(let identifier): + print(identifier) + case .superRefExpr: + return + case .nilLiteralExpr: + return + case .discardAssignmentExpr: + return + case .assignmentExpr(let assignment): + print(assignment) + case .sequenceExpr(let sequence): + print(sequence) + case .exprList(let list): + for item in list { + verify(syntax: item) + } + case .poundLineExpr(let expr): + print(expr) + case .poundFileExpr(let expr): + print(expr) + case .poundFileIDExpr(let expr): + print(expr) + case .poundFilePathExpr(let expr): + print(expr) + case .poundFunctionExpr(let expr): + print(expr) + case .poundDsohandleExpr(let expr): + print(expr) + case .symbolicReferenceExpr(let expr): + print(expr) + case .prefixOperatorExpr(let expr): + print(expr) + case .binaryOperatorExpr(let expr): + print(expr) + case .arrowExpr(let expr): + print(expr) + case .floatLiteralExpr(let expr): + print(expr) + case .tupleExpr(let expr): + print(expr) + case .arrayExpr(let expr): + print(expr) + case .dictionaryExpr(let expr): + print(expr) + case .tupleExprElement(let expr): + print(expr) + case .arrayElement(let expr): + print(expr) + case .dictionaryElement(let expr): + print(expr) + case .integerLiteralExpr(let expr): + print(expr) + case .booleanLiteralExpr(let expr): + print(expr) + case .ternaryExpr(let expr): + print(expr) + case .memberAccessExpr(let expr): + print(expr) + case .isExpr(let expr): + print(expr) + case .asExpr(let expr): + print(expr) + case .typeExpr(let expr): + print(expr) + case .closureCaptureItem(let expr): + print(expr) + case .closureCaptureItemList(let list): + for item in list { + verify(syntax: item) + } + case .closureCaptureSignature(let expr): + print(expr) + case .closureParam(let expr): + print(expr) + case .closureParamList(let expr): + print(expr) + case .closureSignature(let expr): + print(expr) + case .closureExpr(let expr): + print(expr) + case .unresolvedPatternExpr(let expr): + print(expr) + case .multipleTrailingClosureElement(let expr): + print(expr) + case .multipleTrailingClosureElementList(let expr): + print(expr) + case .functionCallExpr(let expr): + print(expr) + case .subscriptExpr(let expr): + print(expr) + case .optionalChainingExpr(let expr): + print(expr) + case .forcedValueExpr(let expr): + print(expr) + case .postfixUnaryExpr(let expr): + print(expr) + case .specializeExpr(let expr): + print(expr) + case .stringSegment(let expr): + print(expr) + case .expressionSegment(let expr): + print(expr) + case .stringLiteralExpr(let expr): + print(expr) + case .keyPathExpr(let expr): + print(expr) + case .keyPathBaseExpr(let expr): + print(expr) + case .objcNamePiece(let expr): + print(expr) + case .objcName(let expr): + print(expr) + case .objcKeyPathExpr(let expr): + print(expr) + case .objcSelectorExpr(let expr): + print(expr) + case .editorPlaceholderExpr(let expr): + print(expr) + case .objectLiteralExpr(let expr): + print(expr) + case .typeInitializerClause(let expr): + print(expr) + case .typealiasDecl(let expr): + print(expr) + case .associatedtypeDecl(let expr): + print(expr) + case .functionParameterList(let list): + for item in list { + verify(syntax: item) + } + case .parameterClause(let expr): + print(expr) + case .returnClause(let expr): + print(expr) + case .functionSignature(let expr): + print(expr) + case .ifConfigClause(let expr): + print(expr) + case .ifConfigClauseList(let expr): + print(expr) + case .ifConfigDecl(let expr): + print(expr) + case .poundErrorDecl(let expr): + print(expr) + case .poundWarningDecl(let expr): + print(expr) + case .poundSourceLocation(let expr): + print(expr) + case .poundSourceLocationArgs(let expr): + print(expr) + case .declModifier(let expr): + print(expr) + case .inheritedType(let expr): + print(expr) + case .inheritedTypeList(let expr): + print(expr) + case .typeInheritanceClause(let expr): + print(expr) + case .classDecl(let expr): + print(expr) + case .structDecl(let expr): + print(expr) + case .protocolDecl(let expr): + print(expr) + case .extensionDecl(let expr): + print(expr) + case .memberDeclBlock(let expr): + print(expr) + case .memberDeclList(let list): + for item in list { + verify(syntax: item) + } + case .memberDeclListItem(let expr): + print(expr) + case .sourceFile(let file): + for item in file.statements { + verify(syntax: item) + } + case .initializerClause(let expr): + print(expr) + case .functionParameter(let expr): + print(expr) + case .modifierList: + return + case .functionDecl(let expr): + print(expr) + case .initializerDecl(let expr): + print(expr) + case .deinitializerDecl(let expr): + print(expr) + case .subscriptDecl(let expr): + print(expr) + case .accessLevelModifier(let expr): + print(expr) + case .accessPathComponent(let expr): + print(expr) + case .accessPath(let expr): + print(expr) + case .importDecl: + return + case .accessorParameter(let expr): + print(expr) + case .accessorDecl(let expr): + print(expr) + case .accessorList(let list): + for item in list { + verify(syntax: list) + } + case .accessorBlock(let expr): + print(expr) + case .patternBinding(let expr): + print(expr) + case .patternBindingList(let list): + for item in list { + verify(syntax: item) + } + case .variableDecl(let expr): + print(expr) + case .enumCaseElement(let expr): + print(expr) + case .enumCaseElementList(let expr): + print(expr) + case .enumCaseDecl(let expr): + print(expr) + case .enumDecl(let expr): + print(expr) + case .operatorDecl(let expr): + print(expr) + case .identifierList(let list): + for item in list { + verify(syntax: item) + } + case .operatorPrecedenceAndTypes: + return + case .precedenceGroupDecl: + return + case .precedenceGroupAttributeList: + return + case .precedenceGroupRelation: + return + case .precedenceGroupNameList: + return + case .precedenceGroupNameElement: + return + case .precedenceGroupAssignment: + return + case .precedenceGroupAssociativity: + return + case .tokenList(let expr): + print(expr) + case .nonEmptyTokenList(let expr): + print(expr) + case .customAttribute(let expr): + print(expr) + case .attribute(let expr): + print(expr) + case .attributeList(let expr): + print(expr) + case .specializeAttributeSpecList(let expr): + print(expr) + case .labeledSpecializeEntry(let expr): + print(expr) + case .namedAttributeStringArgument(let expr): + print(expr) + case .declName(let expr): + print(expr) + case .implementsAttributeArguments(let expr): + print(expr) + case .objCSelectorPiece(let expr): + print(expr) + case .objCSelector(let expr): + print(expr) + case .differentiableAttributeArguments(let expr): + print(expr) + case .differentiabilityParamsClause(let expr): + print(expr) + case .differentiabilityParams(let expr): + print(expr) + case .differentiabilityParamList(let expr): + print(expr) + case .differentiabilityParam(let expr): + print(expr) + case .derivativeRegistrationAttributeArguments(let expr): + print(expr) + case .qualifiedDeclName(let expr): + print(expr) + case .functionDeclName(let expr): + print(expr) + case .continueStmt(let expr): + print(expr) + case .whileStmt(let expr): + print(expr) + case .deferStmt(let expr): + print(expr) + case .expressionStmt(let expr): + print(expr) + case .switchCaseList(let expr): + print(expr) + case .repeatWhileStmt(let expr): + print(expr) + case .guardStmt(let expr): + print(expr) + case .whereClause(let expr): + print(expr) + case .forInStmt(let expr): + print(expr) + case .switchStmt(let expr): + print(expr) + case .catchClauseList(let expr): + print(expr) + case .doStmt(let expr): + print(expr) + case .returnStmt(let expr): + print(expr) + case .yieldStmt(let expr): + print(expr) + case .yieldList(let expr): + print(expr) + case .fallthroughStmt(let expr): + print(expr) + case .breakStmt(let expr): + print(expr) + case .caseItemList(let expr): + print(expr) + case .catchItemList(let expr): + print(expr) + case .conditionElement(let expr): + print(expr) + case .availabilityCondition(let expr): + print(expr) + case .matchingPatternCondition(let expr): + print(expr) + case .optionalBindingCondition(let expr): + print(expr) + case .conditionElementList(let expr): + print(expr) + case .declarationStmt(let expr): + print(expr) + case .throwStmt(let expr): + print(expr) + case .ifStmt(let expr): + print(expr) + case .elseIfContinuation(let expr): + print(expr) + case .elseBlock(let expr): + print(expr) + case .switchCase(let expr): + print(expr) + case .switchDefaultLabel(let expr): + print(expr) + case .caseItem(let expr): + print(expr) + case .catchItem(let expr): + print(expr) + case .switchCaseLabel(let expr): + print(expr) + case .catchClause(let expr): + print(expr) + case .poundAssertStmt(let expr): + print(expr) + case .genericWhereClause(_): + return + case .genericRequirementList(_): + return + case .genericRequirement(_): + return + case .sameTypeRequirement(_): + return + case .genericParameterList(_): + return + case .genericParameter(_): + return + case .genericParameterClause(_): + return + case .conformanceRequirement(_): + return + case .simpleTypeIdentifier(_): + return + case .memberTypeIdentifier(_): + return + case .classRestrictionType(_): + return + case .arrayType(_): + return + case .dictionaryType(_): + return + case .metatypeType(_): + return + case .optionalType(_): + return + case .someType(_): + return + case .implicitlyUnwrappedOptionalType(_): + return + case .compositionTypeElement(_): + return + case .compositionTypeElementList(_): + return + case .compositionType(_): + return + case .tupleTypeElement(_): + return + case .tupleTypeElementList(_): + return + case .tupleType(_): + return + case .functionType(_): + return + case .attributedType(_): + return + case .genericArgumentList(_): + return + case .genericArgument(_): + return + case .genericArgumentClause(_): + return + case .typeAnnotation(let expr): + print(expr) + case .enumCasePattern(let expr): + print(expr) + case .isTypePattern(let expr): + print(expr) + case .optionalPattern(let expr): + print(expr) + case .identifierPattern(let expr): + print(expr) + case .asTypePattern(let expr): + print(expr) + case .tuplePattern(let expr): + print(expr) + case .wildcardPattern(let expr): + print(expr) + case .tuplePatternElement(let expr): + print(expr) + case .expressionPattern(let expr): + print(expr) + case .tuplePatternElementList(let expr): + print(expr) + case .valueBindingPattern(let expr): + print(expr) + case .availabilitySpecList(let expr): + print(expr) + case .availabilityArgument(let expr): + print(expr) + case .availabilityLabeledArgument(let expr): + print(expr) + case .availabilityVersionRestriction(let expr): + print(expr) + case .versionTuple(let expr): + print(expr) + } + } +} diff --git a/Sources/Graphaello/Processing/Pipeline/Diagnostics/WarningDiagnoser.swift b/Sources/Graphaello/Processing/Pipeline/Diagnostics/WarningDiagnoser.swift new file mode 100644 index 0000000..6c60884 --- /dev/null +++ b/Sources/Graphaello/Processing/Pipeline/Diagnostics/WarningDiagnoser.swift @@ -0,0 +1,6 @@ + +import Foundation + +protocol WarningDiagnoser { + func diagnose(parsed: Struct) throws -> [Warning] +} diff --git a/Sources/Graphaello/Processing/Pipeline/Pipeline.swift b/Sources/Graphaello/Processing/Pipeline/Pipeline.swift index fdfd8f3..b58c25e 100644 --- a/Sources/Graphaello/Processing/Pipeline/Pipeline.swift +++ b/Sources/Graphaello/Processing/Pipeline/Pipeline.swift @@ -14,6 +14,8 @@ protocol Pipeline { using apollo: ApolloReference) throws -> Project.State func generate(prepared: Project.State, useFormatting: Bool) throws -> String + + func diagnose(parsed: Struct) throws -> [Warning] } extension Pipeline { diff --git a/Sources/Graphaello/Processing/Pipeline/PipelineFactory.swift b/Sources/Graphaello/Processing/Pipeline/PipelineFactory.swift index baca3d2..52a4e1e 100644 --- a/Sources/Graphaello/Processing/Pipeline/PipelineFactory.swift +++ b/Sources/Graphaello/Processing/Pipeline/PipelineFactory.swift @@ -11,7 +11,8 @@ enum PipelineFactory { cleaner: create(), assembler: create(), preparator: create(), - generator: create()) + generator: create(), + diagnoser: UnusedWarningDiagnoser()) } private static func create() -> Extractor { diff --git a/Sources/Graphaello/Processing/Pipeline/Stage/GraphQLStage.swift b/Sources/Graphaello/Processing/Pipeline/Stage/GraphQLStage.swift index a0f35b7..e1a06be 100644 --- a/Sources/Graphaello/Processing/Pipeline/Stage/GraphQLStage.swift +++ b/Sources/Graphaello/Processing/Pipeline/Stage/GraphQLStage.swift @@ -15,8 +15,8 @@ extension Property where CurrentStage: GraphQLStage { extension Property where CurrentStage: GraphQLStage { - init(code: SourceCode, name: String, type: PropertyType, graphqlPath: CurrentStage.Path?) { - self.init(code: code, name: name, type: type) { CurrentStage.pathKey ~> graphqlPath } + init(code: SourceCode, name: String, type: PropertyType, usr: String, graphqlPath: CurrentStage.Path?) { + self.init(code: code, name: name, type: type, usr: usr) { CurrentStage.pathKey ~> graphqlPath } } } diff --git a/Sources/Graphaello/Processing/Project/Project+State+Pipeline.swift b/Sources/Graphaello/Processing/Project/Project+State+Pipeline.swift index f3dfd53..114c3de 100644 --- a/Sources/Graphaello/Processing/Project/Project+State+Pipeline.swift +++ b/Sources/Graphaello/Processing/Project/Project+State+Pipeline.swift @@ -32,5 +32,9 @@ extension Pipeline { func clean(resolved: Project.State) throws -> Project.State { return resolved.with(structs: try clean(resolved: resolved.structs)) } + + func diagnose(parsed: Project.State) throws -> [Warning] { + return try parsed.structs.flatMap { try diagnose(parsed: $0) } + } } From b094a6b29222fb921b7983e141fb84fc992ee882 Mon Sep 17 00:00:00 2001 From: Mathias Quintero Date: Mon, 25 Jan 2021 00:44:33 +0100 Subject: [PATCH 2/2] Fixing diagnostics using very simple visitor pattern --- .../Commands/Codegen/CodegenCommand.swift | 71 +-- .../Processing/Model/Struct/Property.swift | 10 +- .../1. Extraction/SourceCode/SourceCode.swift | 4 +- .../BasicPropertyExtractor.swift | 3 +- .../Resolving Struct/PropertyResolver.swift | 4 +- .../Diagnostics/UnusedWarningDiagnoser.swift | 550 +----------------- .../Pipeline/Stage/GraphQLStage.swift | 4 +- 7 files changed, 60 insertions(+), 586 deletions(-) diff --git a/Sources/Graphaello/Commands/Codegen/CodegenCommand.swift b/Sources/Graphaello/Commands/Codegen/CodegenCommand.swift index 813b071..542cd5b 100644 --- a/Sources/Graphaello/Commands/Codegen/CodegenCommand.swift +++ b/Sources/Graphaello/Commands/Codegen/CodegenCommand.swift @@ -76,46 +76,51 @@ class CodegenCommand : Command { cache[.lastRunHash] = hashValue } - Console.print(title: "๐Ÿ”Ž Validating Paths against API definitions:") - let validated = try pipeline.validate(parsed: parsed) - Console.print(result: "Checked \(validated.graphQLPaths.count) fields") + do { + Console.print(title: "๐Ÿ”Ž Validating Paths against API definitions:") + let validated = try pipeline.validate(parsed: parsed) + Console.print(result: "Checked \(validated.graphQLPaths.count) fields") - Console.print(title: "๐Ÿงฐ Resolving Fragments and Queries:") - let resolved = try pipeline.resolve(validated: validated) + Console.print(title: "๐Ÿงฐ Resolving Fragments and Queries:") + let resolved = try pipeline.resolve(validated: validated) - Console.print(result: "Resolved \(resolved.allQueries.count) Queries:") - resolved.allQueries.forEach { query in - Console.print(result: "\(inverse: query.name)", indentation: 2) - } + Console.print(result: "Resolved \(resolved.allQueries.count) Queries:") + resolved.allQueries.forEach { query in + Console.print(result: "\(inverse: query.name)", indentation: 2) + } - Console.print(result: "Resolved \(resolved.allFragments.count) Fragments:") - resolved.allFragments.forEach { fragment in - Console.print(result: "\(inverse: fragment.name)", indentation: 2) - } + Console.print(result: "Resolved \(resolved.allFragments.count) Fragments:") + resolved.allFragments.forEach { fragment in + Console.print(result: "\(inverse: fragment.name)", indentation: 2) + } - Console.print(title: "๐Ÿงน Cleaning Queries and Fragments:") - let cleaned = try pipeline.clean(resolved: resolved) + Console.print(title: "๐Ÿงน Cleaning Queries and Fragments:") + let cleaned = try pipeline.clean(resolved: resolved) - Console.print(title: "โœ๏ธ Generating Swift Code:") - - Console.print(title: "๐ŸŽจ Writing GraphQL Code", indentation: 1) - let assembled = try pipeline.assemble(cleaned: cleaned) - - Console.print(title: "๐Ÿš€ Delegating some stuff to Apollo codegen", indentation: 1) - let prepared = try pipeline.prepare(assembled: assembled, using: apollo) - - Console.print(title: "๐ŸŽ Bundling it all together", indentation: 1) - - let autoGeneratedFile = try pipeline.generate(prepared: prepared, useFormatting: !skipFormatting) - - Console.print(result: "Generated \(autoGeneratedFile.components(separatedBy: "\n").count) lines of code") - Console.print(result: "You're welcome ๐Ÿ™ƒ", indentation: 2) + Console.print(title: "โœ๏ธ Generating Swift Code:") + + Console.print(title: "๐ŸŽจ Writing GraphQL Code", indentation: 1) + let assembled = try pipeline.assemble(cleaned: cleaned) + + Console.print(title: "๐Ÿš€ Delegating some stuff to Apollo codegen", indentation: 1) + let prepared = try pipeline.prepare(assembled: assembled, using: apollo) + + Console.print(title: "๐ŸŽ Bundling it all together", indentation: 1) - Console.print(title: "๐Ÿ’พ Saving Autogenerated Code") - try project.writeFile(name: "Graphaello.swift", content: autoGeneratedFile) + let autoGeneratedFile = try pipeline.generate(prepared: prepared, useFormatting: !skipFormatting) - Console.print("") - Console.print(title: "โœ… Done") + Console.print(result: "Generated \(autoGeneratedFile.components(separatedBy: "\n").count) lines of code") + Console.print(result: "You're welcome ๐Ÿ™ƒ", indentation: 2) + + Console.print(title: "๐Ÿ’พ Saving Autogenerated Code") + try project.writeFile(name: "Graphaello.swift", content: autoGeneratedFile) + + Console.print("") + Console.print(title: "โœ… Done") + } catch { + cache?[.lastRunHash] = nil + throw error + } } } diff --git a/Sources/Graphaello/Processing/Model/Struct/Property.swift b/Sources/Graphaello/Processing/Model/Struct/Property.swift index cb24741..f2f97bf 100644 --- a/Sources/Graphaello/Processing/Model/Struct/Property.swift +++ b/Sources/Graphaello/Processing/Model/Struct/Property.swift @@ -9,14 +9,12 @@ struct Property { let code: SourceCode let name: String let type: PropertyType - let usr: String let context: Context - init(code: SourceCode, name: String, type: PropertyType, usr: String, @ContextBuilder context: () throws -> ContextProtocol) rethrows { + init(code: SourceCode, name: String, type: PropertyType, @ContextBuilder context: () throws -> ContextProtocol) rethrows { self.code = code self.name = name self.type = type - self.usr = usr self.context = try Context(context: context) } } @@ -24,7 +22,7 @@ struct Property { extension Property where CurrentStage: GraphQLStage { func map(_ transform: (CurrentStage.Path) throws -> Stage.Path) rethrows -> Property { - return Property(code: code, name: name, type: type, usr: usr, graphqlPath: try graphqlPath.map(transform)) + return Property(code: code, name: name, type: type, graphqlPath: try graphqlPath.map(transform)) } } @@ -32,7 +30,7 @@ extension Property where CurrentStage: GraphQLStage { extension Property { func with(@ContextBuilder context: () throws -> ContextProtocol) rethrows -> Property { - return try Property(code: code, name: name, type: type, usr: usr, context: context) + return try Property(code: code, name: name, type: type, context: context) } } @@ -40,7 +38,7 @@ extension Property { extension Property where CurrentStage: GraphQLStage { func convert() -> Property where Stage.Path == CurrentStage.Path { - return Property(code: code, name: name, type: type, usr: usr, graphqlPath: graphqlPath) + return Property(code: code, name: name, type: type, graphqlPath: graphqlPath) } } diff --git a/Sources/Graphaello/Processing/Pipeline/Component/1. Extraction/SourceCode/SourceCode.swift b/Sources/Graphaello/Processing/Pipeline/Component/1. Extraction/SourceCode/SourceCode.swift index 7477225..bb6db0a 100644 --- a/Sources/Graphaello/Processing/Pipeline/Component/1. Extraction/SourceCode/SourceCode.swift +++ b/Sources/Graphaello/Processing/Pipeline/Component/1. Extraction/SourceCode/SourceCode.swift @@ -32,13 +32,11 @@ extension SourceCode { extension SourceCode { init(file: WithTargets, index: LineColumnIndex, location: Location) throws { - let arguments = ["-sdk", sdkPath(), "-j4", location.file.absoluteURL.path] - let docs = SwiftDocs(file: file.value, arguments: arguments) self.init(file: file.value, index: index, location: location, targets: file.targets, - dictionary: docs?.docsDictionary ?? [:]) + dictionary: try Structure(file: file.value).dictionary) } init(content: String, parent: SourceCode, location: Location) throws { diff --git a/Sources/Graphaello/Processing/Pipeline/Component/1. Extraction/SubExtractors/Implementations/BasicPropertyExtractor.swift b/Sources/Graphaello/Processing/Pipeline/Component/1. Extraction/SubExtractors/Implementations/BasicPropertyExtractor.swift index 7e3b5e9..3d73831 100644 --- a/Sources/Graphaello/Processing/Pipeline/Component/1. Extraction/SubExtractors/Implementations/BasicPropertyExtractor.swift +++ b/Sources/Graphaello/Processing/Pipeline/Component/1. Extraction/SubExtractors/Implementations/BasicPropertyExtractor.swift @@ -21,8 +21,7 @@ struct BasicPropertyExtractor: PropertyExtractor { return Property(code: code, name: try code.name(), - type: finalType.map { .concrete($0) } ?? .inferred, - usr: try code.usr()) { + type: finalType.map { .concrete($0) } ?? .inferred) { .attributes ~> attributes } diff --git a/Sources/Graphaello/Processing/Pipeline/Component/4. Resolution/SubResolvers/Implementations/Resolving Struct/PropertyResolver.swift b/Sources/Graphaello/Processing/Pipeline/Component/4. Resolution/SubResolvers/Implementations/Resolving Struct/PropertyResolver.swift index 9dfd6a3..55fe18c 100644 --- a/Sources/Graphaello/Processing/Pipeline/Component/4. Resolution/SubResolvers/Implementations/Resolving Struct/PropertyResolver.swift +++ b/Sources/Graphaello/Processing/Pipeline/Component/4. Resolution/SubResolvers/Implementations/Resolving Struct/PropertyResolver.swift @@ -9,14 +9,14 @@ struct PropertyResolver: ValueResolver where Resolver.P using context: StructResolution.Context) throws -> StructResolution.Result> { guard let path = value.graphqlPath else { - return .resolved(Property(code: value.code, name: value.name, type: value.type, usr: value.usr, graphqlPath: nil)) + return .resolved(Property(code: value.code, name: value.name, type: value.type, graphqlPath: nil)) } return try locateErrors(with: path.parsed.extracted.code.location) { return try resolver .resolve(value: path, in: value, using: context) .map { path in - Property(code: value.code, name: value.name, type: value.type, usr: value.usr, graphqlPath: path) + Property(code: value.code, name: value.name, type: value.type, graphqlPath: path) } } } diff --git a/Sources/Graphaello/Processing/Pipeline/Diagnostics/UnusedWarningDiagnoser.swift b/Sources/Graphaello/Processing/Pipeline/Diagnostics/UnusedWarningDiagnoser.swift index 653f023..b5e7738 100644 --- a/Sources/Graphaello/Processing/Pipeline/Diagnostics/UnusedWarningDiagnoser.swift +++ b/Sources/Graphaello/Processing/Pipeline/Diagnostics/UnusedWarningDiagnoser.swift @@ -15,34 +15,13 @@ struct UnusedWarningDiagnoser: WarningDiagnoser { } private func diagnose(property: Property, from parsed: Struct) throws -> [Warning] { - guard property.graphqlPath != nil else { return [] } + guard property.graphqlPath != nil, + property.name != "id" else { return [] } + let verifier = UsageVerifier(property: property) + let syntax = try parsed.code.syntaxTree() - let path = property.code.location.file.absoluteURL.path - let arguments = ["-sdk", sdkPath(), "-j4", path] - - let request: SourceKitObject = [ - "key.request": UID("source.request.editor.open"), - "key.name": path, - "key.sourcefile": path, - "key.annotated_decl": 1, - "key.fully_annotated_decl": 1, - "key.compilerargs": arguments, - ] - let info = try Request.customRequest(request: request).send() - - var verifier = UsageVerifier(property: property) - -// for substructure in try parsed.code.substructure() { -// switch try substructure.kind() { -// case .varInstance: -//// verifier.verify(syntax: try substructure.syntaxTree()) -// case .functionMethodInstance: -//// verifier.verify(syntax: try substructure.syntaxTree()) -// default: -// break -// } -// } + verifier.walk(syntax) guard !verifier.isUsed else { return [] } return [Warning(location: property.code.location, @@ -50,525 +29,20 @@ struct UnusedWarningDiagnoser: WarningDiagnoser { } } -struct UsageVerifier { +class UsageVerifier: SyntaxVisitor { let property: Property private(set) var shouldUseSelf = false private(set) var isUsed = false - mutating func verify(syntax: SyntaxProtocol) { - verify(syntax: syntax._syntaxNode) + init(property: Property) { + self.property = property + super.init() } - mutating func verify(syntax: Syntax) { - guard !isUsed else { return } - - let asEnum = syntax.as(SyntaxEnum.self) - switch asEnum { - case .unknown: - return - case .token: - return - case .decl(let decl): - print(decl) - case .expr(let expr): - print(expr) - case .stmt(let stmt): - print(stmt) - case .type: - return - case .pattern(let pattern): - print(pattern) - case .unknownDecl(let decl): - print(decl) - case .unknownExpr(let expr): - print(expr) - case .unknownStmt(let stmt): - print(stmt) - case .unknownType: - return - case .unknownPattern(let pattern): - print(pattern) - case .codeBlockItem(let item): - print(item) - case .codeBlockItemList(let list): - for item in list { - verify(syntax: item) - } - case .codeBlock(let block): - print(block) - case .inOutExpr: - return - case .poundColumnExpr(let expr): - print(expr) - case .tupleExprElementList(let tuple): - print(tuple) - case .arrayElementList(let arrayElementList): - print(arrayElementList) - case .dictionaryElementList(let dictionaryElementList): - print(dictionaryElementList) - case .stringLiteralSegments(let segments): - print(segments) - case .tryExpr(let expr): - print(expr) - case .declNameArgument(let decl): - print(decl) - case .declNameArgumentList(let list): - for item in list { - verify(syntax: item) - } - case .declNameArguments(let list): - print(list) - case .identifierExpr(let identifier): - print(identifier) - case .superRefExpr: - return - case .nilLiteralExpr: - return - case .discardAssignmentExpr: - return - case .assignmentExpr(let assignment): - print(assignment) - case .sequenceExpr(let sequence): - print(sequence) - case .exprList(let list): - for item in list { - verify(syntax: item) - } - case .poundLineExpr(let expr): - print(expr) - case .poundFileExpr(let expr): - print(expr) - case .poundFileIDExpr(let expr): - print(expr) - case .poundFilePathExpr(let expr): - print(expr) - case .poundFunctionExpr(let expr): - print(expr) - case .poundDsohandleExpr(let expr): - print(expr) - case .symbolicReferenceExpr(let expr): - print(expr) - case .prefixOperatorExpr(let expr): - print(expr) - case .binaryOperatorExpr(let expr): - print(expr) - case .arrowExpr(let expr): - print(expr) - case .floatLiteralExpr(let expr): - print(expr) - case .tupleExpr(let expr): - print(expr) - case .arrayExpr(let expr): - print(expr) - case .dictionaryExpr(let expr): - print(expr) - case .tupleExprElement(let expr): - print(expr) - case .arrayElement(let expr): - print(expr) - case .dictionaryElement(let expr): - print(expr) - case .integerLiteralExpr(let expr): - print(expr) - case .booleanLiteralExpr(let expr): - print(expr) - case .ternaryExpr(let expr): - print(expr) - case .memberAccessExpr(let expr): - print(expr) - case .isExpr(let expr): - print(expr) - case .asExpr(let expr): - print(expr) - case .typeExpr(let expr): - print(expr) - case .closureCaptureItem(let expr): - print(expr) - case .closureCaptureItemList(let list): - for item in list { - verify(syntax: item) - } - case .closureCaptureSignature(let expr): - print(expr) - case .closureParam(let expr): - print(expr) - case .closureParamList(let expr): - print(expr) - case .closureSignature(let expr): - print(expr) - case .closureExpr(let expr): - print(expr) - case .unresolvedPatternExpr(let expr): - print(expr) - case .multipleTrailingClosureElement(let expr): - print(expr) - case .multipleTrailingClosureElementList(let expr): - print(expr) - case .functionCallExpr(let expr): - print(expr) - case .subscriptExpr(let expr): - print(expr) - case .optionalChainingExpr(let expr): - print(expr) - case .forcedValueExpr(let expr): - print(expr) - case .postfixUnaryExpr(let expr): - print(expr) - case .specializeExpr(let expr): - print(expr) - case .stringSegment(let expr): - print(expr) - case .expressionSegment(let expr): - print(expr) - case .stringLiteralExpr(let expr): - print(expr) - case .keyPathExpr(let expr): - print(expr) - case .keyPathBaseExpr(let expr): - print(expr) - case .objcNamePiece(let expr): - print(expr) - case .objcName(let expr): - print(expr) - case .objcKeyPathExpr(let expr): - print(expr) - case .objcSelectorExpr(let expr): - print(expr) - case .editorPlaceholderExpr(let expr): - print(expr) - case .objectLiteralExpr(let expr): - print(expr) - case .typeInitializerClause(let expr): - print(expr) - case .typealiasDecl(let expr): - print(expr) - case .associatedtypeDecl(let expr): - print(expr) - case .functionParameterList(let list): - for item in list { - verify(syntax: item) - } - case .parameterClause(let expr): - print(expr) - case .returnClause(let expr): - print(expr) - case .functionSignature(let expr): - print(expr) - case .ifConfigClause(let expr): - print(expr) - case .ifConfigClauseList(let expr): - print(expr) - case .ifConfigDecl(let expr): - print(expr) - case .poundErrorDecl(let expr): - print(expr) - case .poundWarningDecl(let expr): - print(expr) - case .poundSourceLocation(let expr): - print(expr) - case .poundSourceLocationArgs(let expr): - print(expr) - case .declModifier(let expr): - print(expr) - case .inheritedType(let expr): - print(expr) - case .inheritedTypeList(let expr): - print(expr) - case .typeInheritanceClause(let expr): - print(expr) - case .classDecl(let expr): - print(expr) - case .structDecl(let expr): - print(expr) - case .protocolDecl(let expr): - print(expr) - case .extensionDecl(let expr): - print(expr) - case .memberDeclBlock(let expr): - print(expr) - case .memberDeclList(let list): - for item in list { - verify(syntax: item) - } - case .memberDeclListItem(let expr): - print(expr) - case .sourceFile(let file): - for item in file.statements { - verify(syntax: item) - } - case .initializerClause(let expr): - print(expr) - case .functionParameter(let expr): - print(expr) - case .modifierList: - return - case .functionDecl(let expr): - print(expr) - case .initializerDecl(let expr): - print(expr) - case .deinitializerDecl(let expr): - print(expr) - case .subscriptDecl(let expr): - print(expr) - case .accessLevelModifier(let expr): - print(expr) - case .accessPathComponent(let expr): - print(expr) - case .accessPath(let expr): - print(expr) - case .importDecl: - return - case .accessorParameter(let expr): - print(expr) - case .accessorDecl(let expr): - print(expr) - case .accessorList(let list): - for item in list { - verify(syntax: list) - } - case .accessorBlock(let expr): - print(expr) - case .patternBinding(let expr): - print(expr) - case .patternBindingList(let list): - for item in list { - verify(syntax: item) - } - case .variableDecl(let expr): - print(expr) - case .enumCaseElement(let expr): - print(expr) - case .enumCaseElementList(let expr): - print(expr) - case .enumCaseDecl(let expr): - print(expr) - case .enumDecl(let expr): - print(expr) - case .operatorDecl(let expr): - print(expr) - case .identifierList(let list): - for item in list { - verify(syntax: item) - } - case .operatorPrecedenceAndTypes: - return - case .precedenceGroupDecl: - return - case .precedenceGroupAttributeList: - return - case .precedenceGroupRelation: - return - case .precedenceGroupNameList: - return - case .precedenceGroupNameElement: - return - case .precedenceGroupAssignment: - return - case .precedenceGroupAssociativity: - return - case .tokenList(let expr): - print(expr) - case .nonEmptyTokenList(let expr): - print(expr) - case .customAttribute(let expr): - print(expr) - case .attribute(let expr): - print(expr) - case .attributeList(let expr): - print(expr) - case .specializeAttributeSpecList(let expr): - print(expr) - case .labeledSpecializeEntry(let expr): - print(expr) - case .namedAttributeStringArgument(let expr): - print(expr) - case .declName(let expr): - print(expr) - case .implementsAttributeArguments(let expr): - print(expr) - case .objCSelectorPiece(let expr): - print(expr) - case .objCSelector(let expr): - print(expr) - case .differentiableAttributeArguments(let expr): - print(expr) - case .differentiabilityParamsClause(let expr): - print(expr) - case .differentiabilityParams(let expr): - print(expr) - case .differentiabilityParamList(let expr): - print(expr) - case .differentiabilityParam(let expr): - print(expr) - case .derivativeRegistrationAttributeArguments(let expr): - print(expr) - case .qualifiedDeclName(let expr): - print(expr) - case .functionDeclName(let expr): - print(expr) - case .continueStmt(let expr): - print(expr) - case .whileStmt(let expr): - print(expr) - case .deferStmt(let expr): - print(expr) - case .expressionStmt(let expr): - print(expr) - case .switchCaseList(let expr): - print(expr) - case .repeatWhileStmt(let expr): - print(expr) - case .guardStmt(let expr): - print(expr) - case .whereClause(let expr): - print(expr) - case .forInStmt(let expr): - print(expr) - case .switchStmt(let expr): - print(expr) - case .catchClauseList(let expr): - print(expr) - case .doStmt(let expr): - print(expr) - case .returnStmt(let expr): - print(expr) - case .yieldStmt(let expr): - print(expr) - case .yieldList(let expr): - print(expr) - case .fallthroughStmt(let expr): - print(expr) - case .breakStmt(let expr): - print(expr) - case .caseItemList(let expr): - print(expr) - case .catchItemList(let expr): - print(expr) - case .conditionElement(let expr): - print(expr) - case .availabilityCondition(let expr): - print(expr) - case .matchingPatternCondition(let expr): - print(expr) - case .optionalBindingCondition(let expr): - print(expr) - case .conditionElementList(let expr): - print(expr) - case .declarationStmt(let expr): - print(expr) - case .throwStmt(let expr): - print(expr) - case .ifStmt(let expr): - print(expr) - case .elseIfContinuation(let expr): - print(expr) - case .elseBlock(let expr): - print(expr) - case .switchCase(let expr): - print(expr) - case .switchDefaultLabel(let expr): - print(expr) - case .caseItem(let expr): - print(expr) - case .catchItem(let expr): - print(expr) - case .switchCaseLabel(let expr): - print(expr) - case .catchClause(let expr): - print(expr) - case .poundAssertStmt(let expr): - print(expr) - case .genericWhereClause(_): - return - case .genericRequirementList(_): - return - case .genericRequirement(_): - return - case .sameTypeRequirement(_): - return - case .genericParameterList(_): - return - case .genericParameter(_): - return - case .genericParameterClause(_): - return - case .conformanceRequirement(_): - return - case .simpleTypeIdentifier(_): - return - case .memberTypeIdentifier(_): - return - case .classRestrictionType(_): - return - case .arrayType(_): - return - case .dictionaryType(_): - return - case .metatypeType(_): - return - case .optionalType(_): - return - case .someType(_): - return - case .implicitlyUnwrappedOptionalType(_): - return - case .compositionTypeElement(_): - return - case .compositionTypeElementList(_): - return - case .compositionType(_): - return - case .tupleTypeElement(_): - return - case .tupleTypeElementList(_): - return - case .tupleType(_): - return - case .functionType(_): - return - case .attributedType(_): - return - case .genericArgumentList(_): - return - case .genericArgument(_): - return - case .genericArgumentClause(_): - return - case .typeAnnotation(let expr): - print(expr) - case .enumCasePattern(let expr): - print(expr) - case .isTypePattern(let expr): - print(expr) - case .optionalPattern(let expr): - print(expr) - case .identifierPattern(let expr): - print(expr) - case .asTypePattern(let expr): - print(expr) - case .tuplePattern(let expr): - print(expr) - case .wildcardPattern(let expr): - print(expr) - case .tuplePatternElement(let expr): - print(expr) - case .expressionPattern(let expr): - print(expr) - case .tuplePatternElementList(let expr): - print(expr) - case .valueBindingPattern(let expr): - print(expr) - case .availabilitySpecList(let expr): - print(expr) - case .availabilityArgument(let expr): - print(expr) - case .availabilityLabeledArgument(let expr): - print(expr) - case .availabilityVersionRestriction(let expr): - print(expr) - case .versionTuple(let expr): - print(expr) + override func visitPost(_ node: IdentifierExprSyntax) { + if node.identifier.text == property.name { + isUsed = true } } } diff --git a/Sources/Graphaello/Processing/Pipeline/Stage/GraphQLStage.swift b/Sources/Graphaello/Processing/Pipeline/Stage/GraphQLStage.swift index e1a06be..a0f35b7 100644 --- a/Sources/Graphaello/Processing/Pipeline/Stage/GraphQLStage.swift +++ b/Sources/Graphaello/Processing/Pipeline/Stage/GraphQLStage.swift @@ -15,8 +15,8 @@ extension Property where CurrentStage: GraphQLStage { extension Property where CurrentStage: GraphQLStage { - init(code: SourceCode, name: String, type: PropertyType, usr: String, graphqlPath: CurrentStage.Path?) { - self.init(code: code, name: name, type: type, usr: usr) { CurrentStage.pathKey ~> graphqlPath } + init(code: SourceCode, name: String, type: PropertyType, graphqlPath: CurrentStage.Path?) { + self.init(code: code, name: name, type: type) { CurrentStage.pathKey ~> graphqlPath } } }